Migrate DOMConfig in preparation for new settings page

This commit is contained in:
Tamius Han 2025-12-26 21:39:34 +01:00
parent 2a42c3e715
commit 3dbec85269
9 changed files with 247 additions and 152 deletions

View File

@ -1,5 +1,5 @@
export enum PlayerDetectionMode {
Auto = 0,
AncestorIndex = 1,
querySelectors = 2,
QuerySelectors = 2,
};

View File

@ -1,3 +1,4 @@
import { SiteSupportLevel } from './../enums/SiteSupportLevel.enum';
import { Action } from '../../../node_modules/vuex/types/index'
import { AardPollingOptions } from '../../ext/lib/aard/enums/aard-polling-options.enum'
import { AardSubtitleCropMode } from '../../ext/lib/aard/enums/aard-subtitle-crop-mode.enum'
@ -9,6 +10,7 @@ import ExtensionMode from '../enums/ExtensionMode.enum'
import { SiteSupportLevel } from '../enums/SiteSupportLevel.enum'
import StretchType from '../enums/StretchType.enum'
import VideoAlignmentType from '../enums/VideoAlignmentType.enum'
import { PlayerDetectionMode } from '../enums/PlayerDetectionMode.enum';
export enum ExtensionEnvironment {
Normal = ExtensionMode.All,
@ -443,8 +445,8 @@ export interface SiteSettingsInterface {
enableKeyboard: ExtensionMode;
enableUI: ExtensionMode;
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy; // presumed to be 'Always' if not defined
overrideWhenEmbedded?: boolean;
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy; // presumed to be 'Use as default' if not defined
overrideWhenEmbedded?: EmbeddedContentSettingsOverridePolicy;
autocreated?: boolean;
@ -484,11 +486,10 @@ export interface PlayerAutoConfigInterface {
}
export interface SiteDOMSettingsInterface {
type: 'official' | 'community' | 'user-defined' | 'modified' | undefined;
type: SiteSupportLevel; // 'official' | 'community' | 'user-defined' | 'modified' | undefined;
elements?: {
player?: SiteDOMElementSettingsInterface,
video?: SiteDOMElementSettingsInterface,
other?: { [x: number]: SiteDOMElementSettingsInterface }
player?: PlayerDOMSettingsInterface,
video?: PlayerDOMSettingsInterface,
};
customCss?: string;
periodicallyRefreshPlayerElement?: boolean;
@ -499,12 +500,19 @@ export interface SiteDOMSettingsInterface {
anchorElement?: HTMLElement;
}
export interface PlayerDOMSettingsInterface {
playerDetectionMode: PlayerDetectionMode,
allowAutoFallback: boolean,
ancestorIndex?: number,
querySelectors?: string,
customCSS?: string,
}
export interface SiteDOMElementSettingsInterface {
manual?: boolean;
querySelectors?: string;
index?: number; // previously: useRelativeAncestor + videoAncestor
mode?: 'index' | 'qs';
nodeCss?: {[x: string]: string};
}
export default SettingsInterface;

View File

@ -12,6 +12,7 @@ import { update } from 'lodash';
import EmbeddedContentSettingsOverridePolicy from '../../common/enums/EmbeddedContentSettingsOverridePolicy.enum';
import LegacyExtensionMode from '../../common/enums/LegacyExtensionMode.enum';
import ExtensionMode from '../../common/enums/ExtensionMode.enum';
import { PlayerDetectionMode } from '../../common/enums/PlayerDetectionMode.enum';
const ExtensionConfPatch = Object.freeze([
@ -316,6 +317,53 @@ const ExtensionConfPatch = Object.freeze([
userOptions.ui = defaultOptions.ui
};
}
}, {
forVersion: '6.3.996',
updateFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface, logger?) => {
for (const site in userOptions.sites) {
for (const domConf in userOptions.sites.DOMConfig) {
const oldConf = userOptions.sites[site].DOMConfig[domConf] as any;
const newConf: any = {
type: oldConf.type ?? userOptions.sites[site].type,
elements: {}
};
if (oldConf.elements.player) {
newConf.elements['player'] = {
playerDetectionMode: oldConf?.elements?.player?.manual ? (
oldConf?.elements?.player?.querySelectors.trim() ? PlayerDetectionMode.QuerySelectors : PlayerDetectionMode.AncestorIndex
) : PlayerDetectionMode.Auto,
allowAutoFallback: true,
ancestorIndex: oldConf?.elements?.player?.parentIndex,
querySelectors: oldConf?.elements?.player?.querySelectors,
customCSS: oldConf?.elements?.player?.customCss,
}
} else {
newConf.elements['player'] = {
playerDetectionMode: PlayerDetectionMode.Auto,
allowAutoFallback: true,
}
}
if (oldConf.elements.video) {
newConf.elements['video'] = {
type: oldConf.type ?? userOptions.sites[site].type,
elements: {
video: {
playerDetectionMode: oldConf?.elements?.video?.manual ? PlayerDetectionMode.QuerySelectors : PlayerDetectionMode.Auto,
allowAutoFallback: true,
querySelectors: oldConf?.elements?.video?.querySelectors,
customCSS: oldConf?.elements?.video?.customCss,
}
}
}
}
userOptions.sites[site].DOMConfig[domConf] = newConf;
}
}
}
}
]);

View File

@ -13,6 +13,7 @@ import EmbeddedContentSettingsOverridePolicy from '../../common/enums/EmbeddedCo
import { AardPollingOptions } from '../lib/aard/enums/aard-polling-options.enum';
import { AardSubtitleCropMode } from '../lib/aard/enums/aard-subtitle-crop-mode.enum';
import { SiteSupportLevel } from '../../common/enums/SiteSupportLevel.enum';
import { PlayerDetectionMode } from '../../common/enums/PlayerDetectionMode.enum';
if(Debug.debug)
console.log("Loading: ExtensionConf.js");
@ -820,26 +821,66 @@ const ExtensionConf: SettingsInterface = {
crop: {type: AspectRatioType.Automatic},
stretch: {type: StretchType.NoStretch},
alignment: {x: VideoAlignmentType.Center, y: VideoAlignmentType.Center},
},
activeDOMConfig: 'blank',
DOMConfig: {
'blank': {
type: SiteSupportLevel.Unknown,
elements: {
player: {
playerDetectionMode: PlayerDetectionMode.Auto,
allowAutoFallback: true,
// ancestorIndex: 1, // we leave those on undefined,
// querySelectors: '',
// customCSS: ''
}
}
}
}
},
"@empty": { // placeholder settings object with fallbacks to @global
"@empty": {
defaultType: SiteSupportLevel.Unknown,
enable: ExtensionMode.Default,
enableAard: ExtensionMode.Default,
enableKeyboard: ExtensionMode.Default,
enableUI: ExtensionMode.Default,
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.Default,
overrideWhenEmbedded: EmbeddedContentSettingsOverridePolicy.Default,
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.Always,
type: SiteSupportLevel.UserDefined,
defaultType: SiteSupportLevel.UserDefined,
persistCSA: CropModePersistence.Default,
defaults: {
crop: null,
crop: {type: AspectRatioType.Default},
stretch: {type: StretchType.Default},
alignment: {x: VideoAlignmentType.Default, y: VideoAlignmentType.Default},
alignment: {x: VideoAlignmentType.Default, y: VideoAlignmentType.Default}
},
persistCSA: CropModePersistence.Default,
activeDOMConfig: 'empty',
DOMConfig: {
'empty': {
type: SiteSupportLevel.UserDefined,
elements: {
player: {
playerDetectionMode: PlayerDetectionMode.Auto,
allowAutoFallback: true,
// ancestorIndex: 1,
// querySelectors: '',
// customCSS: ''
},
video: {
playerDetectionMode: PlayerDetectionMode.Auto,
allowAutoFallback: true,
// ancestorIndex: 1,
// querySelectors: '',
// customCSS: ''
}
},
}
}
},
"www.youtube.com" : {
"www.youtube.com": {
enable: ExtensionMode.All,
enableAard: ExtensionMode.All,
enableKeyboard: ExtensionMode.All,
@ -858,7 +899,8 @@ const ExtensionConf: SettingsInterface = {
type: SiteSupportLevel.OfficialSupport,
elements: {
player: {
manual: true,
playerDetectionMode: PlayerDetectionMode.QuerySelectors,
allowAutoFallback: true,
querySelectors: "#movie_player, #player, #c4-player",
}
}
@ -885,7 +927,8 @@ const ExtensionConf: SettingsInterface = {
type: SiteSupportLevel.OfficialSupport,
elements: {
player: {
manual: true,
playerDetectionMode: PlayerDetectionMode.QuerySelectors,
allowAutoFallback: true,
querySelectors: "#movie_player, #player, #c4-player",
}
}
@ -901,6 +944,21 @@ const ExtensionConf: SettingsInterface = {
override: false,
type: SiteSupportLevel.CommunitySupport,
defaultType: SiteSupportLevel.CommunitySupport,
DOMConfig: {
'community': {
type: SiteSupportLevel.CommunitySupport,
elements: {
player: {
playerDetectionMode: PlayerDetectionMode.Auto,
allowAutoFallback: true,
// ancestorIndex: 1,
// querySelectors: '',
// customCSS: ''
}
}
}
}
},
"www.disneyplus.com" : {
enable: ExtensionMode.Theater,
@ -917,11 +975,13 @@ const ExtensionConf: SettingsInterface = {
type: SiteSupportLevel.OfficialSupport,
elements: {
player: {
manual: true,
playerDetectionMode: PlayerDetectionMode.QuerySelectors,
allowAutoFallback: true,
querySelectors: ".btm-media-player",
},
video: {
manual: true,
playerDetectionMode: PlayerDetectionMode.QuerySelectors,
allowAutoFallback: true,
querySelectors: ".btm-media-client-element"
}
},
@ -972,19 +1032,6 @@ const ExtensionConf: SettingsInterface = {
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.Never,
type: SiteSupportLevel.OfficialBlacklist,
defaultType: SiteSupportLevel.OfficialBlacklist,
activeDOMConfig: 'official',
DOMConfig: {
'official': {
type: SiteSupportLevel.OfficialSupport,
// customCss: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
elements: {
player: {
manual: false,
querySelectors: '.reddit-video-player-root, .media-preview-content'
}
}
}
},
},
"imgur.com": {
enable: ExtensionMode.Disabled,
@ -1011,7 +1058,8 @@ const ExtensionConf: SettingsInterface = {
type: SiteSupportLevel.CommunitySupport,
elements: {
player: {
manual: true,
playerDetectionMode: PlayerDetectionMode.QuerySelectors,
allowAutoFallback: true,
querySelectors: "#jwplayer-container"
}
}
@ -1027,13 +1075,6 @@ const ExtensionConf: SettingsInterface = {
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.UseAsDefault,
type: SiteSupportLevel.CommunitySupport,
defaultType: SiteSupportLevel.CommunitySupport,
activeDOMConfig: 'community',
DOMConfig: {
'community': {
type: SiteSupportLevel.CommunitySupport,
// customCss: "body {\n background-color: #000;\n}\n\n.application {\n background-color: #000;\n}"
}
}
},
"metaivi.com": {
enable: ExtensionMode.Theater,
@ -1043,17 +1084,6 @@ const ExtensionConf: SettingsInterface = {
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.UseAsDefault,
type: SiteSupportLevel.CommunitySupport,
defaultType: SiteSupportLevel.CommunitySupport,
activeDOMConfig: 'community',
DOMConfig: {
'community': {
type: SiteSupportLevel.CommunitySupport,
elements: {
video: {
nodeCss: {'position': 'absolute !important'}
}
}
}
},
},
"piped.kavin.rocks": {
enable: ExtensionMode.Theater,
@ -1064,13 +1094,6 @@ const ExtensionConf: SettingsInterface = {
applyToEmbeddedContent: EmbeddedContentSettingsOverridePolicy.UseAsDefault,
type: SiteSupportLevel.CommunitySupport,
defaultType: SiteSupportLevel.CommunitySupport,
activeDOMConfig: 'community',
DOMConfig: {
'community': {
type: SiteSupportLevel.CommunitySupport,
// customCss: ".shaka-video-container {\n flex-direction: column !important;\n}"
}
}
},
}
}

View File

@ -39,6 +39,7 @@ export class SiteSettings {
temporaryData: SiteSettingsInterface;
sessionData: SiteSettingsInterface;
readonly defaultSettings: SiteSettingsInterface;
readonly blankSettings: SiteSettingsInterface;
storageChangeSubscriptions: {[x: string]: ((newSiteConf, changes, area) => void)[]} = {};
@ -50,6 +51,7 @@ export class SiteSettings {
this.settings = settings;
this.raw = settings.active.sites[this.site];
this.defaultSettings = settings.active.sites['@global'];
this.blankSettings = settings.active.sites['@empty'];
this.compileSettingsObject();
@ -472,7 +474,7 @@ export class SiteSettings {
// If this function is not being called in response to user actin,
// create fake settings object.
if (options.scripted && !this.settings.active.sites[targetSite]) {
this.settings.active.sites[targetSite] = _cp(this.settings.active.sites['@global']);
this.settings.active.sites[targetSite] = _cp(this.blankSettings);
this.settings.active.sites[targetSite].autocreated = true;
this.settings.active.sites[targetSite].type = SiteSupportLevel.Unknown;
} else {

View File

@ -1,60 +1,68 @@
<template>
<!-- ADVANCED OPTIONS -->
<div v-if="DOMConfigData" class="flex flex-col gap-2">
<div class="flex flex-col gap-2">
<div class="flex flex-row gap-2 justify-end">
<button>Load existing config</button>
<button>Import from file</button>
</div>
<div class="field">
<div class="label">Player detection:</div>
<div class="select">
<select v-model="DOMConfigData.elements.player.playerDetectionMode">
<option :value="PlayerDetectionMode.Auto">Automatic</option>
<option :value="PlayerDetectionMode.AncestorIndex">Fixed player container offset</option>
<option :value="PlayerDetectionMode.QuerySelectors">Query selectors</option>
</select>
</div>
</div>
<div class="field">
<div class="label">Use automatic detection for fallback</div>
<div class="checkbox">
<input type="checkbox" v-model="DOMConfigData.elements.player.allowAutoFallback" />
<template v-if="DOMConfigData" >
<div class="field">
<div class="label">Player detection:</div>
<div class="select">
<select v-model="DOMConfigData.elements.player.playerDetectionMode">
<option :value="PlayerDetectionMode.Auto">Automatic</option>
<option :value="PlayerDetectionMode.AncestorIndex">Fixed player container offset</option>
<option :value="PlayerDetectionMode.QuerySelectors">Query selectors</option>
</select>
</div>
</div>
</div>
<div class="field">
<div class="label">Player container offset</div>
<div class="input">
<input v-model="DOMConfigData.elements.player.ancestorIndex" />
<div class="field">
<div class="label">Use automatic detection for fallback</div>
<div class="checkbox">
<input type="checkbox" v-model="DOMConfigData.elements.player.allowAutoFallback" />
</div>
</div>
<div class="hint">
Defines how far away from video the player container element is. If you don't know what you're doing, start
with 1, save settings, and reload the page. If this doesn't fix your problem, increase the number by 1 and
repeat the procedure. If no value between 1-16 works, the site may require additional CSS in order to work.
</div>
</div>
<div class="field">
<div class="label">Query selector</div>
<div class="input">
<input v-model="DOMConfigData.elements.player.querySelectors" />
<div class="field">
<div class="label">Player container offset</div>
<div class="input">
<input v-model="DOMConfigData.elements.player.ancestorIndex" />
</div>
<div class="hint">
Defines how far away from video the player container element is. If you don't know what you're doing, start
with 1, save settings, and reload the page. If this doesn't fix your problem, increase the number by 1 and
repeat the procedure. If no value between 1-16 works, the site may require additional CSS in order to work.
</div>
</div>
<div class="hint">
You should be at least somewhat proficient with CSS in order to use this option. If you need to provide more
than one query selector, use commas to separate them.
</div>
</div>
<div class="field">
<div class="label">Additional CSS for the page</div>
<div class="input">
<textbox v-model="DOMConfigData.customCss" />
<div class="field">
<div class="label">Query selector</div>
<div class="input">
<input v-model="DOMConfigData.elements.player.querySelectors" />
</div>
<div class="hint">
You should be at least somewhat proficient with CSS in order to use this option. If you need to provide more
than one query selector, use commas to separate them.
</div>
</div>
<div class="hint">
You should be at least somewhat proficient with CSS in order to use this option.
<div class="field">
<div class="label">Additional CSS for the page</div>
<div class="input">
<textarea v-model="DOMConfigData.customCSS" />
</div>
<div class="hint">
You should be at least somewhat proficient with CSS in order to use this option.
</div>
</div>
</div>
</template>
<template v-else>
No DOM config for this site.
</template>
</div>
<div class="w-full flex flex-row gap-2 justify-end">
@ -75,6 +83,7 @@ import { SiteSettings } from '@src/ext/lib/settings/SiteSettings';
import { PlayerDetectionMode } from '@src/common/enums/PlayerDetectionMode.enum';
import Popup from '@components/common/Popup.vue';
import { _cp } from '../../../../../common/js/utils';
export default({
@ -88,6 +97,7 @@ export default({
],
data() {
return {
PlayerDetectionMode,
DOMConfigData: undefined as any,
selectSnapshotDialog: {visible: false},
}
@ -104,7 +114,11 @@ export default({
},
methods: {
loadSiteSettings(siteSettings: SiteSettings) {
this.DOMConfigData = siteSettings.data.DOMConfig[siteSettings.data.activeDOMConfig];
if (siteSettings.data.DOMConfig) {
this.DOMConfigData = siteSettings.data.DOMConfig[siteSettings.data.activeDOMConfig];
} else {
this.DOMConfigData = _cp(siteSettings.blankSettings.DOMConfig.blank)
}
}
}

View File

@ -200,23 +200,23 @@ export default defineComponent({
},
async setPlayer(index) {
// yup.
this.siteSettings.getDOMConfig('modified', 'original');
await this.siteSettings.setUpdateFlags(['PlayerData']);
await this.siteSettings.set('DOMConfig.modified.type', 'modified', {noSave: true});
await this.siteSettings.set('activeDOMConfig', 'modified', {noSave: true});
// this.siteSettings.getDOMConfig('modified', 'original');
// await this.siteSettings.setUpdateFlags(['PlayerData']);
// await this.siteSettings.set('DOMConfig.modified.type', 'modified', {noSave: true});
// await this.siteSettings.set('activeDOMConfig', 'modified', {noSave: true});
// if user agrees with ultrawidify on what element player should be,
// we just unset our settings for this site
if (this.elementStack[index].heuristics?.autoMatch) {
await this.siteSettings.set('DOMConfig.modified.elements.player.manual', false);
this.getPlayerTree();
} else {
// ensure settings exist:
await this.siteSettings.set('DOMConfig.modified.elements.player.manual', true, {noSave: true});
await this.siteSettings.set('DOMConfig.modified.elements.player.mode', 'index', {noSave: true});
await this.siteSettings.set('DOMConfig.modified.elements.player.index', index, true);
this.getPlayerTree();
}
// // if user agrees with ultrawidify on what element player should be,
// // we just unset our settings for this site
// if (this.elementStack[index].heuristics?.autoMatch) {
// await this.siteSettings.set('DOMConfig.modified.elements.player.manual', false);
// this.getPlayerTree();
// } else {
// // ensure settings exist:
// await this.siteSettings.set('DOMConfig.modified.elements.player.manual', true, {noSave: true});
// await this.siteSettings.set('DOMConfig.modified.elements.player.mode', 'index', {noSave: true});
// await this.siteSettings.set('DOMConfig.modified.elements.player.index', index, true);
// this.getPlayerTree();
// }
},
/**
* Toggles active CSS for element of certain parent index.

View File

@ -56,23 +56,23 @@ export default({
},
async setPlayer(index) {
// yup.
this.siteSettings.getDOMConfig('modified', 'original');
await this.siteSettings.setUpdateFlags(['PlayerData']);
await this.siteSettings.set('DOMConfig.modified.type', 'modified', {noSave: true});
await this.siteSettings.set('activeDOMConfig', 'modified', {noSave: true});
// this.siteSettings.getDOMConfig('modified', 'original');
// await this.siteSettings.setUpdateFlags(['PlayerData']);
// await this.siteSettings.set('DOMConfig.modified.type', 'modified', {noSave: true});
// await this.siteSettings.set('activeDOMConfig', 'modified', {noSave: true});
// if user agrees with ultrawidify on what element player should be,
// we just unset our settings for this site
if (this.elementStack[index].heuristics?.autoMatch) {
await this.siteSettings.set('DOMConfig.modified.elements.player.manual', false);
this.getPlayerTree();
} else {
// ensure settings exist:
await this.siteSettings.set('DOMConfig.modified.elements.player.manual', true, {noSave: true});
await this.siteSettings.set('DOMConfig.modified.elements.player.mode', 'index', {noSave: true});
await this.siteSettings.set('DOMConfig.modified.elements.player.index', index, true);
this.getPlayerTree();
}
// // if user agrees with ultrawidify on what element player should be,
// // we just unset our settings for this site
// if (this.elementStack[index].heuristics?.autoMatch) {
// await this.siteSettings.set('DOMConfig.modified.elements.player.manual', false);
// this.getPlayerTree();
// } else {
// // ensure settings exist:
// await this.siteSettings.set('DOMConfig.modified.elements.player.manual', true, {noSave: true});
// await this.siteSettings.set('DOMConfig.modified.elements.player.mode', 'index', {noSave: true});
// await this.siteSettings.set('DOMConfig.modified.elements.player.index', index, true);
// this.getPlayerTree();
// }
},
edit() {

View File

@ -156,23 +156,23 @@ export default({
},
async setPlayer(index) {
// yup.
this.siteSettings.getDOMConfig('modified', 'original');
await this.siteSettings.setUpdateFlags(['PlayerData']);
await this.siteSettings.set('DOMConfig.modified.type', 'modified', {noSave: true});
await this.siteSettings.set('activeDOMConfig', 'modified', {noSave: true});
// this.siteSettings.getDOMConfig('modified', 'original');
// await this.siteSettings.setUpdateFlags(['PlayerData']);
// await this.siteSettings.set('DOMConfig.modified.type', 'modified', {noSave: true});
// await this.siteSettings.set('activeDOMConfig', 'modified', {noSave: true});
// if user agrees with ultrawidify on what element player should be,
// we just unset our settings for this site
if (this.elementStack[index].heuristics?.autoMatch) {
await this.siteSettings.set('DOMConfig.modified.elements.player.manual', false);
this.getPlayerTree();
} else {
// ensure settings exist:
await this.siteSettings.set('DOMConfig.modified.elements.player.manual', true, {noSave: true});
await this.siteSettings.set('DOMConfig.modified.elements.player.mode', 'index', {noSave: true});
await this.siteSettings.set('DOMConfig.modified.elements.player.index', index, true);
this.getPlayerTree();
}
// // if user agrees with ultrawidify on what element player should be,
// // we just unset our settings for this site
// if (this.elementStack[index].heuristics?.autoMatch) {
// await this.siteSettings.set('DOMConfig.modified.elements.player.manual', false);
// this.getPlayerTree();
// } else {
// // ensure settings exist:
// await this.siteSettings.set('DOMConfig.modified.elements.player.manual', true, {noSave: true});
// await this.siteSettings.set('DOMConfig.modified.elements.player.mode', 'index', {noSave: true});
// await this.siteSettings.set('DOMConfig.modified.elements.player.index', index, true);
// this.getPlayerTree();
// }
},
/**
* Toggles active CSS for element of certain parent index.