Get zoom options to mostly work

This commit is contained in:
Tamius Han 2025-04-26 04:23:57 +02:00
parent 32c11d1f61
commit 3d7b50a2e3
5 changed files with 98 additions and 45 deletions

View File

@ -1,6 +1,12 @@
import AspectRatioType from '../enums/AspectRatioType.enum';
export enum ArVariant {
Crop = undefined,
Zoom = 1
}
export interface Ar {
type: AspectRatioType,
ratio?: number
ratio?: number,
variant?: ArVariant
}

View File

@ -43,6 +43,14 @@
<h1>Zoom:</h1>
</div>
<ZoomOptionsPanel
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:isEditing="false"
>
</ZoomOptionsPanel>
</div>
</template>

View File

@ -1,6 +1,7 @@
import AspectRatioType from '../../../common/enums/AspectRatioType.enum';
import ExtensionMode from '../../../common/enums/ExtensionMode.enum';
import { ExtensionEnvironment } from '../../../common/interfaces/SettingsInterface';
import AspectRatioType from '@src/common/enums/AspectRatioType.enum';
import ExtensionMode from '@src/common/enums/ExtensionMode.enum';
import { ArVariant } from '@src/common/interfaces/ArInterface';
import { ExtensionEnvironment } from '@src/common/interfaces/SettingsInterface';
import EventBus from '../EventBus';
import Logger from '../Logger';
import Settings from '../Settings';
@ -413,7 +414,7 @@ export class Aard {
/**
* Checks whether autodetection can run
*/
startCheck() {
startCheck(arVariant?: ArVariant) {
console.log('aard - starting checks')
if (!this.videoData.player) {
console.warn('Player not detected!');

View File

@ -16,7 +16,7 @@ import VideoData from '../video-data/VideoData';
import EventBus from '../EventBus';
import { _cp } from '../../../common/js/utils';
import Settings from '../Settings';
import { Ar } from '../../../common/interfaces/ArInterface';
import { Ar, ArVariant } from '../../../common/interfaces/ArInterface';
import { RunLevel } from '../../enum/run-level.enum';
import * as _ from 'lodash';
import getElementStyles from '../../util/getElementStyles';
@ -26,6 +26,11 @@ if(Debug.debug) {
console.log("Loading: Resizer.js");
}
enum ResizerMode {
Crop = 1,
Zoom = 2
};
/**
* Resizer is the top class and is responsible for figuring out which component needs to crop, which
* component needs to zoom, and which component needs to stretch.
@ -83,9 +88,9 @@ class Resizer {
//#endregion
cycleableAspectRatios: Ar[];
cycleableZoomAspectRatios: Ar[];
nextCycleOptionIndex = 0;
//#region event bus configuration
private eventBusCommands = {
'set-ar': [{
@ -93,7 +98,7 @@ class Resizer {
this.manualZoom = false; // this only gets called from UI or keyboard shortcuts, making this action safe.
if (config.type !== AspectRatioType.Cycle) {
this.setAr(config);
this.setAr({...config, variant: ArVariant.Crop});
} else {
// if we manually switched to a different aspect ratio, cycle from that ratio forward
const lastArIndex = this.cycleableAspectRatios.findIndex(x => x.type === this.lastAr.type && x.ratio === this.lastAr.ratio);
@ -101,11 +106,29 @@ class Resizer {
this.nextCycleOptionIndex = (lastArIndex + 1) % this.cycleableAspectRatios.length;
}
this.setAr(this.cycleableAspectRatios[this.nextCycleOptionIndex]);
this.setAr({...this.cycleableAspectRatios[this.nextCycleOptionIndex], variant: ArVariant.Crop});
this.nextCycleOptionIndex = (this.nextCycleOptionIndex + 1) % this.cycleableAspectRatios.length;
}
}
}],
'set-ar-zoom': [{
function: (config: any) => {
this.manualZoom = false; // this only gets called from UI or keyboard shortcuts, making this action safe.
if (config.type !== AspectRatioType.Cycle) {
this.setAr({...config, variant: ArVariant.Zoom});
} else {
// if we manually switched to a different aspect ratio, cycle from that ratio forward
const lastArIndex = this.cycleableZoomAspectRatios.findIndex(x => x.type === this.lastAr.type && x.ratio === this.lastAr.ratio);
if (lastArIndex !== -1) {
this.nextCycleOptionIndex = (lastArIndex + 1) % this.cycleableZoomAspectRatios.length;
}
this.setAr({...this.cycleableZoomAspectRatios[this.nextCycleOptionIndex], variant: ArVariant.Zoom});
this.nextCycleOptionIndex = (this.nextCycleOptionIndex + 1) % this.cycleableZoomAspectRatios.length;
}
}
}],
'set-alignment': [{
function: (config: any) => {
this.setVideoAlignment(config.x, config.y);
@ -188,6 +211,11 @@ class Resizer {
.filter(x => [AspectRatioType.FitHeight, AspectRatioType.FitWidth, AspectRatioType.Fixed, AspectRatioType.Reset].includes(x?.arguments?.type))
.map(x => x.arguments) as Ar[];
this.cycleableZoomAspectRatios =
(this.settings?.active?.commands?.zoom ?? [])
.filter(x => x.action === 'set-ar-zoom' && x.arguments?.type !== AspectRatioType.Cycle)
.map(x => x.arguments) as Ar[];
this.nextCycleOptionIndex = 0;
this.userCssClassName = videoData.userCssClassName;
}
@ -276,8 +304,27 @@ class Resizer {
}
}
/**
* Starts and stops Aard as necessary. Returns 'true' if we can
* stop setting aspect ratio early.
* @param ar
* @param resizerMode
* @returns
*/
private handleAard(ar: Ar): boolean {
if (ar.type === AspectRatioType.Automatic) {
this.videoData.aard?.startCheck(ar.variant);
return true;
} else if (ar.type !== AspectRatioType.AutomaticUpdate) {
this.videoData.aard?.stop();
} else if (this.stretcher.stretch.type === StretchType.Basic) {
this.videoData?.aard?.stop();
}
}
async setAr(ar: Ar, lastAr?: Ar) {
if (this.destroyed) {
if (this.destroyed || ar == null) {
return;
}
@ -294,11 +341,8 @@ class Resizer {
}
// handle autodetection stuff
if (ar.type === AspectRatioType.Automatic) {
this.videoData.aard?.startCheck();
if (this.handleAard(ar)) {
return;
} else if (ar.type !== AspectRatioType.AutomaticUpdate) {
this.videoData.aard?.stop();
}
if (ar.type !== AspectRatioType.AutomaticUpdate) {
@ -312,10 +356,6 @@ class Resizer {
this.logger.log('info', 'debug', '%c[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', 'background-color: #4c3a2f, color: #ffa349', ar);
if (ar == null) {
return;
}
let stretchFactors: VideoDimensions | any;
// reset zoom, but only on aspect ratio switch. We also know that aspect ratio gets converted to
@ -324,6 +364,7 @@ class Resizer {
(ar.type !== AspectRatioType.Fixed && ar.type !== AspectRatioType.Manual) // anything not these two _always_ changes AR
|| ar.type !== this.lastAr.type // this also means aspect ratio has changed
|| ar.ratio !== this.lastAr.ratio // this also means aspect ratio has changed
|| ar.variant !== this.lastAr.variant
) {
this.zoom.reset();
this.resetPan();
@ -360,26 +401,11 @@ class Resizer {
this.videoData.destroy();
}
// pause AR on:
// * ar.type NOT automatic
// * ar.type is auto, but stretch is set to basic basic stretch
//
// unpause when using other modes
if ((ar.type !== AspectRatioType.Automatic && ar.type !== AspectRatioType.AutomaticUpdate) || this.stretcher.stretch.type === StretchType.Basic) {
this.videoData?.aard?.stop();
} else {
if (ar.type !== AspectRatioType.AutomaticUpdate) {
if (this.lastAr.type === AspectRatioType.Automatic || this.lastAr.type === AspectRatioType.AutomaticUpdate) {
this.videoData?.aard?.stop();
}
}
}
// do stretch thingy
if ([StretchType.NoStretch, StretchType.Conditional, StretchType.FixedSource].includes(this.stretcher.stretch.type)) {
stretchFactors = this.scaler.calculateCrop(ar);
if(! stretchFactors || stretchFactors.error){
if (!stretchFactors || stretchFactors.error){
this.logger.log('error', 'debug', `[Resizer::setAr] <rid:${this.resizerId}> failed to set AR due to problem with calculating crop. Error:`, stretchFactors?.error);
if (stretchFactors?.error === 'no_video'){
this.videoData.destroy();
@ -406,12 +432,11 @@ class Resizer {
this.stretcher.stretch.type === StretchType.Conditional ? 'crop with conditional StretchType.' : 'crop with fixed stretch',
'Stretch factors are:', stretchFactors
);
} else if (this.stretcher.stretch.type === StretchType.Hybrid) {
stretchFactors = this.stretcher.calculateStretch(ar.ratio);
this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for hybrid stretch/crop. Stretch factors are:', stretchFactors);
} else if (this.stretcher.stretch.type === StretchType.Fixed) {
stretchFactors = this.stretcher.calculateStretchFixed(ar.ratio)
stretchFactors = this.stretcher.calculateStretchFixed(ar.ratio);
} else if (this.stretcher.stretch.type === StretchType.Basic) {
stretchFactors = this.stretcher.calculateBasicStretch();
this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for basic StretchType. Stretch factors are:', stretchFactors);
@ -794,8 +819,10 @@ class Resizer {
// conditions are true at the same time, we need to go 'chiny reckon' and recheck our player
// element. Chances are our video is not getting aligned correctly
if (
(this.videoData.video.offsetWidth > this.videoData.player.dimensions.width && this.videoData.video.offsetHeight > this.videoData.player.dimensions.height) ||
(this.videoData.video.offsetWidth < this.videoData.player.dimensions.width && this.videoData.video.offsetHeight < this.videoData.player.dimensions.height)
(
(this.videoData.video.offsetWidth > this.videoData.player.dimensions.width && this.videoData.video.offsetHeight > this.videoData.player.dimensions.height) ||
(this.videoData.video.offsetWidth < this.videoData.player.dimensions.width && this.videoData.video.offsetHeight < this.videoData.player.dimensions.height)
) && ar?.variant !== ArVariant.Zoom
) {
this.logger.log('warn', ['debugger', 'resizer'], `[Resizer::_res_computeOffsets] <rid:${this.resizerId}> We are getting some incredibly funny results here.\n\n`,
`Video seems to be both wider and taller (or shorter and narrower) than player element at the same time. This is super duper not supposed to happen.\n\n`,

View File

@ -3,6 +3,7 @@ import AspectRatioType from '../../../common/enums/AspectRatioType.enum';
import BrowserDetect from '../../conf/BrowserDetect';
import VideoData from '../video-data/VideoData';
import Logger from '../Logger';
import { Ar, ArVariant } from '../../../common/interfaces/ArInterface';
export enum CropStrategy {
@ -100,7 +101,7 @@ class Scaler {
return null;
}
calculateCrop(ar: {type: AspectRatioType, ratio?: number}): VideoDimensions | {error: string, [x: string]: any} {
calculateCrop(ar: Ar): VideoDimensions | {error: string, [x: string]: any} {
/**
* STEP 1: NORMALIZE ASPECT RATIO
*
@ -170,9 +171,15 @@ class Scaler {
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] trying to set ar. args are: ar->",ar.ratio,"; this.conf.player.dimensions->",this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
// If we encounter invalid players, we try to update its dimensions
// ONCE before throwing an error
if( (! this.conf.player.dimensions) || this.conf.player.dimensions.width === 0 || this.conf.player.dimensions.height === 0 ){
this.logger.log('error', 'scaler', "[Scaler::calculateCrop] ERROR — no (or invalid) this.conf.player.dimensions:",this.conf.player.dimensions);
return {error: "this.conf.player.dimensions_error"};
this.conf.player.updatePlayer();
if( (! this.conf.player.dimensions) || this.conf.player.dimensions.width === 0 || this.conf.player.dimensions.height === 0 ){
return {error: "this.conf.player.dimensions_error"};
}
}
// we can finally start computing required video dimensions now:
@ -184,7 +191,7 @@ class Scaler {
}
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] ar is " ,ar.ratio, ", file ar is", streamAr, ", this.conf.player.dimensions are ", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] ar is " ,ar.ratio, ", file ar is", streamAr, ",ar variant", ar.variant ,"\nthis.conf.player.dimensions are ", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions, this.conf.player.element);
const videoDimensions: VideoDimensions = {
xFactor: 1,
@ -199,7 +206,7 @@ class Scaler {
}
}
this.calculateCropCore(videoDimensions, ar.ratio, streamAr, playerAr)
this.calculateCropCore(videoDimensions, ar.ratio, streamAr, playerAr, ar.variant)
return videoDimensions;
}
@ -212,7 +219,11 @@ class Scaler {
* @param {*} streamAr
* @param {*} playerAr
*/
calculateCropCore(videoDimensions: VideoDimensions, ar: number, streamAr: number, playerAr: number) {
calculateCropCore(videoDimensions: VideoDimensions, ar: number, streamAr: number, playerAr: number, variant?: ArVariant) {
if (variant === ArVariant.Zoom) {
playerAr = ar;
}
if (streamAr < playerAr) {
if (streamAr < ar){
// in this situation we have to crop letterbox on top/bottom of the player
@ -254,8 +265,8 @@ class Scaler {
const letterboxRatio = (1 - (playerAr / ar));
videoDimensions.relativeCropLimits = {
top: ar > streamAr ? ( ar > playerAr ? (letterboxRatio * -0.5) : 0) : 0,
left: ar < streamAr ? ( ar < playerAr ? (-0.5 / letterboxRatio) : 0) : 0,
top: ar > streamAr ? ( ar >= playerAr ? (letterboxRatio * -0.5) : 0) : 0,
left: ar < streamAr ? ( ar <= playerAr ? (-0.5 / letterboxRatio) : 0) : 0,
}
videoDimensions.preventAlignment = {
x: ar > playerAr, // video is wider than player, so it's full width already