import Debug from '../conf/Debug'; import currentBrowser from '../conf/BrowserDetect'; import ExtensionConf from '../conf/ExtensionConf'; import ExtensionMode from '../../common/enums/extension-mode.enum'; import ObjectCopy from '../lib/ObjectCopy'; import Stretch from '../../common/enums/stretch.enum'; import VideoAlignment from '../../common/enums/video-alignment.enum'; import ExtensionConfPatch from '../conf/ExtConfPatches'; class Settings { constructor(options) { // Options: activeSettings, updateCallback, logger this.logger = options.logger; const activeSettings = options.activeSettings; const updateCallback = options.updateCallback; this.active = activeSettings ? activeSettings : undefined; this.default = ExtensionConf; this.default['version'] = this.getExtensionVersion(); this.useSync = false; this.version = undefined; this.updateCallback = updateCallback; const ths = this; if(currentBrowser.firefox) { browser.storage.onChanged.addListener( (changes, area) => { this.logger.log('info', 'Settings', "[Settings::] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area); if (changes['uwSettings'] && changes['uwSettings'].newValue) { this.logger.log('info', 'Settings',"[Settings::] new settings object:", JSON.parse(changes.uwSettings.newValue)); } if(changes['uwSettings'] && changes['uwSettings'].newValue) { ths.setActive(JSON.parse(changes.uwSettings.newValue)); } if(this.updateCallback) { try { updateCallback(ths); } catch (e) { this.logger.log('error', 'Settings', "[Settings] CALLING UPDATE CALLBACK FAILED.") } } }); } else if (currentBrowser.chrome) { chrome.storage.onChanged.addListener( (changes, area) => { this.logger.log('info', 'Settings', "[Settings::] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area); if (changes['uwSettings'] && changes['uwSettings'].newValue) { this.logger.log('info', 'Settings',"[Settings::] new settings object:", JSON.parse(changes.uwSettings.newValue)); } if(changes['uwSettings'] && changes['uwSettings'].newValue) { ths.setActive(JSON.parse(changes.uwSettings.newValue)); } if(this.updateCallback) { try { updateCallback(ths); } catch (e) { this.logger.log('error', 'Settings',"[Settings] CALLING UPDATE CALLBACK FAILED.") } } }); } } getExtensionVersion() { if (currentBrowser.firefox) { return browser.runtime.getManifest().version; } else if (currentBrowser.chrome) { return chrome.runtime.getManifest().version; } else if (currentBrowser.edge) { return browser.runtime.getManifest().version; } } compareExtensionVersions(a, b) { aa = a.forVersion.split['.']; bb = b.forVersion.split['.']; if (+aa[0] !== +bb[0]) { // difference on first digit return ++aa[0] - ++bb[0]; } if (+aa[1] !== +bb[1]) { // first digit same, difference on second digit return ++aa[1] - ++bb[1]; } if (+aa[2] !== +bb[2]) { return ++aa[2] - ++bb[2]; // first two digits the same, let's check the third digit } else { // fourth digit is optional. When not specified, 0 is implied // btw, ++(aa[3] || 0) - ++(bb[3] || 0) doesn't work return (aa[3] ? ++aa[3] : 0) - (bb[3] ? ++bb[3] : 0); } } sortConfPatches(patchesIn) { return patchesIn.sort( (a, b) => this.compareExtensionVersions(a, b)); } findFirstNecessaryPatch(version, extconfPatches) { const sorted = this.sortConfPatches(extconfPatches); return sorted.findIndexOf(x => this.compareExtensionVersions(x.forVersion, version) > 0); } applySettingsPatches(oldVersion, patches) { let index = this.findFirstNecessaryPatch(oldVersion, patches); if (index === -1) { // this.logger.log('info','settings','[Settings::applySettingsPatches] There are no pending conf patches.'); return; } // apply all remaining patches // this.logger.log('info', 'settings', `[Settings::applySettingsPatches] There are ${patches.length - index} settings patches to apply`); while (index --< patches.length) { delete patches[index].forVersion; ObjectCopy.overwrite(this.active, patches[index]); } } async init() { const settings = await this.get(); // |—> on first setup, settings is undefined & settings.version is haram // | since new installs ship with updates by default, no patching is // | needed. In this case, we assume we're on the current version const oldVersion = (settings && settings.version) || this.getExtensionVersion(); const currentVersion = this.getExtensionVersion(); if(Debug.debug) { this.logger.log('info', 'Settings', "[Settings::init] Configuration fetched from storage:", settings, "\nlast saved with:", settings.version, "\ncurrent version:", currentVersion ); if (Debug.flushStoredSettings) { this.logger.log('info', 'Settings', "%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd"); Debug.flushStoredSettings = false; // don't do it again this session this.active = this.getDefaultSettings(); this.active.version = currentVersion; this.set(this.active); return this.active; } } // if there's no settings saved, return default settings. if(! settings || (Object.keys(settings).length === 0 && settings.constructor === Object)) { this.active = this.getDefaultSettings(); this.active.version = currentVersion; this.set(this.active); return this.active; } // if last saved settings was for version prior to 4.x, we reset settings to default // it's not like people will notice cos that version didn't preserve settings at all if (settings.version && !settings.version.startsWith('4')) { this.active = this.getDefaultSettings(); this.active.version = currentVersion; this.set(this.active); return this.active; } // in every case, we'll update the version number: settings.version = currentVersion; // if there's settings, set saved object as active settings this.active = settings; // check if extension has been updated. If not, return settings as they were retreived if (oldVersion == currentVersion) { this.logger.log('info', 'Settings', "[Settings::init] extension was saved with current version of ultrawidify. Returning object as-is."); return this.active; } // if extension has been updated, update existing settings with any options added in the // new version. In addition to that, we remove old keys that are no longer used. const patched = ObjectCopy.addNew(settings, this.default); this.logger.log('info', 'Settings',"[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default); if(patched){ this.active = patched; } else { this.active = JSON.parse(JSON.stringify(this.default)); } // in case settings in previous version contained a fucky wucky, we overwrite existing settings with a patch this.applySettingsPatches(oldVersion, ExtensionConfPatch); // set 'whatsNewChecked' flag to false when updating, always this.active.whatsNewChecked = false; // update settings version to current this.active.version = currentVersion; this.set(this.active); return this.active; } async get() { let ret; if (currentBrowser.firefox) { ret = await browser.storage.local.get('uwSettings'); } else if (currentBrowser.chrome) { ret = await new Promise( (resolve, reject) => { chrome.storage.local.get('uwSettings', (res) => resolve(res)); }); } else if (currentBrowser.edge) { ret = await new Promise( (resolve, reject) => { browser.storage.local.get('uwSettings', (res) => resolve(res)); }); } this.logger.log('info', 'Settings', 'Got settings:', ret && ret.uwSettings && JSON.parse(ret.uwSettings)); try { return JSON.parse(ret.uwSettings); } catch(e) { return undefined; } } async set(extensionConf) { this.logger.log('info', 'Settings', "[Settings::set] setting new settings:", extensionConf) if (currentBrowser.firefox || currentBrowser.edge) { extensionConf.version = this.version; return this.useSync ? browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}): browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}); } else if (currentBrowser.chrome) { return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}); } } async setActive(activeSettings) { this.active = activeSettings; } async setProp(prop, value) { this.active[prop] = value; } async save() { if (Debug.debug && Debug.storage) { console.log("[Settings::save] Saving active settings:", this.active); } this.set(this.active); } async rollback() { this.active = await this.get(); } getDefaultSettings() { return JSON.parse(JSON.stringify(this.default)); } setDefaultSettings() { this.default.version = this.getExtensionVersion(); this.set(this.default); } // ----------------------------------------- // Nastavitve za posamezno stran // Config for a given page: // // : { // status: