style: format static/player/state.ts

This commit is contained in:
2026-06-21 02:04:51 +02:00
committed by Milas Holsting
parent ff710a354c
commit 4d4ee7bd58

View File

@@ -1,9 +1,10 @@
import type { ModeSource, SkipSegment, SubtitleCue, SubtitleTrack, ActiveSegment } from "./types"; import type { ModeSource, SkipSegment, SubtitleCue, SubtitleTrack, ActiveSegment } from "./types";
import { parseModeSources, parseSegments } from "./validate";
import { q, qs, dataset } from "../q"; import { q, qs, dataset } from "../q";
import { safeLocalStorage } from "./storage"; import { safeLocalStorage } from "./storage";
import { parseModeSources, parseSegments } from "./validate";
export interface PlayerState { export type PlayerState = {
elements: { elements: {
container: HTMLElement; container: HTMLElement;
video: HTMLVideoElement; video: HTMLVideoElement;
@@ -46,19 +47,10 @@ export interface PlayerState {
activeSegments: ActiveSegment[]; activeSegments: ActiveSegment[];
activeSegment: ActiveSegment | null; activeSegment: ActiveSegment | null;
}; };
subtitles: { subtitles: { activeCues: SubtitleCue[]; tracks: SubtitleTrack[] };
activeCues: SubtitleCue[]; ui: { isScrubbing: boolean; isFullscreen: boolean };
tracks: SubtitleTrack[]; timers: { playerControlsTimeout: number | undefined; progressSaveTimer: number | undefined };
}; };
ui: {
isScrubbing: boolean;
isFullscreen: boolean;
};
timers: {
playerControlsTimeout: number | undefined;
progressSaveTimer: number | undefined;
};
}
const createInitialState = (): PlayerState => ({ const createInitialState = (): PlayerState => ({
elements: { elements: {
@@ -100,23 +92,10 @@ const createInitialState = (): PlayerState => ({
endedProgressSaved: false, endedProgressSaved: false,
lastSavedProgress: { episode: "1", seconds: -1 }, lastSavedProgress: { episode: "1", seconds: -1 },
}, },
skip: { skip: { parsedSegments: [], activeSegments: [], activeSegment: null },
parsedSegments: [], subtitles: { activeCues: [], tracks: [] },
activeSegments: [], ui: { isScrubbing: false, isFullscreen: false },
activeSegment: null, timers: { playerControlsTimeout: undefined, progressSaveTimer: undefined },
},
subtitles: {
activeCues: [],
tracks: [],
},
ui: {
isScrubbing: false,
isFullscreen: false,
},
timers: {
playerControlsTimeout: undefined,
progressSaveTimer: undefined,
},
}); });
export const state: PlayerState = createInitialState(); export const state: PlayerState = createInitialState();
@@ -130,14 +109,14 @@ export const hideEndState = (): void => {
state.elements.container.classList.remove("video-ended"); state.elements.container.classList.remove("video-ended");
}; };
interface RequiredPlayerElements { type RequiredPlayerElements = {
video: HTMLVideoElement; video: HTMLVideoElement;
progress: HTMLElement; progress: HTMLElement;
scrubber: HTMLElement; scrubber: HTMLElement;
buffered: HTMLElement; buffered: HTMLElement;
timeDisplay: HTMLElement; timeDisplay: HTMLElement;
durationDisplay: HTMLElement; durationDisplay: HTMLElement;
} };
const findElement = <T extends Element>( const findElement = <T extends Element>(
container: HTMLElement, container: HTMLElement,
@@ -145,7 +124,9 @@ const findElement = <T extends Element>(
elementType: new () => T, elementType: new () => T,
): T | null => { ): T | null => {
const element = container.querySelector(selector); const element = container.querySelector(selector);
if (element instanceof elementType) return element; if (element instanceof elementType) {
return element;
}
return null; return null;
}; };
@@ -164,13 +145,12 @@ const requiredPlayerElements = (container: HTMLElement): RequiredPlayerElements
return { video, progress, scrubber, buffered, timeDisplay, durationDisplay }; return { video, progress, scrubber, buffered, timeDisplay, durationDisplay };
}; };
/** /** Initializes player state from DOM data attributes. Called once on page load or htmx swap. */
* Initializes player state from DOM data attributes.
* Called once on page load or htmx swap.
*/
export const initState = (c: HTMLElement): boolean => { export const initState = (c: HTMLElement): boolean => {
const elements = requiredPlayerElements(c); const elements = requiredPlayerElements(c);
if (!elements) return false; if (!elements) {
return false;
}
// core elements // core elements
state.elements.container = c; state.elements.container = c;
@@ -232,11 +212,15 @@ export const initState = (c: HTMLElement): boolean => {
// This avoids mismatches where the UI highlights one mode but the video is actually playing the other. // This avoids mismatches where the UI highlights one mode but the video is actually playing the other.
const deriveModeFromVideoSrc = (): string | null => { const deriveModeFromVideoSrc = (): string | null => {
const raw = state.elements.video.currentSrc || state.elements.video.src; const raw = state.elements.video.currentSrc || state.elements.video.src;
if (!raw) return null; if (!raw) {
return null;
}
try { try {
const u = new URL(raw, window.location.href); const u = new URL(raw, window.location.href);
const modeParam = u.searchParams.get("mode"); const modeParam = u.searchParams.get("mode");
if (modeParam === "sub" || modeParam === "dub") return modeParam; if (modeParam === "sub" || modeParam === "dub") {
return modeParam;
}
return null; return null;
} catch (error) { } catch (error) {
console.error("failed to parse mode url:", error); console.error("failed to parse mode url:", error);