@banou/media-player 0.8.19 → 0.8.20

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.
package/README.md CHANGED
@@ -138,6 +138,64 @@ its published name so it stays an honest consumer.
138
138
  Built by `vite.config.ts` into `build/`.
139
139
  - `src/lib/engine/` the pipeline, with no React in it: MediaSource feeding, remux, jassub, thumbnails.
140
140
  Published as `@banou/media-player/engine`.
141
+ - `src/lib/remote` is the player driven from ANOTHER document, over [osra](https://osra.banou.dev).
142
+ Published as `@banou/media-player/remote`.
143
+
144
+ In the document that renders the player, one prop serves it to whoever frames that document,
145
+ and only to them, or to a named origin:
146
+
147
+ ```tsx
148
+ <MediaPlayer expose read={read} size={size} publicPath="/" {...workers} />
149
+ <MediaPlayer expose={{ origin: 'https://anime.fkn.app' }} media={media} />
150
+ ```
151
+
152
+ A document that serves more than one player gives each an id, and an embedder asks for the one it
153
+ wants:
154
+
155
+ ```tsx
156
+ <MediaPlayer expose={{ id: 'left' }} {...left} />
157
+ <MediaPlayer expose={{ id: 'right' }} {...right} />
158
+ ```
159
+
160
+ ```ts
161
+ const left = mediaPlayer(iframe, { id: 'left', origin })
162
+ const right = mediaPlayer(iframe, { id: 'right', origin })
163
+ ```
164
+
165
+ Both sides default to one unnamed player, so a document with one never says it. Whatever the count,
166
+ it is ONE connection per document in each direction: the ids multiplex over it, serving an id twice
167
+ replaces that player (which is how a source switch is followed), and asking for an id nobody serves
168
+ yet simply waits until somebody does.
169
+
170
+ In the embedder, `mediaPlayer` hands back a media of its own, the same `PlayerMedia` shape the
171
+ player drives, so it reads, moves, listens and can even be handed to a second `<MediaPlayer>`:
172
+
173
+ ```ts
174
+ import { mediaPlayer } from '@banou/media-player/remote'
175
+
176
+ const player = mediaPlayer(iframe, { origin: 'https://torrent.fkn.app' })
177
+ await player.ready
178
+ await player.play()
179
+ player.currentTime = 30
180
+ player.addEventListener('seeked', () => console.log(player.currentTime))
181
+ player.destroy()
182
+ ```
183
+
184
+ `play()` settles with the far element's own answer and rejects if the mirror is destroyed while it
185
+ is in flight, the way an element's rejects on an interrupted play, so await it or catch it;
186
+ `pause()` and `load()` swallow theirs.
187
+
188
+ Reads are synchronous because the far side is mirrored: every event over there arrives with a
189
+ snapshot, and a write moves the mirror at once before going out to be applied. `play()` settles
190
+ with the far element's own answer, so an autoplay refusal there rejects here. `ready` stays pending
191
+ while nobody answers and rejects on `destroy()` or an aborted `signal`; a `MessagePort` whose peer
192
+ has gone raises no event, so nothing can tell a dead transport from a slow one and the wait has to
193
+ be bounded rather than waited out. Use `signal` for the player's whole lifetime, or
194
+ `Promise.race([player.ready, timeout])` for the wait alone.
195
+ A player that switches sources, or a player document that reloads, is followed: the mirror reports
196
+ `emptied` and then the new state, the way an element would. Hand a remote player to a second
197
+ `<MediaPlayer media={player}>` after `ready`. A document served with no frame around it serves
198
+ nobody; `exposePlayer(media)` does the same without React.
141
199
  - `src/lib/react/` the player component, its chrome, and the hooks.
142
200
 
143
201
  Built by `vite.lib.config.ts` into `dist/`, which is what npm publishes.