Merge branch 'master' into stable
This commit is contained in:
commit
b6ff740b84
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -5,10 +5,12 @@
|
|||||||
"blackbar",
|
"blackbar",
|
||||||
"blackframe",
|
"blackframe",
|
||||||
"canvas",
|
"canvas",
|
||||||
|
"comms",
|
||||||
"equalish",
|
"equalish",
|
||||||
"insta",
|
"insta",
|
||||||
"recursing",
|
"recursing",
|
||||||
"reddit",
|
"reddit",
|
||||||
|
"rescan",
|
||||||
"resizer",
|
"resizer",
|
||||||
"textbox",
|
"textbox",
|
||||||
"videodata",
|
"videodata",
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -12,7 +12,16 @@ QoL improvements for me:
|
|||||||
|
|
||||||
* logging: allow to enable logging at will and export said logs to a file
|
* logging: allow to enable logging at will and export said logs to a file
|
||||||
|
|
||||||
### v4.3.1 (current)
|
### v.4.4.0 (current)
|
||||||
|
|
||||||
|
* Russian users (and users of other non-latin keyboard layouts) can now use keyboard shortcuts by default, without having to rebind them manually. (NOTE: if you've changed keyboard shortcuts manually, this change will ***NOT*** be applied to your configuration.)
|
||||||
|
* NOTE: when using non-latin layouts, 'zoom' shortcut (`z` by default) uses the position of 'Y' on QWERTY layout.
|
||||||
|
* Ability to preserve aspect ratio between different videos (applies to current page and doesn't survive proper page reloads)
|
||||||
|
* Changing aspect ratio now resets zooming and panning.
|
||||||
|
* Fixed bug where keyboard shortcuts would work while typing in certain text fields
|
||||||
|
* Fixed minor bug with autodetection
|
||||||
|
|
||||||
|
### v4.3.1
|
||||||
|
|
||||||
* Minor rework of settings page (actions & shortcuts section)
|
* Minor rework of settings page (actions & shortcuts section)
|
||||||
* Fixed bug that prevented settings page from opening
|
* Fixed bug that prevented settings page from opening
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ultravidify",
|
"name": "ultravidify",
|
||||||
"version": "4.3.1",
|
"version": "4.4.0",
|
||||||
"description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.",
|
"description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.",
|
||||||
"author": "Tamius Han <tamius.han@gmail.com>",
|
"author": "Tamius Han <tamius.han@gmail.com>",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex action-name">
|
<div class="flex action-name">
|
||||||
<span v-if="action.cmd && action.cmd.length > 1 || action.cmd[0].action === 'set-ar' && action.cmd[0].arg === AspectRatio.Fixed" class="icon red" @click="removeAction()">🗙</span>
|
<span v-if="action.cmd && action.cmd.length > 1 || action.cmd[0].action === 'set-ar' && action.cmd[0].arg === AspectRatio.Fixed" class="icon red" @click="removeAction()">🗙</span>
|
||||||
<span v-else class="icon transparent">🗙</span>
|
<span v-else class="icon transparent">🗙</span>
|
||||||
<span class="icon" @click="editAction()">🖉</span>
|
<span class="icon" @click="editAction()">🖉</span>
|
||||||
{{action.name}}
|
{{action.name}}
|
||||||
|
9
src/common/enums/crop-mode-persistence.enum.js
Normal file
9
src/common/enums/crop-mode-persistence.enum.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
var CropModePersistence = Object.freeze({
|
||||||
|
Default: -1,
|
||||||
|
Disabled: 0,
|
||||||
|
UntilPageReload: 1,
|
||||||
|
CurrentSession: 2,
|
||||||
|
Forever: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CropModePersistence;
|
@ -1,6 +1,6 @@
|
|||||||
class KeyboardShortcutParser {
|
class KeyboardShortcutParser {
|
||||||
static parseShortcut(keypress) {
|
static parseShortcut(keypress) {
|
||||||
var shortcutCombo = '';
|
let shortcutCombo = '';
|
||||||
|
|
||||||
if (keypress.ctrlKey) {
|
if (keypress.ctrlKey) {
|
||||||
shortcutCombo += 'Ctrl + ';
|
shortcutCombo += 'Ctrl + ';
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
scopeActions: function() {
|
scopeActions: function() {
|
||||||
return this.settings.active.actions.filter(x => x.scopes[this.scope] && x.scopes[this.scope].show) || [];
|
return this.settings.active.actions.filter(x => {
|
||||||
|
if (! x.scopes) {
|
||||||
|
console.error('This action does not have a scope.', x);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return x.scopes[this.scope] && x.scopes[this.scope].show
|
||||||
|
}) || [];
|
||||||
},
|
},
|
||||||
extensionActions: function(){
|
extensionActions: function(){
|
||||||
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-extension-mode') || [];
|
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-extension-mode') || [];
|
||||||
@ -12,6 +18,9 @@ export default {
|
|||||||
aspectRatioActions: function(){
|
aspectRatioActions: function(){
|
||||||
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-ar') || [];
|
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-ar') || [];
|
||||||
},
|
},
|
||||||
|
cropModePersistenceActions: function() {
|
||||||
|
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-ar-persistence') || [];
|
||||||
|
},
|
||||||
stretchActions: function(){
|
stretchActions: function(){
|
||||||
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-stretch') || [];
|
return this.scopeActions.filter(x => x.cmd.length === 1 && x.cmd[0].action === 'set-stretch') || [];
|
||||||
},
|
},
|
||||||
|
@ -2,6 +2,7 @@ import VideoAlignment from '../../common/enums/video-alignment.enum';
|
|||||||
import Stretch from '../../common/enums/stretch.enum';
|
import Stretch from '../../common/enums/stretch.enum';
|
||||||
import ExtensionMode from '../../common/enums/extension-mode.enum';
|
import ExtensionMode from '../../common/enums/extension-mode.enum';
|
||||||
import AspectRatio from '../../common/enums/aspect-ratio.enum';
|
import AspectRatio from '../../common/enums/aspect-ratio.enum';
|
||||||
|
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
var ActionList = {
|
var ActionList = {
|
||||||
'set-ar': {
|
'set-ar': {
|
||||||
@ -30,6 +31,33 @@ var ActionList = {
|
|||||||
page: true,
|
page: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'set-ar-persistence': {
|
||||||
|
name: 'Set crop mode persistence',
|
||||||
|
args: [{
|
||||||
|
name: 'Never persist',
|
||||||
|
arg: CropModePersistence.Disabled,
|
||||||
|
},{
|
||||||
|
name: 'While on page',
|
||||||
|
arg: CropModePersistence.UntilPageReload,
|
||||||
|
},{
|
||||||
|
name: 'Current session',
|
||||||
|
arg: CropModePersistence.CurrentSession,
|
||||||
|
},{
|
||||||
|
name: 'Always persist',
|
||||||
|
arg: CropModePersistence.Forever,
|
||||||
|
}, {
|
||||||
|
name: 'Default',
|
||||||
|
arg: CropModePersistence.Default,
|
||||||
|
scopes: {
|
||||||
|
site: true,
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
global: true,
|
||||||
|
site: true,
|
||||||
|
page: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
'set-stretch': {
|
'set-stretch': {
|
||||||
name: 'Set stretch',
|
name: 'Set stretch',
|
||||||
args: [{
|
args: [{
|
||||||
|
@ -117,7 +117,132 @@ const ExtensionConfPatch = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
forVersion: '4.4.0',
|
||||||
|
updateFn: (userOptions, defaultOptions) => {
|
||||||
|
// remove 'press P to toggle panning mode' thing
|
||||||
|
const togglePan = userOptions.actions.find(x => x.cmd && x.cmd.length === 1 && x.cmd[0].action === 'toggle-pan');
|
||||||
|
if (togglePan) {
|
||||||
|
togglePan.scopes = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new actions
|
||||||
|
userOptions.actions.push({
|
||||||
|
name: 'Don\'t persist crop',
|
||||||
|
label: 'Never persist',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: 0,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Persist crop while on page',
|
||||||
|
label: 'Until page load',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: 1,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Persist crop for current session',
|
||||||
|
label: 'Current session',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: 2,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Persist until manually reset',
|
||||||
|
label: 'Always persist',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: 3,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Default crop persistence',
|
||||||
|
label: 'Default',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: -1,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// patch shortcuts for non-latin layouts, but only if the user hasn't changed default keys
|
||||||
|
for (const action of userOptions.actions) {
|
||||||
|
if (!action.cmd || action.cmd.length !== 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// if this fails, then action doesn't have keyboard shortcut associated with it, so we skip it
|
||||||
|
|
||||||
|
const actionDefaults = defaultOptions.actions.find(x => x.cmd && x.cmd.length === 1 // (redundant, default actions have exactly 1 cmd in array)
|
||||||
|
&& x.cmd[0].action === action.cmd[0].action
|
||||||
|
&& x.scopes.page
|
||||||
|
&& x.scopes.page.shortcut
|
||||||
|
&& x.scopes.page.shortcut.length === 1
|
||||||
|
&& x.scopes.page.shortcut[0].key === action.scopes.page.shortcut[0].key // this can throw exception, and it's okay
|
||||||
|
);
|
||||||
|
if (actionDefaults === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// update 'code' property for shortcut
|
||||||
|
action.scopes.page.shortcut[0]['code'] = actionDefaults.scopes.page.shortcut[0].code;
|
||||||
|
} catch (e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
export default ExtensionConfPatch;
|
export default ExtensionConfPatch;
|
@ -5,6 +5,7 @@ import Stretch from '../../common/enums/stretch.enum';
|
|||||||
import ExtensionMode from '../../common/enums/extension-mode.enum';
|
import ExtensionMode from '../../common/enums/extension-mode.enum';
|
||||||
import AntiGradientMode from '../../common/enums/anti-gradient-mode.enum';
|
import AntiGradientMode from '../../common/enums/anti-gradient-mode.enum';
|
||||||
import AspectRatio from '../../common/enums/aspect-ratio.enum';
|
import AspectRatio from '../../common/enums/aspect-ratio.enum';
|
||||||
|
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
if(Debug.debug)
|
if(Debug.debug)
|
||||||
console.log("Loading: ExtensionConf.js");
|
console.log("Loading: ExtensionConf.js");
|
||||||
@ -191,6 +192,7 @@ var ExtensionConf = {
|
|||||||
label: 'Automatic', // example override, takes precedence over default label
|
label: 'Automatic', // example override, takes precedence over default label
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'a',
|
key: 'a',
|
||||||
|
code: 'KeyA',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -204,7 +206,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop',
|
path: 'crop',
|
||||||
},
|
},
|
||||||
},{
|
}, {
|
||||||
name: 'Reset to default',
|
name: 'Reset to default',
|
||||||
label: 'Reset',
|
label: 'Reset',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -216,6 +218,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'r',
|
key: 'r',
|
||||||
|
code: 'KeyR',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -229,7 +232,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop'
|
path: 'crop'
|
||||||
},
|
},
|
||||||
},{
|
}, {
|
||||||
name: 'Fit to width',
|
name: 'Fit to width',
|
||||||
label: 'Fit width',
|
label: 'Fit width',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -241,6 +244,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'w',
|
key: 'w',
|
||||||
|
code: 'KeyW',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -254,7 +258,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop'
|
path: 'crop'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Fit to height',
|
name: 'Fit to height',
|
||||||
label: 'Fit height',
|
label: 'Fit height',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -266,6 +270,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'e',
|
key: 'e',
|
||||||
|
code: 'KeyE',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -279,7 +284,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop'
|
path: 'crop'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Set aspect ratio to 16:9',
|
name: 'Set aspect ratio to 16:9',
|
||||||
label: '16:9',
|
label: '16:9',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -292,6 +297,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 's',
|
key: 's',
|
||||||
|
code: 'KeyS',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -305,7 +311,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop'
|
path: 'crop'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Set aspect ratio to 21:9 (2.39:1)',
|
name: 'Set aspect ratio to 21:9 (2.39:1)',
|
||||||
label: '21:9',
|
label: '21:9',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -318,6 +324,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'd',
|
key: 'd',
|
||||||
|
code: 'KeyD',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -331,7 +338,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop'
|
path: 'crop'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Set aspect ratio to 18:9',
|
name: 'Set aspect ratio to 18:9',
|
||||||
label: '18:9',
|
label: '18:9',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -344,6 +351,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'x',
|
key: 'x',
|
||||||
|
code: 'KeyX',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -357,7 +365,94 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'crop',
|
path: 'crop',
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
|
name: 'Don\'t persist crop',
|
||||||
|
label: 'Never persist',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: CropModePersistence.Never,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Persist crop while on page',
|
||||||
|
label: 'Until page load',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: CropModePersistence.UntilPageReload,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Persist crop for current session',
|
||||||
|
label: 'Current session',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: CropModePersistence.CurrentSession,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Persist until manually reset',
|
||||||
|
label: 'Always persist',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: CropModePersistence.Forever,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Default crop persistence',
|
||||||
|
label: 'Default',
|
||||||
|
cmd: [{
|
||||||
|
action: 'set-ar-persistence',
|
||||||
|
arg: CropModePersistence.Default,
|
||||||
|
}],
|
||||||
|
scopes: {
|
||||||
|
site: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
playerUi: {
|
||||||
|
show: true,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
name: 'Zoom in',
|
name: 'Zoom in',
|
||||||
label: 'Zoom',
|
label: 'Zoom',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -369,6 +464,7 @@ var ExtensionConf = {
|
|||||||
show: false,
|
show: false,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'z',
|
key: 'z',
|
||||||
|
code: 'KeyY',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -381,7 +477,7 @@ var ExtensionConf = {
|
|||||||
playerUi: {
|
playerUi: {
|
||||||
show: false,
|
show: false,
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Zoom out',
|
name: 'Zoom out',
|
||||||
label: 'Unzoom',
|
label: 'Unzoom',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -393,6 +489,7 @@ var ExtensionConf = {
|
|||||||
show: false,
|
show: false,
|
||||||
shortcut: [{
|
shortcut: [{
|
||||||
key: 'u',
|
key: 'u',
|
||||||
|
code: 'KeyU',
|
||||||
ctrlKey: false,
|
ctrlKey: false,
|
||||||
metaKey: false,
|
metaKey: false,
|
||||||
altKey: false,
|
altKey: false,
|
||||||
@ -405,32 +502,20 @@ var ExtensionConf = {
|
|||||||
playerUi: {
|
playerUi: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Toggle panning mode',
|
name: 'Toggle panning mode',
|
||||||
label: 'Toggle pan',
|
label: 'Toggle pan',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
action: 'toggle-pan',
|
action: 'toggle-pan',
|
||||||
arg: 'toggle'
|
arg: 'toggle'
|
||||||
}],
|
}],
|
||||||
scopes: {
|
|
||||||
page: {
|
|
||||||
show: true,
|
|
||||||
shortcut: [{
|
|
||||||
key: 'p',
|
|
||||||
ctrlKey: false,
|
|
||||||
metaKey: false,
|
|
||||||
altKey: false,
|
|
||||||
shiftKey: false,
|
|
||||||
onKeyUp: true,
|
|
||||||
onKeyDown: false,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
playerUi: {
|
playerUi: {
|
||||||
show: true,
|
show: true,
|
||||||
path: 'zoom'
|
path: 'zoom'
|
||||||
|
},
|
||||||
|
scopes: {
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Hold to pan',
|
name: 'Hold to pan',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
action: 'pan',
|
action: 'pan',
|
||||||
@ -479,7 +564,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'stretch'
|
path: 'stretch'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Set stretch to "basic"',
|
name: 'Set stretch to "basic"',
|
||||||
label: 'Basic stretch',
|
label: 'Basic stretch',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -504,7 +589,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'stretch'
|
path: 'stretch'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Set stretch to "hybrid"',
|
name: 'Set stretch to "hybrid"',
|
||||||
label: 'Hybrid stretch',
|
label: 'Hybrid stretch',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -529,7 +614,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'stretch'
|
path: 'stretch'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Stretch only to hide thin borders',
|
name: 'Stretch only to hide thin borders',
|
||||||
label: 'Thin borders only',
|
label: 'Thin borders only',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -554,7 +639,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'stretch'
|
path: 'stretch'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Set stretch to default value',
|
name: 'Set stretch to default value',
|
||||||
label: 'Default',
|
label: 'Default',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -592,7 +677,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'align'
|
path: 'align'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Align video to center',
|
name: 'Align video to center',
|
||||||
label: 'Center',
|
label: 'Center',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -614,7 +699,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'align'
|
path: 'align'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Align video to the right',
|
name: 'Align video to the right',
|
||||||
label: 'Right',
|
label: 'Right',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -636,7 +721,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
path: 'align'
|
path: 'align'
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Use default alignment',
|
name: 'Use default alignment',
|
||||||
label: 'Default',
|
label: 'Default',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -669,7 +754,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Enable extension on whitelisted sites only',
|
name: 'Enable extension on whitelisted sites only',
|
||||||
label: 'On whitelist only',
|
label: 'On whitelist only',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -682,7 +767,7 @@ var ExtensionConf = {
|
|||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Extension mode: use default settings',
|
name: 'Extension mode: use default settings',
|
||||||
label: 'Default',
|
label: 'Default',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -695,7 +780,7 @@ var ExtensionConf = {
|
|||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Disable extension',
|
name: 'Disable extension',
|
||||||
label: 'Disable',
|
label: 'Disable',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -711,7 +796,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Enable automatic aspect ratio detection',
|
name: 'Enable automatic aspect ratio detection',
|
||||||
label: 'Enable',
|
label: 'Enable',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -727,7 +812,7 @@ var ExtensionConf = {
|
|||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Enable automatic aspect ratio detection on whitelisted sites only',
|
name: 'Enable automatic aspect ratio detection on whitelisted sites only',
|
||||||
label: 'On whitelist only',
|
label: 'On whitelist only',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -740,7 +825,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Use default settings for automatic aspect ratio detection',
|
name: 'Use default settings for automatic aspect ratio detection',
|
||||||
label: 'Default',
|
label: 'Default',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -753,7 +838,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Disable automatic aspect ratio detection',
|
name: 'Disable automatic aspect ratio detection',
|
||||||
label: 'Disable',
|
label: 'Disable',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -792,7 +877,7 @@ var ExtensionConf = {
|
|||||||
show: true,
|
show: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Enable keyboard shortcuts on whitelisted sites only',
|
name: 'Enable keyboard shortcuts on whitelisted sites only',
|
||||||
label: 'On whitelist only',
|
label: 'On whitelist only',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -804,7 +889,7 @@ var ExtensionConf = {
|
|||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Keyboard shortcuts mode: use default settings',
|
name: 'Keyboard shortcuts mode: use default settings',
|
||||||
label: 'Default',
|
label: 'Default',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
@ -816,7 +901,7 @@ var ExtensionConf = {
|
|||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
}, {
|
||||||
name: 'Disable keyboard shortcuts',
|
name: 'Disable keyboard shortcuts',
|
||||||
label: 'Disable',
|
label: 'Disable',
|
||||||
cmd: [{
|
cmd: [{
|
||||||
|
@ -133,28 +133,31 @@ class ActionHandler {
|
|||||||
// don't do shit on invalid value of state
|
// don't do shit on invalid value of state
|
||||||
}
|
}
|
||||||
|
|
||||||
preventAction() {
|
preventAction(event) {
|
||||||
var activeElement = document.activeElement;
|
var activeElement = document.activeElement;
|
||||||
|
|
||||||
if(this.logger.canLog('keyboard')) {
|
if(this.logger.canLog('keyboard')) {
|
||||||
this.logger.pause(); // temp disable to avoid recursing;
|
this.logger.pause(); // temp disable to avoid recursing;
|
||||||
|
const preventAction = this.preventAction();
|
||||||
|
this.logger.resume(); // undisable
|
||||||
|
|
||||||
this.logger.log('info', 'keyboard', "[ActionHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" +
|
this.logger.log('info', 'keyboard', "[ActionHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" +
|
||||||
"is full screen? (yes->allow):", PlayerData.isFullScreen(),
|
"is full screen? (yes->allow):", PlayerData.isFullScreen(),
|
||||||
"\nis tag one of defined inputs? (yes->prevent):", this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1,
|
"\nis tag one of defined inputs? (yes->prevent):", this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1,
|
||||||
"\nis role = textbox? (yes -> prevent):", activeElement.getAttribute("role") === "textbox",
|
"\nis role = textbox? (yes -> prevent):", activeElement.getAttribute("role") === "textbox",
|
||||||
"\nis type === 'text'? (yes -> prevent):", activeElement.getAttribute("type") === "text",
|
"\nis type === 'text'? (yes -> prevent):", activeElement.getAttribute("type") === "text",
|
||||||
|
"\nevent.target.isContentEditable? (yes -> prevent):", event.target.isContentEditable,
|
||||||
"\nis keyboard local disabled? (yes -> prevent):", this.keyboardLocalDisabled,
|
"\nis keyboard local disabled? (yes -> prevent):", this.keyboardLocalDisabled,
|
||||||
"\nis keyboard enabled in settings? (no -> prevent)", this.settings.keyboardShortcutsEnabled(window.location.hostname),
|
"\nis keyboard enabled in settings? (no -> prevent)", this.settings.keyboardShortcutsEnabled(window.location.hostname),
|
||||||
"\nwill the action be prevented? (yes -> prevent)", this.preventAction(),
|
"\nwill the action be prevented? (yes -> prevent)", preventAction,
|
||||||
"\n-----------------{ extra debug info }-------------------",
|
"\n-----------------{ extra debug info }-------------------",
|
||||||
"\ntag name? (lowercase):", activeElement.tagName, activeElement.tagName.toLocaleLowerCase(),
|
"\ntag name? (lowercase):", activeElement.tagName, activeElement.tagName.toLocaleLowerCase(),
|
||||||
"\nrole:", activeElement.getAttribute('role'),
|
"\nrole:", activeElement.getAttribute('role'),
|
||||||
"\ntype:", activeElement.getAttribute('type'),
|
"\ntype:", activeElement.getAttribute('type'),
|
||||||
"insta-fail inputs:", this.inputs
|
"\ninsta-fail inputs:", this.inputs,
|
||||||
|
"\nevent:", event,
|
||||||
|
"\nevent.target:", event.target
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.resume(); // undisable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// lately youtube has allowed you to read and write comments while watching video in
|
// lately youtube has allowed you to read and write comments while watching video in
|
||||||
@ -175,25 +178,49 @@ class ActionHandler {
|
|||||||
if (activeElement.getAttribute("role") === "textbox") {
|
if (activeElement.getAttribute("role") === "textbox") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (event.target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (activeElement.getAttribute("type") === "text") {
|
if (activeElement.getAttribute("type") === "text") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isActionMatch(shortcut, event) {
|
isLatin(key) {
|
||||||
|
return 'abcdefghijklmnopqrstuvwxyz,.-+1234567890'.indexOf(key.toLocaleLowerCase()) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
isActionMatchStandard(shortcut, event) {
|
||||||
return shortcut.key === event.key &&
|
return shortcut.key === event.key &&
|
||||||
shortcut.ctrlKey === event.ctrlKey &&
|
shortcut.ctrlKey === event.ctrlKey &&
|
||||||
shortcut.metaKey === event.metaKey &&
|
shortcut.metaKey === event.metaKey &&
|
||||||
shortcut.altKey === event.altKey &&
|
shortcut.altKey === event.altKey &&
|
||||||
shortcut.shiftKey === event.shiftKey
|
shortcut.shiftKey === event.shiftKey
|
||||||
}
|
}
|
||||||
|
isActionMatchKeyCode(shortcut, event) {
|
||||||
|
return shortcut.code === event.code &&
|
||||||
|
shortcut.ctrlKey === event.ctrlKey &&
|
||||||
|
shortcut.metaKey === event.metaKey &&
|
||||||
|
shortcut.altKey === event.altKey &&
|
||||||
|
shortcut.shiftKey === event.shiftKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isActionMatch(shortcut, event, isLatin = true) {
|
||||||
|
// ASCII and symbols fall back to key code matching, because we don't know for sure that
|
||||||
|
// regular matching by key is going to work
|
||||||
|
return isLatin ?
|
||||||
|
this.isActionMatchStandard(shortcut, event) :
|
||||||
|
this.isActionMatchStandard(shortcut, event) || this.isActionMatchKeyCode(shortcut, event);
|
||||||
|
}
|
||||||
|
|
||||||
execAction(actions, event, videoData) {
|
execAction(actions, event, videoData) {
|
||||||
this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] Trying to find and execute action for event. Actions/event: ", "color: #ff0", actions, event);
|
this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] Trying to find and execute action for event. Actions/event: ", "color: #ff0", actions, event);
|
||||||
|
|
||||||
|
const isLatin = event.key ? this.isLatin(event.key) : true;
|
||||||
|
|
||||||
for (var action of actions) {
|
for (var action of actions) {
|
||||||
if (this.isActionMatch(action.shortcut, event)) {
|
if (this.isActionMatch(action.shortcut, event, isLatin)) {
|
||||||
this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action);
|
this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action);
|
||||||
|
|
||||||
for (var cmd of action.cmd) {
|
for (var cmd of action.cmd) {
|
||||||
@ -228,10 +255,17 @@ class ActionHandler {
|
|||||||
this.settings.active.sites[site].arStatus = cmd.arg;
|
this.settings.active.sites[site].arStatus = cmd.arg;
|
||||||
} else if (cmd.action === 'set-keyboard') {
|
} else if (cmd.action === 'set-keyboard') {
|
||||||
this.settings.active.sites[site].keyboardShortcutsEnabled = cmd.arg;
|
this.settings.active.sites[site].keyboardShortcutsEnabled = cmd.arg;
|
||||||
|
} else if (cmd.action === 'set-ar-persistence') {
|
||||||
|
this.settings.active.sites[site]['cropModePersistence'] = cmd.arg;
|
||||||
|
this.pageInfo.setArPersistence(cmd.arg);
|
||||||
|
this.settings.saveWithoutReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd.action !== 'set-ar-persistence') {
|
||||||
this.settings.save();
|
this.settings.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// če smo našli dejanje za to tipko, potem ne preiskujemo naprej
|
// če smo našli dejanje za to tipko, potem ne preiskujemo naprej
|
||||||
// if we found an action for this key, we stop searching for a match
|
// if we found an action for this key, we stop searching for a match
|
||||||
@ -244,7 +278,7 @@ class ActionHandler {
|
|||||||
handleKeyup(event) {
|
handleKeyup(event) {
|
||||||
this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keyup: ", event.keyup, "event:", event);
|
this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keyup: ", event.keyup, "event:", event);
|
||||||
|
|
||||||
if (this.preventAction()) {
|
if (this.preventAction(event)) {
|
||||||
this.logger.log('info', 'keyboard', "[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing.");
|
this.logger.log('info', 'keyboard', "[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -255,7 +289,7 @@ class ActionHandler {
|
|||||||
handleKeydown(event) {
|
handleKeydown(event) {
|
||||||
this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeydown] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event)
|
this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeydown] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event)
|
||||||
|
|
||||||
if (this.preventAction()) {
|
if (this.preventAction(event)) {
|
||||||
this.logger.log('info', 'keyboard', "[ActionHandler::handleKeydown] we are in a text box or something. Doing nothing.");
|
this.logger.log('info', 'keyboard', "[ActionHandler::handleKeydown] we are in a text box or something. Doing nothing.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import ObjectCopy from '../lib/ObjectCopy';
|
|||||||
import Stretch from '../../common/enums/stretch.enum';
|
import Stretch from '../../common/enums/stretch.enum';
|
||||||
import VideoAlignment from '../../common/enums/video-alignment.enum';
|
import VideoAlignment from '../../common/enums/video-alignment.enum';
|
||||||
import ExtensionConfPatch from '../conf/ExtConfPatches';
|
import ExtensionConfPatch from '../conf/ExtConfPatches';
|
||||||
|
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -26,43 +27,30 @@ class Settings {
|
|||||||
|
|
||||||
const ths = this;
|
const ths = this;
|
||||||
|
|
||||||
if(currentBrowser.firefox) {
|
if (currentBrowser.firefox) {
|
||||||
browser.storage.onChanged.addListener( (changes, area) => {
|
browser.storage.onChanged.addListener((changes, area) => {this.storageChangeListener(changes, area)});
|
||||||
|
} else if (currentBrowser.chrome) {
|
||||||
|
chrome.storage.onChanged.addListener((changes, area) => {this.storageChangeListener(changes, area)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
storageChangeListener(changes, area) {
|
||||||
this.logger.log('info', 'settings', "[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
|
this.logger.log('info', 'settings', "[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
|
||||||
if (changes['uwSettings'] && changes['uwSettings'].newValue) {
|
if (changes['uwSettings'] && changes['uwSettings'].newValue) {
|
||||||
this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
|
this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
|
||||||
}
|
}
|
||||||
|
const parsedSettings = JSON.parse(changes.uwSettings.newValue);
|
||||||
if(changes['uwSettings'] && changes['uwSettings'].newValue) {
|
if(changes['uwSettings'] && changes['uwSettings'].newValue) {
|
||||||
ths.setActive(JSON.parse(changes.uwSettings.newValue));
|
this.setActive(parsedSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.updateCallback) {
|
if(!parsedSettings.preventReload && this.updateCallback) {
|
||||||
try {
|
try {
|
||||||
updateCallback(ths);
|
updateCallback(ths);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.log('error', 'settings', "[Settings] CALLING UPDATE CALLBACK FAILED.")
|
this.logger.log('error', 'settings', "[Settings] CALLING UPDATE CALLBACK FAILED.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else if (currentBrowser.chrome) {
|
|
||||||
chrome.storage.onChanged.addListener( (changes, area) => {
|
|
||||||
this.logger.log('info', 'settings', "[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
|
|
||||||
if (changes['uwSettings'] && changes['uwSettings'].newValue) {
|
|
||||||
this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
|
|
||||||
}
|
|
||||||
if(changes['uwSettings'] && changes['uwSettings'].newValue) {
|
|
||||||
ths.setActive(JSON.parse(changes.uwSettings.newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.updateCallback) {
|
|
||||||
try {
|
|
||||||
updateCallback(ths);
|
|
||||||
} catch (e) {
|
|
||||||
this.logger.log('error', 'settings',"[Settings] CALLING UPDATE CALLBACK FAILED.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getExtensionVersion() {
|
getExtensionVersion() {
|
||||||
@ -156,8 +144,23 @@ class Settings {
|
|||||||
// apply all remaining patches
|
// apply all remaining patches
|
||||||
this.logger.log('info', 'settings', `[Settings::applySettingsPatches] There are ${patches.length - index} settings patches to apply`);
|
this.logger.log('info', 'settings', `[Settings::applySettingsPatches] There are ${patches.length - index} settings patches to apply`);
|
||||||
while (index < patches.length) {
|
while (index < patches.length) {
|
||||||
|
const updateFn = patches[index].updateFn;
|
||||||
delete patches[index].forVersion;
|
delete patches[index].forVersion;
|
||||||
|
delete patches[index].updateFn;
|
||||||
|
|
||||||
|
if (Object.keys(patches[index]).length > 0) {
|
||||||
ObjectCopy.overwrite(this.active, patches[index]);
|
ObjectCopy.overwrite(this.active, patches[index]);
|
||||||
|
}
|
||||||
|
if (updateFn) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
updateFn(this.active, this.getDefaultSettings());
|
||||||
|
} catch (e) {
|
||||||
|
console.log("!!!!", e)
|
||||||
|
this.logger.log('error', 'settings', '[Settings::applySettingsPatches] Failed to execute update function. Keeping settings object as-is. Error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,11 +174,12 @@ class Settings {
|
|||||||
// | needed. In this case, we assume we're on the current version
|
// | needed. In this case, we assume we're on the current version
|
||||||
const oldVersion = (settings && settings.version) || this.version;
|
const oldVersion = (settings && settings.version) || this.version;
|
||||||
|
|
||||||
if(Debug.debug) {
|
if (settings) {
|
||||||
this.logger.log('info', 'settings', "[Settings::init] Configuration fetched from storage:", settings,
|
this.logger.log('info', 'settings', "[Settings::init] Configuration fetched from storage:", settings,
|
||||||
"\nlast saved with:", settings.version,
|
"\nlast saved with:", settings.version,
|
||||||
"\ncurrent version:", this.version
|
"\ncurrent version:", this.version
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// if (Debug.flushStoredSettings) {
|
// if (Debug.flushStoredSettings) {
|
||||||
// this.logger.log('info', 'settings', "%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd");
|
// this.logger.log('info', 'settings', "%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd");
|
||||||
@ -185,7 +189,6 @@ class Settings {
|
|||||||
// this.set(this.active);
|
// this.set(this.active);
|
||||||
// return this.active;
|
// return this.active;
|
||||||
// }
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// if there's no settings saved, return default settings.
|
// if there's no settings saved, return default settings.
|
||||||
if(! settings || (Object.keys(settings).length === 0 && settings.constructor === Object)) {
|
if(! settings || (Object.keys(settings).length === 0 && settings.constructor === Object)) {
|
||||||
@ -279,8 +282,10 @@ class Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async set(extensionConf) {
|
async set(extensionConf, options) {
|
||||||
|
if (!options || !options.forcePreserveVersion) {
|
||||||
extensionConf.version = this.version;
|
extensionConf.version = this.version;
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
|
this.logger.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
|
||||||
|
|
||||||
@ -299,11 +304,17 @@ class Settings {
|
|||||||
this.active[prop] = value;
|
this.active[prop] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
async save() {
|
async save(options) {
|
||||||
if (Debug.debug && Debug.storage) {
|
if (Debug.debug && Debug.storage) {
|
||||||
console.log("[Settings::save] Saving active settings:", this.active);
|
console.log("[Settings::save] Saving active settings:", this.active);
|
||||||
}
|
}
|
||||||
|
this.active.preventReload = undefined;
|
||||||
|
await this.set(this.active, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async saveWithoutReload() {
|
||||||
|
this.active.preventReload = true;
|
||||||
await this.set(this.active);
|
await this.set(this.active);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,6 +533,15 @@ class Settings {
|
|||||||
return this.active.sites['@global'].stretch;
|
return this.active.sites['@global'].stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDefaultCropPersistenceMode(site) {
|
||||||
|
if (site && this.active.sites[site] && this.active.sites[site].cropModePersistence !== Stretch.Default) {
|
||||||
|
return this.active.sites[site].cropModePersistence;
|
||||||
|
}
|
||||||
|
|
||||||
|
// persistence mode thing is missing from settings by default
|
||||||
|
return this.active.sites['@global'].cropModePersistence || CropModePersistence.Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
getDefaultVideoAlignment(site) {
|
getDefaultVideoAlignment(site) {
|
||||||
if (site && this.active.sites[site] && this.active.sites[site].videoAlignment !== VideoAlignment.Default) {
|
if (site && this.active.sites[site] && this.active.sites[site].videoAlignment !== VideoAlignment.Default) {
|
||||||
return this.active.sites[site].videoAlignment;
|
return this.active.sites[site].videoAlignment;
|
||||||
|
@ -492,6 +492,13 @@ class ArDetector {
|
|||||||
this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: trueAr}, {type: AspectRatio.Automatic, ratio: trueAr});
|
this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: trueAr}, {type: AspectRatio.Automatic, ratio: trueAr});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearImageData(id) {
|
||||||
|
if (ArrayBuffer.transfer) {
|
||||||
|
ArrayBuffer.transfer(id, 0);
|
||||||
|
}
|
||||||
|
id = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
frameCheck(){
|
frameCheck(){
|
||||||
if(! this.video){
|
if(! this.video){
|
||||||
this.logger.log('error', 'debug', `%c[ArDetect::frameCheck] <@${this.arid}> Video went missing. Destroying current instance of videoData.`);
|
this.logger.log('error', 'debug', `%c[ArDetect::frameCheck] <@${this.arid}> Video went missing. Destroying current instance of videoData.`);
|
||||||
@ -581,6 +588,7 @@ class ArDetector {
|
|||||||
|
|
||||||
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Letterbox not detected in fast test. Letterbox is either gone or we manually corrected aspect ratio. Nothing will be done.`, "color: #fa3");
|
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Letterbox not detected in fast test. Letterbox is either gone or we manually corrected aspect ratio. Nothing will be done.`, "color: #fa3");
|
||||||
|
|
||||||
|
this.clearImageData(imageData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,6 +606,7 @@ class ArDetector {
|
|||||||
// if both succeed, then aspect ratio hasn't changed.
|
// if both succeed, then aspect ratio hasn't changed.
|
||||||
if (!guardLineOut.imageFail && !guardLineOut.blackbarFail) {
|
if (!guardLineOut.imageFail && !guardLineOut.blackbarFail) {
|
||||||
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] guardLine tests were successful. (no imagefail and no blackbarfail)\n`, "color: #afa", guardLineOut);
|
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] guardLine tests were successful. (no imagefail and no blackbarfail)\n`, "color: #afa", guardLineOut);
|
||||||
|
this.clearImageData(imageData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,6 +626,7 @@ class ArDetector {
|
|||||||
this.guardLine.reset();
|
this.guardLine.reset();
|
||||||
this.noLetterboxCanvasReset = true;
|
this.noLetterboxCanvasReset = true;
|
||||||
|
|
||||||
|
this.clearImageData(imageData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,6 +653,7 @@ class ArDetector {
|
|||||||
|
|
||||||
triggerTimeout = this.getTimeout(baseTimeout, startTime);
|
triggerTimeout = this.getTimeout(baseTimeout, startTime);
|
||||||
this.scheduleFrameCheck(triggerTimeout);
|
this.scheduleFrameCheck(triggerTimeout);
|
||||||
|
this.clearImageData(imageData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -664,6 +675,8 @@ class ArDetector {
|
|||||||
// rob ni bil zaznan, zato ne naredimo ničesar.
|
// rob ni bil zaznan, zato ne naredimo ničesar.
|
||||||
// no edge was detected. Let's leave things as they were
|
// no edge was detected. Let's leave things as they were
|
||||||
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Edge wasn't detected with findBars`, "color: #fa3", edgePost, "EdgeStatus.AR_KNOWN:", EdgeStatus.AR_KNOWN);
|
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Edge wasn't detected with findBars`, "color: #fa3", edgePost, "EdgeStatus.AR_KNOWN:", EdgeStatus.AR_KNOWN);
|
||||||
|
|
||||||
|
this.clearImageData(imageData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,14 +709,16 @@ class ArDetector {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// edges weren't gucci, so we'll just reset
|
// edges weren't gucci, so we'll just reset
|
||||||
// the aspect ratio to defaults
|
// the aspect ratio to defaults
|
||||||
try {
|
this.logger.log('error', 'arDetect', `%c[ArDetect::frameCheck] There was a problem setting blackbar. Doing nothing. Error:`, e);
|
||||||
|
|
||||||
this.guardline.reset();
|
this.guardline.reset();
|
||||||
} catch (e) {
|
// WE DO NOT RESET ASPECT RATIO HERE IN CASE OF PROBLEMS, CAUSES UNWARRANTED RESETS:
|
||||||
// guardline wasn't gucci either, but we'll just ignore
|
// (eg. here: https://www.youtube.com/watch?v=nw5Z93Yt-UQ&t=410)
|
||||||
// that and reset the aspect ratio anyway
|
//
|
||||||
}
|
// this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()});
|
||||||
this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clearImageData(imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetBlackLevel(){
|
resetBlackLevel(){
|
||||||
|
@ -34,7 +34,7 @@ class GuardLine {
|
|||||||
// to odstrani vse neveljavne nastavitve in vse možnosti, ki niso smiselne
|
// to odstrani vse neveljavne nastavitve in vse možnosti, ki niso smiselne
|
||||||
// this removes any configs with invalid values or values that dont make sense
|
// this removes any configs with invalid values or values that dont make sense
|
||||||
if (bbTop < 0 || bbBottom >= this.conf.canvas.height ){
|
if (bbTop < 0 || bbBottom >= this.conf.canvas.height ){
|
||||||
throw "INVALID_SETTINGS_IN_GUARDLINE"
|
throw {error: "INVALID_SETTINGS_IN_GUARDLINE", bbTop, bbBottom}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.blackbar = {
|
this.blackbar = {
|
||||||
|
@ -92,6 +92,8 @@ class CommsClient {
|
|||||||
this.pageInfo.setManualTick(message.arg);
|
this.pageInfo.setManualTick(message.arg);
|
||||||
} else if (message.cmd === 'autoar-tick') {
|
} else if (message.cmd === 'autoar-tick') {
|
||||||
this.pageInfo.tick();
|
this.pageInfo.tick();
|
||||||
|
} else if (message.cmd === 'set-ar-persistence') {
|
||||||
|
this.pageInfo.setArPersistence(message.arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import Debug from '../../conf/Debug';
|
|||||||
import VideoData from './VideoData';
|
import VideoData from './VideoData';
|
||||||
import RescanReason from './enums/RescanReason';
|
import RescanReason from './enums/RescanReason';
|
||||||
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
||||||
|
import CropModePersistence from '../../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
if(Debug.debug)
|
if(Debug.debug)
|
||||||
console.log("Loading: PageInfo.js");
|
console.log("Loading: PageInfo.js");
|
||||||
@ -20,23 +21,38 @@ class PageInfo {
|
|||||||
this.lastUrl = window.location.href;
|
this.lastUrl = window.location.href;
|
||||||
this.extensionMode = extensionMode;
|
this.extensionMode = extensionMode;
|
||||||
this.readOnly = readOnly;
|
this.readOnly = readOnly;
|
||||||
|
this.defaultCrop = undefined;
|
||||||
|
this.currentCrop = undefined;
|
||||||
|
|
||||||
if (comms){
|
if (comms){
|
||||||
this.comms = comms;
|
this.comms = comms;
|
||||||
}
|
}
|
||||||
|
|
||||||
// request inject css immediately
|
|
||||||
try {
|
try {
|
||||||
|
// request inject css immediately
|
||||||
const playerStyleString = this.settings.active.sites[window.location.host].css.replace('\\n', '');
|
const playerStyleString = this.settings.active.sites[window.location.host].css.replace('\\n', '');
|
||||||
this.comms.sendMessage({
|
this.comms.sendMessage({
|
||||||
cmd: 'inject-css',
|
cmd: 'inject-css',
|
||||||
cssString: playerStyleString
|
cssString: playerStyleString
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// do nothing. It's ok if there's no special settings for the player element
|
// do nothing. It's ok if there's no special settings for the player element or crop persistence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try getting default crop immediately.
|
||||||
|
const cropModePersistence = this.settings.getDefaultCropPersistenceMode(window.location.host);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// if (cropModePersistence === CropModePersistence.Forever) {
|
||||||
|
// this.defaultCrop = this.settings.active.sites[window.location.host].defaultCrop;
|
||||||
|
// } else if (cropModePersistence === CropModePersistence.CurrentSession) {
|
||||||
|
// this.defaultCrop = JSON.parse(sessionStorage.getItem('uw-crop-mode-session-persistence'));
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// // do nothing. It's ok if there's no special settings for the player element or crop persistence
|
||||||
|
// }
|
||||||
|
this.currentCrop = this.defaultCrop;
|
||||||
|
|
||||||
this.rescan(RescanReason.PERIODIC);
|
this.rescan(RescanReason.PERIODIC);
|
||||||
this.scheduleUrlCheck();
|
this.scheduleUrlCheck();
|
||||||
|
|
||||||
@ -197,11 +213,17 @@ class PageInfo {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
v = new VideoData(video, this.settings, this);
|
v = new VideoData(video, this.settings, this);
|
||||||
|
|
||||||
|
if (!this.defaultCrop) {
|
||||||
if (!v.invalid) {
|
if (!v.invalid) {
|
||||||
v.initArDetection();
|
v.initArDetection();
|
||||||
} else {
|
} else {
|
||||||
this.logger.log('error', 'debug', 'Video is invalid. Aard not started.', video);
|
this.logger.log('error', 'debug', 'Video is invalid. Aard not started.', video);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.logger.log('info', 'debug', 'Default crop is specified for this site. Not starting aard.');
|
||||||
|
}
|
||||||
|
|
||||||
this.videos.push(v);
|
this.videos.push(v);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.log('error', 'debug', "rescan error: failed to initialize videoData. Skipping this video.",e);
|
this.logger.log('error', 'debug', "rescan error: failed to initialize videoData. Skipping this video.",e);
|
||||||
@ -216,7 +238,7 @@ class PageInfo {
|
|||||||
// če smo ostali brez videev, potem odregistriraj stran.
|
// če smo ostali brez videev, potem odregistriraj stran.
|
||||||
// če nismo ostali brez videev, potem registriraj stran.
|
// če nismo ostali brez videev, potem registriraj stran.
|
||||||
//
|
//
|
||||||
// if we're left withotu videos on the current page, we unregister the page.
|
// if we're left without videos on the current page, we unregister the page.
|
||||||
// if we have videos, we call register.
|
// if we have videos, we call register.
|
||||||
if (this.comms) {
|
if (this.comms) {
|
||||||
if (this.videos.length != oldVideoCount) { // only if number of videos changed, tho
|
if (this.videos.length != oldVideoCount) { // only if number of videos changed, tho
|
||||||
@ -551,6 +573,53 @@ class PageInfo {
|
|||||||
setKeyboardShortcutsEnabled(state) {
|
setKeyboardShortcutsEnabled(state) {
|
||||||
this.actionHandler.setKeybordLocal(state);
|
this.actionHandler.setKeybordLocal(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setArPersistence(persistenceMode) {
|
||||||
|
// name of this function is mildly misleading — we don't really _set_ ar persistence. (Ar persistence
|
||||||
|
// mode is set and saved via popup or keyboard shortcuts, if user defined them) We just save the current
|
||||||
|
// aspect ratio whenever aspect ratio persistence mode changes.
|
||||||
|
if (persistenceMode === CropModePersistence.CurrentSession) {
|
||||||
|
sessionStorage.setItem('uw-crop-mode-session-persistence', JSON.stringify(this.currentCrop));
|
||||||
|
} else if (persistenceMode === CropModePersistence.Forever) {
|
||||||
|
if (this.settings.active.sites[window.location.host]) {
|
||||||
|
// | key may be missing, so we do this
|
||||||
|
this.settings.active.sites[window.location.host]['defaultAr'] = this.currentCrop;
|
||||||
|
} else {
|
||||||
|
this.settings.active.sites[window.location.host] = this.settings.getDefaultOption();
|
||||||
|
this.settings.active.sites[window.location.host]['defaultAr'] = this.currentCrop;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.settings.saveWithoutReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCurrentCrop(ar) {
|
||||||
|
this.currentCrop = ar;
|
||||||
|
// This means crop persistance is disabled. If crop persistance is enabled, then settings for current
|
||||||
|
// site MUST exist (crop persistence mode is disabled by default)
|
||||||
|
|
||||||
|
const cropModePersistence = this.settings.getDefaultCropPersistenceMode(window.location.host);
|
||||||
|
|
||||||
|
if (cropModePersistence === CropModePersistence.Disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.defaultCrop = ar;
|
||||||
|
|
||||||
|
if (cropModePersistence === CropModePersistence.CurrentSession) {
|
||||||
|
sessionStorage.setItem('uw-crop-mode-session-persistence', JSON.stringify(ar));
|
||||||
|
} else if (cropModePersistence === CropModePersistence.Forever) {
|
||||||
|
if (this.settings.active.sites[window.location.host]) {
|
||||||
|
// | key may be missing, so we do this
|
||||||
|
this.settings.active.sites[window.location.host]['defaultAr'] = ar;
|
||||||
|
} else {
|
||||||
|
this.settings.active.sites[window.location.host] = this.settings.getDefaultOption();
|
||||||
|
this.settings.active.sites[window.location.host]['defaultAr'] = ar;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.settings.saveWithoutReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PageInfo;
|
export default PageInfo;
|
||||||
|
@ -44,6 +44,7 @@ class VideoData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.resizer = new Resizer(this);
|
this.resizer = new Resizer(this);
|
||||||
|
|
||||||
this.arDetector = new ArDetector(this); // this starts Ar detection. needs optional parameter that prevets ardetdctor from starting
|
this.arDetector = new ArDetector(this); // this starts Ar detection. needs optional parameter that prevets ardetdctor from starting
|
||||||
// player dimensions need to be in:
|
// player dimensions need to be in:
|
||||||
// this.player.dimensions
|
// this.player.dimensions
|
||||||
@ -59,6 +60,11 @@ class VideoData {
|
|||||||
|
|
||||||
// start fallback video/player size detection
|
// start fallback video/player size detection
|
||||||
this.fallbackChangeDetection();
|
this.fallbackChangeDetection();
|
||||||
|
|
||||||
|
// force reload last aspect ratio (if default crop ratio exists)
|
||||||
|
if (this.pageInfo.defaultCrop) {
|
||||||
|
this.resizer.setAr(this.pageInfo.defaultCrop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fallbackChangeDetection() {
|
async fallbackChangeDetection() {
|
||||||
@ -80,19 +86,31 @@ class VideoData {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let confirmAspectRatioRestore = false;
|
||||||
|
|
||||||
for (let mutation of mutationList) {
|
for (let mutation of mutationList) {
|
||||||
if (mutation.type === 'attributes'
|
if (mutation.type === 'attributes') {
|
||||||
&& mutation.attributeName === 'class'
|
if (mutation.attributeName === 'class') {
|
||||||
&& !context.video.classList.contains(this.userCssClassName) ) {
|
if(!context.video.classList.contains(this.userCssClassName) ) {
|
||||||
// force the page to include our class in classlist, if the classlist has been removed
|
// force the page to include our class in classlist, if the classlist has been removed
|
||||||
// while classList.add() doesn't duplicate classes (does nothing if class is already added),
|
// while classList.add() doesn't duplicate classes (does nothing if class is already added),
|
||||||
// we still only need to make sure we're only adding our class to classlist if it has been
|
// we still only need to make sure we're only adding our class to classlist if it has been
|
||||||
// removed. classList.add() will _still_ trigger mutation (even if classlist wouldn't change).
|
// removed. classList.add() will _still_ trigger mutation (even if classlist wouldn't change).
|
||||||
// This is a problem because INFINITE RECURSION TIME, and we _really_ don't want that.
|
// This is a problem because INFINITE RECURSION TIME, and we _really_ don't want that.
|
||||||
|
|
||||||
context.video.classList.add(this.userCssClassName);
|
context.video.classList.add(this.userCssClassName);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// always trigger refresh on class changes, since change of classname might trigger change
|
||||||
|
// of the player size as well.
|
||||||
|
confirmAspectRatioRestore = true;
|
||||||
|
}
|
||||||
|
if (mutation.attributeName === 'style') {
|
||||||
|
confirmAspectRatioRestore = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!confirmAspectRatioRestore) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// adding player observer taught us that if element size gets triggered by a class, then
|
// adding player observer taught us that if element size gets triggered by a class, then
|
||||||
@ -131,8 +149,9 @@ class VideoData {
|
|||||||
const pw = +(pcs.width.split('px')[0]);
|
const pw = +(pcs.width.split('px')[0]);
|
||||||
|
|
||||||
// TODO: check & account for panning and alignment
|
// TODO: check & account for panning and alignment
|
||||||
if (this.isWithin(vh, (ph - (translateY / 2)), 2)
|
if (transformMatrix[0] !== 'none'
|
||||||
&& this.isWithin(vw, (pw - (translateX / 2)), 2)) {
|
&& this.isWithin(vh, (ph - (translateY * 2)), 2)
|
||||||
|
&& this.isWithin(vw, (pw - (translateX * 2)), 2)) {
|
||||||
} else {
|
} else {
|
||||||
this.player.forceRefreshPlayerElement();
|
this.player.forceRefreshPlayerElement();
|
||||||
this.restoreAr();
|
this.restoreAr();
|
||||||
@ -162,7 +181,7 @@ class VideoData {
|
|||||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(this.arDetector){
|
if (this.arDetector){
|
||||||
this.arDetector.init();
|
this.arDetector.init();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@ -177,8 +196,8 @@ class VideoData {
|
|||||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!this.arDetector) {
|
if (!this.arDetector) {
|
||||||
this.arDetector.init();
|
this.initArDetection();
|
||||||
}
|
}
|
||||||
this.arDetector.start();
|
this.arDetector.start();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import ExtensionMode from '../../../common/enums/extension-mode.enum';
|
|||||||
import Stretch from '../../../common/enums/stretch.enum';
|
import Stretch from '../../../common/enums/stretch.enum';
|
||||||
import VideoAlignment from '../../../common/enums/video-alignment.enum';
|
import VideoAlignment from '../../../common/enums/video-alignment.enum';
|
||||||
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
||||||
|
import CropModePersistance from '../../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
if(Debug.debug) {
|
if(Debug.debug) {
|
||||||
console.log("Loading: Resizer.js");
|
console.log("Loading: Resizer.js");
|
||||||
@ -119,7 +120,7 @@ class Resizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setAr(ar, lastAr){
|
setAr(ar, lastAr) {
|
||||||
if (this.destroyed) {
|
if (this.destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -130,12 +131,36 @@ class Resizer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const siteSettings = this.settings.active.sites[window.location.host];
|
||||||
|
|
||||||
|
// reset zoom, but only on aspect ratio switch. We also know that aspect ratio gets converted to
|
||||||
|
// AspectRatio.Fixed when zooming, so let's keep that in mind
|
||||||
|
if (ar.type !== AspectRatio.Fixed) {
|
||||||
|
this.zoom.reset();
|
||||||
|
this.resetPan();
|
||||||
|
} else if (ar.ratio !== this.lastAr.ratio) {
|
||||||
|
// we must check against this.lastAR.ratio because some calls provide same value for ar and lastAr
|
||||||
|
this.zoom.reset();
|
||||||
|
this.resetPan();
|
||||||
|
}
|
||||||
|
|
||||||
|
// most everything that could go wrong went wrong by this stage, and returns can happen afterwards
|
||||||
|
// this means here's the optimal place to set or forget aspect ratio. Saving of current crop ratio
|
||||||
|
// is handled in pageInfo.updateCurrentCrop(), which also makes sure to persist aspect ratio if ar
|
||||||
|
// is set to persist between videos / through current session / until manual reset.
|
||||||
|
if (ar.type === AspectRatio.Automatic ||
|
||||||
|
ar.type === AspectRatio.Reset ||
|
||||||
|
ar.type === AspectRatio.Initial ) {
|
||||||
|
// reset/undo default
|
||||||
|
this.conf.pageInfo.updateCurrentCrop(undefined);
|
||||||
|
} else {
|
||||||
|
this.conf.pageInfo.updateCurrentCrop(ar);
|
||||||
|
}
|
||||||
|
|
||||||
if (ar.type === AspectRatio.Automatic ||
|
if (ar.type === AspectRatio.Automatic ||
|
||||||
ar.type === AspectRatio.Reset && this.lastAr.type === AspectRatio.Initial) {
|
ar.type === AspectRatio.Reset && this.lastAr.type === AspectRatio.Initial) {
|
||||||
// some sites do things that interfere with our site (and aspect ratio setting in general)
|
// some sites do things that interfere with our site (and aspect ratio setting in general)
|
||||||
// first, we check whether video contains anything we don't like
|
// first, we check whether video contains anything we don't like
|
||||||
|
|
||||||
const siteSettings = this.settings.active.sites[window.location.host];
|
|
||||||
if (siteSettings && siteSettings.autoarPreventConditions) {
|
if (siteSettings && siteSettings.autoarPreventConditions) {
|
||||||
if (siteSettings.autoarPreventConditions.videoStyleString) {
|
if (siteSettings.autoarPreventConditions.videoStyleString) {
|
||||||
const styleString = (this.video.getAttribute('style') || '').split(';');
|
const styleString = (this.video.getAttribute('style') || '').split(';');
|
||||||
@ -170,6 +195,8 @@ class Resizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (lastAr) {
|
if (lastAr) {
|
||||||
this.lastAr = this.calculateRatioForLegacyOptions(lastAr);
|
this.lastAr = this.calculateRatioForLegacyOptions(lastAr);
|
||||||
ar = this.calculateRatioForLegacyOptions(ar);
|
ar = this.calculateRatioForLegacyOptions(ar);
|
||||||
@ -247,6 +274,10 @@ class Resizer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toFixedAr() {
|
||||||
|
this.lastAr.type = AspectRatio.Fixed;
|
||||||
|
}
|
||||||
|
|
||||||
resetLastAr() {
|
resetLastAr() {
|
||||||
this.lastAr = {type: AspectRatio.Initial};
|
this.lastAr = {type: AspectRatio.Initial};
|
||||||
}
|
}
|
||||||
@ -272,6 +303,9 @@ class Resizer {
|
|||||||
// dont allow weird floats
|
// dont allow weird floats
|
||||||
this.videoAlignment = VideoAlignment.Center;
|
this.videoAlignment = VideoAlignment.Center;
|
||||||
|
|
||||||
|
// because non-fixed aspect ratios reset panning:
|
||||||
|
this.toFixedAr();
|
||||||
|
|
||||||
const player = this.conf.player.element;
|
const player = this.conf.player.element;
|
||||||
|
|
||||||
const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth;
|
const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth;
|
||||||
@ -283,6 +317,11 @@ class Resizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetPan() {
|
||||||
|
this.pan = {};
|
||||||
|
this.videoAlignment = this.settings.getDefaultVideoAlignment(window.location.host);
|
||||||
|
}
|
||||||
|
|
||||||
setPan(relativeMousePosX, relativeMousePosY){
|
setPan(relativeMousePosX, relativeMousePosY){
|
||||||
// relativeMousePos[X|Y] - on scale from 0 to 1, how close is the mouse to player edges.
|
// relativeMousePos[X|Y] - on scale from 0 to 1, how close is the mouse to player edges.
|
||||||
// use these values: top, left: 0, bottom, right: 1
|
// use these values: top, left: 0, bottom, right: 1
|
||||||
|
@ -120,14 +120,31 @@ class Scaler {
|
|||||||
actualHeight: 0, // height of the video (excluding letterbox) when <video> tag height is equal to height
|
actualHeight: 0, // height of the video (excluding letterbox) when <video> tag height is equal to height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fileAr < playerAr) {
|
||||||
if (fileAr < ar.ratio){
|
if (fileAr < ar.ratio){
|
||||||
// imamo letterbox zgoraj in spodaj -> spremenimo velikost videa (a nikoli širše od ekrana)
|
// in this situation we have to crop letterbox on top/bottom of the player
|
||||||
// letterbox -> change video size (but never to wider than monitor width)
|
// we cut it, but never more than the player
|
||||||
videoDimensions.xFactor = Math.min(ar.ratio, playerAr) / fileAr;
|
videoDimensions.xFactor = Math.min(ar.ratio, playerAr) / fileAr;
|
||||||
videoDimensions.yFactor = videoDimensions.xFactor;
|
videoDimensions.yFactor = videoDimensions.xFactor;
|
||||||
} else {
|
} else {
|
||||||
|
// in this situation, we would be cutting pillarbox. Inside horizontal player.
|
||||||
|
// I don't think so. Except exceptions, we'll wait for bug reports.
|
||||||
|
videoDimensions.xFactor = 1;
|
||||||
|
videoDimensions.yFactor = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fileAr < ar.ratio || playerAr < ar.ratio){
|
||||||
|
// in this situation, we need to add extra letterbox on top of our letterbox
|
||||||
|
// this means we simply don't crop anything _at all_
|
||||||
|
videoDimensions.xFactor = 1;
|
||||||
|
videoDimensions.yFactor = 1;
|
||||||
|
} else {
|
||||||
|
// meant for handling pillarbox crop. not quite implemented.
|
||||||
videoDimensions.xFactor = fileAr / Math.min(ar.ratio, playerAr);
|
videoDimensions.xFactor = fileAr / Math.min(ar.ratio, playerAr);
|
||||||
videoDimensions.yFactor = videoDimensions.xFactor;
|
videoDimensions.yFactor = videoDimensions.xFactor;
|
||||||
|
// videoDimensions.xFactor = Math.max(ar.ratio, playerAr) * fileAr;
|
||||||
|
// videoDimensions.yFactor = videoDimensions.xFactor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
|
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
|
||||||
|
@ -108,7 +108,7 @@ class Stretcher {
|
|||||||
yFactor: 1
|
yFactor: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
if(playerAr >= videoAr){
|
if (playerAr >= videoAr){
|
||||||
// player adds PILLARBOX
|
// player adds PILLARBOX
|
||||||
|
|
||||||
if(actualAr >= playerAr){
|
if(actualAr >= playerAr){
|
||||||
|
@ -18,6 +18,7 @@ class Zoom {
|
|||||||
|
|
||||||
reset(){
|
reset(){
|
||||||
this.scale = 1;
|
this.scale = 1;
|
||||||
|
this.logScale = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomStep(amount){
|
zoomStep(amount){
|
||||||
@ -34,6 +35,8 @@ class Zoom {
|
|||||||
|
|
||||||
this.logger.log('info', 'debug', "[Zoom::zoomStep] changing zoom by", amount, ". New zoom level:", this.scale);
|
this.logger.log('info', 'debug', "[Zoom::zoomStep] changing zoom by", amount, ". New zoom level:", this.scale);
|
||||||
|
|
||||||
|
this.conf.resizer.toFixedAr();
|
||||||
|
|
||||||
this.conf.restoreAr();
|
this.conf.restoreAr();
|
||||||
this.conf.announceZoom(this.scale);
|
this.conf.announceZoom(this.scale);
|
||||||
}
|
}
|
||||||
|
@ -44,26 +44,26 @@ class UW {
|
|||||||
if (!this.logger) {
|
if (!this.logger) {
|
||||||
const loggingOptions = {
|
const loggingOptions = {
|
||||||
logToFile: false,
|
logToFile: false,
|
||||||
logToConsole: false,
|
logToConsole: true,
|
||||||
fileOptions: {
|
fileOptions: {
|
||||||
// really the same stuff as consoleOptions
|
// really the same stuff as consoleOptions
|
||||||
},
|
},
|
||||||
consoleOptions: {
|
consoleOptions: {
|
||||||
enabled: true, // if logging is enabled at all
|
enabled: true, // if logging is enabled at all
|
||||||
'debug': true,
|
// 'debug': true,
|
||||||
'init': true,
|
// 'init': true,
|
||||||
'settings': true,
|
// 'settings': true,
|
||||||
'keyboard': false,
|
// 'keyboard': true,
|
||||||
'mousemove': false,
|
// 'mousemove': false,
|
||||||
'actionHandler': false,
|
// 'actionHandler': false,
|
||||||
'comms': false,
|
// 'comms': false,
|
||||||
'playerDetect': false,
|
// 'playerDetect': false,
|
||||||
// 'resizer': true,
|
// 'resizer': true,
|
||||||
// 'scaler': true,
|
// 'scaler': true,
|
||||||
// 'stretcher': true,
|
// 'stretcher': true,
|
||||||
'videoRescan': false,
|
// 'videoRescan': false,
|
||||||
'arDetect': false,
|
// 'arDetect': true,
|
||||||
'arDetect_verbose': false,
|
// 'arDetect_verbose': true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.logger = new Logger(loggingOptions);
|
this.logger = new Logger(loggingOptions);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Ultrawidify",
|
"name": "Ultrawidify",
|
||||||
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
||||||
"version": "4.3.1.1",
|
"version": "4.4.0",
|
||||||
"applications": {
|
"applications": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
|
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
|
||||||
|
@ -70,7 +70,7 @@ export default {
|
|||||||
if (this.hasError) {
|
if (this.hasError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.settings.save();
|
this.settings.save({forcePreserveVersion: true});
|
||||||
// this.parsedSettings = JSON.stringify(this.settings.active, null, 2);
|
// this.parsedSettings = JSON.stringify(this.settings.active, null, 2);
|
||||||
// this.lastSettings = JSON.parse(JSON.stringify(this.settings.active));
|
// this.lastSettings = JSON.parse(JSON.stringify(this.settings.active));
|
||||||
const ths = this;
|
const ths = this;
|
||||||
|
@ -39,12 +39,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SetShortcutButton from './SetShortcutButton.vue';
|
import SetShortcutButton from './SetShortcutButton';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SetShortcutButton
|
SetShortcutButton,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
scopeOptions: Object,
|
scopeOptions: Object,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
@focus="initiateKeypress"
|
@focus="initiateKeypress"
|
||||||
@keyup="processKeyup"
|
@keyup="processKeyup"
|
||||||
/>
|
/>
|
||||||
<span v-if="shortcut" @click="$emit('set-shortcut')">(Clear shortcut)</span>
|
<span v-if="shortcut" @click="clearShortcut()">(Clear shortcut)</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -38,6 +38,7 @@ export default {
|
|||||||
if (this.waitingForPress) {
|
if (this.waitingForPress) {
|
||||||
const shortcut = {
|
const shortcut = {
|
||||||
key: event.key,
|
key: event.key,
|
||||||
|
code: event.code,
|
||||||
ctrlKey: event.ctrlKey,
|
ctrlKey: event.ctrlKey,
|
||||||
metaKey: event.metaKey,
|
metaKey: event.metaKey,
|
||||||
altKey: event.altKey,
|
altKey: event.altKey,
|
||||||
@ -50,6 +51,11 @@ export default {
|
|||||||
this.shortcutText = KeyboardShortcutParser.parseShortcut(shortcut);
|
this.shortcutText = KeyboardShortcutParser.parseShortcut(shortcut);
|
||||||
}
|
}
|
||||||
this.waitingForPress = false;
|
this.waitingForPress = false;
|
||||||
|
},
|
||||||
|
clearShortcut() {
|
||||||
|
this.shortcutText = '[click to add shortcut]';
|
||||||
|
this.shortcut = undefined;
|
||||||
|
this.$emit('set-shortcut');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class ExecAction {
|
|||||||
this.site = site;
|
this.site = site;
|
||||||
}
|
}
|
||||||
|
|
||||||
exec(action, scope, frame) {
|
async exec(action, scope, frame) {
|
||||||
for (var cmd of action.cmd) {
|
for (var cmd of action.cmd) {
|
||||||
if (scope === 'page') {
|
if (scope === 'page') {
|
||||||
const message = {
|
const message = {
|
||||||
@ -27,6 +27,23 @@ class ExecAction {
|
|||||||
Comms.sendMessage(message);
|
Comms.sendMessage(message);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// set-ar-persistence sends stuff to content scripts as well (!)
|
||||||
|
// it's important to do that BEFORE the save step
|
||||||
|
if (cmd.action === 'set-ar-persistence') {
|
||||||
|
// even when setting global defaults, we only send message to the current tab in
|
||||||
|
// order to avoid problems related to
|
||||||
|
const message = {
|
||||||
|
forwardToActive: true,
|
||||||
|
targetFrame: frame,
|
||||||
|
frame: frame,
|
||||||
|
cmd: cmd.action,
|
||||||
|
arg: cmd.arg,
|
||||||
|
}
|
||||||
|
// this hopefully delays settings.save() until current crops are saved on the site
|
||||||
|
// and thus avoid any fucky-wuckies
|
||||||
|
await Comms.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
let site = this.site;
|
let site = this.site;
|
||||||
if (scope === 'global') {
|
if (scope === 'global') {
|
||||||
site = '@global';
|
site = '@global';
|
||||||
@ -48,11 +65,17 @@ class ExecAction {
|
|||||||
this.settings.active.sites[site].autoar = cmd.arg;
|
this.settings.active.sites[site].autoar = cmd.arg;
|
||||||
} else if (cmd.action === 'set-keyboard') {
|
} else if (cmd.action === 'set-keyboard') {
|
||||||
this.settings.active.sites[site].keyboardShortcutsEnabled = cmd.arg;
|
this.settings.active.sites[site].keyboardShortcutsEnabled = cmd.arg;
|
||||||
|
} else if (cmd.action === 'set-ar-persistence') {
|
||||||
|
this.settings.active.sites[site]['cropModePersistence'] = cmd.arg;
|
||||||
|
this.settings.saveWithoutReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd.action !== 'set-ar-persistence') {
|
||||||
this.settings.save();
|
this.settings.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ExecAction;
|
export default ExecAction;
|
||||||
|
@ -42,9 +42,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- CROP MODE PERSISTENCE -->
|
||||||
|
<div v-if="cropModePersistenceActions.length"
|
||||||
|
class="w100"
|
||||||
|
>
|
||||||
|
<div class="label">Persists crop mode <template v-if="scope === 'site'">for {{site}}</template>:</div>
|
||||||
|
<div class="flex flex-row flex-wrap">
|
||||||
|
<ShortcutButton v-for="(action, index) of cropModePersistenceActions"
|
||||||
|
class="flex flex-grow button b3"
|
||||||
|
:class="{'setting-selected': getCurrent('cropModePersistence') === action.cmd[0].arg}"
|
||||||
|
:key="index"
|
||||||
|
:label="(action.scopes[scope] && action.scopes[scope].label) ? action.scopes[scope].label : action.label"
|
||||||
|
:shortcut="parseShortcut(action)"
|
||||||
|
@click.native="execAction(action)"
|
||||||
|
>
|
||||||
|
</ShortcutButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- DEFAULT SETTINGS -->
|
<!-- DEFAULT SETTINGS -->
|
||||||
<div v-if="stretchActions.length">
|
<div v-if="stretchActions.length">
|
||||||
<div class="label">Default stretching mode:</div>
|
<div class="label experimental">Default stretching mode:</div>
|
||||||
<div class="flex flex-row flex-wrap">
|
<div class="flex flex-row flex-wrap">
|
||||||
<ShortcutButton v-for="(action, index) of stretchActions"
|
<ShortcutButton v-for="(action, index) of stretchActions"
|
||||||
class="flex b3 flex-grow button"
|
class="flex b3 flex-grow button"
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="aspectRatioActions.length">
|
<div v-if="aspectRatioActions.length">
|
||||||
<div class="label">Cropping mode:</div>
|
<div class="label">Cropping mode:</div>
|
||||||
|
<div v-if="cropModePersistence && cropModePersistence > CropModePersistence.Disabled" class="info">
|
||||||
|
Cropping mode will persist
|
||||||
|
<template v-if="cropModePersistence === CropModePersistence.UntilPageReload">until page reload (this includes page navigation!).</template>
|
||||||
|
<template v-if="cropModePersistence === CropModePersistence.CurrentSession">for current session.</template>
|
||||||
|
<template v-if="cropModePersistence === CropModePersistence.Forever">forever (or at least until you change aspect ratio manually).</template>
|
||||||
|
This can be changed in the 'site settings' or 'extension settings' tab.
|
||||||
|
</div>
|
||||||
<div class="flex flex-row flex-wrap">
|
<div class="flex flex-row flex-wrap">
|
||||||
<ShortcutButton v-for="(action, index) of aspectRatioActions"
|
<ShortcutButton v-for="(action, index) of aspectRatioActions"
|
||||||
class="flex b3 flex-grow button"
|
class="flex b3 flex-grow button"
|
||||||
@ -117,11 +124,13 @@ import ExecAction from '../js/ExecAction';
|
|||||||
import KeyboardShortcutParser from '../../common/js/KeyboardShortcutParser';
|
import KeyboardShortcutParser from '../../common/js/KeyboardShortcutParser';
|
||||||
import ShortcutButton from '../../common/components/ShortcutButton';
|
import ShortcutButton from '../../common/components/ShortcutButton';
|
||||||
import ComputeActionsMixin from '../../common/mixins/ComputeActionsMixin';
|
import ComputeActionsMixin from '../../common/mixins/ComputeActionsMixin';
|
||||||
|
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scope: 'page',
|
scope: 'page',
|
||||||
|
CropModePersistence: CropModePersistence,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
@ -131,7 +140,8 @@ export default {
|
|||||||
'settings',
|
'settings',
|
||||||
'frame',
|
'frame',
|
||||||
'zoom',
|
'zoom',
|
||||||
'someSitesDisabledWarning'
|
'someSitesDisabledWarning',
|
||||||
|
'cropModePersistence',
|
||||||
],
|
],
|
||||||
created() {
|
created() {
|
||||||
this.exec = new ExecAction(this.settings);
|
this.exec = new ExecAction(this.settings);
|
||||||
|
@ -2,11 +2,17 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>What's new</h2>
|
<h2>What's new</h2>
|
||||||
<p>Full changelog for older versions <a href="https://github.com/xternal7/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
|
<p>Full changelog for older versions <a href="https://github.com/xternal7/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
|
||||||
<p class="label">4.3.1.1</p>
|
<p class="label">4.4.0</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>[4.3.3.1]</b> Patched twitch.tv</li>
|
<li>Russian users (and users of other non-latin keyboard layouts) can now use keyboard shortcuts by default,
|
||||||
<li>Minor rework of settings page (actions & shortcuts section)</li>
|
without having to rebind them manually. <b>NOTE: this change will only be applied to users who have <i>NOT</i>
|
||||||
<li>Fixed bug that prevented settings page from opening</li>
|
modified their keyboard shortcuts.</b></li>
|
||||||
|
<li>NOTE: when using non-latin layouts, 'zoom' shortcut (`z` by default) uses the position of 'Y' on QWERTY layout.</li>
|
||||||
|
<li>Ability to preserve aspect ratio between different videos (applies to current page and doesn't survive proper
|
||||||
|
page reloads)</li>
|
||||||
|
<li>Changing aspect ratio now resets zooming and panning.</li>
|
||||||
|
<li>Fixed bug where keyboard shortcuts would work while typing in certain text fields</li>
|
||||||
|
<li>Fixed a minor bug with autodetection</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# List of test/sample videos
|
# List of test/sample videos
|
||||||
|
|
||||||
A quick list of videos where letterbox is encoded in the file.
|
A quick list of videos where letterbox is encoded in the file. Inclusion of a video on this list does not imply endorsement of the content expressed by the video or the views expressed by its creator.
|
||||||
|
|
||||||
## Vimeo:
|
## Vimeo:
|
||||||
|
|
||||||
@ -34,11 +34,13 @@ https://www.youtube.com/watch?v=L_u97PqWX6g (also dark at the start)
|
|||||||
|
|
||||||
https://www.youtube.com/watch?v=Xr9Oubxw1gA (triggers autocorrection every now and then)
|
https://www.youtube.com/watch?v=Xr9Oubxw1gA (triggers autocorrection every now and then)
|
||||||
https://www.youtube.com/watch?v=NaTGwlfRB_c (dark, triggers minor corrections)
|
https://www.youtube.com/watch?v=NaTGwlfRB_c (dark, triggers minor corrections)
|
||||||
|
https://www.youtube.com/watch?v=nw5Z93Yt-UQ&t=410 (@ts, dark, resets aspect ratio for no reason within 15s)
|
||||||
|
|
||||||
### Watermark stopping AR
|
### Watermark stopping AR
|
||||||
|
|
||||||
https://www.youtube.com/watch?v=tXTFdDrd7pA
|
https://www.youtube.com/watch?v=tXTFdDrd7pA
|
||||||
|
|
||||||
|
|
||||||
### HARD MODE
|
### HARD MODE
|
||||||
|
|
||||||
For situations that would be _really_ hard to fix (if fix is even possible)
|
For situations that would be _really_ hard to fix (if fix is even possible)
|
||||||
|
Loading…
Reference in New Issue
Block a user