openvibers/openvibe.mediahub Commits

Chapters: no chapter for a moment with no title, or past the video's end (VOD 6026 listed "0:16 " and 41:16 in 32:01) (#142)

OP OpenVibers committed 18 days ago · 12ae1ac976 · 2 files, +15 −3

Changes

ddiff --git a/server/video/pages.js b/server/video/pages.js
iindex 5f322b9..8f097e8 100644
---- a/server/video/pages.js
++++ b/server/video/pages.js
@@@ -383,14 +383,22 @@ function chapterTitle(description) {
return `${cut.slice(0, Math.max(cut.lastIndexOf(' '), 50))}…`;
}
--/** The AI moments as chapters: the first one, then one at least a twelfth of the stream later, at most twelve. */
++/**
++ * The AI moments as chapters: the first one, then one at least a twelfth of the stream later, at most twelve. A moment
++ * with nothing seen to title it (only what was heard), or past the video's end (a stream's moments read for one part of
++ * it, before Live kept parts), is no chapter: VOD 6026 listed "0:16" with no title and 41:16 in a 32-minute video.
++ */
function chapters(mems, durationSeconds) {
-- const gap = Math.max(0, Number(durationSeconds) || 0) / MAX_CHAPTERS;
++ const length = Math.max(0, Number(durationSeconds) || 0);
++ const gap = length / MAX_CHAPTERS;
const out = [];
for (const m of mems) {
if (out.length >= MAX_CHAPTERS) break;
++ if (length && m.offset_seconds >= length) break;
++ const title = chapterTitle(m.description);
++ if (!title) continue;
if (out.length && m.offset_seconds - out[out.length - 1].offset_seconds < gap) continue;
-- out.push({ offset_seconds: m.offset_seconds, description: chapterTitle(m.description) });
++ out.push({ offset_seconds: m.offset_seconds, description: title });
}
return out;
}
ddiff --git a/test/video-chapters.test.js b/test/video-chapters.test.js
iindex ddd131f..28bde90 100644
---- a/test/video-chapters.test.js
++++ b/test/video-chapters.test.js
@@@ -15,6 +15,10 @@ assert.strictEqual(out[0].description, 'Moment 0', 'the heard part is dropped');
// A short clip-length recording keeps close moments (the gap is a twelfth of 45 s).
assert.deepStrictEqual(chapters([{ offset_seconds: 10, description: 'Intro' }, { offset_seconds: 30, description: 'Main' }], 45).map((c) => c.offset_seconds), [10, 30]);
++// A moment with only what was heard (no title), or past the video's end, is no chapter (VOD 6026: "0:16 " and 41:16 in 32:01).
++assert.deepStrictEqual(chapters([{ offset_seconds: 16, description: ' — heard: "hey"' }, { offset_seconds: 287, description: 'A campsite' }, { offset_seconds: 2476, description: 'Later' }], 1921)
++ .map((c) => [c.offset_seconds, c.description]), [[287, 'A campsite']]);
++
// Titles: a trailing period goes; a long one is cut at a word with an ellipsis.
assert.strictEqual(chapterTitle('A streamer waves.'), 'A streamer waves');
const long = chapterTitle('word '.repeat(40));