Save player element settigs + simplified import/export
This commit is contained in:
parent
3f5ab5ecc6
commit
a8847bdeff
@ -354,6 +354,9 @@ const ExtensionConfPatch = Object.freeze([
|
||||
userOptions.sites[site].defaultType = SiteSupportLevel.Unknown;
|
||||
}
|
||||
|
||||
if (siteData.activeDOMConfig?.startsWith('community') || siteData.activeDOMConfig === 'official' || siteData.activeDOMConfig === 'empty' || siteData.activeDOMConfig === 'auto') {
|
||||
siteData.activeDOMConfig = `@${siteData.activeDOMConfig}`;
|
||||
}
|
||||
|
||||
for (const domConf in siteData.DOMConfig) {
|
||||
logger.log('updateFn', "Updating domconf", domConf);
|
||||
@ -405,27 +408,41 @@ const ExtensionConfPatch = Object.freeze([
|
||||
}
|
||||
}
|
||||
|
||||
console.log('new conf:', newConf)
|
||||
|
||||
userOptions.sites[site].DOMConfig[domConf] = newConf;
|
||||
// migrate names — official and community options get @ at the start
|
||||
let domConfName = domConf;
|
||||
if (domConfName.startsWith('community') || domConfName === 'official' || domConfName === 'empty' || domConfName === 'auto') {
|
||||
domConfName = `@${domConfName}`;
|
||||
}
|
||||
|
||||
if (domConfName !== domConf) {
|
||||
logger.warn(`updateFn`, '\n\nnaming for default domConf has changed. Old:', domConf, 'new:', domConfName);
|
||||
delete userOptions.sites[site].DOMConfig[domConf];
|
||||
}
|
||||
|
||||
userOptions.sites[site].DOMConfig[domConfName] = newConf;
|
||||
}
|
||||
}
|
||||
|
||||
// set new defaults for global and empty:
|
||||
userOptions.sites['@global'].DOMConfig = {
|
||||
'auto': {
|
||||
'@auto': {
|
||||
type: SiteSupportLevel.Unknown,
|
||||
elements: {
|
||||
player: {
|
||||
detectionMode: PlayerDetectionMode.Auto,
|
||||
allowAutoFallback: true,
|
||||
},
|
||||
video: {
|
||||
detectionMode: PlayerDetectionMode.Auto,
|
||||
allowAutoFallback: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
userOptions.sites['@global'].activeDOMConfig = 'auto';
|
||||
userOptions.sites['@global'].activeDOMConfig = '@auto';
|
||||
userOptions.sites['@empty'].DOMConfig = {
|
||||
'empty': {
|
||||
'@empty': {
|
||||
type: SiteSupportLevel.UserDefined,
|
||||
elements: {
|
||||
player: {
|
||||
@ -439,7 +456,7 @@ const ExtensionConfPatch = Object.freeze([
|
||||
},
|
||||
}
|
||||
};
|
||||
userOptions.sites['@empty'].activeDOMConfig = 'empty';
|
||||
userOptions.sites['@empty'].activeDOMConfig = '@empty';
|
||||
|
||||
logger.log('updateFn', 'Migration complete. New site settings:', userOptions.sites);
|
||||
}
|
||||
|
||||
@ -823,9 +823,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
alignment: {x: VideoAlignmentType.Center, y: VideoAlignmentType.Center},
|
||||
},
|
||||
|
||||
activeDOMConfig: 'auto',
|
||||
activeDOMConfig: '@auto',
|
||||
DOMConfig: {
|
||||
'auto': {
|
||||
'@auto': {
|
||||
type: SiteSupportLevel.Unknown,
|
||||
elements: {
|
||||
player: {
|
||||
@ -856,9 +856,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
|
||||
persistCSA: CropModePersistence.Default,
|
||||
|
||||
activeDOMConfig: 'empty',
|
||||
activeDOMConfig: '@empty',
|
||||
DOMConfig: {
|
||||
'empty': {
|
||||
'@empty': {
|
||||
type: SiteSupportLevel.UserDefined,
|
||||
elements: {
|
||||
player: {
|
||||
@ -890,9 +890,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
defaultType: SiteSupportLevel.OfficialSupport, // 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',
|
||||
activeDOMConfig: '@official',
|
||||
DOMConfig: {
|
||||
'official': {
|
||||
'@official': {
|
||||
type: SiteSupportLevel.OfficialSupport,
|
||||
elements: {
|
||||
player: {
|
||||
@ -918,9 +918,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
defaultType: SiteSupportLevel.OfficialSupport, // 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',
|
||||
activeDOMConfig: '@official',
|
||||
DOMConfig: {
|
||||
'official': {
|
||||
'@official': {
|
||||
type: SiteSupportLevel.OfficialSupport,
|
||||
elements: {
|
||||
player: {
|
||||
@ -943,7 +943,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
defaultType: SiteSupportLevel.CommunitySupport,
|
||||
|
||||
DOMConfig: {
|
||||
'community': {
|
||||
'@community': {
|
||||
type: SiteSupportLevel.CommunitySupport,
|
||||
elements: {
|
||||
player: {
|
||||
@ -966,9 +966,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.UseAsDefault,
|
||||
type: SiteSupportLevel.CommunitySupport,
|
||||
defaultType: SiteSupportLevel.CommunitySupport,
|
||||
activeDOMConfig: 'community-mstefan99',
|
||||
activeDOMConfig: '@community-mstefan99',
|
||||
DOMConfig: {
|
||||
'community-mstefan99': {
|
||||
'@community-mstefan99': {
|
||||
type: SiteSupportLevel.OfficialSupport,
|
||||
elements: {
|
||||
player: {
|
||||
@ -996,9 +996,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
type: SiteSupportLevel.OfficialSupport,
|
||||
defaultType: SiteSupportLevel.OfficialSupport,
|
||||
|
||||
activeDOMConfig: 'official',
|
||||
activeDOMConfig: '@official',
|
||||
DOMConfig: {
|
||||
'official': {
|
||||
'@official': {
|
||||
type: SiteSupportLevel.OfficialSupport,
|
||||
elements: {
|
||||
player: {
|
||||
@ -1049,9 +1049,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.UseAsDefault,
|
||||
type: SiteSupportLevel.CommunitySupport,
|
||||
defaultType: SiteSupportLevel.CommunitySupport,
|
||||
activeDOMConfig: 'community',
|
||||
activeDOMConfig: '@community',
|
||||
DOMConfig: {
|
||||
'community': {
|
||||
'@community': {
|
||||
type: SiteSupportLevel.CommunitySupport,
|
||||
elements: {
|
||||
player: {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
'normal': dialogType === 'normal'
|
||||
}"
|
||||
>
|
||||
{{ dialogText || 'Confirm action' }}
|
||||
{{ dialogTitle || 'Confirm action' }}
|
||||
</div>
|
||||
<div class="body">
|
||||
{{ dialogText || 'Are you sure you want to do that?' }}
|
||||
@ -41,6 +41,7 @@
|
||||
},
|
||||
btnClass
|
||||
]"
|
||||
:disabled="disabled"
|
||||
@click="popupVisible = true"
|
||||
>
|
||||
<slot></slot>
|
||||
@ -62,7 +63,8 @@ export default defineComponent({
|
||||
'dialogText',
|
||||
'confirmText',
|
||||
'cancelText',
|
||||
'dialogType'
|
||||
'dialogType',
|
||||
'disabled',
|
||||
],
|
||||
methods: {
|
||||
confirmAction() {
|
||||
|
||||
@ -2,14 +2,15 @@
|
||||
<!-- ADVANCED OPTIONS -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-row gap-2 justify-end">
|
||||
<button @click="openSelectSnapshotDialog()">Load existing config</button>
|
||||
<UploadJsonFileButton
|
||||
<button @click="openSelectSnapshotDialog()">Switch preset</button>
|
||||
<!-- <UploadJsonFileButton
|
||||
@importedJson="handleImportedSettings"
|
||||
@error="handleSettingsImportError"
|
||||
>
|
||||
Import settings
|
||||
</UploadJsonFileButton>
|
||||
<button>Export config</button>
|
||||
<button @click="exportDialog.visible = true">Export config</button> -->
|
||||
<button class="flex flex-rows items-center" @click="openCopyPasteDialog()"><mdicon class="font-normal mr-2" name="content-copy" :size="16" /> Copy/paste config</button>
|
||||
</div>
|
||||
|
||||
<div v-if="loaded" class="w-[690px] max-w-full">
|
||||
@ -145,16 +146,16 @@
|
||||
</div>
|
||||
|
||||
<div class="w-full flex flex-row gap-2 justify-end">
|
||||
<button>Save as</button>
|
||||
<button :disabled="DOMConfigName?.startsWith('@')">Save</button>
|
||||
<button>Close</button>
|
||||
<button @click="openSaveAsDialog()">Save as</button>
|
||||
<button :disabled="!siteSettings.raw.DOMConfig?.[DOMConfigName] || DOMConfigName?.startsWith('@')">Save</button>
|
||||
<button @click="closeForm()">Close</button>
|
||||
</div>
|
||||
|
||||
<!-- PRESET SELECT DIALOG -->
|
||||
<Popup
|
||||
v-if="selectSnapshotDialog.visible"
|
||||
title="Select configuration"
|
||||
@onClose="selectSnapshotDialog.visible = false"
|
||||
@onCancel="selectSnapshotDialog.visible = false"
|
||||
>
|
||||
<div>Select configuration:</div>
|
||||
<div class="flex flex-col gap-2 py-4">
|
||||
@ -177,7 +178,39 @@
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
<!-- FINISH IMPORT DIALOG -->
|
||||
<!-- COPY/PASTE CONFIG DIALOG -->
|
||||
<Popup
|
||||
v-if="copyPasteDialog.visible"
|
||||
confirmButtonText="Apply"
|
||||
cancelButtonText="Cancel"
|
||||
title="Copy or paste configuration"
|
||||
@onCancel="copyPasteDialog.onClose()"
|
||||
@onConfirm="copyPasteDialog.onSave()"
|
||||
>
|
||||
<div class="field">
|
||||
<div class="label !min-w-16">Raw config:</div>
|
||||
<div class="input !w-[560px] min-h-[320px]">
|
||||
<textarea class="h-[320px] w-full resize-none" v-model="copyPasteDialog.data.jsonTxt"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="settings.active.ui.devMode" class="field">
|
||||
<div class="label">Change support level:</div>
|
||||
<div class="select">
|
||||
<select @change="_cpDialog_setSupportLevel">
|
||||
<option :value="undefined">(select option to override)</option>
|
||||
<option :value="SiteSupportLevel.OfficialSupport">Official support</option>
|
||||
<option :value="SiteSupportLevel.CommunitySupport">Community-supported</option>
|
||||
<option :value="SiteSupportLevel.BetaSupport">Texsting/experimental</option>
|
||||
<option :value="SiteSupportLevel.UserDefined">User-defined</option>
|
||||
<option :value="SiteSupportLevel.UserModified">User-modified</option>
|
||||
<option :value="SiteSupportLevel.OfficialBlacklist">Officially blacklisted</option>
|
||||
<option :value="SiteSupportLevel.Unknown">Unknown</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
<!-- FINISH IMPORT DIALOG (half-finished, currently unused)-->
|
||||
<Popup
|
||||
v-if="finishImportDialog.visible"
|
||||
:title="finishImportDialog.data.invalidJson ? 'Import failed' : 'Select configuration'"
|
||||
@ -210,9 +243,58 @@
|
||||
</template>
|
||||
</Popup>
|
||||
|
||||
<!-- EXPORT CONFIG DIALOG -->
|
||||
<!-- EXPORT CONFIG DIALOG (half finished, currently unused) -->
|
||||
<Popup
|
||||
v-if="exportDialog.visible"
|
||||
title="Export configuration"
|
||||
:clientSideButtons="true"
|
||||
>
|
||||
<div class="w-[24rem] max-w-full">
|
||||
<div class="field radio">
|
||||
<input type="radio" v-model="exportDialog.data.exportType" value="current">
|
||||
<div class="label-r">Export current configuration</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="field radio ">
|
||||
<input type="radio" v-model="exportDialog.data.exportType" value="multiple">
|
||||
<div class="label-r">Export the following configurations</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
<!-- SAVE AS DIALOG -->
|
||||
<Popup
|
||||
v-if="saveAsDialog.visible"
|
||||
title="Save preset as ..."
|
||||
:clientSideButtons="true"
|
||||
>
|
||||
<div class="field">
|
||||
<div class="label">Configuration name</div>
|
||||
<div class="input">
|
||||
<input v-model="saveAsDialog.data.name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="hint">
|
||||
Configuration name may include letters, numbers, underscores (_) and dashes (-).
|
||||
</div>
|
||||
<div class="flex flex-row justify-end gap-2">
|
||||
<ConfirmButton v-if="siteSettings.raw.DOMConfig?.[saveAsDialog.data.name]"
|
||||
:disabled="!/^[a-zA-Z0-9-_]*$/.test(saveAsDialog.data.name)"
|
||||
dialogType="danger"
|
||||
dialogTitle="Settings preset exists"
|
||||
dialogText="Settings preset with this name already exists. Do you want to overwrite it?"
|
||||
confirmText="Overwrite"
|
||||
@onConfirmed="finishSaveAs"
|
||||
>
|
||||
Save
|
||||
</ConfirmButton>
|
||||
<button v-else @click="finishSaveAs" :disabled="!/^[a-zA-Z0-9-_]*$/.test(saveAsDialog.data.name)">Save</button>
|
||||
<button @click="saveAsDialog.visible = false">Cancel</button>
|
||||
</div>
|
||||
</Popup>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -220,18 +302,19 @@ import { SiteSettings } from '@src/ext/lib/settings/SiteSettings';
|
||||
import { PlayerDetectionMode } from '@src/common/enums/PlayerDetectionMode.enum';
|
||||
import UploadJsonFileButton from '@components/common/UploadJsonFileButton.vue';
|
||||
import SupportLevelIndicator from '@components/common/SupportLevelIndicator.vue';
|
||||
import ConfirmButton from '@components/common/ConfirmButton.vue';
|
||||
|
||||
import Popup from '@components/common/Popup.vue';
|
||||
import { _cp } from '@src/common/js/utils';
|
||||
import { SiteDOMSettingsInterface } from '@src/common/interfaces/SettingsInterface';
|
||||
|
||||
import { SiteSupportLevel } from '../../../../../common/enums/SiteSupportLevel.enum';
|
||||
|
||||
export default({
|
||||
components: {
|
||||
PlayerDetectionMode,
|
||||
UploadJsonFileButton,
|
||||
SupportLevelIndicator,
|
||||
Popup,
|
||||
ConfirmButton,
|
||||
},
|
||||
props: [
|
||||
'settings',
|
||||
@ -240,11 +323,15 @@ export default({
|
||||
data() {
|
||||
return {
|
||||
PlayerDetectionMode,
|
||||
SiteSupportLevel,
|
||||
loaded: false,
|
||||
DOMConfigData: undefined as any,
|
||||
DOMConfigName: undefined as any,
|
||||
selectSnapshotDialog: {visible: false},
|
||||
finishImportDialog: {visible: false}
|
||||
copyPasteDialog: {visible: false},
|
||||
finishImportDialog: {visible: false},
|
||||
exportDialog: {visible: false, data: {exportType: 'current'}},
|
||||
saveAsDialog: {visible: false}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -281,6 +368,8 @@ export default({
|
||||
this.loaded = true;
|
||||
},
|
||||
|
||||
|
||||
|
||||
openSelectSnapshotDialog() {
|
||||
this.selectSnapshotDialog = {
|
||||
visible: true
|
||||
@ -293,13 +382,66 @@ export default({
|
||||
this.selectSnapshotDialog = false;
|
||||
},
|
||||
|
||||
openCopyPasteDialog() {
|
||||
this.copyPasteDialog = {
|
||||
visible: true,
|
||||
data: {
|
||||
jsonTxt: JSON.stringify(this.DOMConfigData, null, 2)
|
||||
},
|
||||
onClose: () => {
|
||||
this.copyPasteDialog = {visible: false};
|
||||
},
|
||||
onSave: () => {
|
||||
if (JSON.stringify(JSON.parse(this.copyPasteDialog.data.jsonTxt)) !== JSON.stringify(this.DOMConfigData) ) {
|
||||
this.DOMConfigData = JSON.parse(this.copyPasteDialog.data.jsonTxt);
|
||||
if (!this.DOMConfigData.type) {
|
||||
this.DOMConfigData.type = SiteSupportLevel.UserDefined;
|
||||
}
|
||||
|
||||
let pastedCount = 0;
|
||||
for (const key in this.siteSettings.data.DOMConfig) {
|
||||
if (key.startsWith('pasted-settings')) {
|
||||
pastedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.DOMConfigName || this.DOMConfigName.startsWith('@')) {
|
||||
this.DOMConfigName = `pasted-settings${pastedCount ? `-${pastedCount}` : ''}`;
|
||||
}
|
||||
|
||||
this.copyPasteDialog = {visible: false}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** Used when dev mode settings are visible in order to easily override config type */
|
||||
_cpDialog_setSupportLevel(event) {
|
||||
const value = event.target.value;
|
||||
|
||||
const obj = JSON.parse(this.copyPasteDialog.data.jsonTxt);
|
||||
delete obj.type;
|
||||
|
||||
this.copyPasteDialog.data.jsonTxt = JSON.stringify({
|
||||
type: value,
|
||||
...obj,
|
||||
}, null, 2);
|
||||
},
|
||||
|
||||
handleImportedSettings(json: {activeDOMConfig?: string, DOMConfig: { [x: string]: SiteDOMSettingsInterface & {overwrite?: boolean}}} | SiteDOMSettingsInterface) {
|
||||
let afterImportDialogData;
|
||||
|
||||
if ((json as any).DOMConfig) {
|
||||
afterImportDialogData = json;
|
||||
} else if ((json as SiteDOMSettingsInterface).type) {
|
||||
const key = `imported-${new Date().toISOString()}`;
|
||||
let importedCount = 0;
|
||||
for (const key in this.siteSettings.data.DOMConfig) {
|
||||
if (key.startsWith('imported-settings')) {
|
||||
importedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
const key = `imported-settings${importedCount ? `-${importedCount}` : ''}`;
|
||||
afterImportDialogData = {
|
||||
activeDOMConfig: key,
|
||||
DOMConfig: {
|
||||
@ -321,6 +463,22 @@ export default({
|
||||
handleSettingsImportError(error) {
|
||||
console.error(`[ultrawidify] Failed to upload snapshot. Error:`, error);
|
||||
},
|
||||
|
||||
openSaveAsDialog() {
|
||||
this.saveAsDialog = {
|
||||
visible: true,
|
||||
data: {
|
||||
name: this.DOMConfigName.replaceAll('@', '').trim(),
|
||||
}
|
||||
}
|
||||
},
|
||||
async finishSaveAs() {
|
||||
this.DOMConfigName = this.saveAsDialog.data.name;
|
||||
this.siteSettings.raw.DOMConfig[this.DOMConfigName] = this.DOMConfigData;
|
||||
this.siteSettings.raw.activeDOMConfig = this.DOMConfigName;
|
||||
this.saveAsDialog = {visible: false};
|
||||
await this.settings.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -132,6 +132,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.radio {
|
||||
@apply flex flex-row gap-4 items-center;
|
||||
}
|
||||
}
|
||||
.hint {
|
||||
@apply text-primary-200/70;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"outDir": "./ts-out",
|
||||
"allowJs": true,
|
||||
"target": "esnext",
|
||||
"lib": ["esnext", "DOM"],
|
||||
"types": [
|
||||
"chrome",
|
||||
"node"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user