Settings snapshots

This commit is contained in:
Tamius Han 2025-04-22 02:42:33 +02:00
parent ae2bb7afcd
commit 391b0ac7ab
4 changed files with 199 additions and 8 deletions

View File

@ -21,7 +21,6 @@ const ExtensionConfPatch = [
normal: ExtensionMode.Default,
}
}
const uiEnabled =
userOptions.sites['@global'].enableUI = {
fullscreen: userOptions.ui.inPlayer.enabled ? ExtensionMode.Enabled : ExtensionMode.Disabled,
theater: ExtensionMode.Enabled,
@ -84,6 +83,9 @@ const ExtensionConfPatch = [
delete (userOptions as any).actions;
userOptions.dev = {
loadFromSnapshot: false
};
userOptions.ui.dev = {
aardDebugOverlay: {
showOnStartup: false,

View File

@ -14,6 +14,10 @@ if(Debug.debug)
console.log("Loading: ExtensionConf.js");
const ExtensionConf: SettingsInterface = {
dev: {
loadFromSnapshot: false,
},
arDetect: {
aardType: 'auto',
@ -728,6 +732,46 @@ const ExtensionConf: SettingsInterface = {
}
}
},
"www.youtube-nocookie.com": {
enable: {
fullscreen: ExtensionMode.Enabled,
theater: ExtensionMode.Enabled,
normal: ExtensionMode.Enabled,
},
enableAard: {
fullscreen: ExtensionMode.Enabled,
theater: ExtensionMode.Enabled,
normal: ExtensionMode.Enabled,
},
enableKeyboard: {
fullscreen: ExtensionMode.Enabled,
theater: ExtensionMode.Enabled,
normal: ExtensionMode.Enabled
},
enableUI: {
fullscreen: ExtensionMode.Enabled,
theater: ExtensionMode.Enabled,
normal: ExtensionMode.Disabled
},
override: false, // ignore value localStorage in favour of this
type: 'official', // is officially supported? (Alternatives are 'community' and 'user-defined')
defaultType: 'official', // if user mucks around with settings, type changes to 'user-defined'.
// We still want to know what the original type was, hence defaultType
activeDOMConfig: 'official',
DOMConfig: {
'official': {
type: 'official',
elements: {
player: {
manual: true,
querySelectors: "#movie_player, #player, #c4-player",
}
}
}
}
},
"www.netflix.com" : {
enable: {
fullscreen: ExtensionMode.Enabled,

View File

@ -12,11 +12,15 @@ import Logger from './Logger';
import SettingsInterface from '../../common/interfaces/SettingsInterface';
import AspectRatioType from '../../common/enums/AspectRatioType.enum';
import { SiteSettings } from './settings/SiteSettings';
import { SettingsSnapshotManager } from './settings/SettingsSnapshotManager';
if(process.env.CHANNEL !== 'stable'){
console.info("Loading Settings");
}
interface SetSettingsOptions {
forcePreserveVersion?: boolean,
}
class Settings {
//#region flags
@ -41,6 +45,17 @@ class Settings {
afterSettingsChangedCallbacks: (() => void)[] = [];
private sortedPatches: any[];
public snapshotManager: SettingsSnapshotManager;
private _migrationReport: string = '';
private set migrationReport(report: string) {
this._migrationReport = report;
}
public get migrationReport(): string {
return this._migrationReport;
}
//#endregion
constructor(options) {
@ -50,11 +65,14 @@ class Settings {
this.afterSettingsSaved = options?.afterSettingsSaved;
this.active = options?.activeSettings ?? undefined;
this.default = ExtensionConf;
this.snapshotManager = new SettingsSnapshotManager();
this.default['version'] = this.getExtensionVersion();
chrome.storage.onChanged.addListener((changes, area) => {this.storageChangeListener(changes, area)});
this.sortedPatches = this.sortConfPatches(ExtensionConfPatch);
}
private storageChangeListener(changes, area) {
@ -186,6 +204,18 @@ class Settings {
return;
}
// save current settings object
const currentSettings = this.active;
this.snapshotManager.createSnapshot(
JSON.parse(JSON.stringify(currentSettings)),
{
label: 'Pre-migration snapshot',
isAutomatic: true
}
);
// apply all remaining patches
this.logger?.log('info', 'settings', `[Settings::applySettingsPatches] There are ${this.sortedPatches.length - index} settings patches to apply`);
while (index < this.sortedPatches.length) {
@ -209,7 +239,16 @@ class Settings {
}
async init() {
const settings = await this.get();
let settings = await this.get();
if (settings?.dev?.loadFromSnapshot) {
this.logger?.log('info', 'settings', '[Settings::init] Dev mode is enabled, Loading settings from snapshot:', settings.dev.loadFromSnapshot);
const snapshot = await this.snapshotManager.getSnapshot();
if (snapshot) {
settings = snapshot.settings;
}
}
this.version = this.getExtensionVersion();
// |—> on first setup, settings is undefined & settings.version is haram
@ -282,7 +321,7 @@ class Settings {
return this.active;
}
async get() {
async get(): Promise<SettingsInterface | undefined> {
let ret;
ret = await chrome.storage.local.get('uwSettings');
@ -290,13 +329,13 @@ class Settings {
this.logger?.log('info', 'settings', 'Got settings:', ret && ret.uwSettings && JSON.parse(ret.uwSettings));
try {
return JSON.parse(ret.uwSettings);
return JSON.parse(ret.uwSettings) as SettingsInterface;
} catch(e) {
return undefined;
}
}
async set(extensionConf, options?) {
async set(extensionConf, options?: SetSettingsOptions) {
if (!options || !options.forcePreserveVersion) {
extensionConf.version = this.version;
}
@ -344,7 +383,7 @@ class Settings {
}
}
async save(options?) {
async save(options?: SetSettingsOptions) {
if (Debug.debug && Debug.storage) {
console.log("[Settings::save] Saving active settings:", this.active);
}
@ -354,10 +393,10 @@ class Settings {
}
async saveWithoutReload() {
async saveWithoutReload(options?: SetSettingsOptions) {
this.active.preventReload = true;
this.active.lastModified = new Date();
await this.set(this.active);
await this.set(this.active, options);
}
async rollback() {

View File

@ -0,0 +1,106 @@
import { settings } from 'cluster'
import SettingsInterface from '@src/common/interfaces/SettingsInterface';
export interface SettingsSnapshot {
isAutomatic?: boolean;
isProtected?: boolean;
isDefault?: boolean;
forVersion: string;
label: string;
settings: SettingsInterface;
createdAt: Date;
}
export interface SettingsSnapshotOptions {
isAutomatic?: boolean,
isProtected?: boolean,
isDefault?: boolean,
label?: string,
forVersion?: string
}
export class SettingsSnapshotManager {
private MAX_AUTOMATIC_SNAPSHOTS = 5;
async getSnapshot(index?: number) {
const snapshots = await this.listSnapshots();
if (!index) {
return snapshots.find(x => x.isDefault);
} else {
if (index < 0 || index >= snapshots.length) {
throw new Error('Invalid index');
}
return snapshots[index];
}
}
async createSnapshot(settings: SettingsInterface, options?: SettingsSnapshotOptions) {
const snapshot = {
...options,
label: options.label ?? 'Automatic snapshot',
forVersion: options.forVersion || settings.version,
settings: JSON.parse(JSON.stringify(settings)),
createdAt: new Date(),
};
const snapshots = await this.listSnapshots();
const automaticSnapshots = snapshots.filter((s) => s.isAutomatic && !s.isProtected);
if (options.isAutomatic && automaticSnapshots.length >= this.MAX_AUTOMATIC_SNAPSHOTS) {
const firstAutomaticIndex = snapshots.findIndex((s) => s.isAutomatic && !s.isProtected);
snapshots.splice(firstAutomaticIndex, 1);
}
snapshots.push(snapshot);
this.set(snapshots);
}
async setDefaultSnapshot(index: number, isDefault: boolean) {
const snapshots = await this.listSnapshots();
if (index < 0 || index >= snapshots.length) {
throw new Error('Invalid index');
}
if (isDefault) {
for (const snapshot of snapshots) {
snapshot.isDefault = false;
}
}
snapshots[index].isDefault = isDefault;
this.set(snapshots);
}
async markSnapshotAsProtected(index: number, isProtected: boolean) {
const snapshots = await this.listSnapshots();
if (index < 0 || index >= snapshots.length) {
throw new Error('Invalid index');
}
snapshots[index].isProtected = isProtected;
this.set(snapshots);
}
async deleteSnapshot(index: number) {
const snapshots = await this.listSnapshots();
if (index < 0 || index >= snapshots.length) {
throw new Error('Invalid index');
}
snapshots.splice(index, 1);
this.set(snapshots);
}
async listSnapshots(): Promise<SettingsSnapshot[]> {
const ret = await chrome.storage.local.get('uwSettings-snapshots');
try {
JSON.parse(ret['uwSettings-snapshots']) as SettingsSnapshot[];
} catch (e) {
return [] as SettingsSnapshot[];
}
}
private async set(snapshots: SettingsSnapshot[]) {
await chrome.storage.local.set({
'uwSettings-snapshots': JSON.stringify(snapshots),
});
}
}