Compare commits

...

9 Commits

Author SHA1 Message Date
f7f046ea53 Propagate messages across server boundary 2025-06-16 21:58:35 +02:00
ec0896e17a Implement zoom in extension popup, in-player UI 2025-05-19 01:18:48 +02:00
a5f35248bd Event-bus: Auto-forward across iframe and commsServer 2025-05-19 01:17:09 +02:00
a05eccce9e fix zoom config 2025-05-19 01:15:05 +02:00
e118777636 Fix debounce 2025-05-19 01:14:19 +02:00
7998e8158e Fix log coloration 2025-05-07 00:45:08 +02:00
14f837d1f0 EventBus: prevent backflow of messages that originate from CommsServer back into CommsServer 2025-05-07 00:42:25 +02:00
cff1d3cf16 Cache active tab in comms server
Previously, if console window was active, this.activeTab would return nothing, and the popup would break. If that happens now, popup will pretend it's on the last active site.
2025-05-07 00:41:45 +02:00
b2cd96982e Further logging fixes 2025-05-04 21:00:15 +02:00
25 changed files with 453 additions and 252 deletions

View File

@ -2,6 +2,14 @@
## v6.0 (current major)
### v6.3.0
* Added zoom segment to in-player UI and popup.
* Fixed keyboard zoom
* Added additional zoom options. If you wonder how zoom options differ from crop, mess around and find out.
* Subdomains now inherit same settings as their parent domain by default
* Extension detects embedded content (but not always)
* Added `www.youtube-nocookie.com` to "officially supported" list
### v6.2.5
* Popup appearance changed — UI advertisement panel was moved to the popup header

View File

