Compare commits

..

4 Commits

Author SHA1 Message Date
32c11d1f61 Fix snapshots 2025-04-26 01:11:51 +02:00
5c48747d0f Add new zoom options (but they don't do anything yet) 2025-04-26 01:11:31 +02:00
5a0abb3595 Fix settings migrations 2025-04-26 01:09:49 +02:00
95b98c9053 Fix loading snapshots 2025-04-26 01:08:43 +02:00
9 changed files with 529 additions and 144 deletions

View File

@ -78,9 +78,7 @@
</Popup> </Popup>
<button class="flex-grow" @click="exportSettings()">Export settings</button> <button class="flex-grow" @click="exportSettings()">Export settings</button>
</div> </div>
<div> <div></div>
</div>
<ConfirmButton <ConfirmButton
dialogType="danger" dialogType="danger"
@onConfirmed="resetSettings" @onConfirmed="resetSettings"
@ -130,15 +128,10 @@
</JsonEditor> </JsonEditor>
</div> </div>
<h2>Settings migration report</h2>
<pre>
{{settings.migrationReport}}
</pre>
<h2>Settings snapshots</h2> <h2>Settings snapshots</h2>
<div class="flex flex-col"> <div class="flex flex-col">
<div v-for="(snapshot, index) of settingsSnapshots" :key="snapshot.createdAt"> <div v-for="(snapshot, index) of settingsSnapshots" :key="snapshot.createdAt">
<small>{{snapshot.createdAt.toISOString()}}</small> <small>{{new Date(snapshot.createdAt).toISOString()}}</small>
<div class="flex flex-row"> <div class="flex flex-row">
<div class="grow"> <div class="grow">
{{snapshot.name}} {{snapshot.name}}
@ -208,6 +201,7 @@ export default {
}, },
mounted() { mounted() {
this.resetSettingsEditor(); this.resetSettingsEditor();
this.loadSettingsSnapshots();
}, },
methods: { methods: {
setTab(tab) { setTab(tab) {

View File

@ -134,16 +134,25 @@
</template> </template>
<script> <script>
import ShortcutButton from '../../../components/ShortcutButton.vue'; import ShortcutButton from '@csui/src/components/ShortcutButton.vue';
import EditShortcutButton from '../../../components/EditShortcutButton'; import EditShortcutButton from '@csui/src/components/EditShortcutButton';
import EditModeMixin from '../../../utils/EditModeMixin'; import EditModeMixin from '@csui/src/utils/EditModeMixin';
import KeyboardShortcutParserMixin from '../../../utils/KeyboardShortcutParserMixin'; import KeyboardShortcutParserMixin from '@csui/src/utils/KeyboardShortcutParserMixin';
import CommsMixin from '../../../utils/CommsMixin'; import CommsMixin from '@csui/src/utils/CommsMixin';
import AspectRatioType from '../../../../../common/enums/AspectRatioType.enum'; import AspectRatioType from '@src/common/enums/AspectRatioType.enum';
export default { export default {
components: {
ShortcutButton,
EditShortcutButton,
},
mixins: [
// ComputeActionsMixin,
EditModeMixin,
KeyboardShortcutParserMixin,
CommsMixin
],
data() { data() {
return { return {
AspectRatioType: AspectRatioType, AspectRatioType: AspectRatioType,
@ -156,12 +165,6 @@ export default {
} }
} }
}, },
mixins: [
// ComputeActionsMixin,
EditModeMixin,
KeyboardShortcutParserMixin,
CommsMixin
],
props: [ props: [
'settings', // required for buttons and actions, which are global 'settings', // required for buttons and actions, which are global
'siteSettings', 'siteSettings',
@ -169,10 +172,6 @@ export default {
'isEditing', 'isEditing',
'allowSettingSiteDefault' 'allowSettingSiteDefault'
], ],
components: {
ShortcutButton,
EditShortcutButton,
},
computed: { computed: {
siteDefaultCrop() { siteDefaultCrop() {
if (!this.siteSettings) { if (!this.siteSettings) {

View File

@ -50,11 +50,11 @@
v-model="editModeOptions.stretch.selected.arguments.limit" v-model="editModeOptions.stretch.selected.arguments.limit"
> >
</div> </div>
</div>
<div class="hint"> <div class="hint">
If vertical borders would take up less than this much of screen width, the image will be stretched. If the borders are too thick, image will not be stretched. If vertical borders would take up less than this much of screen width, the image will be stretched. If the borders are too thick, image will not be stretched.
Value of 1 means 100%. Value of 0.1 means vertical black bars can take up 10% of the width at most. There's no validation on this, use common sense. Value of 1 means 100%. Value of 0.1 means vertical black bars can take up 10% of the width at most. There's no validation on this, use common sense.
</div> </div>
</div>
</template> </template>
<!-- Some options are only shown for type 5 (fixed) stretch --> <!-- Some options are only shown for type 5 (fixed) stretch -->
@ -70,12 +70,12 @@
@blur="editModeOptions.stretch.selected.label === 'Stretch to ...' ? editModeOptions.stretch.selected.label = `Stretch to ${editModeOptions.stretch.selected.arguments.ratio}` : null" @blur="editModeOptions.stretch.selected.label === 'Stretch to ...' ? editModeOptions.stretch.selected.label = `Stretch to ${editModeOptions.stretch.selected.arguments.ratio}` : null"
> >
</div> </div>
</div>
<div class="hint"> <div class="hint">
You can enter a ratio in width:height format (e.g. "21:9" or "1:2.39"), or just the factor You can enter a ratio in width:height format (e.g. "21:9" or "1:2.39"), or just the factor
(in this case, "1:2.39" would become "2.39" and "21:9" would become "2.33"). You should enter (in this case, "1:2.39" would become "2.39" and "21:9" would become "2.33"). You should enter
your numbers without quote marks. Number will be converted to factor form on save. your numbers without quote marks. Number will be converted to factor form on save.
</div> </div>
</div>
<div class="field"> <div class="field">
<div class="label"> <div class="label">
Label: Label:
@ -83,10 +83,10 @@
<div class="input"> <div class="input">
<input v-model="editModeOptions.stretch.selected.label"> <input v-model="editModeOptions.stretch.selected.label">
</div> </div>
</div>
<div class="hint"> <div class="hint">
Label for the button. You can make it say something other than ratio. Label for the button. You can make it say something other than ratio.
</div> </div>
</div>
</template> </template>
<!-- editing keyboard shortcuts is always allowed --> <!-- editing keyboard shortcuts is always allowed -->
@ -99,12 +99,12 @@
> >
</EditShortcutButton> </EditShortcutButton>
</div> </div>
</div>
<div class="hint"> <div class="hint">
<b>Note:</b> Your browser and OS already use certain key combinations that involve Ctrl and Meta (Windows) keys and, to a lesser extent, Alt. <b>Note:</b> Your browser and OS already use certain key combinations that involve Ctrl and Meta (Windows) keys and, to a lesser extent, Alt.
The extension doesn't (and cannot) check whether the keyboard shortcut you enter is actually free for you to use. The extension also won't override The extension doesn't (and cannot) check whether the keyboard shortcut you enter is actually free for you to use. The extension also won't override
any keyboard shortcuts defined by the site itself. any keyboard shortcuts defined by the site itself.
</div> </div>
</div>
<div class="flex flex-row flex-end"> <div class="flex flex-row flex-end">
<div <div

View File

@ -1,5 +1,132 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="sub-panel-content flex flex-row flex-wrap">
<ShortcutButton
v-for="(command, index) of settings?.active.commands.zoom"
class="flex b3 button"
:class="{active: editMode ? index === editModeOptions?.zoom?.selectedIndex : isActiveZoom(command)}"
:key="index"
:label="command.label"
:shortcut="getKeyboardShortcutLabel(command)"
@click="editMode ? editAction(command, index, 'zoom') : execAction(command)"
>
</ShortcutButton>
<!-- "Add new" button -->
<ShortcutButton
v-if="editMode"
class="button b3"
:class="{active: editMode ? editModeOptions?.crop?.selectedIndex === null : isActiveCrop(command)}"
label="Add new"
@click="editAction(
{action: 'set-ar-zoom', label: 'New aspect ratio', arguments: {type: AspectRatioType.Fixed}},
null,
'zoom'
)"
></ShortcutButton>
</div>
<template v-if="isEditing">
<div v-if="editMode && editModeOptions?.zoom?.selected" class="sub-panel-content">
<div class="edit-action-area-header">
<span class="text-primary">Editing options for:</span> <b>{{editModeOptions?.zoom?.selected?.label}}</b>&nbsp;
<template v-if="editModeOptions?.zoom?.selectedIndex === null && editModeOptions?.zoom?.selected?.label !== 'New aspect ratio'">(New ratio)</template>
</div>
<div class="edit-action-area">
<!-- Some options are only shown for type 4 (fixed) zooms -->
<template v-if="editModeOptions?.zoom?.selected?.arguments?.type === AspectRatioType.Fixed">
<div class="field">
<div class="label">
Ratio:
</div>
<div class="input">
<!-- We do an ugly in order to avoid spamming functions down at the bottom -->
<input
v-model="editModeOptions.zoom.selected.arguments.ratio"
@blur="editModeOptions.zoom.selected.label === 'New aspect ratio' ? editModeOptions.zoom.selected.label = editModeOptions.zoom.selected.arguments.ratio : null"
>
</div>
</div>
<div class="hint">
You can enter a ratio in width:height format (e.g. "21:9" or "1:2.39"), or just the factor
(in this case, "1:2.39" would become "2.39" and "21:9" would become "2.33"). You should enter
your numbers without quote marks. Number will be converted to factor form on save.
</div>
<div class="field">
<div class="label">
Label:
</div>
<div class="input">
<input v-model="editModeOptions.zoom.selected.label">
</div>
</div>
<div class="hint">
Label for the button. You can make it say something other than ratio.
</div>
</template>
<!-- editing keyboard shortcuts is always allowed -->
<div class="field">
<div class="label">Shortcut:</div>
<div class="">
<EditShortcutButton
:shortcut="editModeOptions?.zoom?.selected?.shortcut"
@shortcutChanged="updateSelectedShortcut($event, 'zoom')"
>
</EditShortcutButton>
</div>
</div>
<div class="hint">
<b>Note:</b> Your browser and OS already use certain key combinations that involve Ctrl and Meta (Windows) keys and, to a lesser extent, Alt.
The extension doesn't (and cannot) check whether the keyboard shortcut you enter is actually free for you to use. The extension also won't override
any keyboard shortcuts defined by the site itself.
</div>
<div class="flex flex-row flex-end">
<div
v-if="editModeOptions?.zoom?.selected?.arguments?.type === AspectRatioType.Fixed && editModeOptions?.zoom?.selectedIndex !== null"
class="button"
@click="deleteAction('zoom')"
>
<mdicon name="delete"></mdicon> Delete
</div>
<div class="flex-grow"></div>
<div class="button" @click="cancelEdit('zoom')">Cancel</div>
<div class="button" @click="saveShortcut('zoom')">
<mdicon name="floppy"></mdicon>
&nbsp;
<template v-if="editModeOptions?.zoom?.selectedIndex === null">Add</template>
<template v-else>Save</template>
</div>
</div>
</div>
</div>
<!-- <div v-if="siteSettings && allowSettingSiteDefault" class="edit-action-area">
<div class="field">
<div class="label">Default for this site</div>
<div class="select">
<select
:value="siteDefaultZoom"
@change="setDefaultZoom($event, 'site')"
>
<option
v-for="(command, index) of settings?.active.commands.zoom"
:key="index"
:value="JSON.stringify(command.arguments)"
>
{{command.label}}
</option>
</select>
</div>
</div>
</div> -->
</template>
<template v-else>
<!-- <!--
min, max and value need to be implemented in js as this slider min, max and value need to be implemented in js as this slider
should use logarithmic scale should use logarithmic scale
@ -73,14 +200,33 @@
</div> </div>
</div> </div>
</template> </template>
</template>
</div> </div>
</template> </template>
<script> <script>
import ShortcutButton from '@csui/src/components/ShortcutButton.vue';
import EditShortcutButton from '@csui/src/components/EditShortcutButton';
import EditModeMixin from '@csui/src/utils/EditModeMixin';
import KeyboardShortcutParserMixin from '@csui/src/utils/KeyboardShortcutParserMixin';
import CommsMixin from '@csui/src/utils/CommsMixin';
import AspectRatioType from '@src/common/enums/AspectRatioType.enum';
export default { export default {
components: {
ShortcutButton,
EditShortcutButton,
},
mixins: [
// ComputeActionsMixin,
EditModeMixin,
KeyboardShortcutParserMixin,
CommsMixin
],
data() { data() {
return { return {
AspectRatioType,
zoomAspectRatioLocked: true, zoomAspectRatioLocked: true,
zoom: { zoom: {
x: 0, x: 0,
@ -96,15 +242,26 @@ export default {
} }
} }
}, },
mixins: [
],
props: [ props: [
'settings', // required for buttons and actions, which are global 'settings', // required for buttons and actions, which are global
'siteSettings', 'siteSettings',
'eventBus', 'eventBus',
'isEditing' 'isEditing'
], ],
created() {
if (this.isEditing) {
this.enableEditMode();
}
},
watch: {
isEditing(newValue, oldValue) {
if (newValue) {
this.enableEditMode();
} else {
this.disableEditMode();
}
}
},
methods: { methods: {
getZoomForDisplay(axis) { getZoomForDisplay(axis) {
// zoom is internally handled logarithmically, because we want to have x0.5, x1, x2, x4 ... magnifications // zoom is internally handled logarithmically, because we want to have x0.5, x1, x2, x4 ... magnifications
@ -146,6 +303,9 @@ export default {
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: axis ?? 'x'}); this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: axis ?? 'x'});
} }
}, },
isActiveZoom(command) {
return false;
}
} }
} }

View File

@ -135,6 +135,19 @@
:isEditing="true" :isEditing="true"
></StretchOptionsPanel> ></StretchOptionsPanel>
</div> </div>
<!-- ZOOM OPTIONS -->
<div>
<div class="flex flex-row">
<h3 class="mth3">ZOOM OPTIONS</h3>
</div>
<ZoomOptionsPanel
:settings="settings"
:eventBus="eventBus"
:isEditing="true"
></ZoomOptionsPanel>
</div>
</div> </div>
</div> </div>
@ -142,16 +155,18 @@
</template> </template>
<script> <script>
import Button from '../components/Button.vue' import Button from '@csui/src/components/Button.vue'
import BrowserDetect from '../../../ext/conf/BrowserDetect'; import BrowserDetect from '@src/ext/conf/BrowserDetect';
import CropOptionsPanel from './PanelComponents/VideoSettings/CropOptionsPanel.vue' import CropOptionsPanel from '@csui/src/PlayerUiPanels/PanelComponents/VideoSettings/CropOptionsPanel.vue'
import StretchOptionsPanel from './PanelComponents/VideoSettings/StretchOptionsPanel.vue' import StretchOptionsPanel from '@csui/src/PlayerUiPanels/PanelComponents/VideoSettings/StretchOptionsPanel.vue'
import ZoomOptionsPanel from '@csui/src/PlayerUiPanels/PanelComponents/VideoSettings/ZoomOptionsPanel.vue'
export default { export default {
components: { components: {
Button, Button,
CropOptionsPanel, CropOptionsPanel,
StretchOptionsPanel StretchOptionsPanel,
ZoomOptionsPanel,
}, },
data() { data() {
return { return {
@ -267,7 +282,7 @@ export default {
gap: 1rem; gap: 1rem;
> * { > * {
width: calc(50% - 0.5rem); width: calc(33% - 0.5rem);
} }
} }

View File

@ -10,7 +10,7 @@ import CropModePersistence from '../../common/enums/CropModePersistence.enum';
import AspectRatioType from '../../common/enums/AspectRatioType.enum'; import AspectRatioType from '../../common/enums/AspectRatioType.enum';
import { update } from 'lodash'; import { update } from 'lodash';
const ExtensionConfPatch = [ const ExtensionConfPatch = Object.freeze([
{ {
forVersion: '6.2.4', forVersion: '6.2.4',
updateFn: (userOptions: SettingsInterface, defaultOptions) => { updateFn: (userOptions: SettingsInterface, defaultOptions) => {
@ -35,6 +35,19 @@ const ExtensionConfPatch = [
}, { }, {
forVersion: '6.2.6', forVersion: '6.2.6',
updateFn: (userOptions: SettingsInterface, defaultOptions) => { updateFn: (userOptions: SettingsInterface, defaultOptions) => {
console.warn('[ultrawidify] STARTING SETTINGS MIGRATION TO 6.2.6');
if (!userOptions.commands) {
userOptions.commands = {
zoom: [],
crop: [],
stretch: [],
pan: [],
internal: []
};
}
userOptions.commands.zoom = [{ userOptions.commands.zoom = [{
action: 'change-zoom', action: 'change-zoom',
label: 'Zoom +5%', label: 'Zoom +5%',
@ -92,9 +105,139 @@ const ExtensionConfPatch = [
showDetectionDetails: true showDetectionDetails: true
} }
} }
const newZoomActions = [{
action: 'set-zoom',
label: 'Reset zoom',
shortcut: {
key: 'r',
code: 'KeyR',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
},
internalOnly: true,
actionId: 'set-zoom-reset'
}, {
action: 'set-ar-zoom',
label: 'Automatic',
comment: 'Automatically detect aspect ratio and zoom accordingly',
arguments: {
type: AspectRatioType.Automatic
},
shortcut: {
key: 'a',
code: 'KeyA',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar-zoom',
label: 'Cycle',
comment: 'Cycle through zoom options',
arguments: {
type: AspectRatioType.Cycle
},
shortcut: {
key: 'c',
code: 'KeyC',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar-zoom',
label: '21:9',
comment: 'Zoom for 21:9 aspect ratio (1:2.39)',
arguments: {
type: AspectRatioType.Fixed,
ratio: 2.39
},
shortcut: {
key: 'd',
code: 'KeyD',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: false,
onKeyDown: true,
}
}, {
action: 'set-ar-zoom',
label: '18:9',
comment: 'Zoom for 18:9 aspect ratio (1:2)',
arguments: {
type: AspectRatioType.Fixed,
ratio: 1.78
},
shortcut: {
key: 's',
code: 'KeyS',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: false,
onKeyDown: true,
}
}, {
action: 'set-ar-zoom',
label: '32:9',
comment: 'Zoom for 32:9 aspect ratio',
arguments: {
type: AspectRatioType.Fixed,
ratio: 3.56
},
}];
const compareShortcuts = (a: any, b: any) => {
if (!a || !b) {
return false;
}
return a.key === b.key && b.code === b.code && a.ctrlKey == b.ctrlKey && a.shiftKey == b.shiftKey && a.metaKey == a.metaKey && a.altKey == b.altKey;
}
const hasConflict = (shortcut: any) => {
for (const ct in userOptions.commands) {
for (const command of userOptions.commands[ct]) {
if (compareShortcuts(shortcut, command.shortcut)) {
return true;
} }
} }
]; }
return false;
}
for (const zoomAction of newZoomActions) {
if (
!userOptions.commands.zoom.find(
x => x.action === zoomAction.action
&& x.arguments?.type === zoomAction.arguments?.type
&& x.arguments?.ratio === zoomAction.arguments?.ratio
)
) {
userOptions.commands.zoom.push({
...zoomAction,
shortcut: hasConflict(zoomAction.shortcut) ? undefined : zoomAction.shortcut
});
}
}
}
}
]);
export default ExtensionConfPatch; export default ExtensionConfPatch;

View File

@ -401,11 +401,96 @@ const ExtensionConf: SettingsInterface = {
}, { }, {
action: 'set-zoom', action: 'set-zoom',
label: 'Reset zoom', label: 'Reset zoom',
arguments: { shortcut: {
zoom: 1, key: 'r',
code: 'KeyR',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}, },
internalOnly: true, internalOnly: true,
actionId: 'set-zoom-reset' actionId: 'set-zoom-reset'
}, {
action: 'set-ar-zoom',
label: 'Automatic',
comment: 'Automatically detect aspect ratio',
arguments: {
type: AspectRatioType.Automatic
},
shortcut: {
key: 'a',
code: 'KeyA',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar-zoom',
label: 'Cycle',
comment: 'Cycle through crop options',
arguments: {
type: AspectRatioType.Cycle
},
shortcut: {
key: 'c',
code: 'KeyC',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar-zoom',
label: '21:9',
comment: 'Crop for 21:9 aspect ratio (1:2.39)',
arguments: {
type: AspectRatioType.Fixed,
ratio: 2.39
},
shortcut: {
key: 'd',
code: 'KeyD',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: false,
onKeyDown: true,
}
}, {
action: 'set-ar-zoom',
label: '18:9',
comment: 'Crop for 18:9 aspect ratio (1:2)',
arguments: {
type: AspectRatioType.Fixed,
ratio: 1.78
},
shortcut: {
key: 's',
code: 'KeyS',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: false,
onKeyDown: true,
}
}, {
action: 'set-ar-zoom',
label: '32:9',
comment: 'Crop for 32:9 aspect ratio',
arguments: {
type: AspectRatioType.Fixed,
ratio: 3.56
},
}], }],
pan: [{ pan: [{
action: 'set-alignment', action: 'set-alignment',

View File

@ -44,18 +44,9 @@ class Settings {
onChangedCallbacks: (() => void)[] = []; onChangedCallbacks: (() => void)[] = [];
afterSettingsChangedCallbacks: (() => void)[] = []; afterSettingsChangedCallbacks: (() => void)[] = [];
private sortedPatches: any[];
public snapshotManager: SettingsSnapshotManager; public snapshotManager: SettingsSnapshotManager;
private _migrationReport: string = '';
private set migrationReport(report: string) {
this._migrationReport = report;
}
public get migrationReport(): string {
return this._migrationReport;
}
//#endregion //#endregion
constructor(options) { constructor(options) {
@ -70,9 +61,6 @@ class Settings {
this.default['version'] = this.getExtensionVersion(); this.default['version'] = this.getExtensionVersion();
chrome.storage.onChanged.addListener((changes, area) => {this.storageChangeListener(changes, area)}); chrome.storage.onChanged.addListener((changes, area) => {this.storageChangeListener(changes, area)});
this.sortedPatches = this.sortConfPatches(ExtensionConfPatch);
} }
private storageChangeListener(changes, area) { private storageChangeListener(changes, area) {
@ -194,7 +182,7 @@ class Settings {
} }
private findFirstNecessaryPatch(version) { private findFirstNecessaryPatch(version) {
return this.sortedPatches.findIndex(x => this.compareExtensionVersions(x.forVersion, version) > 0); return ExtensionConfPatch.findIndex(x => this.compareExtensionVersions(x.forVersion, version) > 0);
} }
private applySettingsPatches(oldVersion) { private applySettingsPatches(oldVersion) {
let index = this.findFirstNecessaryPatch(oldVersion); let index = this.findFirstNecessaryPatch(oldVersion);
@ -217,20 +205,20 @@ class Settings {
// apply all remaining patches // apply all remaining patches
this.logger?.log('info', 'settings', `[Settings::applySettingsPatches] There are ${this.sortedPatches.length - index} settings patches to apply`); this.logger?.log('info', 'settings', `[Settings::applySettingsPatches] There are ${ExtensionConfPatch.length - index} settings patches to apply`);
while (index < this.sortedPatches.length) { while (index < ExtensionConfPatch.length) {
const updateFn = this.sortedPatches[index].updateFn; const updateFn = ExtensionConfPatch[index].updateFn;
delete this.sortedPatches[index].forVersion;
delete this.sortedPatches[index].updateFn;
if (Object.keys( this.sortedPatches[index]).length > 0) {
ObjectCopy.overwrite(this.active, this.sortedPatches[index]);
}
if (updateFn) { if (updateFn) {
try { try {
updateFn(this.active, this.getDefaultSettings()); updateFn(this.active, this.getDefaultSettings());
} catch (e) { } catch (e) {
this.logger?.log('error', 'settings', '[Settings::applySettingsPatches] Failed to execute update function. Keeping settings object as-is. Error:', e); this.logger?.log('error', 'settings', '[Settings::applySettingsPatches] Failed to execute update function. Keeping settings object as-is. Error:', e);
console.warn(
'————————————————————————————————————\n',
'Applying patch', index, ' failed :', '\n',
e, '\n',
'————————————————————————————————————\n',
);
} }
} }
@ -254,7 +242,7 @@ class Settings {
// |—> on first setup, settings is undefined & settings.version is haram // |—> on first setup, settings is undefined & settings.version is haram
// | since new installs ship with updates by default, no patching is // | since new installs ship with updates by default, no patching is
// | needed. In this case, we assume we're on the current version // | needed. In this case, we assume we're on the current version
const oldVersion = (settings && settings.version) || this.version; const oldVersion = settings?.version ?? this.version;
if (settings) { if (settings) {
this.logger?.log('info', 'settings', "[Settings::init] Configuration fetched from storage:", settings, this.logger?.log('info', 'settings', "[Settings::init] Configuration fetched from storage:", settings,
@ -276,6 +264,7 @@ class Settings {
this.active = this.getDefaultSettings(); this.active = this.getDefaultSettings();
this.active.version = this.version; this.active.version = this.version;
await this.save(); await this.save();
return this.active; return this.active;
} }
@ -339,7 +328,6 @@ class Settings {
if (!options || !options.forcePreserveVersion) { if (!options || !options.forcePreserveVersion) {
extensionConf.version = this.version; extensionConf.version = this.version;
} }
this.logger?.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf) this.logger?.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}); return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
@ -385,7 +373,7 @@ class Settings {
async save(options?: SetSettingsOptions) { async save(options?: SetSettingsOptions) {
if (Debug.debug && Debug.storage) { if (Debug.debug && Debug.storage) {
console.log("[Settings::save] Saving active settings:", this.active); console.log("[Settings::save] Saving active settings — save options", options, "; settings:", this.active);
} }
this.active.preventReload = undefined; this.active.preventReload = undefined;
this.active.lastModified = new Date(); this.active.lastModified = new Date();

View File

@ -92,13 +92,14 @@ export class SettingsSnapshotManager {
async listSnapshots(): Promise<SettingsSnapshot[]> { async listSnapshots(): Promise<SettingsSnapshot[]> {
const ret = await chrome.storage.local.get('uwSettings-snapshots'); const ret = await chrome.storage.local.get('uwSettings-snapshots');
try { try {
JSON.parse(ret['uwSettings-snapshots']) as SettingsSnapshot[]; const json = JSON.parse(ret['uwSettings-snapshots']) as SettingsSnapshot[];
return json;
} catch (e) { } catch (e) {
return [] as SettingsSnapshot[]; return [] as SettingsSnapshot[];
} }
} }
private async set(snapshots: SettingsSnapshot[]) { private async set(snapshots: SettingsSnapshot[] = []) {
await chrome.storage.local.set({ await chrome.storage.local.set({
'uwSettings-snapshots': JSON.stringify(snapshots), 'uwSettings-snapshots': JSON.stringify(snapshots),
}); });