More migrating
This commit is contained in:
parent
fe2f52d76a
commit
fb7f5cf1ba
10
package-lock.json
generated
10
package-lock.json
generated
@ -16,6 +16,7 @@
|
||||
"fs-extra": "^11.3.2",
|
||||
"gl-matrix": "^3.4.4",
|
||||
"json-cyclic": "1.0.2",
|
||||
"json-difference": "^1.16.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mdi-vue": "^3.0.13",
|
||||
"typescript": "^5.9.3",
|
||||
@ -13496,6 +13497,15 @@
|
||||
"integrity": "sha512-K0Y9wQnrc13Ef+P8KY8SjFyVAz941CTrTVmu3oyQPExhaFFYXXLXnEuRi1tqYOS1B8WtFIxIwA7nHRJ64Uvf5Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-difference": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/json-difference/-/json-difference-1.16.1.tgz",
|
||||
"integrity": "sha512-tNVUzBKn2I4BB4Cjn+j+Kq/BfLNwqtEvxhnlyuX5XJmKn9VlfV5MvaTbB/ure/toFgLaD6XglOUt+dd4iMQ3dA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17.x"
|
||||
}
|
||||
},
|
||||
"node_modules/json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
"fs-extra": "^11.3.2",
|
||||
"gl-matrix": "^3.4.4",
|
||||
"json-cyclic": "1.0.2",
|
||||
"json-difference": "^1.16.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mdi-vue": "^3.0.13",
|
||||
"typescript": "^5.9.3",
|
||||
|
||||
@ -11,32 +11,26 @@
|
||||
:value="simpleExtensionSettings.enable"
|
||||
@click="setExtensionMode('enable', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="simpleExtensionSettings.enable === 'complex'"
|
||||
value="complex"
|
||||
>
|
||||
(Site uses advanced settings)
|
||||
</option>
|
||||
<template v-if="isDefaultConfiguration">
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Disabled by default
|
||||
</option>
|
||||
</template>
|
||||
<template v-else>
|
||||
<option value="default">
|
||||
Use default ({{simpleDefaultSettings.enable}})
|
||||
<option :value="ExtensionMode.Default">
|
||||
Use default ({{simpleDefaultSettings.enableAard}})
|
||||
</option>
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Never
|
||||
</option>
|
||||
</template>
|
||||
<option value="fs">
|
||||
<option :value="ExtensionMode.FullScreen">
|
||||
Fullscreen only
|
||||
</option>
|
||||
<option value="theater">
|
||||
<option :value="ExtensionMode.Theater">
|
||||
Fullscreen and theater mode
|
||||
</option>
|
||||
<option value="enabled">
|
||||
<option :value="ExtensionMode.All">
|
||||
Always
|
||||
</option>
|
||||
</select>
|
||||
@ -56,32 +50,26 @@
|
||||
:value="simpleExtensionSettings.enableAard"
|
||||
@click="setExtensionMode('enableAard', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="simpleExtensionSettings.enable === 'complex'"
|
||||
value="complex"
|
||||
>
|
||||
(Site uses advanced settings)
|
||||
</option>
|
||||
<template v-if="isDefaultConfiguration">
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Disabled by default
|
||||
</option>
|
||||
</template>
|
||||
<template v-else>
|
||||
<option value="default">
|
||||
<option :value="ExtensionMode.Default">
|
||||
Use default ({{simpleDefaultSettings.enableAard}})
|
||||
</option>
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Never
|
||||
</option>
|
||||
</template>
|
||||
<option value="fs">
|
||||
<option :value="ExtensionMode.FullScreen">
|
||||
Fullscreen only
|
||||
</option>
|
||||
<option value="theater">
|
||||
<option :value="ExtensionMode.Theater">
|
||||
Fullscreen and theater mode
|
||||
</option>
|
||||
<option value="enabled">
|
||||
<option :value="ExtensionMode.All">
|
||||
Always
|
||||
</option>
|
||||
</select>
|
||||
@ -99,32 +87,26 @@
|
||||
:value="simpleExtensionSettings.enableKeyboard"
|
||||
@click="setExtensionMode('enableKeyboard', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="simpleExtensionSettings.enable === 'complex'"
|
||||
value="complex"
|
||||
>
|
||||
(Site uses advanced settings)
|
||||
</option>
|
||||
<template v-if="isDefaultConfiguration">
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Disabled by default
|
||||
</option>
|
||||
</template>
|
||||
<template v-else>
|
||||
<option value="default">
|
||||
Use default ({{simpleDefaultSettings.enableKeyboard}})
|
||||
<option :value="ExtensionMode.Default">
|
||||
Use default ({{simpleDefaultSettings.enableAard}})
|
||||
</option>
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Never
|
||||
</option>
|
||||
</template>
|
||||
<option value="fs">
|
||||
<option :value="ExtensionMode.FullScreen">
|
||||
Fullscreen only
|
||||
</option>
|
||||
<option value="theater">
|
||||
<option :value="ExtensionMode.Theater">
|
||||
Fullscreen and theater mode
|
||||
</option>
|
||||
<option value="enabled">
|
||||
<option :value="ExtensionMode.All">
|
||||
Always
|
||||
</option>
|
||||
</select>
|
||||
@ -143,23 +125,26 @@
|
||||
@click="setExtensionMode('enableUI', $event)"
|
||||
>
|
||||
<template v-if="isDefaultConfiguration">
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Disabled by default
|
||||
</option>
|
||||
</template>
|
||||
<template v-else>
|
||||
<option value="default">
|
||||
Use default ({{simpleDefaultSettings.enableUI}})
|
||||
<option :value="ExtensionMode.Default">
|
||||
Use default ({{simpleDefaultSettings.enableAard}})
|
||||
</option>
|
||||
<option value="disabled">
|
||||
<option :value="ExtensionMode.Disabled">
|
||||
Never
|
||||
</option>
|
||||
</template>
|
||||
<option value="fs">
|
||||
<option :value="ExtensionMode.FullScreen">
|
||||
Fullscreen only
|
||||
</option>
|
||||
<option value="theater">
|
||||
Always where possible
|
||||
<option :value="ExtensionMode.Theater">
|
||||
Fullscreen and theater mode
|
||||
</option>
|
||||
<option :value="ExtensionMode.All">
|
||||
Always
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -425,64 +410,12 @@ export default {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Disabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Disabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Disabled
|
||||
) {
|
||||
return 'disabled';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Default || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Default
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Default
|
||||
) {
|
||||
// console.log(
|
||||
// component, 'is set to default because:\n',
|
||||
// `\nsettingsData[${component}].normal: ${settingsData?.[component]?.normal} || component is enableUI?`, component,
|
||||
// `\nsettingsData[${component}].theater: ${settingsData?.[component]?.normal}`,
|
||||
// `\nsettingsData[${component}].fullscreen: ${settingsData?.[component]?.normal}`,
|
||||
|
||||
// `\n\n(expected values:`, ExtensionMode.Default
|
||||
// )
|
||||
return 'default';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Disabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Disabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Enabled
|
||||
) {
|
||||
return 'fs';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Disabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Enabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Enabled
|
||||
) {
|
||||
return 'theater';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Enabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Enabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Enabled
|
||||
) {
|
||||
return 'enabled';
|
||||
}
|
||||
|
||||
return 'complex';
|
||||
} catch (e) {
|
||||
return 'loading';
|
||||
}
|
||||
return settingsData[component];
|
||||
},
|
||||
|
||||
getDefaultOptionLabel(component) {
|
||||
const componentValue = this.compileSimpleSettings(component, 'default');
|
||||
|
||||
if (componentValue === 'loading') {
|
||||
return componentValue;
|
||||
}
|
||||
if (component === 'enableUI') {
|
||||
switch (componentValue) {
|
||||
case 'fs':
|
||||
|
||||
@ -17,7 +17,7 @@ import ExtensionMode from '../../common/enums/ExtensionMode.enum';
|
||||
const ExtensionConfPatch = Object.freeze([
|
||||
{
|
||||
forVersion: '6.2.4',
|
||||
updateFn: (userOptions: any, defaultOptions) => {
|
||||
updateFn: (userOptions: any, defaultOptions, logger?) => {
|
||||
for (const site in userOptions.sites) {
|
||||
(userOptions as any).sites[site].enableUI = {
|
||||
fullscreen: LegacyExtensionMode.Default,
|
||||
@ -38,7 +38,7 @@ const ExtensionConfPatch = Object.freeze([
|
||||
}
|
||||
}, {
|
||||
forVersion: '6.2.6',
|
||||
updateFn: (userOptions: any, defaultOptions) => {
|
||||
updateFn: (userOptions: any, defaultOptions, logger?) => {
|
||||
console.log('[ultrawidify] Migrating settings — applying patches for version 6.2.6');
|
||||
|
||||
if (!userOptions.commands) {
|
||||
@ -273,7 +273,7 @@ const ExtensionConfPatch = Object.freeze([
|
||||
},
|
||||
{
|
||||
forVersion: '6.3.98',
|
||||
upgradeFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface) => {
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface) => {
|
||||
userOptions.aard = defaultOptions.aard;
|
||||
userOptions.aardLegacy = defaultOptions.aardLegacy;
|
||||
delete (userOptions as any).arDetect;
|
||||
@ -281,8 +281,9 @@ const ExtensionConfPatch = Object.freeze([
|
||||
},
|
||||
{
|
||||
forVersion: '6.3.994',
|
||||
upgradeFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface) => {
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface, logger?) => {
|
||||
const convertLegacyExtensionMode = (option: {normal: LegacyExtensionMode, theater: LegacyExtensionMode, fullscreen: LegacyExtensionMode}) => {
|
||||
logger.log('updateFn', 'converting option', option);
|
||||
if (option.normal === LegacyExtensionMode.Enabled) {
|
||||
return ExtensionMode.All;
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@ import ExtensionConfPatch from '../../conf/ExtConfPatches';
|
||||
import SettingsInterface from '../../../common/interfaces/SettingsInterface';
|
||||
import AspectRatioType from '../../../common/enums/AspectRatioType.enum';
|
||||
import { GetSiteSettingsOptions, SiteSettings } from './SiteSettings';
|
||||
import { SettingsSnapshotManager } from './SettingsSnapshotManager';
|
||||
import { SettingsSnapshot, SettingsSnapshotManager } from './SettingsSnapshotManager';
|
||||
import { ComponentLogger } from '../logging/ComponentLogger';
|
||||
import { LogAggregator } from '../logging/LogAggregator';
|
||||
import { getDiff } from 'json-difference'
|
||||
|
||||
if(process.env.CHANNEL !== 'stable'){
|
||||
console.info("Loading Settings");
|
||||
@ -100,11 +101,32 @@ class Settings {
|
||||
// this.logger?.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
|
||||
// }
|
||||
const parsedSettings = JSON.parse(changes.uwSettings.newValue);
|
||||
this.setActive(parsedSettings);
|
||||
|
||||
const diff = getDiff(this.active, parsedSettings, {isLodashLike: true});
|
||||
|
||||
const validChangeFn = (x: any) =>
|
||||
x[0] !== 'lastModified';
|
||||
|
||||
const validAdditions = diff.added.filter(validChangeFn);
|
||||
const validEdits = diff.edited.filter(validChangeFn);
|
||||
const validRemovals = diff.removed.filter(validChangeFn).filter(x => x[0] !== 'version');
|
||||
|
||||
this.logger?.info('storageOnChange', "Diff between current and changed settings:", diff, 'valid changes:', {validAdditions, validEdits, validRemovals});
|
||||
|
||||
if (
|
||||
validAdditions.length === 0
|
||||
&& validRemovals.length === 0
|
||||
&& validEdits.length === 0
|
||||
) {
|
||||
this.logger?.warn('storageOnChange', "storageChangeListener fired, but no changes were detected. Sus.\nchanges:", changes, "storage area:", area, 'current:', this.active, 'diff:', diff);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setActive(parsedSettings);
|
||||
this.logger?.info('storageOnChange', 'Does parsedSettings.preventReload exist?', parsedSettings.preventReload, "Does callback exist?", !!this.onSettingsChanged);
|
||||
|
||||
if (!parsedSettings.preventReload) {
|
||||
this.active.preventReload = true;
|
||||
try {
|
||||
for (const fn of this.onChangedCallbacks) {
|
||||
try {
|
||||
@ -116,7 +138,6 @@ class Settings {
|
||||
if (this.onSettingsChanged) {
|
||||
this.onSettingsChanged();
|
||||
}
|
||||
|
||||
this.logger?.info('storageOnChange', 'Update callback finished.')
|
||||
} catch (e) {
|
||||
this.logger?.error('storageOnChange', "CALLING UPDATE CALLBACK FAILED. Reason:", e)
|
||||
@ -212,7 +233,7 @@ class Settings {
|
||||
private findFirstNecessaryPatch(version) {
|
||||
return ExtensionConfPatch.findIndex(x => this.compareExtensionVersions(x.forVersion, version) > 0);
|
||||
}
|
||||
private applySettingsPatches(oldVersion) {
|
||||
private applySettingsPatches(currentSettings, oldVersion, options?: {skipSnapshot?: boolean}) {
|
||||
let index = this.findFirstNecessaryPatch(oldVersion);
|
||||
|
||||
if (index === -1) {
|
||||
@ -221,26 +242,30 @@ class Settings {
|
||||
}
|
||||
|
||||
// save current settings object
|
||||
const currentSettings = this.active;
|
||||
|
||||
this.snapshotManager.createSnapshot(
|
||||
JSON.parse(JSON.stringify(currentSettings)),
|
||||
{
|
||||
label: 'Pre-migration snapshot',
|
||||
isAutomatic: true
|
||||
}
|
||||
);
|
||||
|
||||
// this.active.newFeatureTracker = {};
|
||||
|
||||
if (!options?.skipSnapshot) {
|
||||
this.snapshotManager.createSnapshot(
|
||||
JSON.parse(JSON.stringify(currentSettings)),
|
||||
{
|
||||
label: 'Pre-migration snapshot',
|
||||
isAutomatic: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// apply all remaining patches
|
||||
this.logger?.info('applySettingsPatches', `There are ${ExtensionConfPatch.length - index} settings patches to apply`);
|
||||
const pendingPatchesCount = ExtensionConfPatch.length - index;
|
||||
this.logger?.info('applySettingsPatches', `There are ${pendingPatchesCount} settings patches to apply`);
|
||||
const defaultSettings = this.getDefaultSettings();
|
||||
while (index < ExtensionConfPatch.length) {
|
||||
const updateFn = ExtensionConfPatch[index].updateFn;
|
||||
|
||||
this.logger.info('applySettingsPatches', `Processing patch ${index} / ${ExtensionConfPatch.length}. Patch ${!!updateFn ? 'has' : 'does NOT have'} an update function.`);
|
||||
|
||||
if (updateFn) {
|
||||
try {
|
||||
updateFn(this.active, this.getDefaultSettings());
|
||||
this.logger.log('applySettingsPatches', `Starting to update patch for version ${ExtensionConfPatch[index].forVersion} (${pendingPatchesCount - (ExtensionConfPatch.length - index)} / ${pendingPatchesCount}) | index: ${index}, patches length: ${ExtensionConfPatch.length}`);
|
||||
updateFn(currentSettings, defaultSettings, this.logger);
|
||||
this.logger.log('applySettingsPatches', `Patch for version ${ExtensionConfPatch[index].forVersion} applied. (${pendingPatchesCount - (ExtensionConfPatch.length - index)} / ${pendingPatchesCount})`);
|
||||
} catch (e) {
|
||||
this.logger?.error('applySettingsPatches', 'Failed to execute update function. Keeping settings object as-is. Error:', e);
|
||||
}
|
||||
@ -248,30 +273,37 @@ class Settings {
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return currentSettings;
|
||||
}
|
||||
|
||||
async init() {
|
||||
let settings = await this.get();
|
||||
async init(options?: {dryRun?: boolean, snapshot?: SettingsSnapshot, skipSnapshot?: boolean}) {
|
||||
let settings;
|
||||
|
||||
if (settings?.dev?.loadFromSnapshot) {
|
||||
if (options?.snapshot) {
|
||||
this.logger?.info('init', 'Snapshot was provided — will load settings from snapshot.', options.snapshot);
|
||||
settings = options.snapshot.settings;
|
||||
} else if (settings?.dev?.loadFromSnapshot) {
|
||||
this.logger?.info('init', 'Dev mode is enabled, Loading settings from snapshot:', settings.dev.loadFromSnapshot);
|
||||
const snapshot = await this.snapshotManager.getSnapshot();
|
||||
if (snapshot) {
|
||||
settings = snapshot.settings;
|
||||
}
|
||||
} else {
|
||||
settings = await this.get();
|
||||
}
|
||||
|
||||
this.version = this.getExtensionVersion();
|
||||
const currentVersion = this.getExtensionVersion();
|
||||
|
||||
// |—> 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?.version ?? this.version;
|
||||
const oldVersion = settings?.version ?? currentVersion;
|
||||
|
||||
if (settings) {
|
||||
this.logger?.info('init', "Configuration fetched from storage:", settings,
|
||||
"\nlast saved with:", settings.version,
|
||||
"\ncurrent version:", this.version
|
||||
"\ncurrent version:", currentVersion
|
||||
);
|
||||
}
|
||||
|
||||
@ -284,40 +316,57 @@ class Settings {
|
||||
'\nsettings:',
|
||||
settings
|
||||
);
|
||||
this.active = this.getDefaultSettings();
|
||||
this.active.version = this.version;
|
||||
await this.save();
|
||||
|
||||
return this.active;
|
||||
settings = this.getDefaultSettings();
|
||||
settings.version = currentVersion;
|
||||
|
||||
if (!options?.dryRun) {
|
||||
this.active = settings;
|
||||
this.version = currentVersion;
|
||||
await this.save();
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
// if there's settings, set saved object as active settings
|
||||
this.active = settings;
|
||||
|
||||
// if version number is undefined, we make it defined
|
||||
// this should only happen on first extension initialization
|
||||
if (!this.active.version) {
|
||||
this.active.version = this.version;
|
||||
await this.save();
|
||||
return this.active;
|
||||
if (!settings.version) {
|
||||
settings.version = currentVersion;
|
||||
|
||||
if (!options?.dryRun) {
|
||||
this.active = settings;
|
||||
this.version = currentVersion;
|
||||
await this.save();
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
// check if extension has been updated. If not, return settings as they were retrieved
|
||||
if (this.active.version === this.version) {
|
||||
if (settings.version === currentVersion) {
|
||||
this.logger?.info('init', "extension was saved with current version of ultrawidify. Returning object as-is.");
|
||||
return this.active;
|
||||
if (!options?.dryRun) {
|
||||
this.active = settings;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
// in case settings in previous version contained a fucky wucky, we overwrite existing settings with a patch
|
||||
this.applySettingsPatches(oldVersion);
|
||||
settings = this.applySettingsPatches(settings, oldVersion, {skipSnapshot: options?.dryRun || options?.skipSnapshot});
|
||||
|
||||
// set 'whatsNewChecked' flag to false when updating, always
|
||||
this.active.whatsNewChecked = false;
|
||||
settings.whatsNewChecked = false;
|
||||
// update settings version to current
|
||||
this.active.version = this.version;
|
||||
settings.version = currentVersion;
|
||||
|
||||
await this.save();
|
||||
return this.active;
|
||||
if (!options?.dryRun) {
|
||||
this.active = settings;
|
||||
this.version = currentVersion;
|
||||
await this.save();
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
async get(): Promise<SettingsInterface | undefined> {
|
||||
@ -437,6 +486,11 @@ class Settings {
|
||||
removeAfterChangeListener(fn: () => void): void {
|
||||
this.afterSettingsChangedCallbacks = this.afterSettingsChangedCallbacks.filter(x => x !== fn);
|
||||
}
|
||||
|
||||
async testMigration(snapshot: SettingsSnapshot) {
|
||||
const afterMigrationSettings = await this.init({dryRun: true, snapshot});
|
||||
this.logger.log('testMigration', 'Settings migrated. Settings model after initialization:', afterMigrationSettings);
|
||||
}
|
||||
}
|
||||
|
||||
export default Settings;
|
||||
|
||||
@ -1,29 +1,93 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="text-[1.75em]">Debugging</h2>
|
||||
|
||||
<div>
|
||||
<h1>{{loggerPanel.title}}<small><br/>{{loggerPanel.subtitle}}</small></h1>
|
||||
<div class="w-full grid grid-cols-1 min-[1200px]:grid-cols-2 min-[1920px]:grid-cols-3 max-w-[2300px] gap-8">
|
||||
|
||||
<div>Logger configuration:</div>
|
||||
<div class="grow shrink">
|
||||
<h3 class="mb-4">Settings editor</h3>
|
||||
<div class="flex flex-row w-full">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<div>Enable save button:</div>
|
||||
<input v-model="allowSettingsEditing" type="checkbox">
|
||||
</div>
|
||||
<div class="grow">
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="editorSaveFinished">Settings saved ...</div>
|
||||
<button v-else
|
||||
class="danger"
|
||||
:class="{'opacity-50 select-none hover:border-stone-500 hover:text-stone-300': !allowSettingsEditing}"
|
||||
:disabled="!allowSettingsEditing"
|
||||
@click="() => saveSettingsChanges()"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
<button @click="resetSettingsEditor">
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<JsonEditor
|
||||
v-model="settingsJson"
|
||||
>
|
||||
</JsonEditor>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grow shrink">
|
||||
<h3 class="mb-4">Snapshots</h3>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<div
|
||||
v-for="(snapshot, index) of settingsSnapshots" :key="snapshot.createdAt"
|
||||
class="border border-stone-800 p-2"
|
||||
>
|
||||
<small>Created at: {{new Date(snapshot.createdAt).toISOString()}}</small>
|
||||
<div class="flex flex-row">
|
||||
<div class="grow font-bold">
|
||||
{{snapshot.label ?? '<no label>'}}
|
||||
</div>
|
||||
<div class="mr-8">v. {{snapshot.settings.version ?? '<unknown ver.>'}}</div>
|
||||
<div v-if="settings.isAutomatic">(auto)</div>
|
||||
<div v-if="settings.isAutomatic && settings.isProtected">(protected)</div>
|
||||
<div v-if="settings.default">(default)</div>
|
||||
</div>
|
||||
<div class="flex flex-row w-full justify-end mt-2">
|
||||
<button class="flex flex-col" @click="() => testMigration(index)">Test migration</button>
|
||||
<button class="flex flex-col" @click="() => loadFromSnapshot(index)">Load snapshot and migrate<br/><small>normal migration</small></button>
|
||||
<button class="flex flex-col" @click="() => loadFromSnapshot(index, true)">Load & migrate<br/><small>without creating snapshot</small></button>
|
||||
<button class="flex flex-col" @click="() => markDefaultSnapshot(index)"><template v-if="settings.isDefault">Revoke default</template><template v-else>Make default</template></button>
|
||||
<button class="flex flex-col" v-if="settings.isAutomatic" @click="() => toggleSnapshotProtection(index)">Toggle protection</button>
|
||||
<button class="flex flex-col" @click="() => deleteSnapshot(index)">Delete snapshot</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grow shrink">
|
||||
<h3 class="mb-4">Logger configuration</h3>
|
||||
|
||||
<JsonEditor
|
||||
v-model="lastSettings"
|
||||
></JsonEditor>
|
||||
|
||||
<div class="flex flex-row flex-end">
|
||||
<div class="button" @click="getLoggerSettings()">
|
||||
<div class="flex flex-row justify-end mt-4 w-full">
|
||||
<button class="bg-black button" @click="getLoggerSettings()">
|
||||
Revert
|
||||
</div>
|
||||
<div class="button button-primary" @click="saveLoggerSettings()">
|
||||
</button>
|
||||
<button class="button button-primary" @click="saveLoggerSettings()">
|
||||
Save
|
||||
</div>
|
||||
<div class="button button-primary" @click="startLogging()">
|
||||
</button>
|
||||
<button class="button button-primary" @click="startLogging()">
|
||||
Save and start logging
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -67,7 +131,12 @@ export default defineComponent({
|
||||
},
|
||||
lastSettings: undefined,
|
||||
parsedSettings: undefined,
|
||||
currentSettings: undefined
|
||||
currentSettings: undefined,
|
||||
|
||||
allowSettingsEditing: false,
|
||||
editorSaveFinished: false,
|
||||
settingsJson: {},
|
||||
settingsSnapshots: []
|
||||
};
|
||||
},
|
||||
props: [
|
||||
@ -81,6 +150,11 @@ export default defineComponent({
|
||||
};
|
||||
this.getLoggerSettings();
|
||||
},
|
||||
mounted() {
|
||||
this.loadSettingsSnapshots();
|
||||
this.resetSettingsEditor();
|
||||
this.loadSettingsSnapshots();
|
||||
},
|
||||
methods: {
|
||||
loadDefaultConfig() {
|
||||
this.lastSettings = JSON.parse(JSON.stringify(BLANK_LOGGER_CONFIG));
|
||||
@ -98,6 +172,72 @@ export default defineComponent({
|
||||
await LogAggregator.saveConfig({...this.lastSettings});
|
||||
window.location.reload();
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets settings to default
|
||||
*/
|
||||
resetSettings() {
|
||||
this.settings.active = JSON.parse(JSON.stringify(this.settings.default));
|
||||
this.settings.saveWithoutReload();
|
||||
this.resetSettingsEditor();
|
||||
},
|
||||
|
||||
async saveSettingsChanges() {
|
||||
if (this.allowSettingsEditing) {
|
||||
const currentVersion = this.settings.active?.version;
|
||||
this.settings.active = this.settingsJson;
|
||||
|
||||
if (currentVersion !== this.settingsJson.version) {
|
||||
await this.settings.save({forcePreserveVersion: true});
|
||||
return;
|
||||
} else {
|
||||
await this.settings.saveWithoutReload();
|
||||
}
|
||||
|
||||
this.resetSettingsEditor();
|
||||
this.editorSaveFinished = true;
|
||||
|
||||
setTimeout(() => {
|
||||
this.editorSaveFinished = false;
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
|
||||
resetSettingsEditor() {
|
||||
this.settingsJson = JSON.parse(JSON.stringify(this.settings?.active ?? {}));
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region settings snapshot management
|
||||
async loadSettingsSnapshots() {
|
||||
this.settingsSnapshots = await this.settings.snapshotManager.listSnapshots();
|
||||
},
|
||||
|
||||
async markDefaultSnapshot(index) {
|
||||
await this.settings.snapshotManager.setDefaultSnapshot(index, !this.settingsSnapshots[index].isDefault);
|
||||
await this.loadSettingsSnapshots();
|
||||
this.settings.active.dev.loadFromSnapshot = this.settingsSnapshots[index].isDefault;
|
||||
this.saveSettingsChanges();
|
||||
},
|
||||
|
||||
async toggleSnapshotProtection(index) {
|
||||
await this.settings.snapshotManager.setSnapshotAsProtected(index, !this.settingsSnapshots[index].isProtected);
|
||||
await this.loadSettingsSnapshots();
|
||||
},
|
||||
|
||||
async deleteSnapshot(index) {
|
||||
await this.settings.snapshotManager.deleteSnapshot(index);
|
||||
await this.loadSettingsSnapshots();
|
||||
},
|
||||
|
||||
async loadFromSnapshot(snapshotIndex, skipSnapshot?: boolean) {
|
||||
this.settings.init({snapshot: this.settingsSnapshots[snapshotIndex], skipSnapshot});
|
||||
},
|
||||
|
||||
async testMigration(snapshotIndex) {
|
||||
this.settings.testMigration(this.settingsSnapshots[snapshotIndex]);
|
||||
},
|
||||
}
|
||||
//#endregion
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -2,19 +2,27 @@
|
||||
<p class="mb-4">Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md" target="_blank">is available here</a>.</p>
|
||||
|
||||
<p>Changes in version <b class="font-semibold text-primary-400">6.4.0</b>:</p>
|
||||
|
||||
<b class="text-white">Potentially breaking:</b>
|
||||
<ul>
|
||||
<li>De-spaghettified the part of the settings that controls whether extension runs on a given site or not.</li>
|
||||
</ul>
|
||||
|
||||
<b class="text-white">Autodetection:</b>
|
||||
<ul>
|
||||
<li>In-player UI can now appear in full-screen for websites that put players into top layer (allegedly).</li>
|
||||
<li>Embedded sites now inherit settings of the parent frame. <small>However, this hasn't been tested for all edge cases and may contain bugs.</small></li>
|
||||
<li>Added validation to custom aspect ratio entry menu. Corrected parsing of aspect ratios given in the X:Y format, even though aspect ratios should be ideally given as a single number.</li>
|
||||
<li>Autodetection can be set to stop after first aspect ratio detection, or after a period of no changes.</li>
|
||||
<li>
|
||||
There is a new, experiental mode for autodetection. At this point, it can be manually enabled in the autodetection settings. It will become the default option in 2026.<br/>
|
||||
If you enable experimental mode, please consider reporting problems <a href="https://github.com/tamius-han/ultrawidify/issues/291" target="_blank">in this thread</a> on Github.
|
||||
</li>
|
||||
<li>
|
||||
Autodetection can now detect hardcoded subtitles. You may change how extension handles subtitles in the settings.
|
||||
Use of new experimental autodetection is required for subtitle handling options to work.
|
||||
Experimental autodetection can now detect hardcoded subtitles. You may change how extension handles subtitles in the settings.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<b class="text-white">UI</b>
|
||||
<ul>
|
||||
<li>In-player UI can now appear in full-screen for websites that put players into top layer (allegedly).</li>
|
||||
<li>
|
||||
Keyboard shortcut settings have been split from UI settings, and are now presented in list form on the settings page.
|
||||
</li>
|
||||
@ -23,6 +31,12 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<b class="text-white">Other updates and fixes:</b>
|
||||
<ul>
|
||||
<li>Embedded sites now inherit settings of the parent frame. <small>However, this hasn't been tested for all edge cases and may contain bugs.</small></li>
|
||||
<li>Added validation to custom aspect ratio entry menu. Corrected parsing of aspect ratios given in the X:Y format, even though aspect ratios should be ideally given as a single number.</li>
|
||||
</ul>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import BrowserDetect from '@src/ext/conf/BrowserDetect';
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
@click="setExtensionMode('enable', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="simpleExtensionSettings.enable === 'complex'"
|
||||
value="complex"
|
||||
v-if="simpleExtensionSettings.enable === 'invalid'"
|
||||
:value="undefined"
|
||||
>
|
||||
(Site uses advanced settings)
|
||||
</option>
|
||||
@ -412,7 +412,7 @@ export default defineComponent({
|
||||
/**
|
||||
* Compiles our extension settings into more user-friendly options
|
||||
*/
|
||||
compileSimpleSettings(component, getFor = 'site') {
|
||||
compileSimpleSettings(component, getFor = 'site'): ExtensionMode {
|
||||
|
||||
let settingsData;
|
||||
switch (getFor) {
|
||||
@ -427,86 +427,25 @@ export default defineComponent({
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Disabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Disabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Disabled
|
||||
) {
|
||||
return 'disabled';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Default || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Default
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Default
|
||||
) {
|
||||
// console.log(
|
||||
// component, 'is set to default because:\n',
|
||||
// `\nsettingsData[${component}].normal: ${settingsData?.[component]?.normal} || component is enableUI?`, component,
|
||||
// `\nsettingsData[${component}].theater: ${settingsData?.[component]?.normal}`,
|
||||
// `\nsettingsData[${component}].fullscreen: ${settingsData?.[component]?.normal}`,
|
||||
|
||||
// `\n\n(expected values:`, ExtensionMode.Default
|
||||
// )
|
||||
return 'default';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Disabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Disabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Enabled
|
||||
) {
|
||||
return 'fs';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Disabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Enabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Enabled
|
||||
) {
|
||||
return 'theater';
|
||||
}
|
||||
if (
|
||||
( settingsData?.[component]?.normal === ExtensionMode.Enabled || component === 'enableUI')
|
||||
&& settingsData?.[component]?.theater === ExtensionMode.Enabled
|
||||
&& settingsData?.[component]?.fullscreen === ExtensionMode.Enabled
|
||||
) {
|
||||
return 'enabled';
|
||||
}
|
||||
|
||||
return 'complex';
|
||||
} catch (e) {
|
||||
return 'loading';
|
||||
}
|
||||
return settingsData?.[component];
|
||||
},
|
||||
|
||||
getDefaultOptionLabel(component) {
|
||||
const componentValue = this.compileSimpleSettings(component, 'default');
|
||||
const componentValue: ExtensionMode = this.compileSimpleSettings(component, 'default');
|
||||
|
||||
if (componentValue === 'loading') {
|
||||
return componentValue;
|
||||
}
|
||||
if (component === 'enableUI') {
|
||||
switch (componentValue) {
|
||||
case 'fs':
|
||||
return 'fullscreen only';
|
||||
case 'enabled':
|
||||
case 'theater':
|
||||
return 'where possible';
|
||||
case 'disabled':
|
||||
return 'disabled';
|
||||
}
|
||||
}
|
||||
switch (componentValue) {
|
||||
case 'fs':
|
||||
return 'Fullscreen only';
|
||||
case 'theater':
|
||||
return 'theater & FS';
|
||||
case 'enabled':
|
||||
return 'always';
|
||||
case 'disabled':
|
||||
case ExtensionMode.Disabled:
|
||||
return 'disabled';
|
||||
case 'default':
|
||||
return 'complex'
|
||||
case ExtensionMode.Default:
|
||||
return 'default';
|
||||
case ExtensionMode.FullScreen:
|
||||
return 'fullscreen only';
|
||||
case ExtensionMode.Theater:
|
||||
return 'fullscreen & theater';
|
||||
case ExtensionMode.All:
|
||||
return 'always';
|
||||
default:
|
||||
return '<Invalid value>';
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -168,12 +168,12 @@
|
||||
>
|
||||
</PlayerDetectionPanel>
|
||||
|
||||
<DebugPanel
|
||||
<Debugging
|
||||
v-if="selectedTab === 'debugging'"
|
||||
:settings="settings"
|
||||
:eventBus="eventBus"
|
||||
:site="site"
|
||||
></DebugPanel>
|
||||
></Debugging>
|
||||
|
||||
<!-- <ResetBackupPanel
|
||||
v-if="selectedTab === 'resetBackup'"
|
||||
@ -194,11 +194,11 @@ import UISettings from '@components/UISettings/UISettings.vue';
|
||||
import KeyboardShortcutSettings from '@components/KeyboardShortcuts/KeyboardShortcutSettings.vue';
|
||||
import SiteExtensionSettings from '@components/ExtensionSettings/Panels/SiteExtensionSettings.vue';
|
||||
import FrameSiteSettings from '@components/ExtensionSettings/Panels/FrameSiteSettings.vue';
|
||||
import Debugging from '@components/Debugging/Debugging.vue';
|
||||
|
||||
import WhatsNew from '@components/ExtensionInfo/WhatsNew.vue';
|
||||
import About from '@components/ExtensionInfo/About.vue';
|
||||
|
||||
import DebugPanel from '../../csui/src/PlayerUiPanels/DebugPanel.vue'
|
||||
import PlayerDetectionPanel from '../../csui/src/PlayerUiPanels/PlayerDetectionPanel.vue'
|
||||
import BrowserDetect from '../../ext/conf/BrowserDetect'
|
||||
import ChangelogPanel from '../../csui/src/PlayerUiPanels/ChangelogPanel.vue'
|
||||
@ -257,12 +257,12 @@ export default defineComponent({
|
||||
UISettings,
|
||||
SiteExtensionSettings,
|
||||
FrameSiteSettings,
|
||||
Debugging,
|
||||
|
||||
WhatsNew,
|
||||
About,
|
||||
|
||||
PlayerDetectionPanel,
|
||||
DebugPanel,
|
||||
ChangelogPanel,
|
||||
AboutPanel,
|
||||
SupportLevelIndicator,
|
||||
@ -366,11 +366,13 @@ export default defineComponent({
|
||||
console.log('setting initial path:', this.initialPath)
|
||||
if (path && path.length) {
|
||||
this.selectedTab = path[0];
|
||||
this.$emit('debugStatusChanged', this.selectedTab === 'debugging');
|
||||
}
|
||||
},
|
||||
selectTab(tab) {
|
||||
console.log("Selecting tab", tab);
|
||||
this.selectedTab = tab;
|
||||
this.$emit('debugStatusChanged', tab === 'debugging');
|
||||
window.location.hash = `#${this.role}/${this.selectedTab}`;
|
||||
},
|
||||
setPreventClose(bool) {
|
||||
|
||||
@ -6,7 +6,10 @@
|
||||
">
|
||||
|
||||
<!-- page content -->
|
||||
<div class="w-full max-w-[1920px] h-[100dvh] overflow-hidden flex flex-col">
|
||||
<div
|
||||
class="w-full h-[100dvh] overflow-hidden flex flex-col"
|
||||
:class="{'max-w-[1920px]': !isDebugging}"
|
||||
>
|
||||
<PopupHead
|
||||
v-if="role === 'popup' && settings && siteSettings && eventBus"
|
||||
:settings="settings"
|
||||
@ -32,6 +35,7 @@
|
||||
:logger="logger"
|
||||
:inPlayer="false"
|
||||
:site="site"
|
||||
@debugStatusChanged="setDebugStatus"
|
||||
>
|
||||
</SettingsWindowContent>
|
||||
</div>
|
||||
@ -70,6 +74,7 @@ export default defineComponent({
|
||||
settingsInitialized: false,
|
||||
role: 'settings',
|
||||
initialPath: undefined as string[] | undefined,
|
||||
isDebugging: false,
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@ -87,10 +92,18 @@ export default defineComponent({
|
||||
await this.setupSettingsPage();
|
||||
}
|
||||
|
||||
if (segment !== '#popup') {
|
||||
// undo that workaround that makes popup work correctly if we aren't in a popup
|
||||
document.getElementsByTagName('html')[0].setAttribute('style', '');
|
||||
}
|
||||
|
||||
await this.settings.init();
|
||||
this.settingsInitialized = true;
|
||||
},
|
||||
methods: {
|
||||
setDebugStatus(isDebugging: boolean) {
|
||||
this.isDebugging = isDebugging;
|
||||
},
|
||||
updateConfig() {
|
||||
this.settings.init();
|
||||
this.$nextTick( () => this.$forceUpdate());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user