Recently Written · git

subread-extension

Show your own .srt over a YouTube video, in time with it. Chrome and Firefox.

git clone https://github.com/equwal/subread-extension

Log | Files | Refs


tests/srt.test.cjs (4292 bytes)

1 /* node --test tests */
2 const test = require('node:test');
3 const assert = require('node:assert/strict');
4 const { parse, cueAt, subtitleTime, videoTime, seconds } = require('../src/srt.js');
5 
6 test('an .srt is read: numbers, stamps, text of more than one line, tags removed', () => {
7   const cues = parse('1\r\n00:00:01,500 --> 00:00:04,000\r\nIt was a <i>dark</i> night;\r\nthe rain fell.\r\n\r\n' +
8     '2\r\n01:02:03,004 --> 01:02:05,000\r\n吾輩は猫である。\r\n');
9   assert.deepEqual(cues, [
10     { start: 1.5, end: 4, text: 'It was a dark night;\nthe rain fell.' },
11     { start: 3723.004, end: 3725, text: '吾輩は猫である。' },
12   ]);
13 });
14 
15 test('the text of each checked language is kept as it is: accents, inverted marks, quotes, kana', () => {
16   const lines = {
17     en: 'It was a dark night; the rain fell.',
18     pt: '— Não me parece bonito — disse ela, à porta.',
19     es: '¿Qué es esto? ¡Ñandú, señor Quijote!',
20     ru: '«Ёлка, — сказал он, — и её огни».',
21     ja: '「女のいない男たち」 東京で暮らしている。',
22   };
23   const source = Object.values(lines).map((text, i) => `${i + 1}\n00:00:0${i},000 --> 00:00:0${i},900\n${text}\n`).join('\n');
24   const cues = parse(source);
25   assert.deepEqual(cues.map((c) => c.text), Object.values(lines));
26   Object.values(lines).forEach((text, i) => assert.equal(cueAt(cues, i + 0.5).text, text));
27 });
28 
29 test('a .vtt is read too, and what is not a cue is passed over', () => {
30   const cues = parse('WEBVTT\n\nNOTE made by hand\n\n00:01.000 --> 00:02.5\nHello\n\nbroken --> block\nx\n\n3\n00:00:09,000 --> 00:00:08,000\nends before it starts\n');
31   assert.deepEqual(cues, [{ start: 1, end: 2.5, text: 'Hello' }]);
32 });
33 
34 test('stamps', () => {
35   assert.equal(seconds('00:00:00,004'), 0.004);
36   assert.equal(seconds('10:00:00.5'), 36000.5);
37   assert.ok(Number.isNaN(seconds('soon')));
38 });
39 
40 test('the cue for a moment is the one a slow search finds, for any cues and any moment', () => {
41   let seed = 11;
42   const random = () => (seed = (seed * 1103515245 + 12345) >>> 0) / 2 ** 32;
43   for (let round = 0; round < 300; round++) {
44     const cues = [];
45     let t = random() * 5;
46     for (let i = 0; i < Math.floor(random() * 40); i++) {
47       const start = t, end = start + 0.2 + random() * 5;
48       cues.push({ start, end, text: String(i) });
49       t = end + (random() < 0.5 ? 0 : random() * 3);        // back to back, or a gap
50     }
51     for (let k = 0; k < 60; k++) {
52       const at = random() * (t + 5) - 1;
53       const slow = cues.filter((c) => c.start <= at && at < c.end).pop() ?? null;
54       assert.equal(cueAt(cues, at), slow);
55     }
56   }
57   assert.equal(cueAt([], 3), null);
58 });
59 
60 test('a cue that overlaps the one after it gives way to the later one', () => {
61   const cues = [{ start: 0, end: 10, text: 'long' }, { start: 4, end: 6, text: 'short' }];
62   assert.equal(cueAt(cues, 5).text, 'short');
63   assert.equal(cueAt(cues, 8).text, 'long');
64 });
65 
66 test('the time of the video is moved onto the clock of the subtitles', () => {
67   assert.equal(subtitleTime(100, 0, 1), 100);
68   assert.equal(subtitleTime(100, 12.5, 1), 87.5);            // the upload has a 12.5 s intro
69   assert.ok(Math.abs(subtitleTime(3600, 0, 1.001) - 3603.6) < 1e-9);   // and runs a little slow
70 });
71 
72 test('the transcript panel moves a cue time back onto the clock of the video', () => {
73   assert.equal(videoTime(100, 0, 1), 100);
74   assert.equal(videoTime(87.5, 12.5, 1), 100);               // the 12.5 s intro comes back
75   assert.ok(Math.abs(videoTime(3603.6, 0, 1.001) - 3600) < 1e-9);
76 });
77 
78 test('videoTime undoes subtitleTime, and subtitleTime undoes videoTime, for many offsets and rates', () => {
79   let seed = 7;
80   const random = () => (seed = (seed * 1103515245 + 12345) >>> 0) / 2 ** 32;
81   for (let round = 0; round < 500; round++) {
82     const offset = (random() - 0.5) * 40;         // seconds, either side of 0
83     const rate = 0.9 + random() * 0.2;            // the panel limits rate to 0.9 .. 1.1
84     const videoT = random() * 7200;               // up to two hours in
85     const subT = subtitleTime(videoT, offset, rate);
86     assert.ok(Math.abs(videoTime(subT, offset, rate) - videoT) < 1e-9);
87     assert.ok(Math.abs(subtitleTime(videoTime(subT, offset, rate), offset, rate) - subT) < 1e-9);
88   }
89 });