fix: harden player vtt handling
This commit is contained in:
@@ -43,5 +43,7 @@ export const setupThumbnails = (): void => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => console.error("Failed to fetch thumbnails:", err));
|
.catch(() => {
|
||||||
|
window.showToast?.({ message: "Failed to load episode thumbnails." });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const initPlayer = (): void => {
|
|||||||
teardownPlayer();
|
teardownPlayer();
|
||||||
|
|
||||||
if (!initState(container)) {
|
if (!initState(container)) {
|
||||||
console.error("Video player markup is missing required controls.");
|
window.showToast?.({ message: "Video player markup is missing required controls." });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentContainer = container;
|
currentContainer = container;
|
||||||
|
|||||||
30
static/player/subtitles/vtt.test.ts
Normal file
30
static/player/subtitles/vtt.test.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { describe, test } from "node:test";
|
||||||
|
import { parseVtt, parseVttTime } from "./vtt";
|
||||||
|
|
||||||
|
describe("vtt parsing", () => {
|
||||||
|
test("parses mm:ss timestamps", () => {
|
||||||
|
assert.equal(parseVttTime("01:02.500"), 62.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("parses hh:mm:ss timestamps", () => {
|
||||||
|
assert.equal(parseVttTime("01:02:03.250"), 3723.25);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("parses standard and compact cues", () => {
|
||||||
|
const cues = parseVtt(`WEBVTT
|
||||||
|
|
||||||
|
1
|
||||||
|
00:00.000 --> 00:01.500
|
||||||
|
<i>Hello</i>
|
||||||
|
|
||||||
|
00:02.000 --> 00:03.000
|
||||||
|
World
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.deepEqual(cues, [
|
||||||
|
{ start: 0, end: 1.5, text: "Hello" },
|
||||||
|
{ start: 2, end: 3, text: "World" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
export const parseVttTime = (raw: string): number => {
|
export const parseVttTime = (raw: string): number => {
|
||||||
const parts = raw.trim().split(":");
|
const parts = raw.trim().split(":");
|
||||||
if (parts.length < 2) return 0;
|
if (parts.length < 2) return 0;
|
||||||
const secPart = parts.pop()!;
|
const secPart = parts[parts.length - 1];
|
||||||
const minPart = parts.pop()!;
|
const minPart = parts[parts.length - 2];
|
||||||
const hourPart = parts.pop() ?? "0";
|
const hourPart = parts.length > 2 ? parts[parts.length - 3] : "0";
|
||||||
|
if (!secPart || !minPart) return 0;
|
||||||
return Number(hourPart) * 3600 + Number(minPart) * 60 + Number(secPart.replace(",", "."));
|
return Number(hourPart) * 3600 + Number(minPart) * 60 + Number(secPart.replace(",", "."));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user