From bc6b0aa0648c74e69f60893c3bd7aac8a5565841 Mon Sep 17 00:00:00 2001 From: lauta Date: Wed, 3 May 2023 16:49:08 +0200 Subject: [PATCH] solved bug regarding overwrighting and shifting of subtitltes --- index.js | 38 ++++---- spec/hlsvod_subtitles_spec.js | 179 +++++++++++++++++++--------------- 2 files changed, 123 insertions(+), 94 deletions(-) diff --git a/index.js b/index.js index 72f58d4..86bbd7f 100644 --- a/index.js +++ b/index.js @@ -74,6 +74,9 @@ class HLSVod { if (opts && opts.shouldContainSubtitles) { this.shouldContainSubtitles = opts.shouldContainSubtitles; } + if (opts && opts.expectedSubtitleTracks) { + this.expectedSubtitleTracks = opts.expectedSubtitleTracks; + } this.videoSequencesCount = 0; this.audioSequencesCount = 0; this.defaultAudioGroupAndLang = null; @@ -89,6 +92,7 @@ class HLSVod { audioSegments: this.audioSegments, subtitleSegments: this.subtitleSegments, shouldContainSubtitles: this.shouldContainSubtitles, + expectedSubtitleTracks: this.expectedSubtitleTracks, mediaSequences: this.mediaSequences, SEQUENCE_DURATION: this.SEQUENCE_DURATION, targetDuration: this.targetDuration, @@ -132,6 +136,7 @@ class HLSVod { this.audioSegments = de.audioSegments; this.subtitleSegments = de.subtitleSegments; this.shouldContainSubtitles = de.shouldContainSubtitles; + this.expectedSubtitleTracks = de.expectedSubtitleTracks; this.mediaSequences = de.mediaSequences; this.SEQUENCE_DURATION = de.SEQUENCE_DURATION; this.targetDuration = de.targetDuration; @@ -359,6 +364,11 @@ class HLSVod { if (streamItem.get("subtitles")) { if (!this.subtitleSliceEndpoint) { reject(new Error("Missing subtitle slice URL")); + continue; + } + if (!this.expectedSubtitleTracks) { + reject(new Error("There are no expected subtitle tracks")); + continue; } let subtitleGroupId = streamItem.get("subtitles"); if (!this.subtitleSegments[subtitleGroupId]) { @@ -381,12 +391,17 @@ class HLSVod { } else { itemLang = item.get("language"); } + if (!this.expectedSubtitleTracks.find((track) => track.language === itemLang || track.name === itemLang)) { + return; + } + // Initialize lang. in new group. if (!this.subtitleSegments[subtitleGroupId][itemLang]) { this.subtitleSegments[subtitleGroupId][itemLang] = []; } return (item = itemLang); - }); + }).filter((item) => item !== undefined); + // # Inject default language's segments to every new language relative to previous VOD. // # For the case when this is a VOD following another, every language new or old should @@ -402,20 +417,6 @@ class HLSVod { } } - // # Need to clean up langs. loaded from prev. VOD that current VOD doesn't have. - // # Necessary, for the case when getLiveMediaSequenceSubtitleSegments() tries to - // # access an subtitleGroup's language that the current VOD never had. A False-Positive. - let allLangs = Object.keys(this.subtitleSegments[subtitleGroupId]); - let toRemove = []; - allLangs.map((junkLang) => { - if (!subtitleLanguages.includes(junkLang)) { - toRemove.push(junkLang); - } - }); - toRemove.map((junkLang) => { - delete this.subtitleSegments[subtitleGroupId][junkLang]; - }); - // # For each lang, find the lang playlist uri and do _loadSubtitleManifest() on it. for (let j = 0; j < subtitleLanguages.length; j++) { let subtitleLang = subtitleLanguages[j]; @@ -452,6 +453,9 @@ class HLSVod { if (!this.dummySubtitleEndpoint) { reject(new Error("Loaded VOD does not contain subtitles and there is no dummy subtitle segment URL configured")); } + if (!this.expectedSubtitleTracks) { + reject(new Error("There are no expected subtitle tracks")); + } if (!this.subtitleSliceEndpoint) { reject(new Error("Missing subtitle slice URL")); } @@ -1887,9 +1891,9 @@ class HLSVod { this.subtitleSegments[subtitleGroupId][subtitleLang] = []; } if (lastMediaSubtitleSequence && lastMediaSubtitleSequence.length > 0) { - let start = 0; + let start = this.sequenceAlwaysContainNewSegments ? 0 : 1; if (lastMediaSubtitleSequence[0] && lastMediaSubtitleSequence[0].discontinuity) { - start = 1; + start = this.sequenceAlwaysContainNewSegments ? 1 : 2; } for (let idx = start; idx < lastMediaSubtitleSequence.length; idx++) { let q = lastMediaSubtitleSequence[idx]; diff --git a/spec/hlsvod_subtitles_spec.js b/spec/hlsvod_subtitles_spec.js index 3543576..d22beea 100644 --- a/spec/hlsvod_subtitles_spec.js +++ b/spec/hlsvod_subtitles_spec.js @@ -3,6 +3,30 @@ const fs = require("fs"); const Readable = require("stream").Readable; describe("HLSVod with subtitles", () => { + + const subtitleTracks = [ + { language: "fr", name: "French" }, + { language: "zh", name: "Chinese" }, + { language: "en", name: "English" }, + { language: "sv", name: "Swedish" } + ] + + const hlsOptsAlwaysNewSegmentsFalse = { + dummySubtitleEndpoint: "/dummysubs.vtt", + subtitleSliceEndpoint: "/subtitlevtt.vtt", + shouldContainSubtitles: true, + expectedSubtitleTracks: subtitleTracks, + sequenceAlwaysContainNewSegments: false + } + + const hlsOptsAlwaysNewSegmentsTrue = { + dummySubtitleEndpoint: "/dummysubs.vtt", + subtitleSliceEndpoint: "/subtitlevtt.vtt", + shouldContainSubtitles: true, + expectedSubtitleTracks: subtitleTracks, + sequenceAlwaysContainNewSegments: true + } + describe("", () => { let mockMasterManifestLongSegments; let mockMediaManifestLongSegments; @@ -102,21 +126,18 @@ describe("HLSVod with subtitles", () => { }); it("returns the correct number of bandwidths", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestNoSubs, mockMediaManifestNoSubs, mockAudioManifestNoSubs) .then(() => { expect(mockVod.getBandwidths().length).toBe(1); expect(mockVod.getBandwidths()).toEqual(["2962000"]); - let m3u8 = mockVod.getLiveMediaSequences(0, "2962000", 0) - let subStrings = m3u8.split("\n") - done(); }); }); it("checks serialize size", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { return mockVod2.load(mockMasterManifestNoSubs, mockMediaManifestNoSubs, mockAudioManifestNoSubs) @@ -132,7 +153,7 @@ describe("HLSVod with subtitles", () => { }); it("no splice subtitle url", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", shouldContainSubtitles: true, expectedSubtitleTracks: subtitleTracks }); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .catch((e) => { expect(e.message).toEqual("Missing subtitle slice URL"); @@ -140,8 +161,17 @@ describe("HLSVod with subtitles", () => { }); }); - it("returns the correct first segment", (done) => { + it("no subtitle tracks", (done) => { mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) + .catch((e) => { + expect(e.message).toEqual("There are no expected subtitle tracks"); + done(); + }); + }); + + it("returns the correct first segment", (done) => { + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "subs", "fr", 0); @@ -152,7 +182,7 @@ describe("HLSVod with subtitles", () => { }); it("returns the correct third sequence", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "subs", "fr", 2); @@ -163,7 +193,7 @@ describe("HLSVod with subtitles", () => { }); it("handles split segments correctly", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterPlaylistUnevenSubVideoSegments, mockMediaPlaylistUnevenSubVideoSegments, null, mockSubtitlePlaylistUnevenSubVideoSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "subs", "en", 0); @@ -178,7 +208,7 @@ describe("HLSVod with subtitles", () => { }); it("returns the correct segment when using offset (27sec) with short segments", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, null, 27 * 1000, 0, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, null, 27 * 1000, 0, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestShortSegments, mockMediaManifestShortSegments, null, mockSubtitleManifestShortSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "textstream", "sv", 0); @@ -191,7 +221,7 @@ describe("HLSVod with subtitles", () => { }); }); it("returns the correct segment when using offset (27sec) with long segments", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, null, 27 * 1000, 0, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, null, 27 * 1000, 0, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "subs", "fr", 0); @@ -205,7 +235,7 @@ describe("HLSVod with subtitles", () => { }); it("returns the correct segment when using offset (150sec) with long segments", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, null, 150 * 1000, 0, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, null, 150 * 1000, 0, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "subs", "fr", 0); @@ -218,8 +248,7 @@ describe("HLSVod with subtitles", () => { }); }); it("returns the correct last segment sequenceAlwaysContainNewSegments(true)", (done) => { - let bool = 1; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { sequenceAlwaysContainNewSegments: bool, dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsTrue); mockVod.load(mockMasterManifestShortSegments, mockMediaManifestShortSegments, null, mockSubtitleManifestShortSegments) .then(() => { const m3u8 = mockVod.getLiveMediaSubtitleSequences(0, "textstream", "sv", 0); @@ -233,8 +262,8 @@ describe("HLSVod with subtitles", () => { }); }); it("subs after vod with subs with short segments", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestShortSegments, mockMediaManifestShortSegments, null, mockSubtitleManifestShortSegments) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestShortSegments, mockMediaManifestShortSegments, null, mockSubtitleManifestShortSegments) @@ -243,16 +272,16 @@ describe("HLSVod with subtitles", () => { const m3u8_2 = mockVod2.getLiveMediaSubtitleSequences(0, "textstream", "sv", 1); const subStrings = m3u8.split("\n") const subStrings2 = m3u8_2.split("\n") - expect(subStrings[35]).toEqual("https://vod.streaming.a2d.tv/3e542405-583b-4edc-93ab-eca86427d148/ab92a690-62de-11ed-aa51-c96fb4f9434f_20337209.ism/hls/ab92a690-62de-11ed-aa51-c96fb4f9434f_20337209-textstream_swe=1000-693.webvtt"); - expect(subStrings2[34]).toEqual("#EXT-X-DISCONTINUITY") - expect(subStrings2[35]).toEqual("#EXTINF:3.000,"); - expect(subStrings2[36]).toEqual("https://d3t8zrj2x5ol3r.cloudfront.net/u/file~text_vtt~dummy.vtt/1/s/webvtt.vtt"); + expect(subStrings[33]).toEqual("https://vod.streaming.a2d.tv/3e542405-583b-4edc-93ab-eca86427d148/ab92a690-62de-11ed-aa51-c96fb4f9434f_20337209.ism/hls/ab92a690-62de-11ed-aa51-c96fb4f9434f_20337209-textstream_swe=1000-693.webvtt"); + expect(subStrings2[32]).toEqual("#EXT-X-DISCONTINUITY") + expect(subStrings2[33]).toEqual("#EXTINF:3.000,"); + expect(subStrings2[34]).toEqual("https://d3t8zrj2x5ol3r.cloudfront.net/u/file~text_vtt~dummy.vtt/1/s/webvtt.vtt"); done(); }); }); it("subs with long segments after vod with subs with short segments", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestShortSegments2, mockMediaManifestShortSegments2, null, mockSubtitleManifestShortSegments2) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) @@ -261,17 +290,17 @@ describe("HLSVod with subtitles", () => { const m3u8_2 = mockVod2.getLiveMediaSubtitleSequences(0, "subs", "fr", 2); const subStrings = m3u8.split("\n"); const subStrings2 = m3u8_2.split("\n"); - expect(subStrings[18]).toEqual("#EXTINF:2.000,"); - expect(subStrings[19]).toEqual("http://mock.com/subs/7.webvtt"); - expect(subStrings2[18]).toEqual("#EXT-X-DISCONTINUITY") - expect(subStrings2[19]).toEqual("#EXTINF:6.000,"); - expect(subStrings2[20]).toEqual("/subtitlevtt.vtt?vtturi=http%3A%2F%2Fmock.com%2Fsubtitlechunk_lfra_w1588523518_b160000_slen_t64RW5nbGlzaA%3D%3D_0.webvtt&starttime=0&endtime=6&elapsedtime=0"); + expect(subStrings[16]).toEqual("#EXTINF:2.000,"); + expect(subStrings[17]).toEqual("http://mock.com/subs/7.webvtt"); + expect(subStrings2[16]).toEqual("#EXT-X-DISCONTINUITY") + expect(subStrings2[17]).toEqual("#EXTINF:6.000,"); + expect(subStrings2[18]).toEqual("/subtitlevtt.vtt?vtturi=http%3A%2F%2Fmock.com%2Fsubtitlechunk_lfra_w1588523518_b160000_slen_t64RW5nbGlzaA%3D%3D_0.webvtt&starttime=0&endtime=6&elapsedtime=0"); done(); }); }); it("subs with short segments after vod with subs with long segments", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestShortSegments2, mockMediaManifestShortSegments2, null, mockSubtitleManifestShortSegments2); @@ -280,18 +309,17 @@ describe("HLSVod with subtitles", () => { const m3u8_2 = mockVod2.getLiveMediaSubtitleSequences(0, "subs", "fr", 1); const subStrings = m3u8.split("\n"); const subStrings2 = m3u8_2.split("\n"); - expect(subStrings[22]).toEqual("#EXTINF:6.000,"); - expect(subStrings[23]).toEqual("/dummysubs.vtt?p=107"); - expect(subStrings2[22]).toEqual("#EXT-X-DISCONTINUITY") - expect(subStrings2[23]).toEqual("#EXTINF:4.000,"); - expect(subStrings2[24]).toEqual("http://mock.com/subs/0.webvtt"); + expect(subStrings[20]).toEqual("#EXTINF:6.000,"); + expect(subStrings[21]).toEqual("/dummysubs.vtt?p=107"); + expect(subStrings2[20]).toEqual("#EXT-X-DISCONTINUITY") + expect(subStrings2[21]).toEqual("#EXTINF:4.000,"); + expect(subStrings2[22]).toEqual("http://mock.com/subs/0.webvtt"); done(); }); }); it("subs with long segments after vod with subs with short segments and alwaysNewSegments(true)", (done) => { - let bool = 1; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { sequenceAlwaysContainNewSegments: bool, dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { sequenceAlwaysContainNewSegments: bool, dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsTrue); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsTrue); mockVod.load(mockMasterManifestShortSegments2, mockMediaManifestShortSegments2, null, mockSubtitleManifestShortSegments2) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) @@ -312,8 +340,8 @@ describe("HLSVod with subtitles", () => { }); it("subs with short segments after vod with subs with long segments and alwaysNewSegments(true)", (done) => { const bool = 1; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { sequenceAlwaysContainNewSegments: bool, dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { sequenceAlwaysContainNewSegments: bool, dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsTrue); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsTrue); mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestShortSegments2, mockMediaManifestShortSegments2, null, mockSubtitleManifestShortSegments2) @@ -332,30 +360,30 @@ describe("HLSVod with subtitles", () => { }); it("deltaTimes and playheadPos, alwaysNewSegments(true)", (done) => { const bool = 1; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { sequenceAlwaysContainNewSegments: bool, dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsTrue); + mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { const deltaV = mockVod.getDeltaTimes() const deltaS = mockVod.getDeltaTimes("subtitle") const playheadPosV = mockVod.getPlayheadPositions() const playheadPosS = mockVod.getPlayheadPositions("subtitle") - expect(deltaV).toEqual(deltaS); - expect(playheadPosV).toEqual(playheadPosS); + expect(deltaV).toEqual(deltaS); + expect(playheadPosV).toEqual(playheadPosS); done(); }); }); it("deltaTimes and playheadPos, alwaysNewSegments(false)", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod.load(mockMasterManifestLongSegments, mockMediaManifestLongSegments, mockAudioManifestLongSegments, mockSubtitleManifestLongSegments) .then(() => { const deltaV = mockVod.getDeltaTimes() const deltaS = mockVod.getDeltaTimes("subtitle") const playheadPosV = mockVod.getPlayheadPositions() const playheadPosS = mockVod.getPlayheadPositions("subtitle") - expect(deltaV).toEqual(deltaS); - expect(playheadPosV).toEqual(playheadPosS); + expect(deltaV).toEqual(deltaS); + expect(playheadPosV).toEqual(playheadPosS); done(); }); }); @@ -403,9 +431,8 @@ describe("HLSVod with subtitles", () => { } }) it("no subs after vod with subs with fallback URL", (done) => { - let url = "/sub.vtt"; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestWithSubs, mockMediaManifestWithSubs, mockAudioManifestWithSubs, mockSubtitleManifestWithSubs) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestNoSubs, mockMediaManifestNoSubs) @@ -413,17 +440,16 @@ describe("HLSVod with subtitles", () => { .then(() => { const m3u8 = mockVod2.getLiveMediaSubtitleSequences(0, "subs", "fr", 0); const subStrings = m3u8.split("\n") - expect(subStrings[23]).toEqual("/sub.vtt?p=107"); - expect(subStrings[24]).toEqual("#EXT-X-DISCONTINUITY") - expect(subStrings[25]).toEqual("#EXTINF:2.000,"); - expect(subStrings[26]).toEqual("/sub.vtt?p=9"); + expect(subStrings[21]).toEqual("/dummysubs.vtt?p=107"); + expect(subStrings[22]).toEqual("#EXT-X-DISCONTINUITY") + expect(subStrings[23]).toEqual("#EXTINF:2.000,"); + expect(subStrings[24]).toEqual("/dummysubs.vtt?p=9"); done(); }); }); it("subs after vod with no subs with fallback URL", (done) => { - let url = "/dummy.vtt"; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitleslice.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitleslice.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestNoSubs, mockMediaManifestNoSubs) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestWithSubs, mockMediaManifestWithSubs, mockAudioManifestWithSubs, mockSubtitleManifestWithSubs) @@ -431,18 +457,17 @@ describe("HLSVod with subtitles", () => { .then(() => { const m3u8 = mockVod2.getLiveMediaSubtitleSequences(0, "subs", "fr", 0); const subStrings = m3u8.split("\n") - expect(subStrings[19]).toEqual("/dummy.vtt?p=6"); - expect(subStrings[20]).toEqual("#EXT-X-DISCONTINUITY") - expect(subStrings[21]).toEqual("#EXTINF:6.000,"); - expect(subStrings[22]).toEqual("/subtitleslice.vtt?vtturi=http%3A%2F%2Fmock.com%2Fsubtitlechunk_lfra_w1588523518_b160000_slen_t64RW5nbGlzaA%3D%3D_0.webvtt&starttime=0&endtime=6&elapsedtime=0"); + expect(subStrings[17]).toEqual("/dummysubs.vtt?p=6"); + expect(subStrings[18]).toEqual("#EXT-X-DISCONTINUITY") + expect(subStrings[19]).toEqual("#EXTINF:6.000,"); + expect(subStrings[20]).toEqual("/subtitlevtt.vtt?vtturi=http%3A%2F%2Fmock.com%2Fsubtitlechunk_lfra_w1588523518_b160000_slen_t64RW5nbGlzaA%3D%3D_0.webvtt&starttime=0&endtime=6&elapsedtime=0"); done(); }); }); it("subs after vod without subs", (done) => { - let url = "/sub.vtt"; - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod3 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: url, subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); + mockVod3 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestWithSubs, mockMediaManifestWithSubs, mockAudioManifestWithSubs, mockSubtitleManifestWithSubs) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestNoSubs, mockMediaManifestNoSubs) @@ -453,17 +478,17 @@ describe("HLSVod with subtitles", () => { .then(() => { const m3u8_3 = mockVod3.getLiveMediaSubtitleSequences(0, "subs", "fr", 1); const subStrings3 = m3u8_3.split("\n") - expect(subStrings3[31]).toEqual("#EXTINF:2.000,"); - expect(subStrings3[32]).toEqual("/sub.vtt?p=15"); - expect(subStrings3[33]).toEqual("#EXT-X-DISCONTINUITY") - expect(subStrings3[34]).toEqual("#EXTINF:6.000,"); - expect(subStrings3[35]).toEqual("/subtitlevtt.vtt?vtturi=http%3A%2F%2Fmock.com%2Fsubtitlechunk_lfra_w1588523518_b160000_slen_t64RW5nbGlzaA%3D%3D_0.webvtt&starttime=0&endtime=6&elapsedtime=0"); + expect(subStrings3[29]).toEqual("#EXTINF:2.000,"); + expect(subStrings3[30]).toEqual("/dummysubs.vtt?p=15"); + expect(subStrings3[31]).toEqual("#EXT-X-DISCONTINUITY") + expect(subStrings3[32]).toEqual("#EXTINF:6.000,"); + expect(subStrings3[33]).toEqual("/subtitlevtt.vtt?vtturi=http%3A%2F%2Fmock.com%2Fsubtitlechunk_lfra_w1588523518_b160000_slen_t64RW5nbGlzaA%3D%3D_0.webvtt&starttime=0&endtime=6&elapsedtime=0"); done(); }); }); it("no subs after vod with subs without fallback URL", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); - mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true, expectedSubtitleTracks: subtitleTracks }); + mockVod2 = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true, expectedSubtitleTracks: subtitleTracks }); mockVod.load(mockMasterManifestWithSubs, mockMediaManifestWithSubs, mockAudioManifestWithSubs, mockSubtitleManifestWithSubs) .then(() => { return mockVod2.loadAfter(mockVod, mockMasterManifestNoSubs, mockMediaManifestNoSubs) @@ -491,7 +516,7 @@ describe("HLSVod with subtitles", () => { }); it("generateSmallerSubtitleSegments with one segment", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestNoSubs, mockMediaManifestNoSubs) .then(() => { const segment = { @@ -512,7 +537,7 @@ describe("HLSVod with subtitles", () => { }); it("generateSmallerSubtitleSegments with two segment and uneven", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); mockVod.load(mockMasterManifestNoSubs, mockMediaManifestNoSubs) .then(() => { const segment = { @@ -559,7 +584,7 @@ describe("HLSVod with subtitles", () => { }); }); it("generate subtitle sequences type A", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt", shouldContainSubtitles: true }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); let mockSequence = { duration: 10, timelinePosition: 0, @@ -591,7 +616,7 @@ describe("HLSVod with subtitles", () => { }); it("generate subtitle sequences type B", (done) => { - mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, { dummySubtitleEndpoint: "/dummysubs.vtt", subtitleSliceEndpoint: "/subtitlevtt.vtt" }); + mockVod = new HLSVod("http://mock.com/mock.m3u8", null, 0, 0, null, hlsOptsAlwaysNewSegmentsFalse); let mockSequence = { duration: 10, timelinePosition: 0,