@htmlbricks/hb-player-live 0.71.35 → 0.71.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +171 -19
  2. package/manifest.json +22 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,37 +1,136 @@
1
- ## `hb-player-live` — player live
1
+ # `hb-player-live`
2
2
 
3
3
  **Category:** media
4
4
  **Tags:** media, video, streaming
5
5
 
6
- ### What it does
6
+ Live streaming player built on a native `<video>` element. It supports **HLS** (via [hls.js](https://github.com/video-dev/hls.js/) when Media Source Extensions are available, or the browser’s built-in HLS where supported), **WebRTC over WebSocket** ([`simple-webrtc-element`](https://www.npmjs.com/package/simple-webrtc-element)), and **WHEP** ([`MediaMTXWebRTCReader`](https://www.npmjs.com/package/simple-webrtc-element-whep) for MediaMTX-style endpoints).
7
7
 
8
- Live streaming `<video>` player for HLS (hls.js or native), WebSocket WebRTC (`simple-webrtc-element`), or WHEP (MediaMTX). Polls the manifest for HLS liveness, exposes the element via `getVideoElement`, and emits `liveStatus` and `htmlVideoInit`. When the stream is offline or missing, shows optional title/subtitle/text from `replacewithtext`, `forcecover`, or fallback labels.
8
+ For **HLS**, the component periodically **fetches the manifest URL** to decide whether the source is reachable (“live” for overlay purposes). For **WebRTC** and **WHEP**, **online/offline** is driven by the underlying player callbacks, which also update `liveStatus`.
9
9
 
10
- ### Custom element
10
+ When the URI is missing, the stream is considered offline, or you force a cover state, the component can show a **full-area overlay** (default copy, `replacewithtext` JSON, and optional slots).
11
+
12
+ ---
13
+
14
+ ## Custom element
11
15
 
12
16
  `hb-player-live`
13
17
 
14
- ### Attributes (snake_case; use string values in HTML)
18
+ ---
19
+
20
+ ## Attributes (snake_case; string values in HTML)
21
+
22
+ Web component attributes are always strings. Use **`yes`** / **`no`** for boolean-like flags where noted. Pass **JSON as a single string** for object props (for example `replacewithtext='{"title":"…"}'`).
23
+
24
+ | Attribute | Required | Description |
25
+ | --- | --- | --- |
26
+ | `mediauri` | Yes | Stream endpoint: HLS playlist (`.m3u8`), WebSocket signaling URL for `webrtc`, or WHEP URL for `whep`. Use an empty string if you intentionally have no URI (placeholder state). |
27
+ | `media_type` | No | Playback mode: `hls`, `webrtc`, `whep`, or `auto` (see [Media type](#media-type)). Default in the implementation is `auto`. The `<video>` node is only rendered when both `mediauri` and `media_type` are non-empty. |
28
+ | `forcecover` | No | Any non-empty value (commonly `yes`) forces the structured overlay when the conditions in the template are met (together with `replacewithtext` shape). |
29
+ | `replacewithtext` | No | JSON string: `{ "title": string, "subtitle"?: string, "text"?: string }`. Used for default overlay copy; the component also parses a string value into an object when possible. |
30
+ | `no_controls` | No | Hide native `<video>` controls when set to any truthy value except the strings `no` or `false` (for example `yes`). |
31
+ | `id` | No | Passed through on custom events and when exposing the video element. |
32
+
33
+ The authoring `Component` type also allows `style`; styling is normally done via CSS variables, `::part`, and host layout.
34
+
35
+ ---
36
+
37
+ ## Media type
38
+
39
+ Set `media_type` explicitly for working playback:
40
+
41
+ - **`hls`** — Loads `mediauri` with hls.js (or assigns `src` on Safari / browsers that report native HLS support). Autoplay is attempted with **muted** video.
42
+ - **`webrtc`** — Uses `simple-webrtc-element` with `wsUri: mediauri` on the bound `<video>`.
43
+ - **`whep`** — Uses `MediaMTXWebRTCReader` with `url: mediauri`; the first stream track is assigned to `video.srcObject`.
44
+
45
+ The literal value **`auto`** appears in the public type union and is the Svelte default, but the internal `setVideo` path only wires **`hls`**, **`webrtc`**, and **`whep`**. Treat **`auto`** as reserved / not implemented for playback until a future version adds detection.
46
+
47
+ ---
48
+
49
+ ## Live status and polling
50
+
51
+ - **`hls`**: `loadLive()` performs a `fetch(mediauri)` on the manifest. A response in the **1xx–299** range sets internal “live” to true and dispatches `liveStatus` with `live: true`. On failure, it dispatches `live: false` and **retries after 5 seconds** (also when `mediauri` is empty).
52
+ - **`webrtc` / `whep`**: `liveStatus` is dispatched from **online/offline** handlers in the respective integrations (`live: true` / `live: false`).
53
+
54
+ ---
55
+
56
+ ## Overlay and fallback UI
57
+
58
+ The dark **16:9** surface uses Bulma variables `--bulma-dark` and `--bulma-dark-invert` (see [Styling](#styling)).
59
+
60
+ Rough behavior (see `component.wc.svelte` for exact conditions):
61
+
62
+ 1. **`forcecover`** is set, or **`mediauri` is set**, **`isLive` is false**, and **`replacewithtext`** includes at least one of `title`, `subtitle`, or `text` — shows the **`replacewithtext`** part with the **default slot layout** (one, two, or three lines depending on which JSON fields are present), unless you override the `replacewithtext` slot entirely.
63
+ 2. Otherwise, if there is a **`mediauri`** but the stream is **not live** and there is **no** `replacewithtext` copy — shows the literal **`offline`** label in the overlay.
64
+ 3. If there is **no `mediauri`** — shows **`nouri`** in the overlay.
65
+
66
+ If you supply the **`replacewithtext`** slot, you replace the entire default overlay markup for that branch; the inner slots (`replacetitle`, `replacesubtitle`, `replacetext`) only apply inside the **default** structure.
67
+
68
+ ---
69
+
70
+ ## Events
71
+
72
+ Listen with `addEventListener` on the host element (names are camelCase in the type definitions).
73
+
74
+ | Event | `detail` (runtime) |
75
+ | --- | --- |
76
+ | `liveStatus` | `{ live: boolean; id: string }` |
77
+ | `htmlVideoInit` | `{ htmlVideoElement: HTMLVideoElement; id: string }` — fired when the `<video>` is bound. The authoring `Events` type may use a `video` field name; the implementation uses **`htmlVideoElement`**. |
78
+
79
+ ---
80
+
81
+ ## Host API
82
+
83
+ After upgrade, the custom element exposes:
84
+
85
+ - **`getVideoElement()`** — Returns the internal `HTMLVideoElement` when it exists, otherwise `undefined`.
86
+
87
+ ---
88
+
89
+ ## Styling (CSS custom properties)
90
+
91
+ Set on the host or an ancestor. The video frame and overlay use Bulma dark tokens.
92
+
93
+ | Variable | Role |
94
+ | --- | --- |
95
+ | `--bulma-dark` | Background of the 16:9 video area and offline/cover overlay. |
96
+ | `--bulma-dark-invert` | Foreground (text) on that surface. |
97
+
98
+ See [Bulma CSS variables](https://bulma.io/documentation/features/css-variables/) for theme-wide tuning.
15
99
 
16
- - `id`, `style` (optional): strings.
17
- - `mediauri` (required): string — stream URL (HLS, WebRTC, WHEP as configured).
18
- - `media_type` (optional): `"hls"` | `"webrtc"` | `"auto"` | `"whep"` (empty string allowed in examples).
19
- - `forcecover` (optional): string — e.g. `"yes"` to force cover layout with placeholder text.
20
- - `replacewithtext` (optional): JSON string — `{ title; subtitle?; text? }` when offline.
21
- - `no_controls` (optional): boolean string — hide native/custom controls.
100
+ ---
22
101
 
23
- ### Events
102
+ ## CSS parts (`::part(...)`)
24
103
 
25
- - `liveStatus`: `{ live: boolean; id: string }`.
26
- - `htmlVideoInit`: `{ video; id: string }`.
104
+ | Part | Purpose |
105
+ | --- | --- |
106
+ | `container` | Root wrapper around the player and overlay; sizing and positioning of the whole component. |
107
+ | `replacewithtext` | Full-bleed overlay when the stream is missing, not live, `forcecover` applies, or placeholder copy is shown. |
108
+ | `video` | The native `<video>` element (streaming surface, native controls when enabled). |
27
109
 
28
- ### Usage notes
110
+ ---
29
111
 
30
- - **CSS parts:** `container`, `replacewithtext`, `video`.
31
- - **Slots:** `replacewithtext` (wrapper when stream is covered/offline), `replacetitle`, `replacesubtitle`, `replacetext` — override fallback copy (still combined with `replacewithtext` / `forcecover` props when unset).
32
- - Pick `media_type` to match your pipeline (`whep` for WHEP examples in docs).
112
+ ## HTML slots
33
113
 
34
- ### Minimal HTML example
114
+ | Slot | When it matters | Purpose |
115
+ | --- | --- | --- |
116
+ | `replacewithtext` | Overlay branch with default structure | Replace the entire offline/cover layout. If you fill this slot, the default grid and nested slots are not used unless you reintroduce them in your markup. |
117
+ | `replacetitle` | Default overlay only | Title line; falls back to `replacewithtext.title`. |
118
+ | `replacesubtitle` | Default overlay (two- or three-line layout) | Subtitle line; falls back to `replacewithtext.subtitle` when the prop defines both title and subtitle. |
119
+ | `replacetext` | Default three-line layout | Body copy; falls back to `replacewithtext.text`. |
120
+
121
+ ---
122
+
123
+ ## Usage notes
124
+
125
+ - **Autoplay**: The implementation sets **`muted`** and calls **`play()`** where possible; browser policies may still block autoplay with sound or without user gesture.
126
+ - **Changing `mediauri`**: When the URI changes, WHEP readers are closed, live state is reset, and the video is reinitialized.
127
+ - **Accessibility**: The markup includes a captions `<track>` placeholder; provide real captions/tracks in your integration if you need accessibility compliance.
128
+
129
+ ---
130
+
131
+ ## Examples
132
+
133
+ **HLS (public test stream)**
35
134
 
36
135
  ```html
37
136
  <hb-player-live
@@ -39,3 +138,56 @@ Live streaming `<video>` player for HLS (hls.js or native), WebSocket WebRTC (`s
39
138
  media_type="hls"
40
139
  ></hb-player-live>
41
140
  ```
141
+
142
+ **WHEP endpoint** (replace with your server URL)
143
+
144
+ ```html
145
+ <hb-player-live
146
+ mediauri="https://example.com/path/to/whep"
147
+ media_type="whep"
148
+ ></hb-player-live>
149
+ ```
150
+
151
+ **Forced cover with JSON copy** (`replacewithtext` must be a valid JSON string attribute)
152
+
153
+ ```html
154
+ <hb-player-live
155
+ mediauri="https://example.com/stream/whep"
156
+ media_type="whep"
157
+ forcecover="yes"
158
+ replacewithtext='{"title":"Stream paused","subtitle":"We will be back soon","text":"Thank you for waiting."}'
159
+ ></hb-player-live>
160
+ ```
161
+
162
+ **Hide native controls**
163
+
164
+ ```html
165
+ <hb-player-live
166
+ mediauri="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"
167
+ media_type="hls"
168
+ no_controls="yes"
169
+ ></hb-player-live>
170
+ ```
171
+
172
+ **Listen for live state and grab the video element**
173
+
174
+ ```html
175
+ <hb-player-live
176
+ id="cam1"
177
+ mediauri="https://example.com/live.m3u8"
178
+ media_type="hls"
179
+ ></hb-player-live>
180
+ <script>
181
+ const el = document.querySelector("#cam1");
182
+ el.addEventListener("liveStatus", (e) => {
183
+ console.log(e.detail.live, e.detail.id);
184
+ });
185
+ el.addEventListener("htmlVideoInit", (e) => {
186
+ console.log(e.detail.htmlVideoElement, e.detail.id);
187
+ });
188
+ customElements.whenDefined("hb-player-live").then(() => {
189
+ const v = el.getVideoElement?.();
190
+ if (v) console.log("video", v);
191
+ });
192
+ </script>
193
+ ```
package/manifest.json CHANGED
@@ -146,19 +146,32 @@
146
146
  }
147
147
  },
148
148
  "styleSetup": {
149
- "vars": [],
149
+ "vars": [
150
+ {
151
+ "name": "--bulma-dark",
152
+ "valueType": "color",
153
+ "defaultValue": "",
154
+ "description": "Background of the 16:9 video area and offline/cover overlay; pair with `--bulma-dark-invert` for readable contrast."
155
+ },
156
+ {
157
+ "name": "--bulma-dark-invert",
158
+ "valueType": "color",
159
+ "defaultValue": "",
160
+ "description": "Foreground (text) color on the dark video/placeholder surface."
161
+ }
162
+ ],
150
163
  "parts": [
151
164
  {
152
165
  "name": "container",
153
- "description": ""
166
+ "description": "Root wrapper around the player and overlay; use for layout, sizing, or positioning the whole component."
154
167
  },
155
168
  {
156
169
  "name": "replacewithtext",
157
- "description": ""
170
+ "description": "Full-bleed overlay shown when `forcecover` is set, the stream is not live, or there is no URI; contains default copy or slotted content."
158
171
  },
159
172
  {
160
173
  "name": "video",
161
- "description": ""
174
+ "description": "The native `<video>` element (HLS / WebRTC / WHEP); style dimensions, object-fit, or controls appearance from the host page."
162
175
  }
163
176
  ]
164
177
  },
@@ -166,19 +179,19 @@
166
179
  "htmlSlots": [
167
180
  {
168
181
  "name": "replacewithtext",
169
- "description": "Custom block when the stream is unavailable or covered (wraps title/subtitle/text slots)."
182
+ "description": "Replaces the entire offline/cover layout when shown. Use for custom markup; inner slots (`replacetitle`, `replacesubtitle`, `replacetext`) only apply inside the default structure when you do not override this slot."
170
183
  },
171
184
  {
172
185
  "name": "replacetitle",
173
- "description": "Title inside the replace-with-text block."
186
+ "description": "Heading line in the default overlay; falls back to `replacewithtext.title` from the JSON prop when empty."
174
187
  },
175
188
  {
176
189
  "name": "replacesubtitle",
177
- "description": "Subtitle inside the replace-with-text block."
190
+ "description": "Secondary line in the default overlay; falls back to `replacewithtext.subtitle` when empty (only when both title and subtitle are defined in props)."
178
191
  },
179
192
  {
180
193
  "name": "replacetext",
181
- "description": "Body text inside the replace-with-text block."
194
+ "description": "Body copy in the default overlay; falls back to `replacewithtext.text` when empty (three-line layout only)."
182
195
  }
183
196
  ],
184
197
  "i18n": [],
@@ -264,5 +277,5 @@
264
277
  "size": {},
265
278
  "iifePath": "main.iife.js",
266
279
  "repoName": "@htmlbricks/hb-player-live",
267
- "version": "0.71.35"
280
+ "version": "0.71.36"
268
281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlbricks/hb-player-live",
3
- "version": "0.71.35",
3
+ "version": "0.71.36",
4
4
  "contributors": [],
5
5
  "description": "Live streaming `<video>` player for HLS (hls.js or native), WebSocket WebRTC (`simple-webrtc-element`), or WHEP (MediaMTX). Polls the manifest for HLS liveness, exposes the element via `getVideoElement`, and emits `liveStatus` and `htmlVideoInit`. When the stream is offline or missing, shows optional title/subtitle/text from `replacewithtext`, `forcecover`, or fallback labels.",
6
6
  "licenses": [