Skip to content

Commit 76e241e

Browse files
authored
BADGER-16: hide subtitles when seeking away (#408)
1 parent fde510c commit 76e241e

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

src/subtitles/imscsubtitles.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ function IMSCSubtitles(
2424
let currentSubtitlesElement
2525
let updateInterval
2626

27+
let previousTime = null
28+
2729
if (autoStart) start()
2830

2931
function hasOffset() {
@@ -299,6 +301,7 @@ function IMSCSubtitles(
299301
function renderSubtitle(xml, currentTime, subsElement, styleOpts, renderHeight, renderWidth) {
300302
try {
301303
const isd = generateISD(xml, currentTime)
304+
302305
renderHTML(isd, subsElement, null, renderHeight, renderWidth, false, null, null, false, styleOpts)
303306
} catch (error) {
304307
error.name = "SubtitlesRenderError"
@@ -368,6 +371,15 @@ function IMSCSubtitles(
368371
}
369372

370373
function update(currentTime) {
374+
// clears state to ensure we always check if subtitles should be rendered after a seek
375+
if (typeof previousTime === "number" && (previousTime > currentTime || currentTime - previousTime > 2)) {
376+
for (const segment of segments) {
377+
segment.previousSubtitleIndex = undefined
378+
}
379+
removeCurrentSubtitlesElement()
380+
}
381+
previousTime = currentTime
382+
371383
const segment = getSegmentToRender(currentTime)
372384

373385
if (segment) {

src/subtitles/imscsubtitles.test.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,42 @@ describe("IMSC Subtitles", () => {
635635

636636
expect(Plugins.interface.onSubtitlesRenderError).toHaveBeenCalledTimes(1)
637637
})
638+
639+
it("removes subtitle element after seeking to an unsubtitled region", () => {
640+
captions = [{ url: "mock://some.media/captions/subtitles.xml", cdn: "foo" }]
641+
642+
subtitles = IMSCSubtitles(mockMediaPlayer, targetElement, mockMediaSources, {
643+
autoStart: true,
644+
})
645+
646+
setTime(20)
647+
648+
const preSeekAwayContainer = document.querySelector("#bsp_subtitles")
649+
expect(preSeekAwayContainer).not.toBeNull()
650+
651+
setTime(0)
652+
653+
const postSeekAwayContainer = document.querySelector("#bsp_subtitles")
654+
expect(postSeekAwayContainer).toBeNull()
655+
})
656+
657+
it("keeps subtitle element rendered after seeking forward within the same subtitle", () => {
658+
captions = [{ url: "mock://some.media/captions/subtitles.xml", cdn: "foo" }]
659+
660+
subtitles = IMSCSubtitles(mockMediaPlayer, targetElement, mockMediaSources, {
661+
autoStart: true,
662+
})
663+
664+
setTime(20)
665+
666+
const preSeekAwayContainer = document.querySelector("#bsp_subtitles")
667+
expect(preSeekAwayContainer).not.toBeNull()
668+
669+
setTime(30)
670+
671+
const postSeekAwayContainer = document.querySelector("#bsp_subtitles")
672+
expect(postSeekAwayContainer).not.toBeNull()
673+
})
638674
})
639675

640676
describe("subtitles delivered as segments", () => {
@@ -1324,6 +1360,93 @@ describe("IMSC Subtitles", () => {
13241360
expect(generateISD).not.toHaveBeenCalled()
13251361
expect(renderHTML).not.toHaveBeenCalled()
13261362
})
1363+
1364+
it("keeps subtitle element rendered after seeking between segments", () => {
1365+
captions = [
1366+
{
1367+
type: "application/ttml+xml",
1368+
url: "mock://some.media/captions/$segment$.m4s",
1369+
cdn: "foo",
1370+
segmentLength: 3.84,
1371+
},
1372+
]
1373+
1374+
const epochStartTimeSeconds = 1614769200
1375+
1376+
const convertSecondsToEpoch = (...seconds) =>
1377+
seconds.map((time) => (time === 0 ? 0 : epochStartTimeSeconds + time))
1378+
1379+
const buildMockSegment = ({ beginTimes, id } = {}) => ({
1380+
_mockedSegmentID: id,
1381+
body: {
1382+
contents: ["stub"],
1383+
},
1384+
head: {
1385+
styling: {},
1386+
},
1387+
getMediaTimeEvents: () => beginTimes,
1388+
})
1389+
1390+
fromXML.mockReturnValueOnce(
1391+
buildMockSegment({
1392+
id: 1,
1393+
beginTimes: convertSecondsToEpoch(0, 1, 2, 3.84),
1394+
})
1395+
)
1396+
1397+
fromXML.mockReturnValueOnce(
1398+
buildMockSegment({
1399+
id: 2,
1400+
beginTimes: convertSecondsToEpoch(0, 3.84, 4, 7.68),
1401+
})
1402+
)
1403+
1404+
fromXML.mockReturnValueOnce(
1405+
buildMockSegment({
1406+
id: 3,
1407+
beginTimes: convertSecondsToEpoch(0, 7.68, 9, 9.7, 11.52),
1408+
})
1409+
)
1410+
1411+
fromXML.mockReturnValueOnce(
1412+
buildMockSegment({
1413+
id: 4,
1414+
beginTimes: convertSecondsToEpoch(0, 11.52, 14, 16),
1415+
})
1416+
)
1417+
1418+
// back to segment 1
1419+
fromXML.mockReturnValueOnce(
1420+
buildMockSegment({
1421+
id: 1,
1422+
beginTimes: convertSecondsToEpoch(0, 1, 2, 3.84),
1423+
})
1424+
)
1425+
1426+
fromXML.mockReturnValue(buildMockSegment({ id: null }))
1427+
1428+
generateISD.mockReturnValue({ contents: ["mockContents"] })
1429+
1430+
subtitles = IMSCSubtitles(mockMediaPlayer, targetElement, mockMediaSources, {
1431+
autoStart: true,
1432+
})
1433+
1434+
progressTime(3.5)
1435+
1436+
const preSeekAwayContainer = document.querySelector("#bsp_subtitles")
1437+
expect(preSeekAwayContainer).not.toBeNull()
1438+
1439+
progressTime(2.5)
1440+
1441+
const postSeekAwayContainer = document.querySelector("#bsp_subtitles")
1442+
expect(postSeekAwayContainer).not.toBeNull()
1443+
1444+
// back to segment 1
1445+
progressTime(-2.5)
1446+
1447+
const postSeekAwayContainer2 = document.querySelector("#bsp_subtitles")
1448+
expect(postSeekAwayContainer2).not.toBeNull()
1449+
})
13271450
})
13281451
})
13291452

0 commit comments

Comments
 (0)