From 8857d012ddd1a7bd0adedba1fe500b9be6a094c6 Mon Sep 17 00:00:00 2001 From: Florent Date: Mon, 13 Nov 2023 18:40:22 +0100 Subject: [PATCH 01/11] fix bug: subtitle no longer blink in low latency --- .../text/html/__tests__/utils.test.ts | 15 +++++++ .../text/html/text_track_cues_store.ts | 45 ++++++++++++++++--- .../implementations/text/html/utils.ts | 21 ++++++++- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/core/segment_buffers/implementations/text/html/__tests__/utils.test.ts b/src/core/segment_buffers/implementations/text/html/__tests__/utils.test.ts index 697f38a8e5..2e9c2b8299 100644 --- a/src/core/segment_buffers/implementations/text/html/__tests__/utils.test.ts +++ b/src/core/segment_buffers/implementations/text/html/__tests__/utils.test.ts @@ -261,6 +261,21 @@ describe("HTML Text buffer utils - areNearlyEqual", () => { it("should return true if input number are equals", () => { expect(areNearlyEqual(5, 5)).toBe(true); }); + it( + "should return false if input number are not nearly equals with delta parameter", + () => { + expect(areNearlyEqual(5, 5.1, 0.02)).toBe(false); + }); + it( + "should return true if input number are nearly equals with delta parameter", + () => { + expect(areNearlyEqual(5, 5.01, 0.02)).toBe(true); + }); + it( + "should return true if input number are equals with delta parameter", + () => { + expect(areNearlyEqual(5, 5, 0.02)).toBe(true); + }); }); describe("HTML Text buffer utils - removeCuesInfosBetween", () => { diff --git a/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts b/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts index c73670fb4f..fcdb96a90f 100644 --- a/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts +++ b/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts @@ -26,6 +26,11 @@ import { removeCuesInfosBetween, } from "./utils"; +const DELTA_CUES_GROUP = 1e-3; // 1ms + +// segment_duration / RELATIVE_DELTA_RATIO = relative_delta +// relative_delta is the tolerance to determine if two segements are the same +const RELATIVE_DELTA_RATIO = 5; /** * Manage the buffer of the HTMLTextSegmentBuffer. * Allows to add, remove and recuperate cues at given times. @@ -72,6 +77,17 @@ export default class TextTrackCuesStore { ret.push(cues[j].element); } } + // first or last IHTMLCue in a group can have a slighlty different start + // or end time than the start or end time of the ICuesGroup due to parsing + // approximation. + // Add a tolerance of 1ms to fix this issue + if (ret.length === 0 && cues.length) { + if (areNearlyEqual(time, cues[0].start, DELTA_CUES_GROUP)) { + ret.push(cues[0].element); + } else if (areNearlyEqual(time, cues[cues.length - 1].end, DELTA_CUES_GROUP)) { + ret.push(cues[cues.length - 1].element); + } + } return ret; } } @@ -163,6 +179,11 @@ export default class TextTrackCuesStore { insert(cues : IHTMLCue[], start : number, end : number) : void { const cuesBuffer = this._cuesBuffer; const cuesInfosToInsert = { start, end, cues }; + // it's preferable to have a delta depending on the duration of the segment + // if the delta is one fifth of the length of the segment: + // a segment of [0, 2] is the "same" segment as [0, 2.1] + // but [0, 0.04] is not the "same" segement as [0,04, 0.08] + const relativeDelta = Math.abs(start - end) / RELATIVE_DELTA_RATIO; /** * Called when we found the index of the next cue relative to the cue we @@ -175,7 +196,7 @@ export default class TextTrackCuesStore { function onIndexOfNextCueFound(indexOfNextCue : number) : void { const nextCue = cuesBuffer[indexOfNextCue]; if (nextCue === undefined || // no cue - areNearlyEqual(cuesInfosToInsert.end, nextCue.end)) // samey end + areNearlyEqual(cuesInfosToInsert.end, nextCue.end, relativeDelta)) // samey end { // ours: |AAAAA| // the current one: |BBBBB| @@ -210,8 +231,8 @@ export default class TextTrackCuesStore { for (let cueIdx = 0; cueIdx < cuesBuffer.length; cueIdx++) { let cuesInfos = cuesBuffer[cueIdx]; if (start < cuesInfos.end) { - if (areNearlyEqual(start, cuesInfos.start)) { - if (areNearlyEqual(end, cuesInfos.end)) { + if (areNearlyEqual(start, cuesInfos.start, relativeDelta)) { + if (areNearlyEqual(end, cuesInfos.end, relativeDelta)) { // exact same segment // ours: |AAAAA| // the current one: |BBBBB| @@ -257,7 +278,7 @@ export default class TextTrackCuesStore { // - add ours before the current one cuesBuffer.splice(cueIdx, 0, cuesInfosToInsert); return; - } else if (areNearlyEqual(end, cuesInfos.start)) { + } else if (areNearlyEqual(end, cuesInfos.start, relativeDelta)) { // our cue goes just before the current one: // ours: |AAAAAAA| // the current one: |BBBB| @@ -268,7 +289,7 @@ export default class TextTrackCuesStore { cuesInfos.start = end; cuesBuffer.splice(cueIdx, 0, cuesInfosToInsert); return; - } else if (areNearlyEqual(end, cuesInfos.end)) { + } else if (areNearlyEqual(end, cuesInfos.end, relativeDelta)) { // ours: |AAAAAAA| // the current one: |BBBB| // Result: |AAAAAAA| @@ -297,7 +318,7 @@ export default class TextTrackCuesStore { } // else -> start > cuesInfos.start - if (areNearlyEqual(cuesInfos.end, end)) { + if (areNearlyEqual(cuesInfos.end, end, relativeDelta)) { // ours: |AAAAAA| // the current one: |BBBBBBBB| // Result: |BBAAAAAA| @@ -333,6 +354,18 @@ export default class TextTrackCuesStore { } } } + + if (cuesBuffer.length) { + const lastCue = cuesBuffer[cuesBuffer.length - 1]; + if (areNearlyEqual(lastCue.end, start, relativeDelta)) { + // Match the end of the previous cue to the start of + // the following one if they are close enough + // ours: |AAAAA| + // the current one: |BBBBB|... + // Result: |BBBBBBBAAAAA| + lastCue.end = start; + } + } // no cues group has the end after our current start. // These cues should be the last one cuesBuffer.push(cuesInfosToInsert); diff --git a/src/core/segment_buffers/implementations/text/html/utils.ts b/src/core/segment_buffers/implementations/text/html/utils.ts index 82e4ee280e..285e61c6a5 100644 --- a/src/core/segment_buffers/implementations/text/html/utils.ts +++ b/src/core/segment_buffers/implementations/text/html/utils.ts @@ -50,6 +50,21 @@ import { * Setting a value too high might lead to two segments targeting different times * to be wrongly believed to target the same time. In worst case scenarios, this * could lead to wanted text tracks being removed. + * + * When comparing 2 segments s1 and s2, you may want to take into account the duration + * of the segments: + * - if s1 is [0, 2] and s2 is [0, 2.1] s1 and s2 can be considered as nearly equal as + * there is a relative difference of: (2.1-2) / 2 = 5%; + * Formula: (end_s1 - end_s2) / duration_s2 = relative_difference + * - if s1 is [0, 0.04] and s2 is [0.04, 0.08] s1 and s2 may not considered as nearly + * equal as there is a relative difference of: (0.04-0.08) / 0.04 = 100% + * + * To compare relatively to the duration of a segment you can provide and additional + * parameter "delta" that remplace MAX_DELTA_BUFFER_TIME. + * If parameter "delta" is higher than MAX_DELTA_BUFFER_TIME, MAX_DELTA_BUFFER_TIME + * is used instead of delta. This ensure that segments are nearly equal when comparing + * relatively AND absolutely. + * * @type Number */ const MAX_DELTA_BUFFER_TIME = 0.2; @@ -58,10 +73,12 @@ const MAX_DELTA_BUFFER_TIME = 0.2; * @see MAX_DELTA_BUFFER_TIME * @param {Number} a * @param {Number} b + * @param {Number} delta * @returns {Boolean} */ -export function areNearlyEqual(a : number, b : number) : boolean { - return Math.abs(a - b) <= MAX_DELTA_BUFFER_TIME; +export function areNearlyEqual( + a : number, b : number, delta: number = MAX_DELTA_BUFFER_TIME) : boolean { + return Math.abs(a - b) <= Math.min(delta, MAX_DELTA_BUFFER_TIME); } /** From 6ee2433c19138cbcf11c623b9e455aa1b958bdf0 Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Thu, 2 Nov 2023 14:10:41 +0100 Subject: [PATCH 02/11] Add the possibility to set a new `keySystems` option on the `reload` API A majority of the bigger issues we encounter in production is DRM-related, leading us to either work-around those in the RxPlayer, or to facilitate a work-around on the application-side through a better DRM-related API. Recently, we've seen that many Windows/Edge users (but still a minority of them) could encounter an issue on the `generateRequest` EME call when relying on PlayReady SL3000 (hardware-backed decryption and playback, seen as one the most secure DRM mechanism for OTT contents) which would lead to a failure to play the content. When this happens, fallbacking to a different key system like PlayReady SL2000 (where decryption happens in software) or Widevine usually (though not always) seems to avoid the issue, even if it might lead to less protection and thus might lead generally to only lower video qualities (as higher security requirements are in practice generally just enforced for the higher video qualities, depending on license policies). After brainstorming whether this fallback should be done on the RxPlayer-side, or on the application-side, we're for now implementing the easier way (for us :p) of just providing here an API allowing to just let the application replay the last loaded content (whose loading may have failed due to the aforementioned `generateRequest` error) with a different `keySystems` configuration, thus allowing an application to reload the last loaded content after blacklisting the current key system if the error appears to be linked to that issue. --- doc/api/Basic_Methods/reload.md | 11 +++++++++++ src/core/api/option_utils.ts | 8 ++++++++ src/core/api/public_api.ts | 14 +++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/api/Basic_Methods/reload.md b/doc/api/Basic_Methods/reload.md index cc3534ba03..d64547a486 100644 --- a/doc/api/Basic_Methods/reload.md +++ b/doc/api/Basic_Methods/reload.md @@ -35,6 +35,17 @@ The options argument is an object containing : content was playing the last time it was played and stay in the `"LOADED"` state (and paused) if it was paused last time it was played. +- _keySystems_ (`Array. | undefined`): If set, a new configuration will + be set on this reloaded content regarding its decryption. + + The value of this property follows the exact same structure than for the + original `loadVideo` call, it is described in the [decryption options + documentation page](../Decryption_Options.md). + + You might for example want to update that way the `keySystems` option compared + to the one of the original `loadVideo` call when you suspect that there is a + decryption-related issue with the original `keySystems` given. + Note that despite this method's name, the player will not go through the `RELOADING` state while reloading the content but through the regular `LOADING` state - as if `loadVideo` was called on that same content again. diff --git a/src/core/api/option_utils.ts b/src/core/api/option_utils.ts index 1b00fd1778..ed7c230437 100644 --- a/src/core/api/option_utils.ts +++ b/src/core/api/option_utils.ts @@ -397,6 +397,8 @@ function parseConstructorOptions( */ function checkReloadOptions(options?: { reloadAt?: { position?: number; relative?: number }; + keySystems?: IKeySystemOption[]; + autoPlay?: boolean; }): void { if (options === null || (typeof options !== "object" && options !== undefined)) { @@ -414,6 +416,12 @@ function checkReloadOptions(options?: { options?.reloadAt?.relative !== undefined) { throw new Error("API: reload - Invalid 'reloadAt.relative' option format."); } + if (!Array.isArray(options?.keySystems) && options?.keySystems !== undefined) { + throw new Error("API: reload - Invalid 'keySystems' option format."); + } + if (options?.autoPlay !== undefined && typeof options.autoPlay !== "boolean") { + throw new Error("API: reload - Invalid 'autoPlay' option format."); + } } /** diff --git a/src/core/api/public_api.ts b/src/core/api/public_api.ts index 8d1ff7682b..40d044e4ca 100644 --- a/src/core/api/public_api.ts +++ b/src/core/api/public_api.ts @@ -59,6 +59,7 @@ import { IConstructorOptions, IDecipherabilityUpdateContent, IKeySystemConfigurationOutput, + IKeySystemOption, ILoadVideoOptions, IPeriod, IPlayerError, @@ -577,6 +578,7 @@ class Player extends EventEmitter { */ reload(reloadOpts?: { reloadAt?: { position?: number; relative?: number }; + keySystems?: IKeySystemOption[]; autoPlay?: boolean; }): void { const { options, @@ -609,6 +611,13 @@ class Player extends EventEmitter { autoPlay = !reloadInPause; } + let keySystems : IKeySystemOption[] | undefined; + if (reloadOpts?.keySystems !== undefined) { + keySystems = reloadOpts.keySystems; + } else if (this._priv_reloadingMetadata.options?.keySystems !== undefined) { + keySystems = this._priv_reloadingMetadata.options.keySystems; + } + const newOptions = { ...options, initialManifest: manifest }; if (startAt !== undefined) { @@ -617,6 +626,9 @@ class Player extends EventEmitter { if (autoPlay !== undefined) { newOptions.autoPlay = autoPlay; } + if (keySystems !== undefined) { + newOptions.keySystems = keySystems; + } this._priv_initializeContentPlayback(newOptions); } @@ -626,7 +638,7 @@ class Player extends EventEmitter { if (features.createDebugElement === null) { throw new Error("Feature `DEBUG_ELEMENT` not added to the RxPlayer"); } - const canceller = new TaskCanceller() ; + const canceller = new TaskCanceller(); features.createDebugElement(element, this, canceller.signal); return { dispose() { From dd71e574e18947dda8d22e56b1e0d9a1c16605fa Mon Sep 17 00:00:00 2001 From: Florent Date: Tue, 14 Nov 2023 13:30:22 +0100 Subject: [PATCH 03/11] add comments and format --- .../text/html/text_track_cues_store.ts | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts b/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts index fcdb96a90f..4448c0748b 100644 --- a/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts +++ b/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts @@ -26,10 +26,22 @@ import { removeCuesInfosBetween, } from "./utils"; -const DELTA_CUES_GROUP = 1e-3; // 1ms +/** + * first or last IHTMLCue in a group can have a slighlty different start + * or end time than the start or end time of the ICuesGroup due to parsing + * approximation. + * DELTA_CUES_GROUP defines the tolerance level when comparing the start/end + * of a IHTMLCue to the start/end of a ICuesGroup. + * Having this value too high may lead to have unwanted subtitle displayed + * Having this value too low may lead to have subtitles not displayed + */ +const DELTA_CUES_GROUP = 1e-3; -// segment_duration / RELATIVE_DELTA_RATIO = relative_delta -// relative_delta is the tolerance to determine if two segements are the same +/** + * segment_duration / RELATIVE_DELTA_RATIO = relative_delta + * + * relative_delta is the tolerance to determine if two segements are the same + */ const RELATIVE_DELTA_RATIO = 5; /** * Manage the buffer of the HTMLTextSegmentBuffer. @@ -358,11 +370,15 @@ export default class TextTrackCuesStore { if (cuesBuffer.length) { const lastCue = cuesBuffer[cuesBuffer.length - 1]; if (areNearlyEqual(lastCue.end, start, relativeDelta)) { - // Match the end of the previous cue to the start of - // the following one if they are close enough - // ours: |AAAAA| - // the current one: |BBBBB|... - // Result: |BBBBBBBAAAAA| + // Match the end of the previous cue to the start of the following one + // if they are close enough. If there is a small gap between two segments + // it can lead to having no subtitles for a short time, this is noticeable when + // two successive segments displays the same text, making it diseappear + // and reappear quickly, which gives the impression of blinking + // + // ours: |AAAAA| + // the current one: |BBBBB|... + // Result: |BBBBBBBAAAAA| lastCue.end = start; } } From 5e36a77dd3aedebee39d7a41bbe0fe424bdff2e3 Mon Sep 17 00:00:00 2001 From: Florent Date: Tue, 14 Nov 2023 13:30:49 +0100 Subject: [PATCH 04/11] handle the case where multiple cues can target the same time --- .../text/html/text_track_cues_store.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts b/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts index 4448c0748b..16d2942039 100644 --- a/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts +++ b/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts @@ -93,11 +93,13 @@ export default class TextTrackCuesStore { // or end time than the start or end time of the ICuesGroup due to parsing // approximation. // Add a tolerance of 1ms to fix this issue - if (ret.length === 0 && cues.length) { - if (areNearlyEqual(time, cues[0].start, DELTA_CUES_GROUP)) { - ret.push(cues[0].element); - } else if (areNearlyEqual(time, cues[cues.length - 1].end, DELTA_CUES_GROUP)) { - ret.push(cues[cues.length - 1].element); + if (ret.length === 0 && cues.length > 0) { + for (let j = 0; j < cues.length; j++) { + if (areNearlyEqual(time, cues[j].start, DELTA_CUES_GROUP) + || areNearlyEqual(time, cues[j].end, DELTA_CUES_GROUP) + ) { + ret.push(cues[j].element); + } } } return ret; From 098385f4ca6671de4993074d641b0f701cdf6abf Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Fri, 17 Nov 2023 17:22:15 +0100 Subject: [PATCH 05/11] Debug: update buffer graph maximum size so it becomes more readable for long contents When displaying the RxPlayer's debug element, a graph describing the audio, video and text qualities in the various buffers might be displayed. At maximum, that graph could display 10000 seconds of content, which made in that case the graph poorly readable. I now chose to reduce it to maximum 30 minutes, as you rarely intend to see more when displaying debug information, making it much more readable. --- src/core/api/debug/buffer_graph.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/api/debug/buffer_graph.ts b/src/core/api/debug/buffer_graph.ts index 44e5da72e4..cb026b03ef 100644 --- a/src/core/api/debug/buffer_graph.ts +++ b/src/core/api/debug/buffer_graph.ts @@ -1,7 +1,7 @@ import { Representation } from "../../../manifest"; import { IBufferedChunk } from "../../segment_buffers"; -const BUFFER_WIDTH_IN_SECONDS = 10000; +const BUFFER_WIDTH_IN_SECONDS = 30 * 60; const COLORS = [ "#2ab7ca", @@ -96,8 +96,8 @@ export default class SegmentBufferGraph { let maximumPosition; if (maximumPoint - minimumPoint > BUFFER_WIDTH_IN_SECONDS) { if (currentTime === undefined) { - minimumPosition = minimumPoint; maximumPosition = maximumPoint; + minimumPosition = maximumPoint - BUFFER_WIDTH_IN_SECONDS; } else if (maximumPoint - currentTime < BUFFER_WIDTH_IN_SECONDS / 2) { maximumPosition = maximumPoint; minimumPosition = maximumPoint - BUFFER_WIDTH_IN_SECONDS; From d429e55b5aa70937c50cf64ead95485c0aca82f9 Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Mon, 20 Nov 2023 18:02:19 +0100 Subject: [PATCH 06/11] Debug: always synchronize SegmentInventory before reporting it through the API We have a minor issue with an undocumented API letting applications know the content of the various buffers (audio, video and text), which may show in some rare cases to an unsynchronized view into one of those buffers. As this API is not documented and put behind an unwelcoming method name, the only impact that unsynchronized status could have are: - information shown in the RxPlayer's debug element (through the `createDebugElement API`) could not reflect the exact reality. The only case I've seen now is that when enabling then disabling text tracks, we may still see a view making it seems that the since-remove text segments pushed were still here (it is in reality not, as should be expected). - Likewise, our demo page's buffer graph, which rely on the same API, could show an unsynchronized view into the buffer in the same situation. The solution I found was just to make sure the `SegmentInventory`, the module actually storing that buffer information, is always synchronized to the buffer at the time that hidden API is called. This could mean unnecessary calls when the buffer is already synchronized, but we do not care much as that API is only called for debug anyway and not even performance-sensitive for the moment. --- src/core/api/public_api.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/api/public_api.ts b/src/core/api/public_api.ts index 8d1ff7682b..765c752d00 100644 --- a/src/core/api/public_api.ts +++ b/src/core/api/public_api.ts @@ -2429,9 +2429,11 @@ class Player extends EventEmitter { } const segmentBufferStatus = this._priv_contentInfos .segmentBuffersStore.getStatus(bufferType); - return segmentBufferStatus.type === "initialized" ? - segmentBufferStatus.value.getInventory() : - null; + if (segmentBufferStatus.type === "initialized") { + segmentBufferStatus.value.synchronizeInventory(); + return segmentBufferStatus.value.getInventory(); + } + return null; } /** From d3ccc85f02613bd47e4b3e823c153d8915d44480 Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Tue, 21 Nov 2023 18:33:31 +0100 Subject: [PATCH 07/11] debug: remove impossible case --- src/core/api/debug/buffer_graph.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/api/debug/buffer_graph.ts b/src/core/api/debug/buffer_graph.ts index cb026b03ef..e587b4c1a4 100644 --- a/src/core/api/debug/buffer_graph.ts +++ b/src/core/api/debug/buffer_graph.ts @@ -95,10 +95,7 @@ export default class SegmentBufferGraph { let minimumPosition; let maximumPosition; if (maximumPoint - minimumPoint > BUFFER_WIDTH_IN_SECONDS) { - if (currentTime === undefined) { - maximumPosition = maximumPoint; - minimumPosition = maximumPoint - BUFFER_WIDTH_IN_SECONDS; - } else if (maximumPoint - currentTime < BUFFER_WIDTH_IN_SECONDS / 2) { + if (maximumPoint - currentTime < BUFFER_WIDTH_IN_SECONDS / 2) { maximumPosition = maximumPoint; minimumPosition = maximumPoint - BUFFER_WIDTH_IN_SECONDS; } else if (currentTime - minimumPoint < BUFFER_WIDTH_IN_SECONDS / 2) { From da7efb6f3eebfdd34cdf0e1b94baf26df74305c7 Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Wed, 22 Nov 2023 12:43:39 +0100 Subject: [PATCH 08/11] Replace docgen.ico by in-canal readme.doc --- package-lock.json | 84 +++++++++++++++++++++++------------------------ package.json | 4 +-- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index bce1ea0190..d1123e1f11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@babel/plugin-transform-runtime": "7.22.15", "@babel/preset-env": "7.22.20", "@babel/preset-react": "7.22.15", + "@canalplus/readme.doc": "^0.3.0", "@types/chai": "4.3.6", "@types/jest": "29.5.5", "@types/mocha": "10.0.1", @@ -29,7 +30,6 @@ "babel-loader": "9.1.3", "chai": "4.3.8", "core-js": "3.32.2", - "docgen.ico": "^0.2.3", "esbuild": "0.19.3", "eslint": "8.50.0", "eslint-plugin-ban": "1.6.0", @@ -1937,6 +1937,27 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@canalplus/readme.doc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@canalplus/readme.doc/-/readme.doc-0.3.0.tgz", + "integrity": "sha512-MVTz6iJs8a0KucpheT37gLADqyFTTk3PRaf95g5MRduRSwangwE4zq3306QtUId8dPuTLPXxWGUyULY00jmeRw==", + "dev": true, + "dependencies": { + "cheerio": "1.0.0-rc.12", + "highlight.js": "11.7.0", + "html-entities": "2.3.3", + "markdown-it": "13.0.1" + }, + "bin": { + "readme.doc": "build/index.js" + } + }, + "node_modules/@canalplus/readme.doc/node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -5691,27 +5712,6 @@ "node": ">=8" } }, - "node_modules/docgen.ico": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/docgen.ico/-/docgen.ico-0.2.3.tgz", - "integrity": "sha512-dfXbeTpcQwZbpXXTFOR4MCGm1aQr171c3kA0KZqvzawGm5WJe8IqojO+JHdu2xXDep/rDxC8BPfELzRKAZeK3w==", - "dev": true, - "dependencies": { - "cheerio": "1.0.0-rc.12", - "highlight.js": "11.7.0", - "html-entities": "2.3.3", - "markdown-it": "13.0.1" - }, - "bin": { - "docgen.ico": "build/index.js" - } - }, - "node_modules/docgen.ico/node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", - "dev": true - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -16174,6 +16174,26 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@canalplus/readme.doc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@canalplus/readme.doc/-/readme.doc-0.3.0.tgz", + "integrity": "sha512-MVTz6iJs8a0KucpheT37gLADqyFTTk3PRaf95g5MRduRSwangwE4zq3306QtUId8dPuTLPXxWGUyULY00jmeRw==", + "dev": true, + "requires": { + "cheerio": "1.0.0-rc.12", + "highlight.js": "11.7.0", + "html-entities": "2.3.3", + "markdown-it": "13.0.1" + }, + "dependencies": { + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + } + } + }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -18928,26 +18948,6 @@ "path-type": "^4.0.0" } }, - "docgen.ico": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/docgen.ico/-/docgen.ico-0.2.3.tgz", - "integrity": "sha512-dfXbeTpcQwZbpXXTFOR4MCGm1aQr171c3kA0KZqvzawGm5WJe8IqojO+JHdu2xXDep/rDxC8BPfELzRKAZeK3w==", - "dev": true, - "requires": { - "cheerio": "1.0.0-rc.12", - "highlight.js": "11.7.0", - "html-entities": "2.3.3", - "markdown-it": "13.0.1" - }, - "dependencies": { - "html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", - "dev": true - } - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", diff --git a/package.json b/package.json index 562ba965ec..730fbc2de7 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "demo": "node ./scripts/generate_full_demo.js --production-mode", "demo:min": "node ./scripts/generate_full_demo.js --production-mode --minify", "demo:watch": "node ./scripts/generate_full_demo.js --watch --production-mode", - "doc": "docgen.ico doc/ doc/generated \"$(cat VERSION)\"", + "doc": "readme.doc doc/ doc/generated \"$(cat VERSION)\"", "lint": "eslint src -c .eslintrc.js", "lint:demo": "eslint -c demo/full/.eslintrc.js demo/full/scripts", "lint:tests": "eslint tests/**/*.js --ignore-pattern '/tests/performance/bundle*'", @@ -84,6 +84,7 @@ "@babel/plugin-transform-runtime": "7.22.15", "@babel/preset-env": "7.22.20", "@babel/preset-react": "7.22.15", + "@canalplus/readme.doc": "^0.3.0", "@types/chai": "4.3.6", "@types/jest": "29.5.5", "@types/mocha": "10.0.1", @@ -97,7 +98,6 @@ "babel-loader": "9.1.3", "chai": "4.3.8", "core-js": "3.32.2", - "docgen.ico": "^0.2.3", "esbuild": "0.19.3", "eslint": "8.50.0", "eslint-plugin-ban": "1.6.0", From 19e76c264a616360171f69caefa597c2ba69c8e5 Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Mon, 27 Nov 2023 18:28:27 +0100 Subject: [PATCH 09/11] Remove unneeded tslint dependency --- package-lock.json | 17 +++++++++++++---- package.json | 1 - 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d1123e1f11..1a6f6eb72d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,6 @@ "terser-webpack-plugin": "5.3.9", "ts-jest": "29.1.1", "ts-loader": "9.4.4", - "tslint": "6.1.3", "typescript": "5.2.2", "webpack": "5.88.2", "webpack-bundle-analyzer": "4.9.1", @@ -4925,6 +4924,7 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5687,6 +5687,7 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "peer": true, "engines": { "node": ">=0.3.1" } @@ -13841,6 +13842,7 @@ "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", @@ -13868,6 +13870,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "peer": true, "bin": { "semver": "bin/semver" } @@ -13877,6 +13880,7 @@ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, + "peer": true, "dependencies": { "tslib": "^1.8.1" } @@ -18367,7 +18371,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "dev": true, + "peer": true }, "bytes": { "version": "3.1.2", @@ -18931,7 +18936,8 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true + "dev": true, + "peer": true }, "diff-sequences": { "version": "29.6.3", @@ -24983,6 +24989,7 @@ "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", "dev": true, + "peer": true, "requires": { "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", @@ -25003,13 +25010,15 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true + "dev": true, + "peer": true }, "tsutils": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, + "peer": true, "requires": { "tslib": "^1.8.1" } diff --git a/package.json b/package.json index 730fbc2de7..c50facab7e 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,6 @@ "terser-webpack-plugin": "5.3.9", "ts-jest": "29.1.1", "ts-loader": "9.4.4", - "tslint": "6.1.3", "typescript": "5.2.2", "webpack": "5.88.2", "webpack-bundle-analyzer": "4.9.1", From 8ec3ca75bc3aac9a34447a24b2417e2f675a454e Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Thu, 30 Nov 2023 11:25:37 +0100 Subject: [PATCH 10/11] Remove unneeded object-assign typing file --- src/typings/object-assign.d.ts | 48 ---------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/typings/object-assign.d.ts diff --git a/src/typings/object-assign.d.ts b/src/typings/object-assign.d.ts deleted file mode 100644 index 08544f31a3..0000000000 --- a/src/typings/object-assign.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -declare module "object-assign" { - function objectAssign(target : T, source : U) : T & U; - function objectAssign( - target : T, - source1 : U, - source2 : V - ) : T & U & V; - function objectAssign( - target : T, - source1 : U, - source2 : V, - source3 : W - ) : T & U & V & W; - function objectAssign( - target : T, - source1 : U, - source2 : V, - source3 : W, - source4 : X - ) : T & U & V & W & X; - function objectAssign( - target : T, - source1 : U, - source2 : V, - source3 : W, - source4 : X, - source5 : Y - ) : T & U & V & W & Y; - // eslint-disable-next-line @typescript-eslint/ban-types - function objectAssign(target : object, ...sources : T[]) : T; - export default objectAssign; -} From f85997150eedae507f606e284fba0690aec1f41b Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Thu, 30 Nov 2023 11:26:42 +0100 Subject: [PATCH 11/11] Stream: Fix end GC log --- src/core/stream/representation/utils/get_needed_segments.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/stream/representation/utils/get_needed_segments.ts b/src/core/stream/representation/utils/get_needed_segments.ts index c139532f14..a2681a8cae 100644 --- a/src/core/stream/representation/utils/get_needed_segments.ts +++ b/src/core/stream/representation/utils/get_needed_segments.ts @@ -493,8 +493,8 @@ function doesEndSeemGarbageCollected( currentSeg.end - currentSeg.bufferedEnd > MAX_TIME_MISSING_FROM_COMPLETE_SEGMENT) { log.info("Stream: The end of the wanted segment has been garbage collected", - currentSeg.start, - currentSeg.bufferedStart); + currentSeg.end, + currentSeg.bufferedEnd); return true; }