add all frontend TypeScript modules

This commit is contained in:
2026-02-19 11:44:48 +02:00
parent 28cc8491c2
commit 61379d9b64
7 changed files with 1888 additions and 1 deletions

83
src/store.ts Normal file
View File

@@ -0,0 +1,83 @@
/**
* Shared mutable state and pure utility functions.
* All modules import from here - no circular dependencies.
*/
import type { LibraryInfo, VideoItem } from './types';
// ---- Shared mutable state ----
export let library: LibraryInfo | null = null;
export let currentIndex = 0;
export let prefs: Record<string, any> | null = null;
export let suppressTick = false;
export let lastTick = 0;
export let seeking = false;
export function setLibrary(lib: LibraryInfo | null) { library = lib; }
export function setCurrentIndex(idx: number) { currentIndex = idx; }
export function setPrefs(p: Record<string, any> | null) { prefs = p; }
export function setSuppressTick(v: boolean) { suppressTick = v; }
export function setLastTick(v: number) { lastTick = v; }
export function setSeeking(v: boolean) { seeking = v; }
// ---- Cross-module callbacks (set by main.ts) ----
export const cb = {
loadIndex: null as ((idx: number, tc?: number, pause?: boolean, autoplay?: boolean) => Promise<void>) | null,
renderList: null as (() => void) | null,
updateInfoPanel: null as (() => void) | null,
updateOverall: null as (() => void) | null,
notify: null as ((msg: string) => void) | null,
refreshCurrentVideoMeta: null as (() => Promise<void>) | null,
onLibraryLoaded: null as ((info: LibraryInfo, startScan: boolean) => Promise<void>) | null,
buildSpeedMenu: null as ((rate: number) => void) | null,
};
// ---- Pure utility functions ----
export function clamp(n: number, a: number, b: number): number {
return Math.max(a, Math.min(b, n));
}
export function fmtTime(sec: number): string {
sec = Math.max(0, Math.floor(sec || 0));
const h = Math.floor(sec / 3600);
const m = Math.floor((sec % 3600) / 60);
const s = sec % 60;
if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
return `${m}:${String(s).padStart(2, '0')}`;
}
export function fmtBytes(n: number): string {
n = Number(n || 0);
if (!isFinite(n) || n <= 0) return '-';
const u = ['B', 'KB', 'MB', 'GB', 'TB'];
let i = 0;
while (n >= 1024 && i < u.length - 1) { n /= 1024; i++; }
return `${n.toFixed(i === 0 ? 0 : 1)} ${u[i]}`;
}
export function fmtDate(ts: number): string {
if (!ts) return '-';
try { return new Date(ts * 1000).toLocaleString(); } catch { return '-'; }
}
export function fmtBitrate(bps: number): string | null {
const n = Number(bps || 0);
if (!isFinite(n) || n <= 0) return null;
const kb = n / 1000.0;
if (kb < 1000) return `${kb.toFixed(0)} kbps`;
return `${(kb / 1000).toFixed(2)} Mbps`;
}
export function currentItem(): VideoItem | null {
if (!library || !library.items) return null;
return library.items[currentIndex] || null;
}
export function computeResumeTime(item: VideoItem | null): number {
if (!item) return 0.0;
if (item.finished) return 0.0;
const pos = Number(item.pos || 0.0);
const dur = Number(item.duration || 0.0);
if (dur > 0) return clamp(pos, 0.0, Math.max(0.0, dur - 0.25));
return Math.max(0.0, pos);
}