Allow zoom modes to be set as default crop

This commit is contained in:
Tamius Han 2026-01-28 23:54:26 +01:00
parent 822d069b82
commit 3b91c2224c
7 changed files with 152 additions and 67 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "ultrawidify",
"version": "6.3.997",
"version": "6.3.998",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ultrawidify",
"version": "6.3.997",
"version": "6.3.998",
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@mdi/font": "^7.4.47",

View File

@ -1,6 +1,6 @@
{
"name": "ultrawidify",
"version": "6.3.997",
"version": "6.3.998",
"description": "Aspect ratio fixer for youtube and other sites, with automatic aspect ratio detection. Supports ultrawide and other ratios.",
"author": "Tamius Han <tamius.han@gmail.com>",
"scripts": {

View File

@ -485,6 +485,51 @@ const ExtensionConfPatch = Object.freeze([
if (!userOptions.sites["www.amazon.com"]) {
userOptions.sites["www.amazon.com"] = _cp(defaultOptions.sites["www.amazon.com"] );
}
if (userOptions.commands?.zoom) {
const firstFixed = userOptions.commands?.zoom.findIndex(x => x.arguments.type === AspectRatioType.Fixed);
if (firstFixed === -1) {
userOptions.commands.zoom.push({
action: 'set-ar-zoom',
label: 'Cover',
comment: 'Covers the entire screen, cropping as much as needed',
arguments: {
type: AspectRatioType.Cover
},
shortcut: {
key: 'w',
code: 'KeyW',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}
});
} else {
userOptions.commands.zoom.splice(firstFixed, 0, {
action: 'set-ar-zoom',
label: 'Cover',
comment: 'Covers the entire screen, cropping as much as needed',
arguments: {
type: AspectRatioType.Cover
},
shortcut: {
key: 'w',
code: 'KeyW',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: true,
onKeyUp: true,
onKeyDown: false,
}
});
}
}
}
}

View File

@ -355,40 +355,6 @@ const ExtensionConf: SettingsInterface = {
onKeyDown: false,
}
}, {
action: 'set-ar',
label: 'Fit width',
comment: 'Make the video fit the entire width of the player, crop top and bottom if necessary',
arguments: {
type: AspectRatioType.FitWidth
},
shortcut: {
key: 'w',
code: 'KeyW',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: false,
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar',
label: 'Fit height',
comment: 'Make the video fit the entire height of the player, crop left and right if necessary',
arguments: {
type: AspectRatioType.FitHeight
},
shortcut: {
key: 'e',
code: 'KeyE',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: false,
onKeyUp: true,
onKeyDown: false,
}
},{
action: 'set-ar',
label: 'Cycle',
comment: 'Cycle through crop options',
@ -573,6 +539,23 @@ const ExtensionConf: SettingsInterface = {
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar-zoom',
label: 'Cover',
comment: 'Covers the entire screen, cropping as much as needed',
arguments: {
type: AspectRatioType.Cover
},
shortcut: {
key: 'w',
code: 'KeyW',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: false,
onKeyUp: true,
onKeyDown: false,
}
}, {
action: 'set-ar-zoom',
label: 'Cycle',

View File

@ -299,17 +299,22 @@ class Resizer {
let fileAr = this.getFileAr();
if (ar.type === AspectRatioType.FitWidth){
ar.ratio = ratioOut > fileAr ? ratioOut : fileAr;
}
else if(ar.type === AspectRatioType.FitHeight){
ar.ratio = ratioOut < fileAr ? ratioOut : fileAr;
}
else if(ar.type === AspectRatioType.Reset){
this.logger.info('modeToAr', "Using original aspect ratio -", fileAr);
ar.ratio = fileAr;
} else {
return null;
switch (ar.type) {
case AspectRatioType.FitWidth:
ar.ratio = ratioOut > fileAr ? ratioOut : fileAr;
break;
case AspectRatioType.FitHeight:
ar.ratio = ratioOut < fileAr ? ratioOut : fileAr;
break;
case AspectRatioType.Cover:
ar.ratio = Math.max(ratioOut, fileAr);
break;
case AspectRatioType.Reset:
this.logger.info('modeToAr', "Using original aspect ratio -", fileAr);
ar.ratio = fileAr;
break;
default:
return null;
}
return ar;

View File

@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "Ultrawidify",
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
"version": "6.3.997",
"version": "6.3.998",
"icons": {
"32":"res/icons/uw-32.png",
"64":"res/icons/uw-64.png"

View File

@ -209,7 +209,8 @@
<!-- Default crop -->
<div class="field">
<div class="label">Default crop:</div>
<div class="select">
<div class="select grow shrink flex flex-row">
<select
:value="siteDefaultCrop"
@change="setOption('defaults.crop', $event)"
@ -218,15 +219,48 @@
v-if="!isDefaultConfiguration"
:value="JSON.stringify({useDefault: true})"
>
Use default ({{getCommandValue(settings?.active.commands.crop, siteSettings.data.defaults.crop)}})
Use default ({{getDefaultCrop(siteSettings.defaultSettings.defaults.crop)}})
</option>
<option
v-for="(command, index) of settings?.active.commands.crop"
:key="index"
:value="JSON.stringify(command.arguments)"
:value="JSON.stringify({type: AspectRatioType.Reset})"
>
{{command.label}}
Initial/reset
</option>
<optgroup label="Crop">
<template
v-for="(command, index) of settings?.active.commands.crop"
:key="index"
>
<option
v-if="
command.arguments.type === AspectRatioType.Fixed
|| command.arguments.type === AspectRatioType.Automatic
|| command.arguments.type === AspectRatioType.FitWidth
|| command.arguments.type === AspectRatioType.FitHeight
"
:value="JSON.stringify(command.arguments)"
>
{{command.label}} (crop)
</option>
</template>
</optgroup>
<optgroup label="Zoom">
<template
v-for="(command, index) of settings?.active.commands.zoom"
:key="index"
>
<option
v-if="
command.arguments.type === AspectRatioType.Fixed
|| command.arguments.type === AspectRatioType.Automatic
|| command.arguments.type === AspectRatioType.Cover
"
:value="JSON.stringify({...command.arguments, variant: ArVariant.Zoom})"
>
{{command.label}} (zoom)
</option>
</template>
</optgroup>
</select>
</div>
</div>
@ -244,7 +278,7 @@
v-if="!isDefaultConfiguration"
:value="JSON.stringify({useDefault: true})"
>
Use default ({{getCommandValue(settings?.active.commands.stretch, siteSettings.data.defaults.stretch)}})
Use default ({{getCommandValue(settings?.active.commands.stretch, siteSettings.defaultSettings.defaults.stretch)}})
</option>
<option
v-for="(command, index) of settings?.active.commands.stretch"
@ -269,7 +303,7 @@
v-if="!isDefaultConfiguration"
:value="JSON.stringify({useDefault: true})"
>
Use default ({{getAlignmentLabel(siteSettings.data.defaults.alignment)}})
Use default ({{getAlignmentLabel(siteSettings.defaultSettings.defaults.alignment)}})
</option>
<option
v-for="(command, index) of alignmentOptions"
@ -337,9 +371,10 @@ import VideoAlignmentType from '@src/common/enums/VideoAlignmentType.enum';
import CropModePersistence from '@src/common/enums/CropModePersistence.enum';
import EmbeddedContentSettingsOverridePolicy from '@src/common/enums/EmbeddedContentSettingsOverridePolicy.enum';
import { InputHandlingMode } from '@src/common/enums/InputHandlingMode.enum';
import AspectRatioType from '@src/common/enums/AspectRatioType.enum';
import { ArVariant } from '@src/common/interfaces/ArInterface';
export default defineComponent({
components: {
Popup,
PlayerSelectorAdvancedForm,
@ -353,7 +388,9 @@ export default defineComponent({
],
data() {
return {
CropModePersistence: CropModePersistence,
CropModePersistence,
AspectRatioType,
ArVariant,
ExtensionMode,
EmbeddedContentSettingsOverridePolicy,
InputHandlingMode,
@ -370,7 +407,8 @@ export default defineComponent({
],
playerDetectionOptionsDialog: {
visible: false,
}
},
defaultCropCommand: 'set-ar',
}
},
mixins: [
@ -395,9 +433,6 @@ export default defineComponent({
siteDefaultAlignment() {
return this.siteSettings.raw?.defaults?.alignment ? JSON.stringify(this.siteSettings.raw?.defaults?.alignment) : JSON.stringify({useDefault: true});
},
siteDefaultCropPersistence() {
return this.siteSettings.raw?.persistCSA ?? undefined;
},
defaultPersistenceLabel() {
switch (this.siteSettings.defaultSettings.persistCSA) {
case CropModePersistence.CurrentSession:
@ -511,6 +546,22 @@ export default defineComponent({
}
},
getDefaultCrop(command) {
for (const cmd of this.settings?.active.commands.crop) {
if (JSON.stringify(cmd.arguments) === JSON.stringify(command)) {
return cmd.label;
}
}
for (const cmd of this.settings?.active.commands.zoom) {
if (JSON.stringify({...cmd.arguments, variant: ArVariant.Zoom}) === JSON.stringify(command)) {
return `${cmd.label} (zoom)`;
}
}
return 'Unknown';
},
getCommandValue(availableCommands, command) {
for (const cmd of availableCommands) {
if (JSON.stringify(cmd.arguments) === JSON.stringify(command)) {
@ -555,13 +606,14 @@ export default defineComponent({
getOption(option) {
},
async setOption(option, $event) {
const value = $event.target.value;
let commandArguments;
async setOption(option, $event, extras = {}) {
const value = $event?.target?.value ?? {};
let commandArguments;
// if argument is json, parse json. Otherwise, pass the value as-is
try {
commandArguments = value !== undefined ? JSON.parse(value) : undefined;
const intermediary = value !== undefined ? JSON.parse(value) : undefined;
commandArguments = {...intermediary, ...extras};
} catch(e) {
commandArguments = value;
}