Adapter: Subtitle Style Store
player.subtitleStyle() (see Subtitles & Text Tracks) keeps the user’s font, color, and edge-style choices in memory and emits 'subtitleStyle' on every change, it never persists anything on its own. ISubtitleStyleStore is the contract for the other half: load a saved preference after ready() and apply it, save on every change so it survives the next session.
The interface
interface ISubtitleStyleStore {
/** Persisted style, or null when nothing was saved yet. */
load(): Promise<Partial<SubtitleStyle> | null>;
/** Persist style so it survives a reload. */
save(style: SubtitleStyle): Promise<void>;
/** Clear any persisted preference ("reset to defaults"). */
clear(): Promise<void>;
}
The shipped implementation
StorageBackedSubtitleStyleStore persists through the kit’s IStorage port, the same swappable storage interface the kit’s plugins persist their preferences through via this.storage, under the key 'subtitle-style' (namespaced automatically when the storage backend itself is namespaced):
The constructor takes an IStorage instance directly, not the player, the player has no public accessor for its own active storage adapter (only plugin code reaches it, via this.storage). Construct the store with the same instance passed to setup({ storage }), or with a fresh LocalStorageBackend (the kit’s own default) when setup() didn’t override it:
import { StorageBackedSubtitleStyleStore } from '@nomercy-entertainment/nomercy-video-player';
import { LocalStorageBackend } from '@nomercy-entertainment/nomercy-player-core';
const store = new StorageBackedSubtitleStyleStore(new LocalStorageBackend());
Wiring it end to end
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
const player = nmplayer('player');
await player.ready();
const saved = await store.load();
if (saved) player.subtitleStyle(saved);
player.on('subtitleStyle', (style) => {
void store.save(style);
});
load() returns Partial<SubtitleStyle>, not the full shape, because a store might only have persisted a subset of fields across app versions. player.subtitleStyle(patch) already merges a partial onto the current style, so passing the loaded value straight through is correct even when it’s incomplete.
Rules & restrictions
- The player never calls any of these three methods itself, wiring load-on-ready and save-on-change is entirely the consumer’s responsibility, exactly like the pattern in Recipe: Swap an Adapter for other kit-level ports.
clear()only removes the persisted record, it does not reset the livesubtitleStyle()value, callplayer.subtitleStyle(defaultStyle)yourself alongside it for a “reset to defaults” action that also affects the currently-rendered subtitles.
How to extend it
Implement the three methods against a remote store for cross-device sync, or any other backing store you already have:
class ApiSubtitleStyleStore implements ISubtitleStyleStore {
async load(): Promise<Partial<SubtitleStyle> | null> {
return fetchUserPreference('subtitleStyle');
}
async save(style: SubtitleStyle): Promise<void> {
await saveUserPreference('subtitleStyle', style);
}
async clear(): Promise<void> {
await deleteUserPreference('subtitleStyle');
}
}
Next steps
- Reference: Types: the full
SubtitleStylefield list this adapter persists.