Files
iptvnator/libs/services/src/lib/settings-store.defaults.ts
T
4grayandClaude Fable 5.1 83e70a52c5 feat(settings): add PIN-protected parental lock for categories (#285)
Locks are per category (Xtream category ids, Stalker genre ids, M3U group
titles) and kept in one renderer lock store persisted to app_state /
localStorage; `categories.locked` is the SQLite index re-stamped from it.
While the lock is active the DB worker filters every content read, the PWA
data source, the Stalker store and the M3U channel list filter in memory,
and the enforcement service reloads the stores and steps off withheld
selections. Settings → Parental lock sets the PIN (PBKDF2, never in
Settings), the relock timeout and Lock now; lock toggles live in the
Xtream/M3U management dialogs and a new Stalker lock dialog, all behind
the PIN. Backups carry the locks per playlist entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 22:48:27 +02:00

114 lines
3.5 KiB
TypeScript

import {
DEFAULT_DASHBOARD_RAILS_SETTINGS,
DEFAULT_PARENTAL_LOCK_RELOCK_MINUTES,
DEFAULT_TMDB_SETTINGS,
Language,
Settings,
StartupBehavior,
StreamFormat,
Theme,
VideoPlayer,
} from '@iptvnator/shared/interfaces';
/** Defaults and boot-time helpers of `SettingsStore`, split out for size. */
export const DEFAULT_SETTINGS: Settings = {
player: VideoPlayer.VideoJs,
webPlayerSharedControls: true,
playerAmbientMode: false,
playerUpNextRail: true,
fullscreenChannelPanel: true,
vodAutoFailover: false,
m3uVodDetails: true,
streamFormat: StreamFormat.AutoStreamFormat,
openStreamOnDoubleClick: false,
language: Language.ENGLISH,
showCaptions: false,
showDashboard: true,
startupBehavior: StartupBehavior.FirstView,
startupWindowMode: 'normal',
showExternalPlaybackBar: true,
stripCountryPrefix: false,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvPlayerArguments: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
vlcPlayerArguments: '',
vlcReuseInstance: false,
remoteControl: false,
remoteControlPort: 8765,
epgUrl: [],
downloadFolder: '',
recordingFolder: '',
embeddedMpvFrameCopy: false,
embeddedMpvExtraOptions: '',
embeddedMpvAutoReconnect: true,
portalConnectivityGuard: true,
coverSize: 'medium',
epgViewMode: 'timeline',
epgOffsetMinutes: 0,
dashboardRails: DEFAULT_DASHBOARD_RAILS_SETTINGS,
preferUploadedEpgOverXtream: false,
trustedPrivateNetworkEpgUrls: [],
trustedInsecureTlsHosts: [],
tmdb: DEFAULT_TMDB_SETTINGS,
parentalLockEnabled: false,
parentalLockRelockMinutes: DEFAULT_PARENTAL_LOCK_RELOCK_MINUTES,
};
/**
* Which half of the settings persistence round-trip failed, if any.
*
* Settings live in the renderer's IndexedDB, which can be unavailable for
* reasons the app cannot control (a second instance holding the Chromium
* storage lock, a corrupted profile, storage blocked by security software).
* Both failures used to be swallowed: `updateSettings` patches the in-memory
* state before persisting, so a failed write still looked applied until the
* next restart (issue #1156). Recording the failure lets the settings UI say
* so instead of pretending the change stuck.
*/
export type SettingsStorageFailure = 'load' | 'save';
export interface SettingsStorageState {
storageFailure: SettingsStorageFailure | null;
}
let embeddedMpvPrepareScheduled = false;
export function scheduleEmbeddedMpvPrepare(): void {
if (
embeddedMpvPrepareScheduled ||
typeof window === 'undefined' ||
!window.electron?.prepareEmbeddedMpv
) {
return;
}
embeddedMpvPrepareScheduled = true;
const prepare = () => {
void window.electron
.prepareEmbeddedMpv?.()
.then((support) => {
if (!support?.supported) {
embeddedMpvPrepareScheduled = false;
}
})
.catch((error) => {
embeddedMpvPrepareScheduled = false;
console.warn('Failed to prepare embedded MPV.', error);
});
};
const idleWindow = window as typeof window & {
requestIdleCallback?: (
callback: IdleRequestCallback,
options?: IdleRequestOptions
) => number;
};
if (idleWindow.requestIdleCallback) {
idleWindow.requestIdleCallback(prepare, { timeout: 5000 });
} else {
window.setTimeout(prepare, 2000);
}
}