@banou/media-player 0.0.3 → 0.2.1
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/build/chrome/bottom.d.ts +1 -1
- package/build/chrome/index.d.ts +1 -1
- package/build/chrome/overlay.d.ts +1 -1
- package/build/index.d.ts +3 -3
- package/build/index.js +1789 -1711
- package/build/utils.d.ts +3 -4
- package/package.json +5 -6
- package/src/index.tsx +137 -271
- package/src/main.tsx +10 -56
- package/src/utils.ts +135 -280
package/src/utils.ts
CHANGED
|
@@ -7,6 +7,38 @@ export type Chunk = {
|
|
|
7
7
|
buffered: boolean
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export function debounceImmediateAndLatest<T extends (...args: any[]) => any>(
|
|
11
|
+
wait: number,
|
|
12
|
+
func: T
|
|
13
|
+
): T {
|
|
14
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
15
|
+
let lastArgs: any[] | null = null;
|
|
16
|
+
|
|
17
|
+
const debouncedFunction = function(...args: any[]) {
|
|
18
|
+
const context = this;
|
|
19
|
+
|
|
20
|
+
if (timeoutId === null) {
|
|
21
|
+
// Call immediately on the first call
|
|
22
|
+
func.apply(context, args);
|
|
23
|
+
} else {
|
|
24
|
+
// Store the latest arguments for the last call
|
|
25
|
+
lastArgs = args;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
clearTimeout(timeoutId as ReturnType<typeof setTimeout>);
|
|
29
|
+
|
|
30
|
+
timeoutId = setTimeout(() => {
|
|
31
|
+
if (lastArgs) {
|
|
32
|
+
func.apply(context, lastArgs);
|
|
33
|
+
lastArgs = null;
|
|
34
|
+
}
|
|
35
|
+
timeoutId = null;
|
|
36
|
+
}, wait);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return debouncedFunction as T;
|
|
40
|
+
}
|
|
41
|
+
|
|
10
42
|
export const queuedDebounceWithLastCall = <T2 extends any[], T extends (...args: T2) => any>(time: number, func: T) => {
|
|
11
43
|
let runningFunction: Promise<ReturnType<T>> | undefined
|
|
12
44
|
let lastCall: Promise<ReturnType<T>> | undefined
|
|
@@ -84,63 +116,6 @@ export const queuedDebounceWithLastCall = <T2 extends any[], T extends (...args:
|
|
|
84
116
|
}
|
|
85
117
|
}
|
|
86
118
|
|
|
87
|
-
// todo: reimplement this into a ReadableByteStream https://web.dev/streams/ once FF gets support
|
|
88
|
-
// todo: remove firefox workaround once https://bugzilla.mozilla.org/show_bug.cgi?id=1808868 ships
|
|
89
|
-
export const bufferStream = ({ stream, size: SIZE }: { stream: ReadableStream, size: number }) =>
|
|
90
|
-
new ReadableStream<Uint8Array>({
|
|
91
|
-
start() {
|
|
92
|
-
// @ts-expect-error
|
|
93
|
-
this.reader = stream.getReader()
|
|
94
|
-
},
|
|
95
|
-
async pull(controller) {
|
|
96
|
-
try {
|
|
97
|
-
// @ts-expect-error
|
|
98
|
-
const { leftOverData }: { leftOverData: Uint8Array | undefined } = this
|
|
99
|
-
|
|
100
|
-
const accumulate = async ({ buffer = new Uint8Array(SIZE), currentSize = 0 } = {}): Promise<{ buffer?: Uint8Array, currentSize?: number, done: boolean }> => {
|
|
101
|
-
// @ts-expect-error
|
|
102
|
-
const { value: newBuffer, done } = await this.reader.read()
|
|
103
|
-
|
|
104
|
-
if (currentSize === 0 && leftOverData) {
|
|
105
|
-
// console.log('currentSize', currentSize)
|
|
106
|
-
// console.log('buffer', buffer)
|
|
107
|
-
// console.log('leftOverData', leftOverData)
|
|
108
|
-
buffer.set(leftOverData)
|
|
109
|
-
currentSize += leftOverData.byteLength
|
|
110
|
-
// @ts-expect-error
|
|
111
|
-
this.leftOverData = undefined
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (done) {
|
|
115
|
-
return { buffer: buffer.slice(0, currentSize), currentSize, done }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let newSize
|
|
119
|
-
const slicedBuffer = newBuffer.slice(0, SIZE - currentSize)
|
|
120
|
-
newSize = currentSize + slicedBuffer.byteLength
|
|
121
|
-
buffer.set(slicedBuffer, currentSize)
|
|
122
|
-
|
|
123
|
-
if (newSize === SIZE) {
|
|
124
|
-
// @ts-expect-error
|
|
125
|
-
this.leftOverData = newBuffer.slice(SIZE - currentSize)
|
|
126
|
-
return { buffer, currentSize: newSize, done: false }
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return accumulate({ buffer, currentSize: newSize })
|
|
130
|
-
}
|
|
131
|
-
const { buffer, done } = await accumulate()
|
|
132
|
-
if (buffer?.byteLength) controller.enqueue(buffer)
|
|
133
|
-
if (done) controller.close()
|
|
134
|
-
} catch (err) {
|
|
135
|
-
console.error(err)
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
cancel() {
|
|
139
|
-
// @ts-expect-error
|
|
140
|
-
this.reader.cancel()
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
|
|
144
119
|
const getTimeRanges = (sourceBuffer: SourceBuffer) =>
|
|
145
120
|
Array(sourceBuffer.buffered.length)
|
|
146
121
|
.fill(undefined)
|
|
@@ -156,230 +131,110 @@ const getTimeRange =
|
|
|
156
131
|
getTimeRanges(sourceBuffer)
|
|
157
132
|
.find(({ start, end }) => time >= start && time <= end)
|
|
158
133
|
|
|
159
|
-
// const setupListeners = (sourceBuffer: SourceBuffer, resolve: (value: Event) => void, reject: (reason: Event) => void) => {
|
|
160
|
-
// const updateEndListener = (ev: Event) => {
|
|
161
|
-
// resolve(ev)
|
|
162
|
-
// unregisterListeners()
|
|
163
|
-
// }
|
|
164
|
-
// const abortListener = (ev: Event) => {
|
|
165
|
-
// resolve(ev)
|
|
166
|
-
// unregisterListeners()
|
|
167
|
-
// }
|
|
168
|
-
// const errorListener = (ev: Event) => {
|
|
169
|
-
// reject(ev),
|
|
170
|
-
// unregisterListeners()
|
|
171
|
-
// }
|
|
172
|
-
// const unregisterListeners = () => {
|
|
173
|
-
// sourceBuffer.removeEventListener('updateend', updateEndListener)
|
|
174
|
-
// sourceBuffer.removeEventListener('abort', abortListener)
|
|
175
|
-
// sourceBuffer.removeEventListener('error', errorListener)
|
|
176
|
-
// }
|
|
177
|
-
// sourceBuffer.addEventListener('updateend', updateEndListener, { once: true })
|
|
178
|
-
// sourceBuffer.addEventListener('abort', abortListener, { once: true })
|
|
179
|
-
// sourceBuffer.addEventListener('error', errorListener, { once: true })
|
|
180
|
-
// }
|
|
181
|
-
|
|
182
|
-
// const appendBuffer = (queue: PQueue, sourceBuffer: SourceBuffer, buffer: ArrayBuffer) =>
|
|
183
|
-
// queue.add(() =>
|
|
184
|
-
// new Promise<Event>((resolve, reject) => {
|
|
185
|
-
// setupListeners(sourceBuffer, resolve, reject)
|
|
186
|
-
// sourceBuffer.appendBuffer(buffer)
|
|
187
|
-
// })
|
|
188
|
-
// )
|
|
189
|
-
|
|
190
|
-
// const bufferChunk = async (queue: PQueue, sourceBuffer: SourceBuffer, chunk: Chunk) => {
|
|
191
|
-
// await appendBuffer(queue, sourceBuffer, chunk.buffer.buffer)
|
|
192
|
-
// chunk.buffered = true
|
|
193
|
-
// }
|
|
194
|
-
|
|
195
|
-
// const unbufferChunk = async (queue: PQueue, sourceBuffer: SourceBuffer, chunks: Chunk[], chunk: Chunk) =>
|
|
196
|
-
// queue.add(() =>
|
|
197
|
-
// new Promise((resolve, reject) => {
|
|
198
|
-
// setupListeners(sourceBuffer, resolve, reject)
|
|
199
|
-
|
|
200
|
-
// const chunkIndex = chunks.indexOf(chunk)
|
|
201
|
-
// if (chunkIndex === -1) return reject('No chunk found')
|
|
202
|
-
// sourceBuffer.remove(chunk.pts, chunk.pts + chunk.duration)
|
|
203
|
-
// chunk.buffered = false
|
|
204
|
-
// })
|
|
205
|
-
// )
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// const listenForOperationResult =
|
|
218
|
-
// (sourceBuffer: SourceBuffer) =>
|
|
219
|
-
// (resolve: (value: Event) => void, reject: (reason: Event) => void) => {
|
|
220
|
-
// const updateEndListener = (ev: Event) => {
|
|
221
|
-
// resolve(ev)
|
|
222
|
-
// unregisterListeners()
|
|
223
|
-
// }
|
|
224
|
-
// const abortListener = (ev: Event) => {
|
|
225
|
-
// resolve(ev)
|
|
226
|
-
// unregisterListeners()
|
|
227
|
-
// }
|
|
228
|
-
// const errorListener = (ev: Event) => {
|
|
229
|
-
// reject(ev),
|
|
230
|
-
// unregisterListeners()
|
|
231
|
-
// }
|
|
232
|
-
// const unregisterListeners = () => {
|
|
233
|
-
// sourceBuffer.removeEventListener('updateend', updateEndListener)
|
|
234
|
-
// sourceBuffer.removeEventListener('abort', abortListener)
|
|
235
|
-
// sourceBuffer.removeEventListener('error', errorListener)
|
|
236
|
-
// }
|
|
237
|
-
// sourceBuffer.addEventListener('updateend', updateEndListener, { once: true })
|
|
238
|
-
// sourceBuffer.addEventListener('abort', abortListener, { once: true })
|
|
239
|
-
// sourceBuffer.addEventListener('error', errorListener, { once: true })
|
|
240
|
-
// }
|
|
241
|
-
|
|
242
|
-
// export const appendBuffer =
|
|
243
|
-
// (sourceBuffer: SourceBuffer) =>
|
|
244
|
-
// (buffer: ArrayBuffer) =>
|
|
245
|
-
// new Promise<Event>((resolve, reject) => {
|
|
246
|
-
// listenForOperationResult(sourceBuffer)(resolve, reject)
|
|
247
|
-
// sourceBuffer.appendBuffer(buffer)
|
|
248
|
-
// })
|
|
249
134
|
|
|
250
|
-
//
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// .filter(({ startTime, endTime }) =>
|
|
301
|
-
// currentTime - PRE_SEEK_NEEDED_BUFFERS_IN_SECONDS < startTime
|
|
302
|
-
// && currentTime + POST_SEEK_NEEDED_BUFFERS_IN_SECONDS > endTime
|
|
303
|
-
// )
|
|
304
|
-
// ]
|
|
135
|
+
// todo: reimplement this into a ReadableByteStream https://web.dev/streams/ once Safari gets support
|
|
136
|
+
export const toStreamChunkSize = (SIZE: number) => (stream: ReadableStream) =>
|
|
137
|
+
new ReadableStream<Uint8Array>({
|
|
138
|
+
reader: undefined,
|
|
139
|
+
leftOverData: undefined,
|
|
140
|
+
start() {
|
|
141
|
+
this.reader = stream.getReader()
|
|
142
|
+
},
|
|
143
|
+
async pull(controller) {
|
|
144
|
+
const { leftOverData }: { leftOverData: Uint8Array | undefined } = this
|
|
145
|
+
|
|
146
|
+
const accumulate = async ({ buffer = new Uint8Array(SIZE), currentSize = 0 } = {}): Promise<{ buffer?: Uint8Array, currentSize?: number, done: boolean }> => {
|
|
147
|
+
const { value: newBuffer, done } = await this.reader!.read()
|
|
148
|
+
if (currentSize === 0 && leftOverData) {
|
|
149
|
+
buffer.set(leftOverData)
|
|
150
|
+
currentSize += leftOverData.byteLength
|
|
151
|
+
this.leftOverData = undefined
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (done) {
|
|
155
|
+
const finalResult = { buffer: buffer.slice(0, currentSize), currentSize, done }
|
|
156
|
+
this.reader = undefined
|
|
157
|
+
this.leftOverData = undefined
|
|
158
|
+
return finalResult
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let newSize
|
|
162
|
+
const slicedBuffer = newBuffer.slice(0, SIZE - currentSize)
|
|
163
|
+
newSize = currentSize + slicedBuffer.byteLength
|
|
164
|
+
buffer.set(slicedBuffer, currentSize)
|
|
165
|
+
|
|
166
|
+
if (newSize === SIZE) {
|
|
167
|
+
this.leftOverData = newBuffer.slice(SIZE - currentSize)
|
|
168
|
+
return { buffer, currentSize: newSize, done: false }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return accumulate({ buffer, currentSize: newSize })
|
|
172
|
+
}
|
|
173
|
+
const { buffer, done } = await accumulate()
|
|
174
|
+
if (buffer?.byteLength) controller.enqueue(buffer)
|
|
175
|
+
if (done) controller.close()
|
|
176
|
+
},
|
|
177
|
+
cancel() {
|
|
178
|
+
this.reader!.cancel()
|
|
179
|
+
this.leftOverData = undefined
|
|
180
|
+
}
|
|
181
|
+
} as UnderlyingDefaultSource<Uint8Array> & {
|
|
182
|
+
reader: ReadableStreamDefaultReader<Uint8Array> | undefined
|
|
183
|
+
leftOverData: Uint8Array | undefined
|
|
184
|
+
})
|
|
305
185
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
186
|
+
export const toBufferedStream = (SIZE: number) => (stream: ReadableStream) =>
|
|
187
|
+
new ReadableStream<Uint8Array>({
|
|
188
|
+
buffers: [],
|
|
189
|
+
currentPullPromise: undefined,
|
|
190
|
+
reader: undefined,
|
|
191
|
+
leftOverData: undefined,
|
|
192
|
+
start() {
|
|
193
|
+
this.reader = stream.getReader()
|
|
194
|
+
},
|
|
195
|
+
async pull(controller) {
|
|
196
|
+
const pull = async () => {
|
|
197
|
+
if (this.buffers.length >= SIZE) return
|
|
198
|
+
this.currentPullPromise = this.reader!.read()
|
|
199
|
+
const { value: newBuffer, done } = await this.currentPullPromise
|
|
200
|
+
this.currentPullPromise = undefined
|
|
201
|
+
if (done) {
|
|
202
|
+
try {
|
|
203
|
+
controller.close()
|
|
204
|
+
} catch (err) {
|
|
205
|
+
// console.error(err)
|
|
206
|
+
}
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
this.buffers.push(newBuffer)
|
|
210
|
+
return newBuffer
|
|
211
|
+
}
|
|
310
212
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
213
|
+
const tryToBuffer = async (): Promise<void> => {
|
|
214
|
+
if (this.buffers.length >= SIZE) return
|
|
215
|
+
|
|
216
|
+
if (this.buffers.length === 0) {
|
|
217
|
+
const buffer = await pull()
|
|
218
|
+
if (!buffer) return
|
|
219
|
+
return tryToBuffer()
|
|
220
|
+
} else {
|
|
221
|
+
pull().then((buffer) => {
|
|
222
|
+
if (!buffer) return
|
|
223
|
+
tryToBuffer()
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
}
|
|
314
227
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
// }
|
|
329
|
-
// if (err.message !== 'No TimeRange found with this chunk') throw err
|
|
330
|
-
// }
|
|
331
|
-
// }
|
|
332
|
-
// const bufferedOutOfRangeRanges =
|
|
333
|
-
// getTimeRanges(sourceBuffer)
|
|
334
|
-
// .filter(({ start, end }) =>
|
|
335
|
-
// currentTime - PRE_SEEK_NEEDED_BUFFERS_IN_SECONDS > start && currentTime - PRE_SEEK_NEEDED_BUFFERS_IN_SECONDS > end ||
|
|
336
|
-
// currentTime + POST_SEEK_NEEDED_BUFFERS_IN_SECONDS < start && currentTime + POST_SEEK_NEEDED_BUFFERS_IN_SECONDS < end
|
|
337
|
-
// )
|
|
338
|
-
// for (const range of bufferedOutOfRangeRanges) {
|
|
339
|
-
// try {
|
|
340
|
-
// await removeRange(sourceBuffer)(range)
|
|
341
|
-
// } catch (err) {
|
|
342
|
-
// throw err
|
|
343
|
-
// }
|
|
344
|
-
// }
|
|
345
|
-
// for (const chunk of neededChunks) {
|
|
346
|
-
// // console.log('chunk', chunk, neededChunks, bufferedChunksMap.has(chunk.keyframeIndex), chunk.keyframeIndex + 1 === chunks.length)
|
|
347
|
-
// if (bufferedChunksMap.has(chunk.keyframeIndex) || (chunk.keyframeIndex !== 0 && chunk.keyframeIndex + 1 === chunks.length)) continue
|
|
348
|
-
// // console.log('check PASSED', chunk, neededChunks)
|
|
349
|
-
// try {
|
|
350
|
-
// const cachedBuffer = cache.get(chunk.keyframeIndex)
|
|
351
|
-
// if (!cachedBuffer) {
|
|
352
|
-
// const fetchBuffer =
|
|
353
|
-
// getChunkArrayBuffer(chunk.keyframeIndex)
|
|
354
|
-
// .then(arrayBuffer => {
|
|
355
|
-
// if (arrayBuffer) cache.set(chunk.keyframeIndex, arrayBuffer)
|
|
356
|
-
// return arrayBuffer
|
|
357
|
-
// })
|
|
358
|
-
// cache.set(chunk.keyframeIndex, fetchBuffer)
|
|
359
|
-
// }
|
|
360
|
-
// const buffer = await cache.get(chunk.keyframeIndex)
|
|
361
|
-
// if (renderCount !== currentRenderCount + 1) return
|
|
362
|
-
// if (!buffer) continue
|
|
363
|
-
// const _chunk = { ...chunk, arrayBuffer: buffer }
|
|
364
|
-
// await appendChunk(sourceBuffer)(_chunk).catch(err => {
|
|
365
|
-
// bufferedChunksMap.delete(chunk.keyframeIndex)
|
|
366
|
-
// throw err
|
|
367
|
-
// })
|
|
368
|
-
// bufferedChunksMap.set(chunk.keyframeIndex, buffer)
|
|
369
|
-
// } catch (err) {
|
|
370
|
-
// if (!(err instanceof Event)) {
|
|
371
|
-
// for (const range of getTimeRanges(sourceBuffer)) {
|
|
372
|
-
// await removeRange(sourceBuffer)(range)
|
|
373
|
-
// // todo: remove cached buffers from Maps
|
|
374
|
-
// }
|
|
375
|
-
// if (!retry) await update({ currentTime, chunks, retry: true })
|
|
376
|
-
// else throw err
|
|
377
|
-
// }
|
|
378
|
-
// // if (err.message !== 'Failed to execute \'appendBuffer\' on \'SourceBuffer\': This SourceBuffer is still processing an \'appendBuffer\' or \'remove\' operation.') throw err
|
|
379
|
-
// break
|
|
380
|
-
// }
|
|
381
|
-
// }
|
|
382
|
-
// }
|
|
383
|
-
|
|
384
|
-
// return update
|
|
385
|
-
// }
|
|
228
|
+
await tryToBuffer()
|
|
229
|
+
controller.enqueue(this.buffers.shift())
|
|
230
|
+
tryToBuffer()
|
|
231
|
+
},
|
|
232
|
+
cancel() {
|
|
233
|
+
this.reader!.cancel()
|
|
234
|
+
}
|
|
235
|
+
} as UnderlyingDefaultSource<Uint8Array> & {
|
|
236
|
+
reader: ReadableStreamDefaultReader<Uint8Array> | undefined
|
|
237
|
+
leftOverData: Uint8Array | undefined
|
|
238
|
+
buffers: Uint8Array[]
|
|
239
|
+
currentPullPromise: Promise<ReadableStreamReadResult<Uint8Array>> | undefined
|
|
240
|
+
})
|