All files / src/lib subtitle-session.ts

100% Statements 15/15
100% Branches 9/9
100% Functions 3/3
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73                        2x                                                       2x 99x 99x   1x               2x 231x 231x               2x         15x 15x 10x 10x    
// SPDX-License-Identifier: GPL-3.0-only
// Copyright (C) 2026 Max Boksem. See NOTICE for additional terms under GPLv3 section 7.
 
// The subtitles the player showed when its page last closed, kept in
// sessionStorage. Playback goes on while another page is open, and mpv
// doesn't draw the subtitles the app draws itself. So when the player page
// opens again on the same item, it shows these again.
 
import { readStorage, removeStorage, writeStorage } from "./storage";
import type { SubtitlePosition } from "./subtitle-position";
import type { SubtitleCue, SubtitleEntry } from "./types";
 
const KEY = "mvp_lastSubtitles";
 
/** The language, and the place in it, to pick subtitles from for the next episode. */
export interface SubtitlePreference {
	languageCode: string;
	rankInLanguage: number;
}
 
export interface SubtitleSession {
	/** The item the subtitles were shown over. */
	channelId: string;
	/** The URL the player last loaded for it, or null while it hadn't started. */
	url: string | null;
	/** The subtitle file picked, or null for none. */
	fileId: number | null;
	entry: SubtitleEntry | null;
	cues: SubtitleCue[];
	/** The delay picked for the subtitles, in seconds. */
	delay: number;
	position: SubtitlePosition;
	fontSize: number;
	fontFamily: string;
	preference: SubtitlePreference | null;
	/** Whether the next episode's subtitles were still loading. */
	autoLoad: boolean;
}
 
/** The subtitles saved when the player page last closed, or null. */
export const readSubtitleSession = (): SubtitleSession | null => {
	try {
		return JSON.parse(readStorage(KEY, "session") ?? "null") as SubtitleSession | null;
	} catch {
		return null;
	}
};
 
/**
 * Saves the subtitles for when the player page opens again, or forgets them
 * for null. The old ones go first, so a save that fails leaves none.
 */
export const saveSubtitleSession = (session: SubtitleSession | null): void => {
	removeStorage(KEY, "session");
	if (session) writeStorage(KEY, JSON.stringify(session), "session");
};
 
/**
 * Changes the saved subtitles of the item `channelId` when the player last
 * loaded `url` for it, as the page saved them. Returns false, and changes
 * nothing, when none are saved or they're for another item or stream.
 */
export const updateSubtitleSession = (
	channelId: string,
	url: string | null,
	change: Partial<SubtitleSession>
): boolean => {
	const saved = readSubtitleSession();
	if (!saved || saved.channelId !== channelId || saved.url !== url) return false;
	saveSubtitleSession({ ...saved, ...change });
	return true;
};