Add options for controlling how aard runs in small players and background tabs + allow auto-disabling aard after first detection

This commit is contained in:
Tamius Han 2025-10-08 19:35:12 +02:00
parent 4276a9f03a
commit accc320971
12 changed files with 239 additions and 268 deletions

View File

@ -1,4 +1,5 @@
import { Action } from '../../../node_modules/vuex/types/index' import { Action } from '../../../node_modules/vuex/types/index'
import { AardPollingOptions } from '../../ext/lib/aard/enums/aard-polling-options.enum'
import AntiGradientMode from '../enums/AntiGradientMode.enum' import AntiGradientMode from '../enums/AntiGradientMode.enum'
import AspectRatioType from '../enums/AspectRatioType.enum' import AspectRatioType from '../enums/AspectRatioType.enum'
import CropModePersistence from '../enums/CropModePersistence.enum' import CropModePersistence from '../enums/CropModePersistence.enum'
@ -74,6 +75,10 @@ export interface AardSettings {
stopTimeout: number; stopTimeout: number;
}, },
polling: {
runInBackgroundTabs: AardPollingOptions;
runOnSmallVideos: AardPollingOptions;
}
disabledReason: string, // if automatic aspect ratio has been disabled, show reason disabledReason: string, // if automatic aspect ratio has been disabled, show reason
allowedMisaligned: number, // top and bottom letterbox thickness can differ by this much. allowedMisaligned: number, // top and bottom letterbox thickness can differ by this much.
@ -87,13 +92,17 @@ export interface AardSettings {
minimumTimeout: number, minimumTimeout: number,
tickrate: number, // 1 tick every this many milliseconds tickrate: number, // 1 tick every this many milliseconds
}, },
autoDisable: { // settings for automatically disabling the extension
maxExecutionTime: number, // if execution time of main autodetect loop exceeds this many milliseconds,
// we disable it.
consecutiveTimeoutCount: number, // we only do it if it happens this many consecutive times
// FOR FUTURE USE subtitles: {
consecutiveArResets: number // if aspect ratio reverts immediately after AR change is applied, we disable everything resetIfDetected?: boolean, // reset if subtitles are detected
resumeAfter?: number, // resume after X ms of no subtitles
},
autoDisable: { // settings for automatically disabling the extension
onFirstChange: boolean,
ifNotChanged: boolean,
ifNotChangedTimeout: number,
ifSubtitles: boolean;
}, },
canvasDimensions: { canvasDimensions: {
blackframeCanvas: { // smaller than sample canvas, blackframe canvas is used to recon for black frames blackframeCanvas: { // smaller than sample canvas, blackframe canvas is used to recon for black frames

View File

@ -463,7 +463,7 @@ export default {
if (!this.site) { if (!this.site) {
this.origin = event.origin; this.origin = event.origin;
this.site = event.origin.split('//')[1]; this.site = event.origin.split('//')[1];
this.siteSettings = this.settings.getSiteSettings({site: this.site}); this.siteSettings = this.settings.getSiteSettings({site: this.site, isIframe: event.data.isIframe});
} }
return this.handleProbe(event.data, event.origin); // handleProbe is defined in UIProbeMixin return this.handleProbe(event.data, event.origin); // handleProbe is defined in UIProbeMixin
case 'uw-bus-tunnel': case 'uw-bus-tunnel':

View File

@ -9,217 +9,7 @@
</div> </div>
<div class="aard-settings-group"> <div class="aard-settings-group">
<!-- the last time i tried to comment out this block, it didn't work properly v-if="false" it is -->
<div v-if="false">
<p>
<b>Autodetection performance</b>
</p>
<p>
Automatic aspect ratio detection is a resource-hungry feature.
This page allows you to trade autodetection accuracy and/or frequency for
better performance.
</p>
<p>
Note that some browsers <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/now" target="_blank">limit the accuracy of time measurements</a>, though once the bars go past the blue line those limitations are largely inconsequential.
</p>
<div class="performance-graph-container">
<div class="performance-graph">
<div class="time-budget hz144"></div>
<div class="time-budget hz120"></div>
<div class="time-budget hz60"></div>
<div class="time-budget hz30"></div>
<div class="time-budget hz24"></div>
<div class="time-budget rest"></div>
<div class="bar-container">
<div class="average-case">
<div class="stats">
<b>Average: </b>
<span class="draw">draw (main) {{(performanceData?.imageDraw?.averageTime ?? 0).toFixed(1)}} ms</span> |
<span class="draw-blackframe">blackframe {{(performanceData?.blackFrame?.averageTime ?? 0).toFixed(1)}} ms</span> |
<span class="processing">
processing {{
Math.max(
(performanceData?.total?.averageTime ?? 0)
- (performanceData?.imageDraw?.averageTime ?? 0)
- (performanceData?.blackFrame?.averageTime ?? 0),
0
).toFixed(1)
}} ms
</span>
</div>
<div class="bar">
<div
class="draw"
:style="{'width': (performanceData?.imageDraw?.averageTime ?? 0) + '%'}"
>
</div>
<div
class="draw-blackframe"
:style="{'width': (performanceData?.blackFrame?.averageTime ?? 0) + '%'}"
>
</div>
<div
class="processing"
:style="{
'width': Math.max(
(performanceData?.total?.averageTime ?? 0)
- (performanceData?.imageDraw?.averageTime ?? 0)
- (performanceData?.blackFrame?.averageTime ?? 0),
0
) + '%'
}"
>
</div>
</div>
</div>
<div class="worst-case">
<div class="stats">
<b>Worst: </b>
<span class="draw">draw (main) {{(performanceData?.imageDraw?.worstTime ?? 0).toFixed(1)}} ms</span> |
<span class="draw-blackframe">blackframe {{(performanceData?.blackFrame?.worstTime ?? 0).toFixed(1)}} ms</span> |
<span class="processing">
processing {{
Math.max(
(performanceData?.total?.worstTime ?? 0)
- (performanceData?.imageDraw?.worstTime ?? 0)
- (performanceData?.blackFrame?.worstTime ?? 0),
0
).toFixed(1)
}} ms
</span>
</div>
<div class="bar">
<div
class="draw"
:style="{'width': (performanceData?.imageDraw?.worstTime ?? 0) + '%'}"
>
</div>
<div
class="draw-blackframe"
:style="{'width': (performanceData?.blackFrame?.worstTime ?? 0) + '%'}"
>
</div>
<div
class="processing"
:style="{
'width': Math.max(
(performanceData?.total?.worstTime ?? 0)
- (performanceData?.imageDraw?.worstTime ?? 0)
- (performanceData?.blackFrame?.worstTime ?? 0),
0
) + '%'
}"
>
</div>
</div>
</div>
<div class="average-case">
<div class="stats">
<b>AR change (average): </b>
<span class="draw">draw (main) {{(performanceData?.imageDraw?.averageTime ?? 0).toFixed(1)}} ms</span> |
<span class="draw-blackframe">blackframe {{(performanceData?.blackFrame?.averageTime ?? 0).toFixed(1)}} ms</span> |
<span class="processing">processing {{
(
(performanceData?.fastLetterbox?.averageTime ?? 0)
+ (performanceData?.edgeDetect?.averageTime ?? 0)
).toFixed(1)
}} ms</span>
</div>
<div class="bar">
<div
class="draw"
:style="{'width': (performanceData?.imageDraw?.averageTime ?? 0) + '%'}"
>
</div>
<div
class="draw-blackframe"
:style="{'width': (performanceData?.blackFrame?.averageTime ?? 0) + '%'}"
>
</div>
<div
class="processing"
:style="{
'width': (
(performanceData?.fastLetterbox?.averageTime ?? 0)
+ (performanceData?.edgeDetect?.averageTime ?? 0)
) + '%'
}"
>
</div>
</div>
</div>
<div class="worst-case">
<div class="stats">
<b>AR change (worst): </b>
<span class="draw">draw (main) {{(performanceData?.imageDraw?.worstTime ?? 0).toFixed(1)}} ms</span> |
<span class="draw-blackframe">blackframe {{(performanceData?.blackFrame?.worstTime ?? 0).toFixed(1)}} ms</span> |
<span class="processing">processing {{
(
(performanceData?.fastLetterbox?.worstTime ?? 0)
+ (performanceData?.edgeDetect?.worstTime ?? 0)
).toFixed(1)
}} ms</span>
</div>
<div class="bar">
<div
class="draw"
:style="{'width': (performanceData?.imageDraw?.worstTime ?? 0) + '%'}"
>
</div>
<div
class="draw-blackframe"
:style="{'width': (performanceData?.blackFrame?.worstTime ?? 0) + '%'}"
>
</div>
<div
class="processing"
:style="{
'width': (
(performanceData?.fastLetterbox?.worstTime ?? 0)
+ (performanceData?.edgeDetect?.worstTime ?? 0)
) + '%'
}"
>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="settings-segment"> <div class="settings-segment">
<!-- <h2>Basic settings</h2> -->
<!-- <div class="field">
<div class="label">
Stop autodetection after first detection:
</div>
<div class="">
<input type="checkbox" v-model="settings.active.arDetect.earlyStopOptions.stopAfterFirstDetection" />
</div>
</div>
<div class="field">
<div class="label">
Stop detection after a period of time:
</div>
<div class="">
<input type="checkbox" v-model="settings.active.arDetect.earlyStopOptions.stopAfterTimeout" />
</div>
</div>
<div class="field">
<div class="label">
Stop detection after:
</div>
<div class="input">
<input type="input" v-model="settings.active.arDetect.earlyStopOptions.stopTimeout" />
<div class="unit">seconds</div>
</div>
</div> -->
<div class="field"> <div class="field">
<div class="label">Autodetection frequency (time between samples)</div> <div class="label">Autodetection frequency (time between samples)</div>
@ -243,7 +33,97 @@
</div> </div>
<div class="field"> <div class="field">
<div class="label">Frame extraction canvas type:</div> <div class="label">Reduced autodetection frequency</div>
<div class="range-input">
<input
type="range"
:value="Math.log(settings.active.arDetect.timers.playingReduced)"
@change="setArCheckFrequency($event.target.value, 'playingReduced')"
min="2.3"
max="9.3"
step="0.01"
/>
<input
v-model="settings.active.arDetect.timers.playingReduced"
@change="setArCheckFrequency($event.target.value, 'playingReduced')"
class="input"
type="text"
>
<div class="unit">ms</div>
</div>
</div>
<div class="field">
<div class="label">Poll for aspect ratio changes in background tabs:</div>
<div class="select">
<select v-model="settings.active.arDetect.polling.runInBackgroundTabs" @change="settings.saveWithoutReload">
<option :value="AardPollingOptions.No">Never</option>
<option :value="AardPollingOptions.Reduced">Use reduced polling rate</option>
<option :value="AardPollingOptions.Full">Use normal polling rate</option>
</select>
</div>
</div>
<div v-if="settings.active.arDetect.polling.runInBackgroundTabs === AardPollingOptions.Full" class="hint warn">
Using normal polling rate in background tabs is NOT recommended.
</div>
<div class="field">
<div class="label">Poll for aspect ratio changes in small players:</div>
<div class="select">
<select v-model="settings.active.arDetect.polling.runOnSmallVideos" @change="settings.saveWithoutReload">
<option :value="AardPollingOptions.No">Never</option>
<option :value="AardPollingOptions.Reduced">Use reduced polling rate</option>
<option :value="AardPollingOptions.Full">Use normal polling rate</option>
</select>
</div>
</div>
<div v-if="settings.active.arDetect.polling.runOnSmallVideos === AardPollingOptions.Full" class="hint warn">
Using normal polling rate on small videos is NOT recommended.
</div>
<div class="field">
<div class="label">Stop autodetection after first detection:</div>
<div class="select">
<select v-model="settings.active.arDetect.autoDisable.onFirstChange" @change="settings.saveWithoutReload">
<option :value="true">Yes</option>
<option :value="false">No</option>
</select>
</div>
</div>
<div class="field" :class="{disabled: settings.active.arDetect.autoDisable.onFirstChange}">
<div class="label">Stop autodetection if aspect ratio doesn't change for some time:</div>
<div class="select">
<select v-model="settings.active.arDetect.autoDisable.ifNotChanged" @change="settings.saveWithoutReload">
<option :value="true">Yes</option>
<option :value="false">No</option>
</select>
</div>
</div>
<div v-if="settings.active.arDetect.autoDisable.ifNotChanged" class="field">
<div class="label">Stop autodetection if aspect ratio doesn't change for:</div>
<div class="range-input">
<input
type="range"
:value="Math.log(settings.active.arDetect.autoDisable.ifNotChangedTimeout / 10)"
@change="setAutoDisableTimeout($event.target.value, 10)"
min="2.3"
max="9.3"
step="0.01"
/>
<input
:value="settings.active.arDetect.autoDisable.ifNotChangedTimeout / 1000"
@change="setAutoDisableTimeout($event.target.value, 1000)"
class="input"
type="text"
>
<div class="unit">s</div>
</div>
</div>
<div class="field">
<div class="label">Autodetection canvas type:</div>
<div class="select"> <div class="select">
<select v-model="settings.active.arDetect.aardType" @change="settings.saveWithoutReload"> <select v-model="settings.active.arDetect.aardType" @change="settings.saveWithoutReload">
<option value="auto">Automatic</option> <option value="auto">Automatic</option>
@ -258,11 +138,11 @@
<div class="input"> <div class="input">
<input v-model="settings.active.arDetect.allowedMisaligned" /> <input v-model="settings.active.arDetect.allowedMisaligned" />
</div> </div>
<div class="hint"> </div>
Ultrawidify detects letterbox only if video is vertically centered. Some people are bad at vertically <div class="hint">
centering the content, though. This is how off-center the video can be before autodetection will Ultrawidify detects letterbox only if video is vertically centered. Some people are bad at vertically
refuse to crop it (% of total height). centering the content, though. This is how off-center the video can be before autodetection will
</div> refuse to crop it (% of total height).
</div> </div>
</div> </div>
@ -310,6 +190,7 @@ import StretchType from '../../../common/enums/StretchType.enum';
import CropModePersistence from '../../../common/enums/CropModePersistence.enum'; import CropModePersistence from '../../../common/enums/CropModePersistence.enum';
import AlignmentOptionsControlComponent from './AlignmentOptionsControlComponent.vue'; import AlignmentOptionsControlComponent from './AlignmentOptionsControlComponent.vue';
import JsonEditor from '@csui/src/components/JsonEditor'; import JsonEditor from '@csui/src/components/JsonEditor';
import {AardPollingOptions} from '@src/ext/lib/aard/enums/aard-polling-options.enum';
export default { export default {
components: { components: {
@ -333,6 +214,9 @@ export default {
performanceData: {}, performanceData: {},
graphRefreshInterval: undefined, graphRefreshInterval: undefined,
settingsJson: {}, settingsJson: {},
// enums n stuff
AardPollingOptions,
} }
}, },
computed: { computed: {
@ -348,7 +232,7 @@ export default {
}, },
mounted() { mounted() {
this.eventBus.sendToTunnel('get-aard-timing'); this.eventBus.sendToTunnel('get-aard-timing');
this.graphRefreshInterval = setInterval(() => this.eventBus.sendToTunnel('get-aard-timing'), 500); // this.graphRefreshInterval = setInterval(() => this.eventBus.sendToTunnel('get-aard-timing'), 500);
this.resetSettingsEditor(); this.resetSettingsEditor();
}, },
destroyed() { destroyed() {
@ -359,8 +243,13 @@ export default {
async openOptionsPage() { async openOptionsPage() {
BrowserDetect.runtime.openOptionsPage(); BrowserDetect.runtime.openOptionsPage();
}, },
setArCheckFrequency(event) { setArCheckFrequency(event, timer) {
this.settings.active.arDetect.timers.playing = Math.floor(Math.pow(Math.E, event)); this.settings.active.arDetect.timers[timer ?? 'playing'] = Math.floor(Math.pow(Math.E, event));
this.settings.saveWithoutReload();
},
setAutoDisableTimeout(event, multiplier) {
this.settings.active.arDetect.autoDisable.ifNotChangedTimeout = Math.floor(Math.pow(Math.E, event)) * multiplier;
this.settings.saveWithoutReload();
}, },
refreshGraph() { refreshGraph() {
this.eventBus.sendToTunnel('get-aard-timing'); this.eventBus.sendToTunnel('get-aard-timing');

View File

@ -425,7 +425,6 @@ export default {
break; break;
} }
// console.log('getting data from:', settingsData);
try { try {
if ( if (
@ -594,8 +593,6 @@ export default {
setExtensionMode(component, event) { setExtensionMode(component, event) {
const option = event.target.value; const option = event.target.value;
console.log('SET EXTENSION MODE — OPTIONS:', option);
if (option === 'complex') { if (option === 'complex') {
return; return;
} }

View File

@ -9,18 +9,21 @@
<div class="info"> <div class="info">
Extension is not enabled for this site. Extension is not enabled for this site.
</div> </div>
<div> <div class="text-center">
Please enable extension for this site. <p>Please enable extension for this site.</p>
</div> </div>
<div> <div>
<button <button
class="flex flex-row items-center" class="flex flex-row items-center"
style="background-color: transparent; padding: 0.25rem 0.5rem; margin-top: 1rem;" style="background-color: transparent; padding: 0.5rem 1rem; margin-top: 1rem; border: 1px solid #fa68;"
@click="openSettings()" @click="openSettings()"
> >
Open settings <mdicon style="margin-left: 0.5rem;" name="open-in-new" size="16"></mdicon> Open settings <mdicon style="margin-left: 0.5rem;" name="open-in-new" size="16"></mdicon>
</button> </button>
</div> </div>
<div class="text-center">
<p><small>Extension may work on content embedded from other sites.</small></p>
</div>
</div> </div>
</template> </template>

View File

@ -251,7 +251,16 @@ const ExtensionConfPatch = Object.freeze([
} }
} }
} }
},
{
forVersion: '6.3.93',
updateFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface) => {
userOptions.arDetect.polling = defaultOptions.arDetect.polling;
userOptions.arDetect.subtitles = defaultOptions.arDetect.subtitles;
userOptions.arDetect.autoDisable = defaultOptions.arDetect.autoDisable;
}
} }
]); ]);

View File

@ -10,6 +10,7 @@ import SettingsInterface from '../../common/interfaces/SettingsInterface';
import BrowserDetect from './BrowserDetect'; import BrowserDetect from './BrowserDetect';
import { Extension } from 'typescript'; import { Extension } from 'typescript';
import EmbeddedContentSettingsOverridePolicy from '../../common/enums/EmbeddedContentSettingsOverridePolicy.enum'; import EmbeddedContentSettingsOverridePolicy from '../../common/enums/EmbeddedContentSettingsOverridePolicy.enum';
import { AardPollingOptions } from '../lib/aard/enums/aard-polling-options.enum';
if(Debug.debug) if(Debug.debug)
console.log("Loading: ExtensionConf.js"); console.log("Loading: ExtensionConf.js");
@ -22,6 +23,16 @@ const ExtensionConf: SettingsInterface = {
arDetect: { arDetect: {
aardType: 'auto', aardType: 'auto',
polling: {
runInBackgroundTabs: AardPollingOptions.Reduced,
runOnSmallVideos: AardPollingOptions.Reduced
},
subtitles: {
resetIfDetected: true,
resumeAfter: 5000,
},
earlyStopOptions: { earlyStopOptions: {
stopAfterFirstDetection: false, stopAfterFirstDetection: false,
stopAfterTimeout: false, stopAfterTimeout: false,
@ -41,12 +52,10 @@ const ExtensionConf: SettingsInterface = {
tickrate: 10, // 1 tick every this many milliseconds tickrate: 10, // 1 tick every this many milliseconds
}, },
autoDisable: { // settings for automatically disabling the extension autoDisable: { // settings for automatically disabling the extension
maxExecutionTime: 6000, // if execution time of main autodetect loop exceeds this many milliseconds, onFirstChange: false, // disable once we have a stable aspect ratio
// we disable it. ifNotChanged: false, // disable if Ar hasn't changed for this long
consecutiveTimeoutCount: 5, // we only do it if it happens this many consecutive times ifNotChangedTimeout: 20000, // if user enables ifNotChangedTimeout, we default to 20s
ifSubtitles: false, // disable if subtitles are detected
// FOR FUTURE USE
consecutiveArResets: 5 // if aspect ratio reverts immediately after AR change is applied, we disable everything
}, },
canvasDimensions: { canvasDimensions: {
blackframeCanvas: { // smaller than sample canvas, blackframe canvas is used to recon for black frames blackframeCanvas: { // smaller than sample canvas, blackframe canvas is used to recon for black frames

View File

@ -19,6 +19,7 @@ import { AardStatus, initAardStatus } from './interfaces/aard-status.interface';
import { AardTestResults, initAardTestResults, resetAardTestResults, resetGuardLine } from './interfaces/aard-test-results.interface'; import { AardTestResults, initAardTestResults, resetAardTestResults, resetGuardLine } from './interfaces/aard-test-results.interface';
import { AardTimers, initAardTimers } from './interfaces/aard-timers.interface'; import { AardTimers, initAardTimers } from './interfaces/aard-timers.interface';
import { ComponentLogger } from '../logging/ComponentLogger'; import { ComponentLogger } from '../logging/ComponentLogger';
import { AardPollingOptions } from './enums/aard-polling-options.enum';
/** /**
@ -232,7 +233,7 @@ export class Aard {
private eventBusCommands = { private eventBusCommands = {
'uw-environment-change': { 'uw-environment-change': {
function: (newEnvironment: ExtensionEnvironment) => { function: (newEnvironment: ExtensionEnvironment) => {
console.log('received extension environment:', newEnvironment, 'player env:', this.videoData?.player?.environment); // console.log('received extension environment:', newEnvironment, 'player env:', this.videoData?.player?.environment);
this.startCheck(); this.startCheck();
} }
}, },
@ -244,6 +245,11 @@ export class Aard {
this.hideDebugCanvas(); this.hideDebugCanvas();
} }
} }
},
'url-changed': {
function: () => {
this.clearAutoDisabled();
}
} }
// 'get-aard-timing': { // 'get-aard-timing': {
// function: () => this.handlePerformanceDataRequest() // function: () => this.handlePerformanceDataRequest()
@ -430,10 +436,19 @@ export class Aard {
} }
} }
/**
* Clears autoDisable flag
*/
clearAutoDisabled() {
this.status.autoDisabled = false;
this.timers.autoDisableAt = undefined;
}
/** /**
* Starts autodetection loop. * Starts autodetection loop.
*/ */
start() { start() {
this.clearAutoDisabled();
this.forceFullRecheck = true; this.forceFullRecheck = true;
if (this.videoData.resizer.lastAr.type === AspectRatioType.AutomaticUpdate) { if (this.videoData.resizer.lastAr.type === AspectRatioType.AutomaticUpdate) {
// ensure first autodetection will run in any case // ensure first autodetection will run in any case
@ -450,6 +465,11 @@ export class Aard {
this.status.aardActive = true; this.status.aardActive = true;
this.animationFrame = window.requestAnimationFrame( (ts: DOMHighResTimeStamp) => this.onAnimationFrame(ts)); this.animationFrame = window.requestAnimationFrame( (ts: DOMHighResTimeStamp) => this.onAnimationFrame(ts));
// set auto-disable timer if detection timeout is set
if (this.settings.active.arDetect.autoDisable.ifNotChanged) {
this.timers.autoDisableAt = Date.now() + this.settings.active.arDetect.autoDisable.ifNotChangedTimeout;
}
} }
/** /**
@ -482,24 +502,42 @@ export class Aard {
* @returns * @returns
*/ */
private canTriggerFrameCheck() { private canTriggerFrameCheck() {
// if (this._paused || this._halted || this._exited) {
// return false; // console.log('ard check status:', this.status);
// }
// if video was paused & we know that we already checked that frame, // if video was paused & we know that we already checked that frame,
// we will not check it again. // we will not check it again.
const videoState = this.getVideoPlaybackState(); const videoState = this.getVideoPlaybackState();
const polling = this.settings.active.arDetect.polling;
const now = Date.now();
if (videoState !== VideoPlaybackState.Playing) { if (videoState !== VideoPlaybackState.Playing) {
if (this.status.lastVideoStatus === videoState) { if (this.status.lastVideoStatus === videoState) {
return false; return false;
} }
} }
if (this.status.autoDisabled) {
return false;
}
if (this.timers.autoDisableAt < now) {
this.status.autoDisabled = true;
return false;
}
this.status.lastVideoStatus = videoState; this.status.lastVideoStatus = videoState;
const now = Date.now(); const tabVisible = document.visibilityState === 'visible';
if (!tabVisible && polling.runInBackgroundTabs === AardPollingOptions.No) {
return false;
}
if (this.videoData.player.isTooSmall && polling.runOnSmallVideos === AardPollingOptions.No) {
return false;
}
if (now < (this.videoData.player.isTooSmall ? this.timers.reducedPollingNextCheckTime : this.timers.nextFrameCheckTime)) { const isActive = (tabVisible || polling.runInBackgroundTabs !== AardPollingOptions.Reduced)
&& (!this.videoData.player.isTooSmall || polling.runOnSmallVideos !== AardPollingOptions.Reduced);
const nextCheck = isActive ? this.timers.nextFrameCheckTime : this.timers.reducedPollingNextCheckTime;
if (now < nextCheck) {
return false; return false;
} }
@ -508,6 +546,12 @@ export class Aard {
return true; return true;
} }
/**
* Bootstraps the main loop.
*
* Honestly this doesn't need description, but I want to put some green
* between two adjacent functions.
*/
private onAnimationFrame(ts: DOMHighResTimeStamp) { private onAnimationFrame(ts: DOMHighResTimeStamp) {
if (this.canTriggerFrameCheck()) { if (this.canTriggerFrameCheck()) {
resetAardTestResults(this.testResults); resetAardTestResults(this.testResults);
@ -671,7 +715,7 @@ export class Aard {
// console.warn('ASPECT RATIO UNCERTAIN, GUARD LINE INVALIDATED (resetting)') // console.warn('ASPECT RATIO UNCERTAIN, GUARD LINE INVALIDATED (resetting)')
this.timer.arChanged(); this.timer.arChanged();
this.updateAspectRatio(this.defaultAr); this.updateAspectRatio(this.defaultAr, {uncertainDetection: true});
break; break;
} }
@ -2027,14 +2071,12 @@ export class Aard {
/** /**
* Updates aspect ratio if new aspect ratio is different enough from the old one * Updates aspect ratio if new aspect ratio is different enough from the old one
*/ */
private updateAspectRatio(overrideAr?: number) { private updateAspectRatio(ar: number, options?: {uncertainDetection?: boolean}) {
const ar = overrideAr ?? this.getAr();
// Calculate difference between two ratios // Calculate difference between two ratios
const maxRatio = Math.max(ar, this.testResults.activeAspectRatio); const maxRatio = Math.max(ar, this.testResults.activeAspectRatio);
const diff = Math.abs(ar - this.testResults.activeAspectRatio); const diff = Math.abs(ar - this.testResults.activeAspectRatio);
if (overrideAr || (diff / maxRatio) > this.settings.active.arDetect.allowedArVariance) { if ((diff / maxRatio) > this.settings.active.arDetect.allowedArVariance) {
this.videoData.resizer.updateAr({ this.videoData.resizer.updateAr({
type: AspectRatioType.AutomaticUpdate, type: AspectRatioType.AutomaticUpdate,
ratio: this.getAr(), ratio: this.getAr(),
@ -2042,6 +2084,16 @@ export class Aard {
variant: this.arVariant variant: this.arVariant
}); });
this.testResults.activeAspectRatio = ar; this.testResults.activeAspectRatio = ar;
if (!options?.uncertainDetection) {
if (this.settings.active.arDetect.autoDisable.onFirstChange) {
this.status.autoDisabled = true;
}
if (this.settings.active.arDetect.autoDisable.ifNotChanged) {
this.timers.autoDisableAt = Date.now() + this.settings.active.arDetect.autoDisable.ifNotChangedTimeout;
}
}
} }
} }

View File

@ -0,0 +1,5 @@
export enum AardPollingOptions {
No = 0,
Reduced = 1,
Full = 2
}

View File

@ -5,7 +5,7 @@ export interface AardStatus {
aardReducedPolling: boolean, aardReducedPolling: boolean,
checkInProgress: boolean, checkInProgress: boolean,
lastVideoStatus: VideoPlaybackState, lastVideoStatus: VideoPlaybackState,
autoDisabled: boolean,
} }
export function initAardStatus(): AardStatus { export function initAardStatus(): AardStatus {
@ -14,5 +14,6 @@ export function initAardStatus(): AardStatus {
aardReducedPolling: true, aardReducedPolling: true,
checkInProgress: false, checkInProgress: false,
lastVideoStatus: VideoPlaybackState.NotInitialized, lastVideoStatus: VideoPlaybackState.NotInitialized,
autoDisabled: false,
} }
} }

View File

@ -1,4 +1,5 @@
export interface AardTimers { export interface AardTimers {
autoDisableAt: number | undefined;
nextFrameCheckTime: number; nextFrameCheckTime: number;
reducedPollingNextCheckTime: number; reducedPollingNextCheckTime: number;
} }
@ -7,5 +8,6 @@ export function initAardTimers(): AardTimers {
return { return {
nextFrameCheckTime: 0, nextFrameCheckTime: 0,
reducedPollingNextCheckTime: 0, reducedPollingNextCheckTime: 0,
autoDisableAt: undefined,
}; };
} }

View File

@ -111,15 +111,6 @@ class PageInfo {
this.scheduleUrlCheck(); this.scheduleUrlCheck();
document.addEventListener('fullscreenchange', this.fsEventListener); document.addEventListener('fullscreenchange', this.fsEventListener);
this.eventBus.subscribeMulti({
'probe-video': {
function: () => {
console.log(`[${window.location}] probe-video received.`)
this.rescan();
}
}
});
} }
destroy() { destroy() {
@ -407,17 +398,20 @@ class PageInfo {
scheduleUrlCheck() { scheduleUrlCheck() {
try{ try{
if(this.urlCheckTimer){ if(this.urlCheckTimer){
clearTimeout(this.urlCheckTimer); clearTimeout(this.urlCheckTimer);
} }
let ths = this; let ths = this;
this.urlCheckTimer = setTimeout(function(){ this.urlCheckTimer = setTimeout(
ths.urlCheckTimer = null; function(){
ths.ghettoUrlCheck(); ths.urlCheckTimer = null;
ths = null; ths.ghettoUrlCheck();
}, this.settings.active.pageInfo.timeouts.urlCheck) ths = null;
},
this.settings.active.pageInfo.timeouts.urlCheck
);
} catch(e){ } catch(e){
this.logger.log('scheduleUrlCheck', "scheduling URL check failed. Here's why:",e) this.logger.log('scheduleUrlCheck', "scheduling URL check failed. Here's why:",e)
} }
@ -428,6 +422,7 @@ class PageInfo {
this.logger.warn('ghettoUrlCheck', "URL has changed. Triggering a rescan!"); this.logger.warn('ghettoUrlCheck', "URL has changed. Triggering a rescan!");
this.rescan(RescanReason.URL_CHANGE); this.rescan(RescanReason.URL_CHANGE);
this.eventBus.send("url-changed", {newUrl: window.location.href});
this.lastUrl = window.location.href; this.lastUrl = window.location.href;
} }