Move settings to a different folder, iframes default to parent page settings

This commit is contained in:
Tamius Han 2025-07-15 19:42:35 +02:00
parent f88f703e84
commit 75670ef3f9
5 changed files with 137 additions and 23 deletions

View File

@ -308,6 +308,9 @@ export interface SiteSettingsInterface {
enableKeyboard: ExtensionEnvironmentSettingsInterface; enableKeyboard: ExtensionEnvironmentSettingsInterface;
enableUI: ExtensionEnvironmentSettingsInterface; // Lies! enableUI doesn't use 'theater' property (but uses the other two) enableUI: ExtensionEnvironmentSettingsInterface; // Lies! enableUI doesn't use 'theater' property (but uses the other two)
applyToEmbeddedContent?: boolean; // presumed to be 'true' if not defined
autocreated?: boolean; autocreated?: boolean;
type?: 'official' | 'community' | 'user-defined' | 'testing' | 'officially-disabled' | 'unknown' | 'modified'; type?: 'official' | 'community' | 'user-defined' | 'testing' | 'officially-disabled' | 'unknown' | 'modified';
defaultType: 'official' | 'community' | 'user-defined' | 'testing' | 'officially-disabled' | 'unknown' | 'modified'; defaultType: 'official' | 'community' | 'user-defined' | 'testing' | 'officially-disabled' | 'unknown' | 'modified';

View File

@ -8,6 +8,7 @@ import { SiteSettings } from './lib/settings/SiteSettings';
import UI from './lib/uwui/UI'; import UI from './lib/uwui/UI';
import { BLANK_LOGGER_CONFIG, LogAggregator } from './lib/logging/LogAggregator'; import { BLANK_LOGGER_CONFIG, LogAggregator } from './lib/logging/LogAggregator';
import { ComponentLogger } from './lib/logging/ComponentLogger'; import { ComponentLogger } from './lib/logging/ComponentLogger';
import { getIframeParentHost, setupHostnameReporting } from './util/getHost';
export default class UWContent { export default class UWContent {
pageInfo: PageInfo; pageInfo: PageInfo;
@ -19,6 +20,7 @@ export default class UWContent {
logger: ComponentLogger; logger: ComponentLogger;
eventBus: EventBus; eventBus: EventBus;
isIframe: boolean = false; isIframe: boolean = false;
parentHostname: string;
globalUi: any; globalUi: any;
@ -28,7 +30,8 @@ export default class UWContent {
} }
constructor(){ constructor(){
this.isIframe = window.self !== window.top setupHostnameReporting();
this.isIframe = window.self !== window.top;
} }
reloadSettings() { reloadSettings() {
@ -41,6 +44,11 @@ export default class UWContent {
} }
async init(){ async init(){
if (this.isIframe) {
this.parentHostname = await getIframeParentHost();
console.warn('[uw-content] got iframe parent:', this.parentHostname);
}
try { try {
if (Debug.debug) { if (Debug.debug) {
console.log("[uw::main] loading configuration ..."); console.log("[uw::main] loading configuration ...");
@ -57,6 +65,7 @@ export default class UWContent {
console.error("logger init failed!", e) console.error("logger init failed!", e)
} }
// init() is re-run any time settings change // init() is re-run any time settings change
if (this.comms) { if (this.comms) {
this.comms.destroy(); this.comms.destroy();
@ -70,7 +79,7 @@ export default class UWContent {
logAggregator: this.logAggregator logAggregator: this.logAggregator
}); });
await this.settings.init(); await this.settings.init();
this.siteSettings = this.settings.getSiteSettings(); this.siteSettings = this.settings.getSiteSettings({site: window.location.hostname, isIframe: this.isIframe, parentHostname: this.parentHostname});
} }
this.eventBus = new EventBus(); this.eventBus = new EventBus();

View File

@ -1,14 +1,14 @@
import Debug from '../conf/Debug'; import Debug from '../../conf/Debug';
import ExtensionConf from '../conf/ExtensionConf'; import ExtensionConf from '../../conf/ExtensionConf';
import ObjectCopy from './ObjectCopy'; import ObjectCopy from '../ObjectCopy';
import StretchType from '../../common/enums/StretchType.enum'; import StretchType from '../../../common/enums/StretchType.enum';
import ExtensionConfPatch from '../conf/ExtConfPatches'; import ExtensionConfPatch from '../../conf/ExtConfPatches';
import SettingsInterface from '../../common/interfaces/SettingsInterface'; import SettingsInterface from '../../../common/interfaces/SettingsInterface';
import AspectRatioType from '../../common/enums/AspectRatioType.enum'; import AspectRatioType from '../../../common/enums/AspectRatioType.enum';
import { SiteSettings } from './settings/SiteSettings'; import { GetSiteSettingsOptions, SiteSettings } from './SiteSettings';
import { SettingsSnapshotManager } from './settings/SettingsSnapshotManager'; import { SettingsSnapshotManager } from './SettingsSnapshotManager';
import { ComponentLogger } from './logging/ComponentLogger'; import { ComponentLogger } from '../logging/ComponentLogger';
import { LogAggregator } from './logging/LogAggregator'; import { LogAggregator } from '../logging/LogAggregator';
if(process.env.CHANNEL !== 'stable'){ if(process.env.CHANNEL !== 'stable'){
console.info("Loading Settings"); console.info("Loading Settings");
@ -25,6 +25,7 @@ interface SetSettingsOptions {
forcePreserveVersion?: boolean, forcePreserveVersion?: boolean,
} }
const SETTINGS_LOGGER_STYLES = { const SETTINGS_LOGGER_STYLES = {
log: 'color: #81d288', log: 'color: #81d288',
} }
@ -413,8 +414,8 @@ class Settings {
} }
} }
getSiteSettings(site: string = window.location.hostname): SiteSettings { getSiteSettings(options: GetSiteSettingsOptions = {site: window.location.hostname}): SiteSettings {
return new SiteSettings(this, site); return new SiteSettings(this, options);
} }
listenOnChange(fn: () => void): void { listenOnChange(fn: () => void): void {

View File

@ -6,6 +6,13 @@ import Settings from './Settings';
import StretchType from '../../../common/enums/StretchType.enum'; import StretchType from '../../../common/enums/StretchType.enum';
import VideoAlignmentType from '../../../common/enums/VideoAlignmentType.enum'; import VideoAlignmentType from '../../../common/enums/VideoAlignmentType.enum';
export interface GetSiteSettingsOptions {
site: string,
isIframe?: boolean,
parentHostname?: string,
}
/** /**
* Contains settings that are currently in effect for a given site. If a certain option * Contains settings that are currently in effect for a given site. If a certain option
* doesn't have a value — or if it has 'default' option, SiteSettings.data will contain * doesn't have a value — or if it has 'default' option, SiteSettings.data will contain
@ -22,6 +29,7 @@ export class SiteSettings {
public get site() { public get site() {
return this._site; return this._site;
} }
private options: GetSiteSettingsOptions;
raw: SiteSettingsInterface; // actual settings raw: SiteSettingsInterface; // actual settings
data: SiteSettingsInterface; // effective settings data: SiteSettingsInterface; // effective settings
@ -33,10 +41,12 @@ export class SiteSettings {
storageChangeSubscriptions: {[x: string]: ((newSiteConf, changes, area) => void)[]} = {}; storageChangeSubscriptions: {[x: string]: ((newSiteConf, changes, area) => void)[]} = {};
//#region lifecycle //#region lifecycle
constructor(settings: Settings, site: string) { constructor(settings: Settings, options: GetSiteSettingsOptions) {
this.options = options;
this.site = options.site;
this.settings = settings; this.settings = settings;
this.raw = settings.active.sites[site]; this.raw = settings.active.sites[this.site];
this.site = site;
this.defaultSettings = settings.active.sites['@global']; this.defaultSettings = settings.active.sites['@global'];
this.compileSettingsObject(); this.compileSettingsObject();
@ -56,19 +66,53 @@ export class SiteSettings {
/** /**
* Tries to match websites, even if we're on a different subdomain. * Tries to match websites, even if we're on a different subdomain.
*
* Priority chain:
*
* START HERE
* |
* [ exact hostname match ]
* | |
* no yes > return settings for hostname
* V
* | matches hostname on |
* | different subdomain? |
* | |
* no yes > return settings for matching subdomain
* V
* [ are we inside of an iframe? ]
* | |
* no yes
* V V
* return default | exact parent |
* settings | hostname match? |
* A | |
* | no yes > [ applyToEmbeddedContent set? ]
* | V | |
* | | parent matches hostname | no yes
* | | on different subdomain? | V V
* | | | use default use parent settings
* +< no yes
* | |
* +< no [ applyToEmbeddedContent set? ]
* |
* yes
* V
* use settings for matching subdomain of parent
*
* @returns * @returns
*/ */
private getSettingsForSite() { private getSettingsForSite(options: GetSiteSettingsOptions) {
if (!this.site) { if (!options.site) {
return { return {
siteSettings: this.settings.active.sites['@global'], siteSettings: this.settings.active.sites['@global'],
usesSettingsFor: '@global' usesSettingsFor: '@global'
}; };
} }
if (this.settings.active.sites[this.site]) { if (this.settings.active.sites[options.site]) {
return { return {
siteSettings: this.settings.active.sites[this.site], siteSettings: this.settings.active.sites[options.site],
usesSettingsFor: undefined usesSettingsFor: undefined
}; };
} }
@ -97,6 +141,14 @@ export class SiteSettings {
} }
} }
// If we're inside of an iframe, let's see whether we can use parent settings
if (options.isIframe) {
const potentialSettings = this.getSettingsForSite({site: options.parentHostname});
if (potentialSettings.siteSettings.applyToEmbeddedContent !== false) {
return potentialSettings;
}
}
return { return {
siteSettings: this.settings.active.sites['@global'], siteSettings: this.settings.active.sites['@global'],
usesSettingsFor: '@global' usesSettingsFor: '@global'
@ -108,7 +160,7 @@ export class SiteSettings {
* Alan pls ensure default settings object follows the correct structure * Alan pls ensure default settings object follows the correct structure
*/ */
private compileSettingsObject() { private compileSettingsObject() {
const {siteSettings, usesSettingsFor} = this.getSettingsForSite(); const {siteSettings, usesSettingsFor} = this.getSettingsForSite(this.options);
this.data = _cp(siteSettings); this.data = _cp(siteSettings);
this.usesSettingsFor = usesSettingsFor; this.usesSettingsFor = usesSettingsFor;

49
src/ext/util/getHost.ts Normal file
View File

@ -0,0 +1,49 @@
/**
* Reqzests iframe parent hostname
* @returns
*/
export async function getIframeParentHost(): Promise<string> {
return new Promise<any>((resolve) => {
let resolved = false;
let resendInterval;
function handleMessage(event) {
if (event.data.action === 'uw-parent-hostname') {
resolved = true;
clearInterval(resendInterval);
window.removeEventListener('message', handleMessage);
resolve(event.data.hostname);
}
}
window.addEventListener('message', handleMessage);
resendInterval = setInterval(
() => {
if (!resolved) {
window.parent.postMessage(
{ action: 'uw-get-parent-hostname' },
'*'
);
}
},
500
);
});
}
function handleMessage(event) {
if (event.data.action === 'uw-get-parent-hostname') {
event.source.postMessage(
{action: 'uw-parent-hostname', hostname: window.location.hostname},
'*' as any
)
}
}
export async function setupHostnameReporting() {
window.removeEventListener('message', handleMessage); // setupHostnameReporting may run more than once
window.addEventListener('message', handleMessage);
}