@ -44,13 +44,6 @@ export default {
},
async created() {
this.logger = new Logger();
// this prolly needs to be taken out
await this.logger.init({
allowLogging: true,
});
/**
* Setup the "companion" onMouseMove handler to the one in the content script.
* We can handle events with the same function we use to handle events from

View File

@ -64,7 +64,7 @@
</GhettoContextMenuOption>
</slot>
</GhettoContextMenu>
<!-- <GhettoContextMenu alignment="right">
<GhettoContextMenu alignment="right">
<template v-slot:activator>
Zoom
</template>
@ -86,7 +86,7 @@
/>
</GhettoContextMenuItem>
</slot>
</GhettoContextMenu> -->
</GhettoContextMenu>
<GhettoContextMenu alignment="right">
<template v-slot:activator>
<div class="context-item">
@ -213,6 +213,8 @@ import CommsMixin from '@csui/src/utils/CommsMixin';
import SupportLevelIndicator from '@csui/src/components/SupportLevelIndicator.vue';
import TriggerZoneEditor from '@csui/src/components/TriggerZoneEditor.vue';
import ZoomControl from '@csui/src/popup/player-menu/ZoomControl.vue';
import { LogAggregator } from '@src/ext/lib/logging/LogAggregator';
import { ComponentLogger } from '@src/ext/lib/logging/ComponentLogger';
export default {
components: {
@ -329,11 +331,6 @@ export default {
this.logAggregator = new LogAggregator('player-overlay');
this.logger = new ComponentLogger(this.logAggregator, 'PlayerOverlay.vue');
// this prolly needs to be taken out
await this.logger.init({
allowLogging: true,
});
this.settings = new Settings({afterSettingsSaved: this.updateConfig, logger: this.logger});
this.settings.listenAfterChange(() => this.updateTriggerZones());
@ -575,7 +572,17 @@ export default {
},
handleBusTunnelIn(payload) {
this.eventBus.send(payload.action, payload.config, payload.routingData);
this.eventBus.send(
payload.action,
payload.config,
{
...payload.context,
borderCrossings: {
...payload.context?.borderCrossings,
iframe: true
}
}
);
},
updateConfig() {

View File

@ -176,11 +176,8 @@ export default {
try {
this.logAggregator = new LogAggregator('🔵ext-popup🔵');
this.logger = new ComponentLogger(this.logAggregator, 'Popup');
await this.logger.init({
allowLogging: true,
});
this.settings = new Settings({afterSettingsSaved: () => this.updateConfig(), logger: this.logger});
this.settings = new Settings({afterSettingsSaved: () => this.updateConfig(), logAggregator: this.logAggregator});
await this.settings.init();
this.settingsInitialized = true;
@ -277,8 +274,14 @@ export default {
try {
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
// CSM.port.postMessage({command: 'get-current-site'});
this.eventBus.send(
'probe-video',
{},
{ comms: {forwardTo: 'active'} }
);
this.eventBus.send(
'get-current-site',
{},
{
comms: {forwardTo: 'active'}
}

View File

@ -5,13 +5,15 @@
<h1>What's new</h1>
<!-- <p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md" target="_blank">is available here</a>.</p> -->
<h2>6.2.6</h2>
<h2>6.3.0</h2>
<ul>
<li>Automatic aspect ratio detection: do not apply negative aspect ratios</li>
<li>Keyboard zoom now works</li>
<li><code>www.youtube-nocookie.com</code> has been added to the "officially supported" list</li>
<li>Fixed the bug where UI would sometimes refuse to stay hidden</li>
<li>New experimental zoom options</li>
<li>Subdomains now inherit same settings as their parent domain by default</li>
<li>Extension attempts to detect embedded content.</li>
</ul>
</div>
<div style="width: 1rem; height: 0px;"></div>

View File

@ -27,7 +27,7 @@
</template>
<script>
import { LogAggregator } from '@src/ext/lib/logging/LogAggregator';
import { LogAggregator, BLANK_LOGGER_CONFIG } from '@src/ext/lib/logging/LogAggregator';
import JsonEditor from '@csui/src/components/JsonEditor';
export default {
@ -79,21 +79,23 @@ export default {
...this.loggerPanelRotation[Math.floor(Math.random() * this.loggerPanelRotation.length)],
pasteConfMode: false,
};
this.loadDefaultConfig();
this.getLoggerSettings();
},
methods: {
loadDefaultConfig() {
this.lastSettings = baseLoggingOptions;
this.lastSettings = JSON.parse(JSON.stringify(BLANK_LOGGER_CONFIG));
},
async getLoggerSettings() {
this.lastSettings = await LogAggregator.getConfig() || baseLoggingOptions;
this.lastSettings = await LogAggregator.getConfig() || BLANK_LOGGER_CONFIG;
},
saveLoggerSettings() {
LogAggregator.saveConfig({...this.lastSettings});
async saveLoggerSettings() {
console.log('Saving logger settings', this.lastSettings);
await LogAggregator.saveConfig({...this.lastSettings});
console.log('[ok] logger settings saved');
},
async startLogging(){
this.logStringified = undefined;
await LogAggregator.saveConfig({...this.lastSettings, allowLogging: true});
await LogAggregator.saveConfig({...this.lastSettings});
window.location.reload();
},
}

View File

@ -108,26 +108,6 @@
</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>
<!--
@ -228,6 +208,13 @@ export default {
KeyboardShortcutParserMixin,
CommsMixin
],
props: [
'settings', // required for buttons and actions, which are global
'siteSettings',
'eventBus',
'isEditing',
'compact',
],
data() {
return {
AspectRatioType,
@ -247,13 +234,6 @@ export default {
}
}
},
props: [
'settings', // required for buttons and actions, which are global
'siteSettings',
'eventBus',
'isEditing',
'compact',
],
created() {
if (this.isEditing) {
this.enableEditMode();
@ -272,7 +252,6 @@ export default {
getZoomForDisplay(axis) {
// zoom is internally handled logarithmically, because we want to have x0.5, x1, x2, x4 ... magnifications
// spaced out at regular intervals. When displaying, we need to convert that to non-logarithmic values.
return `${(Math.pow(2, this.zoom[axis]) * 100).toFixed()}%`
},
toggleZoomAr() {

View File

@ -6,74 +6,79 @@
current settings do not allow the extension to only be disabled while in full screen
-->
<template v-if="siteSettings.isEnabledForEnvironment(false, true) === ExtensionMode.Disabled">
<div class="info">
Extension is not enabled for this site.
<div class="h-full flex flex-col items-center justify-center">
<div class="info">
Extension is not enabled for this site.
</div>
<div>
Please enable extension for this site.
</div>
</div>
</template>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>CROP</span>
</div>
<div
style="margin-top: -0.69rem; margin-bottom: 0.88rem;"
>
<CropOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
:compact="true"
<template v-else>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>CROP</span>
</div>
<div
style="margin-top: -0.69rem; margin-bottom: 0.88rem;"
>
</CropOptionsPanel>
</div>
<CropOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
:compact="true"
>
</CropOptionsPanel>
</div>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>STRETCH</span>
</div>
<div
style="margin-top: -0.69rem; margin-bottom: 0.88rem;"
>
<StretchOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
:compact="true"
></StretchOptionsPanel>
</div>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>ZOOM</span>
</div>
<div
style="margin-top: -0.69rem; margin-bottom: 0.88rem;"
>
<ZoomOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
:compact="true"
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>STRETCH</span>
</div>
<div
style="margin-top: -0.69rem; margin-bottom: 0.88rem;"
>
</ZoomOptionsPanel>
</div>
<StretchOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
:compact="true"
></StretchOptionsPanel>
</div>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>ALIGN</span>
</div>
<div
style="margin-bottom: 0.88rem;"
>
<AlignmentOptionsControlComponent
:eventBus="eventBus"
:large="true"
> </AlignmentOptionsControlComponent>
</div>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>ZOOM</span>
</div>
<div
style="margin-top: -0.69rem; margin-bottom: 0.88rem;"
>
<ZoomOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
:compact="true"
>
</ZoomOptionsPanel>
</div>
<div class="flex flex-row">
<mdicon name="crop" :size="16" />&nbsp;&nbsp;
<span>ALIGN</span>
</div>
<div
style="margin-bottom: 0.88rem;"
>
<AlignmentOptionsControlComponent
:eventBus="eventBus"
:large="true"
> </AlignmentOptionsControlComponent>
</div>
</template>
</div>

View File

@ -1,42 +1,109 @@
<template>
<div>
Custom zoom
<div class="flex flex-row" style="width: 250px;">
<div class="flex-grow">
Custom zoom
</div>
<div class="flex flex-row">
<Button
v-if="zoomAspectRatioLocked"
icon="lock"
:iconSize="16"
:fixedWidth="true"
:noPad="true"
@click="toggleZoomAr()"
>
</Button>
<Button
v-else
icon="lock-open-variant"
:iconSize="16"
:fixedWidth="true"
:noPad="true"
@click="toggleZoomAr()"
>
</Button>
<Button
icon="restore"
:iconSize="16"
:noPad="true"
@click="resetZoom()"
></Button>
</div>
</div>
<div class="top-label">Zoom:</div>
<div class="input range-input">
<input
type="range"
class="slider"
min="0"
max="3"
step="0.01"
/>
<input
/>
</div>
<template v-if="true">
<div class="top-label">Vertical zoom:</div>
<div class="input range-input">
<template v-if="zoomAspectRatioLocked">
<div class="input range-input no-bg">
<input
type="range"
class="slider"
min="0"
min="-1"
max="3"
step="0.01"
:value="zoom.x"
@input="changeZoom($event.target.value)"
/>
<input
class="disabled"
style="width: 2rem;"
:value="getZoomForDisplay('x')"
/>
</div>
</template>
<template v-else>
<div class="top-label">Horizontal zoom:</div>
<div class="input range-input no-bg">
<input
type="range"
class="slider"
min="-1"
max="3"
step="0.01"
:value="zoom.x"
@input="changeZoom($event.target.value, 'x')"
/>
<input
class="disabled"
style="width: 2rem;"
:value="getZoomForDisplay('x')"
/>
</div>
<div class="top-label">Vertical zoom:</div>
<div class="input range-input no-bg">
<input
type="range"
class="slider"
min="-1"
max="3"
step="0.01"
:value="zoom.y"
@input="changeZoom($event.target.value, 'y')"
/>
<input
class="disabled"
style="width: 2rem;"
:value="getZoomForDisplay('y')"
/>
</div>
</template>
<div><input type="checkbox"/> Control vertical and horizontal zoom independently.</div>
</template>
<script>
import Button from '@csui/src/components/Button.vue';
import * as _ from 'lodash';
export default {
components: {
Button,
},
mixins: [
],
props: [
'settings', // required for buttons and actions, which are global
'eventBus'
],
data() {
return {
zoomAspectRatioLocked: true,
@ -51,17 +118,42 @@ export default {
stretch: null,
zoom: null,
pan: null
}
},
pollingInterval: undefined,
debouncedGetEffectiveZoom: undefined,
}
},
mixins: [
],
props: [
'settings', // required for buttons and actions, which are global
'eventBus'
],
created() {
this.eventBus?.subscribeMulti(
{
'announce-zoom': {
function: (data) => {
this.zoom = {
x: Math.log2(data.x),
y: Math.log2(data.y)
};
}
}
},
this
);
this.debouncedGetEffectiveZoom = _.debounce(
() => {
this.getEffectiveZoom();
},
250
),
this.getEffectiveZoom();
this.pollingInterval = setInterval(this.debouncedGetEffectiveZoom, 2000);
},
destroyed() {
this.eventBus.unsubscribe(this);
clearInterval(this.pollingInterval);
},
methods: {
getEffectiveZoom() {
this.eventBus?.sendToTunnel('get-effective-zoom', {});
},
getZoomForDisplay(axis) {
// zoom is internally handled logarithmically, because we want to have x0.5, x1, x2, x4 ... magnifications
// spaced out at regular intervals. When displaying, we need to convert that to non-logarithmic values.
@ -81,25 +173,36 @@ export default {
// this.eventBus.send('set-zoom', {zoom: 1, axis: 'y'});
// this.eventBus.send('set-zoom', {zoom: 1, axis: 'x'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: 1, axis: 'y'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: 1, axis: 'x'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: 1});
},
changeZoom(newZoom, axis) {
// we store zoom logarithmically on this compnent
if (!axis) {
this.zoom.x = newZoom;
changeZoom(newZoom, axis, isLinear) {
if (isNaN(+newZoom)) {
return;
}
let logZoom, linZoom;
if (isLinear) {
newZoom /= 100;
logZoom = Math.log2(newZoom);
linZoom = newZoom;
} else {
this.zoom[axis] = newZoom;
logZoom = newZoom;
linZoom = Math.pow(2, newZoom);
}
// we store zoom logarithmically on this component
if (!axis) {
this.zoom.x = logZoom;
} else {
this.zoom[axis] = logZoom;
}
// we do not use logarithmic zoom elsewhere, therefore we need to convert
newZoom = Math.pow(2, newZoom);
if (this.zoomAspectRatioLocked) {
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: 'y'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: 'x'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: linZoom});
} else {
this.eventBus?.sendToTunnel('set-zoom', {zoom: newZoom, axis: axis ?? 'x'});
this.eventBus?.sendToTunnel('set-zoom', {zoom: {[axis ?? 'x']: linZoom}});
}
},
}

View File

@ -89,6 +89,12 @@ button, .button {
border-bottom: 1px solid rgba($primary, 0.5);
}
&.no-bg {
background-color: transparent;
border-color: transparent;
}
input {
width: 100%;
outline: none;

View File

@ -119,6 +119,9 @@ const ExtensionConfPatch = Object.freeze([
onKeyUp: true,
onKeyDown: false,
},
arguments: {
zoom: 1
},
internalOnly: true,
actionId: 'set-zoom-reset'
}, {

View File

@ -411,6 +411,9 @@ const ExtensionConf: SettingsInterface = {
onKeyUp: true,
onKeyDown: false,
},
arguments: {
zoom: 1,
},
internalOnly: true,
actionId: 'set-zoom-reset'
}, {

View File

@ -19,6 +19,10 @@ export interface EventBusContext {
frame?: any,
sourceFrame?: IframeData
forwardTo?: 'all' | 'active' | 'contentScript' | 'server' | 'sameOrigin' | 'popup' | 'all-frames',
};
borderCrossings?: {
commsServer?: boolean,
iframe?: boolean,
}
}
@ -29,6 +33,9 @@ export default class EventBus {
private disableTunnel: boolean = false;
private popupContext: any = {};
private iframeForwardingList: {iframe: any, fn: (action, payload, context?) => void}[] = [];
// private uiUri = window.location.href;
constructor(options?: {isUWServer?: boolean}) {
@ -83,6 +90,18 @@ export default class EventBus {
}
}
forwardToIframe(iframe: any, fn: (action: string, payload: any, context?: EventBusContext) => void) {
this.cancelIframeForwarding(iframe);
this.iframeForwardingList.push({iframe, fn});
}
cancelIframeForwarding(iframe: any) {
const existingForwarding = this.iframeForwardingList.findIndex((x: any) => x.iframe === iframe);
if (existingForwarding !== -1) {
this.iframeForwardingList.splice(existingForwarding, 1);
}
}
send(command: string, commandData: any, context?: EventBusContext) {
// execute commands we have subscriptions for
@ -94,8 +113,27 @@ export default class EventBus {
// preventing messages from flowing back to their original senders is
// CommsServer's job. EventBus does not have enough data for this decision.
if (this.comms) {
// We do, however, have enough data to prevent backflow of messages that
// crossed CommsServer once already.
if (this.comms && context?.origin !== CommsOrigin.Server && !context?.borderCrossings?.commsServer) {
this.comms.sendMessage({command, config: commandData, context}, context);
};
// call forwarding functions if they exist
if (!context?.borderCrossings?.iframe) {
for (const forwarding of this.iframeForwardingList) {
forwarding.fn(
command,
commandData,
{
...context,
borderCrossings: {
...context?.borderCrossings,
iframe: true
}
}
);
}
}
if (context?.stopPropagation) {

View File

@ -186,7 +186,9 @@ export class AardDebugUi {
<div style="flex-grow: 1">${this.generateMiniGraphBar(this.aard.timer.average)}</div>
</div>
<div style="display: flex; flex-direction: row">
<div style="width: 120px">Last chg.:</div><div style="flex-grow: 1">${this.generateMiniGraphBar(this.aard.timer.lastChange)}</div>
<div style="width: 120px">Last chg.:</div>
<div></div>
<div style="flex-grow: 1">${this.generateMiniGraphBar(this.aard.timer.lastChange)}</div>
</div>
`;

View File

@ -128,7 +128,7 @@ class CommsClient {
}
//#endregion
async sendMessage(message, context?: EventBusContext){
async sendMessage(message, context?: EventBusContext, borderCrossings?){
this.logger.info('sendMessage', ' <<< Sending message to background script:', message);
message = JSON.parse(JSON.stringify(message)); // vue quirk. We should really use vue store instead
@ -144,8 +144,11 @@ class CommsClient {
return port.postMessage(message);
}
}
// send to server
return chrome.runtime.sendMessage(null, message, null);
if (!context?.borderCrossings?.commsServer) {
return chrome.runtime.sendMessage(null, message, null);
}
}
/**
@ -170,7 +173,10 @@ class CommsClient {
message.config,
{
comms,
origin: CommsOrigin.Server
origin: CommsOrigin.Server,
borderCrossings: {
commsServer: true
}
}
);
}

View File

@ -52,9 +52,26 @@ class CommsServer {
} = {};
popupPort: any;
private _lastActiveTab: chrome.tabs.Tab | undefined;
//#region getters
get activeTab() {
return chrome.tabs.query({currentWindow: true, active: true});
get activeTab(): Promise<chrome.tabs.Tab | undefined> {
return new Promise((resolve, reject) => {
chrome.tabs
.query({currentWindow: true, active: true})
.then((tabs) => {
if (tabs.length === 0) {
this.logger.warn('<getter-activeTab>', 'no active tab found, returning last valid active tab instead ...', this._lastActiveTab);
resolve(this._lastActiveTab);
} else {
this.logger.log('<getter-activeTab>', 'getting active tab', tabs[0]);
this._lastActiveTab = tabs[0];
resolve(tabs[0]);
}
})
.catch((err) => {
this.logger.error('<getter-activeTab>', 'error while getting active tab — returned last valid active tab instead ...', err, this._lastActiveTab);
});
});
}
//#endregion
@ -110,6 +127,10 @@ class CommsServer {
// stop messages from returning where they came from, and prevent
// cross-pollination between content scripts running in different
// tabs.
if (!context) {
this.logger.debug('sendMessage', 'context was not passed in as parameter - does message have context?', message.context);
context = message.context;
}
if (context?.origin !== CommsOrigin.ContentScript) {
if (context?.comms.forwardTo === 'all') {
@ -236,13 +257,13 @@ class CommsServer {
private async sendToActive(message) {
this.logger.info('sendToActive', ` <——— trying to send a message ${message.command ?? ''} to active tab. Message:`, message);
const tabs = await this.activeTab;
const tab = await this.activeTab;
this.logger.info('sendToActive', "currently active tab(s)?", tabs);
this.logger.info('sendToActive', "currently active tab?", tab);
for (const frame in this.ports[tabs[0].id]) {
this.logger.info('sendToActive', "sending message to frame:", frame, this.ports[tabs[0].id][frame], '; message:', message);
this.sendToFrameContentScripts(message, tabs[0].id, frame);
for (const frame in this.ports[tab.id]) {
this.logger.info('sendToActive', "sending message to frame:", frame, this.ports[tab.id][frame], '; message:', message);
this.sendToFrameContentScripts(message, tab.id, frame);
}
}
@ -269,7 +290,7 @@ class CommsServer {
}
private processReceivedMessage_nonpersistent(message, sender){
this.logger.info('processMessage_nonpersistent', ` ==> Received message from background script!`, "background-color: #11D; color: #aad", message, sender);
this.logger.info('processMessage_nonpersistent', ` ==> Received message from background script!`, message, sender);
this.eventBus.send(
message.command,

View File

@ -22,12 +22,13 @@ export class ComponentLogger {
constructor(logAggregator: LogAggregator, component: string, componentOptions?: ComponentLoggerOptions) {
this.logAggregator = logAggregator;
this.component = component;
this.componentOptions = componentOptions;
}
private handleLog(logLevel: LogLevel, sourceFunction: string | LogSourceOptions, ...message: any) {
let functionSource = typeof sourceFunction === 'string' ? sourceFunction : sourceFunction?.src;
let consoleMessageString = `[${this.component}${functionSource ? `::${functionSource}` : ''}] `;
let consoleMessageString = `[${this.component}${functionSource ? `::${functionSource}` : ''}]`;
const consoleMessageData = []
for (const m of message) {
@ -35,10 +36,13 @@ export class ComponentLogger {
consoleMessageString = `${consoleMessageString} ${m}`;
} else if (typeof m === 'number') {
consoleMessageString = `${consoleMessageString} %f`;
} else if (m instanceof HTMLElement) {
consoleMessageData.unshift(m);
} else if (typeof HTMLElement !== 'undefined' && m instanceof HTMLElement) { // HTMLElement does not exist in background script, but this class may
consoleMessageString = `${consoleMessageString} %o`;
consoleMessageData.unshift(m);
} else {
consoleMessageString = `${consoleMessageString} %O`;
consoleMessageData.unshift(m);
}
}

View File

@ -4,11 +4,6 @@ export const BLANK_LOGGER_CONFIG: LogConfig = {
logToConsole: false,
logToFile: false,
component: {
aard: { enabled: false },
resizer: { enabled: false },
comms: { enabled: false },
settings: { enabled: false },
eventBus: { enabled: false },
},
origins: {
videoRescan: { disabled: true},
@ -36,6 +31,7 @@ export interface LogConfig {
}
}
const STORAGE_LOG_SETTINGS_KEY = 'uw-log-config';
export class LogAggregator {
private segment: string;
@ -46,29 +42,34 @@ export class LogAggregator {
history: any[];
static async getConfig() {
let ret = await chrome.storage.local.get('uw-log-config');
let ret = await chrome.storage.local.get(STORAGE_LOG_SETTINGS_KEY);
if (process.env.CHANNEL === 'dev') {
try {
console.info("[Logger::getSaved] Got settings:", JSON.parse(ret.uwLogger));
console.info("[LogAggregator::getSaved] Got settings:", JSON.parse(ret[STORAGE_LOG_SETTINGS_KEY]));
} catch (e) {
console.info("[Logger::getSaved] No settings.")
console.info("[LogAggregator::getSaved] No settings.", ret)
}
}
try {
return JSON.parse(ret['uw-log-config']);
return JSON.parse(ret[STORAGE_LOG_SETTINGS_KEY]);
} catch (e) {
return JSON.parse(JSON.stringify(BLANK_LOGGER_CONFIG));
}
}
static saveConfig(conf: LogConfig) {
if (process.env.CHANNEL === 'dev') {
console.info('Saving logger conf:', conf)
}
static async saveConfig(conf: LogConfig) {
try {
const confCp = JSON.parse(JSON.stringify(conf));
if (process.env.CHANNEL === 'dev') {
console.info('Saving logger conf:', confCp)
}
chrome.storage.local.set( {'uw-log-config': JSON.stringify(conf)});
await chrome.storage.local.set({[STORAGE_LOG_SETTINGS_KEY]: JSON.stringify(confCp)} );
} catch (e) {
console.warn('[LogAggregator::saveConfig] Error while trying to save logger config:', e);
}
}
static syncConfig(callback: (x) => void) {
@ -89,26 +90,35 @@ export class LogAggregator {
chrome.storage.onChanged.addListener((changes, area) => {
this.storageChangeListener(changes, area)
});
this.init();
}
private canLog(component: string, sourceOptions?: LogSourceOptions): boolean {
// component is not in config, so we add a blank entry
if (this.config && !this.config.component[component]) {
this.config.component[component] = {enabled: false};
LogAggregator.saveConfig(this.config);
return false;
}
if (this.config?.component?.[component]?.enabled) {
if (sourceOptions?.origin && this.config?.origins?.[sourceOptions.origin]?.disabled) {
return false;
}
return true;
}
return false;
}
private storageChangeListener(changes, area) {
if (!changes.uwLogger) {
console.info('We dont have any logging settings, not processing frther');
if (!changes[STORAGE_LOG_SETTINGS_KEY]) {
console.info('We dont have any logging settings, not processing frther', changes);
return;
}
try {
this.config = JSON.parse(changes['uw-log-config'].newValue);
this.config = JSON.parse(changes[STORAGE_LOG_SETTINGS_KEY].newValue);
} catch (e) {
console.warn('[uwLogger] Error while trying to parse new conf for logger:', e, '\nWe received the following changes:', changes, 'for area:', area);
}
@ -188,7 +198,11 @@ export class LogAggregator {
}
async init(config: LogConfig) {
async init(config?: LogConfig) {
if (!config) {
config = await LogAggregator.getConfig();
}
this.config = config;
this.startTime = performance.now();
@ -211,7 +225,7 @@ export class LogAggregator {
}
if (this.config.logToConsole) {
if (this.config.logToConsole){
console[logLevel](`[${this.segment}]>>${message}`, ...data, {stack: this.parseStack()});
}
}

View File

@ -205,10 +205,18 @@ class UI {
document.addEventListener('mousemove', fn, true);
}
this.eventBus.forwardToIframe(
this.uiIframe,
(action, payload) => {
this.sendToIframe(action, payload, {})
}
);
this.rootDiv.appendChild(iframe);
}
unloadIframe() {
this.eventBus.cancelIframeForwarding(this.uiIframe);
window.removeEventListener('message', this.messageHandlerFn);
this.uiIframe?.remove();
delete this.uiIframe;
@ -416,7 +424,17 @@ class UI {
break;
case 'uw-bus-tunnel':
const busCommand = event.data.payload;
this.eventBus.send(busCommand.action, busCommand.config, busCommand.routingData);
this.eventBus.send(
busCommand.action,
busCommand.config,
{
...busCommand?.context,
borderCrossings: {
...busCommand?.context?.borderCrossings,
iframe: true,
}
}
);
break;
case 'uwui-get-role':
this.sendToIframeLowLevel('uwui-set-role', {role: this.isGlobal ? 'global' : 'player'});

View File

@ -190,7 +190,7 @@ class PlayerData {
constructor(videoData) {
try {
// set all our helper objects
this.logger = new ComponentLogger(videoData.logAggregator, 'PlayerData', {styles: Debug.getLoggingStyles()});
this.logger = new ComponentLogger(videoData.logAggregator, 'PlayerData', {styles: {}});
this.videoData = videoData;
this.videoElement = videoData.video;
this.pageInfo = videoData.pageInfo;
@ -482,10 +482,17 @@ class PlayerData {
}
}
onPlayerDimensionsChanged(mutationList?, observer?) {
this.trackDimensionChanges();
this.trackEnvironmentChanges();
}
onPlayerDimensionsChanged: ResizeObserverCallback = _.debounce(
(mutationList?, observer?) => {
this.trackDimensionChanges();
this.trackEnvironmentChanges();
},
250, // do it once per this many ms
{
leading: true, // do it when we call this fallback first
trailing: true // do it after the timeout if we call this callback few more times
}
);
//#region player element change detection
@ -499,29 +506,19 @@ class PlayerData {
}
try {
this.observer = new ResizeObserver(
_.debounce( // don't do this too much:
(m,o) => {
this.onPlayerDimensionsChanged(m,o)
},
250, // do it once per this many ms
{
leading: true, // do it when we call this fallback first
trailing: true // do it after the timeout if we call this callback few more times
}
)
);
if (this.observer) {
this.observer.disconnect();
}
const observerConf = {
attributes: true,
// attributeFilter: ['style', 'class'],
attributeOldValue: true,
};
this.observer = new ResizeObserver(
this.onPlayerDimensionsChanged
);
this.observer.observe(this.element);
} catch (e) {
console.error("failed to set observer",e )
console.error("failed to set observer",e );
}
// legacy mode still exists, but acts as a fallback for observers and is triggered less
// frequently in order to avoid too many pointless checks
this.legacyChangeDetection();

View File

@ -63,6 +63,8 @@ class Resizer {
currentCssValidFor: any;
currentVideoSettings: any;
private effectiveZoom: {x: number, y: number} = {x: 1, y: 1};
_lastAr: Ar = {type: AspectRatioType.Initial};
set lastAr(x: Ar) {
// emit updates for UI when setting lastAr, but only if AR really changed
@ -88,6 +90,11 @@ class Resizer {
//#region event bus configuration
private eventBusCommands = {
'get-effective-zoom': [{
function: () => {
this.eventBus.send('announce-zoom', this.manualZoom ? {x: this.zoom.scale, y: this.zoom.scaleY} : this.zoom.effectiveZoom);
}
}],
'set-ar': [{
function: (config: any) => {
this.manualZoom = false; // this only gets called from UI or keyboard shortcuts, making this action safe.
@ -136,7 +143,9 @@ class Resizer {
}
}],
'set-zoom': [{
function: (config: any) => this.setZoom(config.zoom)
function: (config: any) => {
this.setZoom(config?.zoom ?? {zoom: 1});
}
}],
'change-zoom': [{
function: (config: any) => this.zoomStep(config.zoom)
@ -449,12 +458,12 @@ class Resizer {
}
applyScaling(stretchFactors: VideoDimensions, options?: {noAnnounce?: boolean, ar?: Ar}) {
// this.stretcher.chromeBugMitigation(stretchFactors);
this.zoom.effectiveZoom = {x: stretchFactors.xFactor, y: stretchFactors.yFactor};
// let the UI know
if(!options?.noAnnounce) {
this.videoData.eventBus.send('announce-zoom', {x: stretchFactors.xFactor, y: stretchFactors.yFactor});
}
// announcing zoom somehow keeps incorrectly resetting zoom sliders in UI — UI is now polling for effective zoom while visible
// if(!options?.noAnnounce) {
// this.videoData.eventBus.send('announce-zoom', this.manualZoom ? {x: this.zoom.scale, y: this.zoom.scaleY} : this.zoom.effectiveZoom);
// }
let translate = this.computeOffsets(stretchFactors, options?.ar);
this.applyCss(stretchFactors, translate);

View File

@ -30,6 +30,7 @@ class Zoom {
maxScale = 8;
//#endregion
effectiveZoom: {x: number, y: number}; // we're setting this in Resizer based on Resizer data!
constructor(videoData) {
this.conf = videoData;
@ -50,7 +51,12 @@ class Zoom {
* @param axis leave undefined to apply zoom to both axes
*/
zoomStep(amount: number, axis?: 'x' | 'y') {
let newLog = axis === 'y' ? this.logScaleY : this.logScale;
const effectiveLog = {
x: Math.log2(this.effectiveZoom.x),
y: Math.log2(this.effectiveZoom.y)
};
let newLog = axis === 'y' ? effectiveLog.y : effectiveLog.x;
newLog += amount;
newLog = Math.min(Math.max(newLog, LOG_MIN_SCALE), LOG_MAX_SCALE);
@ -65,7 +71,6 @@ class Zoom {
this.scale = Math.pow(2, this.logScale);
this.scaleY = Math.pow(2, this.logScaleY);
this.logger.info('zoomStep', "changing zoom by", amount, ". New zoom level:", this.scale);
this.processZoom();
}
@ -94,18 +99,6 @@ class Zoom {
this.conf.resizer.toFixedAr();
this.conf.resizer.applyScaling({xFactor: this.scale, yFactor: this.scaleY}, {noAnnounce: true});
}
applyZoom(stretchFactors){
if (!stretchFactors) {
return;
}
this.logger.info('setZoom', "Applying zoom. Stretch factors pre:", stretchFactors, " —> scale:", this.scale);
stretchFactors.xFactor *= this.scale;
stretchFactors.yFactor *= this.scale;
this.logger.info('setZoom', "Applying zoom. Stretch factors post:", stretchFactors);
}
}
export default Zoom;

View File

@ -85,11 +85,8 @@ export default {
async created() {
this.logAggregator = new LogAggregator('');
this.logger = new ComponentLogger(this.logAggregator, 'App.vue');
await this.logger.init({
allowLogging: true,
});
this.settings = new Settings({updateCallback: () => this.updateConfig(), logger: this.logger});
this.settings = new Settings({updateCallback: () => this.updateConfig(), logAggregator: this.logAggregator });
await this.settings.init();
this.settingsInitialized = true;
},

View File

@ -87,11 +87,7 @@ export default {
this.logAggregator = new LogAggregator('');
this.logger = new ComponentLogger(this.logAggregator, 'App.vue');
await this.logger.init({
allowLogging: true,
});
this.settings = new Settings({updateCallback: () => this.updateConfig(), logger: this.logger});
this.settings = new Settings({updateCallback: () => this.updateConfig(), logAggregator: this.logAggregator});
await this.settings.init();
this.settingsInitialized = true;
},

View File

@ -111,10 +111,6 @@
<script>
import Donate from '../common/misc/Donate.vue';
import SuperAdvancedSettings from './SuperAdvancedSettings.vue';
import Debug from '../ext/conf/Debug';
import BrowserDetect from '../ext/conf/BrowserDetect';
import ExtensionConf from '../ext/conf/ExtensionConf';
import ObjectCopy from '../ext/lib/ObjectCopy';
import Settings from '../ext/lib/Settings';
import GeneralSettings from './GeneralSettings';
import ControlsSettings from './controls-settings/ControlsSettings';
@ -122,7 +118,6 @@ import AddEditActionPopup from './controls-settings/AddEditActionPopup';
import ConfirmPopup from './common/ConfirmationPopup';
import About from './about'
import AutodetectionSettings from './AutodetectionSettings';
// import SuperAdvancedSettings from './'
import { LogAggregator } from '@src/ext/lib/logging/LogAggregator';
import { ComponentLogger } from '@src/ext/lib/logging/ComponentLogger';
@ -149,11 +144,8 @@ export default {
async created () {
this.logAggregator = new LogAggregator('');
this.logger = new ComponentLogger(this.logAggregator, 'App.vue');
await this.logger.init({
allowLogging: true,
});
this.settings = new Settings({updateCallback: this.updateSettings, logger: this.logger});
this.settings = new Settings({updateCallback: this.updateSettings, logAggregator: this.logAggregator});
await this.settings.init();
this.settingsInitialized = true;