Merge branch 'master' into feature/player-ui
This commit is contained in:
commit
0e0eb57fd9
4
.babelrc
4
.babelrc
@ -1,6 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-optional-chaining"
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
],
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
@ -8,7 +8,7 @@
|
||||
"targets": {
|
||||
"esmodules": true,
|
||||
},
|
||||
}]
|
||||
}],
|
||||
]
|
||||
}
|
||||
// {
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -9,3 +9,7 @@ build/
|
||||
*.pem
|
||||
|
||||
*.kate-swp
|
||||
|
||||
src/res/img/git-ignore/
|
||||
|
||||
test/debug-configs/
|
||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -16,6 +16,16 @@
|
||||
|
||||
## v4.x (current major)
|
||||
|
||||
### v4.5.1
|
||||
|
||||
* Fixed the misalignment issue on netflix ... hopefully.
|
||||
* 'Site settings' tab should now work in Chrome as well ([#126](https://github.com/tamius-han/ultrawidify/issues/126))
|
||||
* Popup interface now refreshes properly ([#127](https://github.com/tamius-han/ultrawidify/issues/127))
|
||||
* Videos should now be scaled correctly when the display is narrower than video's native aspect ratio ([#118](https://github.com/tamius-han/ultrawidify/issues/118))
|
||||
* Edge users using CWS version of the extension get a very aggressive warning when trying to use the extension with Edge
|
||||
* Fullscreen videos on streamable are aligned correctly ([#116](https://github.com/tamius-han/ultrawidify/issues/118)).
|
||||
* **[4.5.1.1]** Streamable fix broke old.reddit + RES on embeds from v.redd.it and streamable.com. We're now using an alternative implementation. ([#128](https://github.com/tamius-han/ultrawidify/issues/128))
|
||||
|
||||
### v4.5.0 (Current)
|
||||
|
||||
* Under the hood: migrated from vue2 to vue3, because optional chaining in templates is too OP.
|
||||
@ -24,7 +34,6 @@
|
||||
* (In Firefox) When extension was placed in overflow menu, the popup was cut off. That should be fixed now. [#119](https://github.com/tamius-han/ultrawidify/issues/119)
|
||||
* The extension will now show a notification when autodetection can't run due to DRM
|
||||
* Videos on facebook and reddit no longer get shifted up and to the left for me (cropping most of the video off-screen), but I haven't been deliberately trying to fix that issue. If you experience that issue, please consider contacting me (via github or email) with a link to a problematic video.
|
||||
* **[4.5.0.1]** Fixed the misalignment issue on netflix ...
|
||||
|
||||
### v4.4.10
|
||||
|
||||
|
10
README.md
10
README.md
@ -2,7 +2,9 @@
|
||||
|
||||
## Super TL;DR: I'm just looking for the install links, thanks
|
||||
|
||||
[Firefox](https://addons.mozilla.org/en/firefox/addon/ultrawidify/), [Chrome](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi), [Edge](https://microsoftedge.microsoft.com/addons/detail/lmpgpgechmkkkehkihpiddbcbgibokbi) (Chromium-based only)
|
||||
[Firefox](https://addons.mozilla.org/en/firefox/addon/ultrawidify/), [Chrome](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi).
|
||||
|
||||
**Microsoft Edge is not supported at this time, as Edge features some bugs that make it impossible for extension to work.** [Read more](https://github.com/tamius-han/ultrawidify/issues/117#issuecomment-747109695).
|
||||
|
||||
There's also [nightly "builds"](https://stuff.lionsarch.tamius.net/ultrawidify/nightly/).
|
||||
|
||||
@ -235,7 +237,6 @@ However, I do plan on implementing this feature. Hopefully by the end of the yea
|
||||
|
||||
|
||||
|
||||
|
||||
## Plans for the future
|
||||
|
||||
1. Handle porting of extension settings between versions.
|
||||
@ -254,7 +255,8 @@ However, I do plan on implementing this feature. Hopefully by the end of the yea
|
||||
|
||||
[Latest stable for Chrome — download from Chrome store](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi)
|
||||
|
||||
[Latest stable for Edge — Download from Microsoft store](https://microsoftedge.microsoft.com/addons/detail/lmpgpgechmkkkehkihpiddbcbgibokbi)
|
||||
Edge version is currently not available, as Edge has some bugs that prevent this extension from working correctly. [Read more](https://github.com/tamius-han/ultrawidify/issues/117#issuecomment-747109695)
|
||||
<!-- [Latest stable for Edge — Download from Microsoft store](https://microsoftedge.microsoft.com/addons/detail/lmpgpgechmkkkehkihpiddbcbgibokbi) -->
|
||||
|
||||
### Installing the current, github version
|
||||
|
||||
@ -268,7 +270,7 @@ Requirements: npm, node.
|
||||
|
||||
1. Clone this repo
|
||||
2. run `npm install`
|
||||
3. If using **Firefox,** run: `npm run watch:dev`. If using **Chrome,** run: `npm run watch-chrome:dev`. If using Edge, run: `npm run watch-edge:dev`.
|
||||
3. If using **Firefox,** run: `npm run watch:dev`. If using **Chrome,** run: `npm run watch-chrome:dev`.
|
||||
|
||||
TODO: see if #3 already loads the extension in FF
|
||||
|
||||
|
113
package-lock.json
generated
113
package-lock.json
generated
@ -421,12 +421,111 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-class-properties": {
|
||||
"version": "7.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz",
|
||||
"integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==",
|
||||
"version": "7.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz",
|
||||
"integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==",
|
||||
"requires": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.10.4",
|
||||
"@babel/helper-create-class-features-plugin": "^7.12.1",
|
||||
"@babel/helper-plugin-utils": "^7.10.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/generator": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz",
|
||||
"integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.12.11",
|
||||
"jsesc": "^2.5.1",
|
||||
"source-map": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz",
|
||||
"integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==",
|
||||
"requires": {
|
||||
"@babel/helper-function-name": "^7.10.4",
|
||||
"@babel/helper-member-expression-to-functions": "^7.12.1",
|
||||
"@babel/helper-optimise-call-expression": "^7.10.4",
|
||||
"@babel/helper-replace-supers": "^7.12.1",
|
||||
"@babel/helper-split-export-declaration": "^7.10.4"
|
||||
}
|
||||
},
|
||||
"@babel/helper-member-expression-to-functions": {
|
||||
"version": "7.12.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz",
|
||||
"integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.12.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-replace-supers": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz",
|
||||
"integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==",
|
||||
"requires": {
|
||||
"@babel/helper-member-expression-to-functions": "^7.12.7",
|
||||
"@babel/helper-optimise-call-expression": "^7.12.10",
|
||||
"@babel/traverse": "^7.12.10",
|
||||
"@babel/types": "^7.12.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-optimise-call-expression": {
|
||||
"version": "7.12.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz",
|
||||
"integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.12.10"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
|
||||
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
|
||||
"integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg=="
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.12.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
|
||||
"integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/generator": "^7.12.10",
|
||||
"@babel/helper-function-name": "^7.10.4",
|
||||
"@babel/helper-split-export-declaration": "^7.11.0",
|
||||
"@babel/parser": "^7.12.10",
|
||||
"@babel/types": "^7.12.10",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0",
|
||||
"lodash": "^4.17.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz",
|
||||
"integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.12.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz",
|
||||
"integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.12.11",
|
||||
"lodash": "^4.17.19",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-dynamic-import": {
|
||||
@ -9799,9 +9898,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||
},
|
||||
"lodash._reinterpolate": {
|
||||
"version": "3.0.0",
|
||||
|
@ -20,6 +20,7 @@
|
||||
"start": "npm run dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||
"@types/core-js": "^2.5.3",
|
||||
"@types/es6-promise": "^3.3.0",
|
||||
"@vue/cli": "^4.5.9",
|
||||
|
33
src/common/js/ChromeShittinessMitigations.js
Normal file
33
src/common/js/ChromeShittinessMitigations.js
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* For some reason, Chrome really doesn't like when chrome.runtime
|
||||
* methods are wrapped inside a ES6 proxy object. If 'port' is a
|
||||
* ES6 Proxy of a Port object that `chrome.runtime.connect()` creates,
|
||||
* then Chrome will do bullshits like `port.sendMessage` and
|
||||
* `port.onMessage.addListener` crashing your Vue3 UI with bullshits
|
||||
* excuses, e.g.
|
||||
*
|
||||
* | TypeError: Illegal invocation. Function must be called on
|
||||
* | an object of type Port
|
||||
*
|
||||
* which is some grade A bullshit because Firefox can handle that just
|
||||
* fine.
|
||||
*
|
||||
* There's two ways how I could handle this:
|
||||
* * Find out how to get the original object from the proxy Vue3
|
||||
* creates, which would take time and ruin my xmass holiday, or
|
||||
* * make a global object with a passive-aggressive name and ignore
|
||||
* the very real possibility that there's prolly a reason Chrome
|
||||
* does things in its own very special(tm) way, as if it had one
|
||||
* extra chromosome over Firefox.
|
||||
*
|
||||
* Easy chhoice, really.
|
||||
*/
|
||||
export class ChromeShittinessMitigations {
|
||||
static port = null;
|
||||
|
||||
static setProperty(property, value) {
|
||||
ChromeShittinessMitigations[property] = value;
|
||||
}
|
||||
}
|
||||
|
||||
export default ChromeShittinessMitigations;
|
@ -1,3 +1,5 @@
|
||||
import browser from "vuex-webextensions/dist/browser";
|
||||
|
||||
if (process.env.CHANNEL !== 'stable') {
|
||||
console.info('Loaded BrowserDetect');
|
||||
}
|
||||
@ -9,6 +11,9 @@ const BrowserDetect = {
|
||||
edge: process.env.BROWSER === 'edge',
|
||||
processEnvBrowser: process.env.BROWSER,
|
||||
processEnvChannel: process.env.CHANNEL,
|
||||
isEdgeUA: () => /Edg\/(\.?[0-9]*)*$/.test(window.navigator.userAgent),
|
||||
getBrowserObj: () => { return process.env.BROWSER === 'firefox' ? browser : chrome; },
|
||||
getURL: (url) => { console.log('getting file:', url); console.log(process.env.BROWSER === 'firefox' ? browser.runtime.getURL(url) : chrome.runtime.getURL(url)); return process.env.BROWSER === 'firefox' ? browser.runtime.getURL(url) : chrome.runtime.getURL(url); },
|
||||
}
|
||||
|
||||
if (process.env.CHANNEL !== 'stable') {
|
||||
|
@ -407,7 +407,7 @@ const ExtensionConfPatch = [
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '4.5.0.1',
|
||||
forVersion: '4.5.1',
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
for (const site in userOptions.sites) {
|
||||
try {
|
||||
@ -418,6 +418,24 @@ const ExtensionConfPatch = [
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '4.5.1.1',
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
if (!userOptions.sites['streamable.com']) {
|
||||
userOptions.sites['streamable.com'] = {
|
||||
mode: 3,
|
||||
autoar: 3,
|
||||
type: 'official',
|
||||
stretch: -1,
|
||||
videoAlignment: -1,
|
||||
keyboardShortcutsEnabled: 0,
|
||||
css: ".player {text-align: left}"
|
||||
};
|
||||
}
|
||||
if (!userOptions.sites['streamable.com'].css) {
|
||||
userOptions.sites['streamable.com'].css = '.player {text-align: left}'
|
||||
};
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -1032,7 +1032,7 @@ var ExtensionConf = {
|
||||
},
|
||||
"www.netflix.com" : {
|
||||
mode: ExtensionMode.Enabled,
|
||||
autoar: currentBrowser.firefox ? ExtensionMode.Enabled : ExtensionMode.Disabled,
|
||||
autoar: ExtensionMode.Enabled,
|
||||
override: false,
|
||||
type: 'official',
|
||||
stretch: Stretch.Default,
|
||||
@ -1086,6 +1086,15 @@ var ExtensionConf = {
|
||||
}
|
||||
}
|
||||
},
|
||||
"streamable.com": {
|
||||
mode: 3,
|
||||
autoar: 3,
|
||||
type: 'official',
|
||||
stretch: -1,
|
||||
videoAlignment: -1,
|
||||
keyboardShortcutsEnabled: 0,
|
||||
css: ".player {text-align: left}"
|
||||
},
|
||||
"vimeo.com": {
|
||||
mode: 3,
|
||||
autoar: 3,
|
||||
|
@ -7,6 +7,7 @@ import Stretch from '../../common/enums/stretch.enum';
|
||||
import VideoAlignment from '../../common/enums/video-alignment.enum';
|
||||
import ExtensionConfPatch from '../conf/ExtConfPatches';
|
||||
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
||||
import BrowserDetect from '../conf/BrowserDetect';
|
||||
|
||||
if(process.env.CHANNEL !== 'stable'){
|
||||
console.info("Loading Settings");
|
||||
@ -16,9 +17,10 @@ class Settings {
|
||||
|
||||
constructor(options) {
|
||||
// Options: activeSettings, updateCallback, logger
|
||||
this.logger = options.logger;
|
||||
this.onSettingsChanged = options.onSettingsChanged;
|
||||
this.active = options.activeSettings ?? undefined;
|
||||
this.logger = options?.logger;
|
||||
this.onSettingsChanged = options?.onSettingsChanged;
|
||||
this.afterSettingsSaved = options?.afterSettingsSaved;
|
||||
this.active = options?.activeSettings ?? undefined;
|
||||
this.default = ExtensionConf;
|
||||
this.default['version'] = this.getExtensionVersion();
|
||||
this.useSync = false;
|
||||
@ -35,27 +37,27 @@ class Settings {
|
||||
if (!changes.uwSettings) {
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
// 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);
|
||||
this.setActive(parsedSettings);
|
||||
|
||||
this.logger.log('info', 'debug', 'Does parsedSettings.preventReload exist?', parsedSettings.preventReload, "Does callback exist?", !!this.onSettingsChanged);
|
||||
this.logger?.log('info', 'debug', 'Does parsedSettings.preventReload exist?', parsedSettings.preventReload, "Does callback exist?", !!this.onSettingsChanged);
|
||||
|
||||
if (!parsedSettings.preventReload && this.onSettingsChanged) {
|
||||
try {
|
||||
this.onSettingsChanged();
|
||||
|
||||
|
||||
|
||||
|
||||
this.logger.log('info', 'settings', '[Settings] Update callback finished.')
|
||||
this.logger?.log('info', 'settings', '[Settings] Update callback finished.')
|
||||
} catch (e) {
|
||||
this.logger.log('error', 'settings', "[Settings] CALLING UPDATE CALLBACK FAILED. Reason:", e)
|
||||
this.logger?.log('error', 'settings', "[Settings] CALLING UPDATE CALLBACK FAILED. Reason:", e)
|
||||
}
|
||||
}
|
||||
if (this.afterSettingsSaved) {
|
||||
this.afterSettingsSaved();
|
||||
}
|
||||
}
|
||||
|
||||
static getExtensionVersion() {
|
||||
@ -143,12 +145,12 @@ class Settings {
|
||||
applySettingsPatches(oldVersion, patches) {
|
||||
let index = this.findFirstNecessaryPatch(oldVersion, patches);
|
||||
if (index === -1) {
|
||||
this.logger.log('info','settings','[Settings::applySettingsPatches] There are no pending conf patches.');
|
||||
this.logger?.log('info','settings','[Settings::applySettingsPatches] There are no pending conf patches.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
const updateFn = patches[index].updateFn;
|
||||
delete patches[index].forVersion;
|
||||
@ -162,7 +164,7 @@ class Settings {
|
||||
try {
|
||||
updateFn(this.active, this.getDefaultSettings());
|
||||
} catch (e) {
|
||||
this.logger.log('error', 'settings', '[Settings::applySettingsPatches] Failed to execute update function. Keeping settings object as-is. Error:', e);
|
||||
this.logger?.log('error', 'settings', '[Settings::applySettingsPatches] Failed to execute update function. Keeping settings object as-is. Error:', e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,14 +182,14 @@ class Settings {
|
||||
const oldVersion = (settings && settings.version) || this.version;
|
||||
|
||||
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,
|
||||
"\ncurrent version:", this.version
|
||||
);
|
||||
}
|
||||
|
||||
// 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");
|
||||
// Debug.flushStoredSettings = false; // don't do it again this session
|
||||
// this.active = this.getDefaultSettings();
|
||||
// this.active.version = this.version;
|
||||
@ -197,7 +199,7 @@ class Settings {
|
||||
|
||||
// if there's no settings saved, return default settings.
|
||||
if(! settings || (Object.keys(settings).length === 0 && settings.constructor === Object)) {
|
||||
this.logger.log(
|
||||
this.logger?.log(
|
||||
'info',
|
||||
'settings',
|
||||
'[Settings::init] settings don\'t exist. Using defaults.\n#keys:',
|
||||
@ -234,7 +236,7 @@ class Settings {
|
||||
|
||||
// check if extension has been updated. If not, return settings as they were retrieved
|
||||
if (this.active.version === this.version) {
|
||||
this.logger.log('info', 'settings', "[Settings::init] extension was saved with current version of ultrawidify. Returning object as-is.");
|
||||
this.logger?.log('info', 'settings', "[Settings::init] extension was saved with current version of ultrawidify. Returning object as-is.");
|
||||
return this.active;
|
||||
}
|
||||
|
||||
@ -245,7 +247,7 @@ class Settings {
|
||||
// if extension has been updated, update existing settings with any options added in the
|
||||
// new version. In addition to that, we remove old keys that are no longer used.
|
||||
const patched = ObjectCopy.addNew(settings, this.default);
|
||||
this.logger.log('info', 'settings',"[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default);
|
||||
this.logger?.log('info', 'settings',"[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default);
|
||||
|
||||
if (patched) {
|
||||
this.active = patched;
|
||||
@ -278,7 +280,7 @@ class Settings {
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.log('info', 'settings', 'Got settings:', ret && ret.uwSettings && JSON.parse(ret.uwSettings));
|
||||
this.logger?.log('info', 'settings', 'Got settings:', ret && ret.uwSettings && JSON.parse(ret.uwSettings));
|
||||
|
||||
try {
|
||||
return JSON.parse(ret.uwSettings);
|
||||
@ -317,11 +319,11 @@ class Settings {
|
||||
|
||||
this.fixSitesSettings(extensionConf.sites);
|
||||
|
||||
this.logger.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
|
||||
this.logger?.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
|
||||
|
||||
if (currentBrowser.firefox || currentBrowser.edge) {
|
||||
if (BrowserDetect.firefox) {
|
||||
return browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
|
||||
} else if (currentBrowser.chrome) {
|
||||
} else {
|
||||
return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
|
||||
}
|
||||
}
|
||||
@ -392,7 +394,7 @@ class Settings {
|
||||
site = window.location.hostname;
|
||||
|
||||
if (!site) {
|
||||
this.logger.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
|
||||
this.logger?.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
|
||||
return ExtensionMode.Disabled;
|
||||
}
|
||||
}
|
||||
@ -418,7 +420,7 @@ class Settings {
|
||||
}
|
||||
|
||||
} catch(e){
|
||||
this.logger.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\n\nerror:", e, "\n\nSettings object:", this)
|
||||
this.logger?.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\n\nerror:", e, "\n\nSettings object:", this)
|
||||
|
||||
return ExtensionMode.Disabled;
|
||||
}
|
||||
@ -430,7 +432,7 @@ class Settings {
|
||||
site = window.location.hostname;
|
||||
|
||||
if (!site) {
|
||||
this.logger.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
|
||||
this.logger?.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -457,7 +459,7 @@ class Settings {
|
||||
return false;
|
||||
}
|
||||
} catch(e) {
|
||||
this.logger.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\nSettings object:", this);
|
||||
this.logger?.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\nSettings object:", this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -479,7 +481,7 @@ class Settings {
|
||||
return this.active.sites[site].keyboardShortcutsEnabled === ExtensionMode.Enabled;
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.log('info', 'settings',"[Settings.js::keyboardDisabled] something went wrong:", e);
|
||||
this.logger?.log('info', 'settings',"[Settings.js::keyboardDisabled] something went wrong:", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -498,7 +500,7 @@ class Settings {
|
||||
site = window.location.hostname;
|
||||
|
||||
if (!site) {
|
||||
this.logger.log('warn', ['settings', 'init', 'debug'], `[Settings::canStartAutoAr] No site — even window.location.hostname returned nothing!: ${window.location.hostname}`);
|
||||
this.logger?.log('warn', ['settings', 'init', 'debug'], `[Settings::canStartAutoAr] No site — even window.location.hostname returned nothing!: ${window.location.hostname}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -511,7 +513,7 @@ class Settings {
|
||||
// const csar = this.canStartAutoAr(site);
|
||||
// Debug.debug = true;
|
||||
|
||||
this.logger.log('info', ['settings', 'init', 'debug'], "[Settings::canStartAutoAr] ----------------\nCAN WE START AUTOAR ON SITE", site,
|
||||
this.logger?.log('info', ['settings', 'init', 'debug'], "[Settings::canStartAutoAr] ----------------\nCAN WE START AUTOAR ON SITE", site,
|
||||
"?\n\nsettings.active.sites[site]=", this.active.sites[site], "settings.active.sites[@global]=", this.active.sites['@global'],
|
||||
"\nAutoar mode (global)?", this.active.sites['@global'].autoar,
|
||||
`\nAutoar mode (${site})`, this.active.sites[site] ? this.active.sites[site].autoar : '<not defined>',
|
||||
@ -521,18 +523,18 @@ class Settings {
|
||||
|
||||
// if site is not defined, we use default mode:
|
||||
if (! this.active.sites[site]) {
|
||||
this.logger.log('info', ['settings', 'aard', 'init', 'debug'], "[Settings::canStartAutoAr] Settings not defined for this site, returning defaults.", site, this.active.sites[site], this.active.sites);
|
||||
this.logger?.log('info', ['settings', 'aard', 'init', 'debug'], "[Settings::canStartAutoAr] Settings not defined for this site, returning defaults.", site, this.active.sites[site], this.active.sites);
|
||||
return this.active.sites['@global'].autoar === ExtensionMode.Enabled;
|
||||
}
|
||||
|
||||
if (this.active.sites['@global'].autoar === ExtensionMode.Enabled) {
|
||||
this.logger.log('info', ['settings', 'aard', 'init', 'debug'], `[Settings::canStartAutoAr] Aard is enabled by default. Extension can run unless disabled for this site.`, this.active.sites[site].autoar);
|
||||
this.logger?.log('info', ['settings', 'aard', 'init', 'debug'], `[Settings::canStartAutoAr] Aard is enabled by default. Extension can run unless disabled for this site.`, this.active.sites[site].autoar);
|
||||
return this.active.sites[site].autoar !== ExtensionMode.Disabled;
|
||||
} else if (this.active.sites['@global'].autoar === ExtensionMode.Whitelist) {
|
||||
this.logger.log('info', ['settings', 'init', 'debug'], "canStartAutoAr — can(not) start aard because extension is in whitelist mode, and this site is (not) equal to", ExtensionMode.Enabled)
|
||||
this.logger?.log('info', ['settings', 'init', 'debug'], "canStartAutoAr — can(not) start aard because extension is in whitelist mode, and this site is (not) equal to", ExtensionMode.Enabled)
|
||||
return this.active.sites[site].autoar === ExtensionMode.Enabled;
|
||||
} else {
|
||||
this.logger.log('info', ['settings', 'init', 'debug'], "canStartAutoAr — cannot start aard because extension is globally disabled")
|
||||
this.logger?.log('info', ['settings', 'init', 'debug'], "canStartAutoAr — cannot start aard because extension is globally disabled")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import GuardLine from './GuardLine';
|
||||
import VideoAlignment from '../../../common/enums/video-alignment.enum';
|
||||
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
||||
import {sleep} from '../../lib/Util';
|
||||
import BrowserDetect from '../../conf/BrowserDetect';
|
||||
|
||||
class ArDetector {
|
||||
|
||||
@ -550,6 +551,7 @@ class ArDetector {
|
||||
|
||||
// special browsers require special tests
|
||||
if (this.hasDRM()) {
|
||||
this.fallbackMode = false;
|
||||
throw 'Video is protected by DRM. Autodetection cannot run here.';
|
||||
}
|
||||
this.fallbackMode = false;
|
||||
@ -559,9 +561,21 @@ class ArDetector {
|
||||
// nothing to see here, really, if fallback mode isn't supported by browser
|
||||
if (!this.drmNotificationShown) {
|
||||
this.drmNotificationShown = true;
|
||||
|
||||
// if we detect Edge, we'll throw the aggressive popup
|
||||
this.conf.player.showEdgeNotification();
|
||||
this.conf.player.showNotification('AARD_DRM');
|
||||
|
||||
this.conf.resizer.setAr({type: AspectRatio.Reset});
|
||||
return;
|
||||
}
|
||||
|
||||
// in case of DRM errors, we need to prevent the execution to reach the aspec
|
||||
// ratio setting part of this function
|
||||
if (e === 'Video is protected by DRM. Autodetection cannot run here.') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! this.canvasReadyForDrawWindow()) {
|
||||
// this means canvas needs to be resized, so we'll just re-run setup with all those new parameters
|
||||
this.stop();
|
||||
|
129
src/ext/lib/uwui/FontLoader.js
Normal file
129
src/ext/lib/uwui/FontLoader.js
Normal file
@ -0,0 +1,129 @@
|
||||
import BrowserDetect from '../../conf/BrowserDetect';
|
||||
|
||||
function url(file) {
|
||||
return BrowserDetect.getURL(file);
|
||||
}
|
||||
|
||||
export default class FontLoader {
|
||||
static loadFonts() {
|
||||
const fontsStyleElement = document.createElement('style');
|
||||
fontsStyleElement.type = 'text/css';
|
||||
|
||||
fontsStyleElement.textContent = `
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-thin.woff2')} format('woff2'); /* Super Modern Browsers */
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-thin-italic.woff2')} format('woff2');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-extralight.woff2')} format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-extralight-italic.woff2')} format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-light.woff2')} format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-light-italic.woff2')} format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-regular.woff2')} format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-italic.woff2')} format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-semibold.woff2')} format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-semibold-italic.woff2')} format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-bold.woff2')} format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: ${url('res/fonts/overpass-webfont/overpass-bold-italic.woff2')} format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass mono';
|
||||
src: ${url('res/fonts/overpass-mono-webfont/overpass-mono-light.woff2')} format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass mono';
|
||||
src: ${url('res/fonts/overpass-mono-webfont/overpass-mono-regular.woff2')} format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass mono';
|
||||
src: ${url('res/fonts/overpass-mono-webfont/overpass-mono-semibold.woff2')} format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass mono';
|
||||
src: ${url('res/fonts/overpass-mono-webfont/overpass-mono-bold.woff2')} format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
`;
|
||||
|
||||
document.head.appendChild(fontsStyleElement);
|
||||
console.log("font loaded!")
|
||||
}
|
||||
}
|
@ -50,13 +50,11 @@ class PlayerNotificationUi extends UI {
|
||||
},
|
||||
mutations: {
|
||||
'uw-set-notification'(state, payload) {
|
||||
console.log('mutation!', state, payload);
|
||||
state['notificationConfig'] = payload;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
'uw-set-notification'({commit}, payload) {
|
||||
console.log('action!', commit, payload);
|
||||
commit('uw-set-notification', payload);
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ class PlayerData {
|
||||
this.extensionMode = videoData.extensionMode;
|
||||
this.invalid = false;
|
||||
this.element = this.getPlayer();
|
||||
|
||||
this.notificationService = new PlayerNotificationUi(this.element, this.settings);
|
||||
this.ui = new PlayerUi(this.element, this.settings);
|
||||
this.dimensions = undefined;
|
||||
@ -483,6 +484,15 @@ class PlayerData {
|
||||
showNotification(notificationId) {
|
||||
this.notificationService?.showNotification(notificationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: this method needs to be deleted once Edge gets its shit together.
|
||||
*/
|
||||
showEdgeNotification() {
|
||||
if (BrowserDetect.isEdgeUA() && !this.settings.active.mutedNotifications?.browserSpecific?.edge?.brokenDrm?.[window.hostname]) {
|
||||
this.ui = new PlayerUi(this.element, this.settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.CHANNEL !== 'stable'){
|
||||
|
@ -56,7 +56,10 @@ class VideoData {
|
||||
try {
|
||||
await this.pageInfo.injectCss(`
|
||||
.uw-ultrawidify-base-wide-screen {
|
||||
margin: 0px 0px 0px 0px !important; width: initial !important; align-self: start !important; justify-self: start !important;
|
||||
margin: 0px 0px 0px 0px !important;
|
||||
width: initial !important;
|
||||
align-self: start !important;
|
||||
justify-self: start !important;
|
||||
}
|
||||
`);
|
||||
} catch (e) {
|
||||
@ -277,6 +280,54 @@ class VideoData {
|
||||
return a < b + diff && a > b - diff
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contents of the style attribute of the video element
|
||||
* in a form of an object.
|
||||
*/
|
||||
getVideoStyle() {
|
||||
// This will _always_ give us an array. Empty string gives an array
|
||||
// that contains one element. That element is an empty string.
|
||||
const styleArray = (this.video.getAttribute('style') || '').split(';');
|
||||
|
||||
const styleObject = {};
|
||||
|
||||
for (const style of styleArray) {
|
||||
// not a valid CSS, so we skip those
|
||||
if (style.indexOf(':') === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// let's play _very_ safe
|
||||
let [property, value] = style.split('!important')[0].split(':');
|
||||
value = value.trim();
|
||||
styleObject[property] = value;
|
||||
}
|
||||
|
||||
return styleObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some sites try to accomodate ultrawide users by "cropping" videos
|
||||
* by setting 'style' attribute of the video element to 'height: X%',
|
||||
* where 'X' is something greater than 100.
|
||||
*
|
||||
* This function gets that percentage and converts it into a factor.
|
||||
*/
|
||||
getHeightCompensationFactor() {
|
||||
const heightStyle = this.getVideoStyle()?.height;
|
||||
|
||||
if (!heightStyle || !heightStyle.endsWith('%')) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const heightCompensationFactor = heightStyle.split('%')[0] / 100;
|
||||
if (isNaN(heightCompensationFactor)) {
|
||||
return 1;
|
||||
}
|
||||
return heightCompensationFactor;
|
||||
}
|
||||
|
||||
|
||||
firstTimeArdInit(){
|
||||
if(this.destroyed || this.invalid) {
|
||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
||||
|
@ -177,43 +177,41 @@ class Resizer {
|
||||
this.conf.pageInfo.updateCurrentCrop(ar);
|
||||
}
|
||||
|
||||
if (ar.type === AspectRatio.Automatic ||
|
||||
ar.type === AspectRatio.Reset && this.lastAr.type === AspectRatio.Initial) {
|
||||
// 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
|
||||
if (siteSettings?.autoarPreventConditions?.videoStyleString) {
|
||||
const styleString = (this.video.getAttribute('style') || '').split(';');
|
||||
// if (ar.type === AspectRatio.Automatic ||
|
||||
// ar.type === AspectRatio.Reset && this.lastAr.type === AspectRatio.Initial) {
|
||||
// // 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
|
||||
// if (siteSettings?.autoarPreventConditions?.videoStyleString) {
|
||||
// const styleString = (this.video.getAttribute('style') || '').split(';');
|
||||
|
||||
if (siteSettings.autoarPreventConditions.videoStyleString.containsProperty) {
|
||||
const bannedProperties = siteSettings.autoarPreventConditions.videoStyleString.containsProperty;
|
||||
for (const prop in bannedProperties) {
|
||||
for (const s of styleString) {
|
||||
if (s.trim().startsWith(prop)) {
|
||||
// if (siteSettings.autoarPreventConditions.videoStyleString.containsProperty) {
|
||||
// const bannedProperties = siteSettings.autoarPreventConditions.videoStyleString.containsProperty;
|
||||
// for (const prop in bannedProperties) {
|
||||
// for (const s of styleString) {
|
||||
// if (s.trim().startsWith(prop)) {
|
||||
|
||||
// check if css property has a list of allowed values:
|
||||
if (bannedProperties[prop].allowedValues) {
|
||||
const styleValue = s.split(':')[1].trim();
|
||||
// // check if css property has a list of allowed values:
|
||||
// if (bannedProperties[prop].allowedValues) {
|
||||
// const styleValue = s.split(':')[1].trim();
|
||||
|
||||
// check if property value is on the list of allowed values
|
||||
// if it's not, we aren't allowed to start aard
|
||||
if (bannedProperties[prop].allowedValues.indexOf(styleValue) === -1) {
|
||||
this.logger.log('error', 'debug', "%c[Resizer::setAr] video style contains forbidden css property/value combo: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// no allowed values, no problem. We have forbidden property
|
||||
// and this means aard can't start.
|
||||
this.logger.log('info', 'debug', "%c[Resizer::setAr] video style contains forbidden css property: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // check if property value is on the list of allowed values
|
||||
// // if it's not, we aren't allowed to start aard
|
||||
// if (bannedProperties[prop].allowedValues.indexOf(styleValue) === -1) {
|
||||
// this.logger.log('error', 'debug', "%c[Resizer::setAr] video style contains forbidden css property/value combo: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
|
||||
// return;
|
||||
// }
|
||||
// } else {
|
||||
// // no allowed values, no problem. We have forbidden property
|
||||
// // and this means aard can't start.
|
||||
// this.logger.log('info', 'debug', "%c[Resizer::setAr] video style contains forbidden css property: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (lastAr) {
|
||||
this.lastAr = this.calculateRatioForLegacyOptions(lastAr);
|
||||
@ -229,11 +227,11 @@ class Resizer {
|
||||
this.lastAr = {type: ar.type, ratio: ar.ratio}
|
||||
}
|
||||
|
||||
if (this.extensionMode === ExtensionMode.Basic && !PlayerData.isFullScreen() && ar.type !== AspectRatio.Reset) {
|
||||
// don't actually apply or calculate css when using basic mode if not in fullscreen
|
||||
// ... unless we're resetting the aspect ratio to original
|
||||
return;
|
||||
}
|
||||
// if (this.extensionMode === ExtensionMode.Basic && !PlayerData.isFullScreen() && ar.type !== AspectRatio.Reset) {
|
||||
// // don't actually apply or calculate css when using basic mode if not in fullscreen
|
||||
// // ... unless we're resetting the aspect ratio to original
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (! this.video) {
|
||||
this.conf.destroy();
|
||||
@ -259,7 +257,6 @@ class Resizer {
|
||||
|
||||
var stretchFactors = this.scaler.calculateCrop(ar);
|
||||
|
||||
|
||||
if(! stretchFactors || stretchFactors.error){
|
||||
this.logger.log('error', 'debug', `[Resizer::setAr] <rid:${this.resizerId}> failed to set AR due to problem with calculating crop. Error:`, stretchFactors?.error);
|
||||
if (stretchFactors?.error === 'no_video'){
|
||||
@ -297,7 +294,7 @@ class Resizer {
|
||||
var stretchFactors = this.stretcher.calculateBasicStretch();
|
||||
this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for basic stretch. Stretch factors are:', stretchFactors);
|
||||
} else {
|
||||
var stretchFactors = {xFactor: 1, yFactor: 1}
|
||||
var stretchFactors = {xFactor: 1, yFactor: 1};
|
||||
this.logger.log('error', 'debug', '[Resizer::setAr] Okay wtf happened? If you see this, something has gone wrong', stretchFactors,"\n------[ i n f o d u m p ]------\nstretcher:", this.stretcher);
|
||||
}
|
||||
|
||||
@ -736,6 +733,8 @@ class Resizer {
|
||||
styleArray.push(`transform: translate(${translate.x}px, ${translate.y}px) scale(${stretchFactors.xFactor}, ${stretchFactors.yFactor}) !important;`);
|
||||
|
||||
// important — guarantees video will be properly aligned
|
||||
// Note that position:absolute cannot be put here, otherwise old.reddit /w RES breaks — videos embedded
|
||||
// from certain hosts will get a height: 0px. This is bad.
|
||||
styleArray.push("top: 0px !important; left: 0px !important; bottom: 0px !important; right: 0px;");
|
||||
|
||||
// important — some websites (cough reddit redesign cough) may impose some dumb max-width and max-height
|
||||
|
@ -66,6 +66,40 @@ class Scaler {
|
||||
}
|
||||
|
||||
calculateCrop(ar) {
|
||||
/**
|
||||
* STEP 1: NORMALIZE ASPECT RATIO
|
||||
*
|
||||
* Video width is normalized based on 100% of the parent. That means if the player AR
|
||||
* is narrower than video ar, we need to pre-downscale the video. This scaling already
|
||||
* undoes any zoom that style="height:123%" on the video element adds.
|
||||
*
|
||||
* There are few exceptions and additional caveatss:
|
||||
* * AspectRatio.FitHeight: we don't want to pre-downscale the video at all, as things
|
||||
* will be scaled to fit height as-is.
|
||||
* * When player is wider than stream, we want to undo any height compensations site
|
||||
* tacks on the video tag.
|
||||
*
|
||||
* Quick notes:
|
||||
* * when I say 'video AR', I actually mean aspect ratio after we've compensated for
|
||||
* any possible 'height:' stuffs in the style attribute of the video tag
|
||||
* * because video width is normalized on 100% of the parent, we don't need to correct
|
||||
* anything when the player is wider than the video.
|
||||
*/
|
||||
const streamAr = this.conf.video.videoWidth / this.conf.video.videoHeight;
|
||||
const playerAr = this.conf.player.dimensions.width / this.conf.player.dimensions.height;
|
||||
const heightCompensationFactor = this.conf.getHeightCompensationFactor();
|
||||
const compensatedStreamAr = streamAr * heightCompensationFactor;
|
||||
|
||||
let arCorrectionFactor = 1;
|
||||
|
||||
if (ar.type !== AspectRatio.FitHeight) {
|
||||
if (playerAr < compensatedStreamAr) {
|
||||
arCorrectionFactor = this.conf.player.dimensions.width / this.conf.video.offsetWidth;
|
||||
} else if (ar.type !== AspectRatio.Reset) {
|
||||
arCorrectionFactor /= heightCompensationFactor;
|
||||
}
|
||||
}
|
||||
|
||||
if(!this.conf.video){
|
||||
this.logger.log('info', 'debug', "[Scaler::calculateCrop] ERROR — no video detected. Conf:", this.conf, "video:", this.conf.video, "video dimensions:", this.conf.video && this.conf.video.videoWidth, '×', this.conf.video && this.conf.video.videoHeight);
|
||||
|
||||
@ -81,7 +115,7 @@ class Scaler {
|
||||
}
|
||||
|
||||
if (ar.type === AspectRatio.Reset){
|
||||
return {xFactor: 1, yFactor: 1}
|
||||
return {xFactor: arCorrectionFactor, yFactor: arCorrectionFactor}
|
||||
}
|
||||
|
||||
// handle fuckie-wuckies
|
||||
@ -102,15 +136,13 @@ class Scaler {
|
||||
|
||||
// Dejansko razmerje stranic datoteke/<video> značke
|
||||
// Actual aspect ratio of the file/<video> tag
|
||||
var fileAr = this.conf.video.videoWidth / this.conf.video.videoHeight;
|
||||
var playerAr = this.conf.player.dimensions.width / this.conf.player.dimensions.height;
|
||||
|
||||
if (ar.type === AspectRatio.Initial || !ar.ratio) {
|
||||
ar.ratio = fileAr;
|
||||
ar.ratio = streamAr;
|
||||
}
|
||||
|
||||
|
||||
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] ar is " ,ar.ratio, ", file ar is", fileAr, ", this.conf.player.dimensions are ", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
|
||||
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] ar is " ,ar.ratio, ", file ar is", streamAr, ", this.conf.player.dimensions are ", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
|
||||
|
||||
var videoDimensions = {
|
||||
xFactor: 1,
|
||||
@ -119,11 +151,11 @@ class Scaler {
|
||||
actualHeight: 0, // height of the video (excluding letterbox) when <video> tag height is equal to height
|
||||
}
|
||||
|
||||
if (fileAr < playerAr) {
|
||||
if (fileAr < ar.ratio){
|
||||
if (streamAr < playerAr) {
|
||||
if (streamAr < ar.ratio){
|
||||
// in this situation we have to crop letterbox on top/bottom of the player
|
||||
// we cut it, but never more than the player
|
||||
videoDimensions.xFactor = Math.min(ar.ratio, playerAr) / fileAr;
|
||||
videoDimensions.xFactor = Math.min(ar.ratio, playerAr) / streamAr;
|
||||
videoDimensions.yFactor = videoDimensions.xFactor;
|
||||
} else {
|
||||
// in this situation, we would be cutting pillarbox. Inside horizontal player.
|
||||
@ -132,14 +164,14 @@ class Scaler {
|
||||
videoDimensions.yFactor = 1;
|
||||
}
|
||||
} else {
|
||||
if (fileAr < ar.ratio || playerAr < ar.ratio){
|
||||
if (streamAr < 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 = streamAr / Math.min(ar.ratio, playerAr);
|
||||
videoDimensions.yFactor = videoDimensions.xFactor;
|
||||
// videoDimensions.xFactor = Math.max(ar.ratio, playerAr) * fileAr;
|
||||
// videoDimensions.yFactor = videoDimensions.xFactor;
|
||||
@ -148,6 +180,10 @@ class Scaler {
|
||||
|
||||
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
|
||||
|
||||
// correct the factors
|
||||
videoDimensions.xFactor *= arCorrectionFactor;
|
||||
videoDimensions.yFactor *= arCorrectionFactor;
|
||||
|
||||
return videoDimensions;
|
||||
}
|
||||
}
|
||||
|
@ -133,9 +133,19 @@ squeezeFactor: ${squeezeFactor}`, '\nvideo', this.conf.video);
|
||||
return this.calculateStretch(actualAr, this.fixedStretchRatio);
|
||||
}
|
||||
|
||||
calculateStretch(actualAr, playerArOverride) {
|
||||
getArCorrectionFactor() {
|
||||
const streamAr = this.conf.video.videoWidth / this.conf.video.videoHeight;
|
||||
const playerAr = this.conf.player.dimensions.width / this.conf.player.dimensions.height;
|
||||
|
||||
let arCorrectionFactor = 1;
|
||||
arCorrectionFactor = this.conf.player.dimensions.width / this.conf.video.offsetWidth;
|
||||
|
||||
return arCorrectionFactor;
|
||||
}
|
||||
|
||||
calculateStretch(actualAr, playerArOverride) {
|
||||
const playerAr = playerArOverride || this.conf.player.dimensions.width / this.conf.player.dimensions.height;
|
||||
const videoAr = this.conf.video.videoWidth / this.conf.video.videoHeight;
|
||||
const streamAr = this.conf.video.videoWidth / this.conf.video.videoHeight;
|
||||
|
||||
if (! actualAr){
|
||||
actualAr = playerAr;
|
||||
@ -146,7 +156,7 @@ squeezeFactor: ${squeezeFactor}`, '\nvideo', this.conf.video);
|
||||
yFactor: 1
|
||||
};
|
||||
|
||||
if (playerAr >= videoAr){
|
||||
if (playerAr >= streamAr){
|
||||
// player adds PILLARBOX
|
||||
|
||||
if(actualAr >= playerAr){
|
||||
@ -155,18 +165,18 @@ squeezeFactor: ${squeezeFactor}`, '\nvideo', this.conf.video);
|
||||
// actual > player > video — video is letterboxed
|
||||
// solution: horizontal stretch according to difference between video and player AR
|
||||
// vertical stretch according to difference between actual AR and player AR
|
||||
stretchFactors.xFactor = playerAr / videoAr;
|
||||
stretchFactors.yFactor = actualAr / videoAr;
|
||||
stretchFactors.xFactor = playerAr / streamAr;
|
||||
stretchFactors.yFactor = actualAr / streamAr;
|
||||
|
||||
this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 1")
|
||||
} else if ( actualAr >= videoAr) {
|
||||
} else if ( actualAr >= streamAr) {
|
||||
// VERIFIED WORKS
|
||||
|
||||
// player > actual > video — video is still letterboxed
|
||||
// we need vertical stretch to remove black bars in video
|
||||
// we need horizontal stretch to make video fit width
|
||||
stretchFactors.xFactor = playerAr / videoAr;
|
||||
stretchFactors.yFactor = actualAr / videoAr;
|
||||
stretchFactors.xFactor = playerAr / streamAr;
|
||||
stretchFactors.yFactor = actualAr / streamAr;
|
||||
|
||||
this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 2")
|
||||
} else {
|
||||
@ -186,10 +196,10 @@ squeezeFactor: ${squeezeFactor}`, '\nvideo', this.conf.video);
|
||||
// video > player > actual
|
||||
// video is PILLARBOXED
|
||||
stretchFactors.xFactor = actualAr / playerAr;
|
||||
stretchFactors.yFactor = videoAr / playerAr;
|
||||
stretchFactors.yFactor = streamAr / playerAr;
|
||||
|
||||
this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 4")
|
||||
} else if ( actualAr < videoAr ) {
|
||||
} else if ( actualAr < streamAr ) {
|
||||
// NEEDS CHECKING
|
||||
|
||||
// video > actual > player
|
||||
@ -211,6 +221,12 @@ squeezeFactor: ${squeezeFactor}`, '\nvideo', this.conf.video);
|
||||
}
|
||||
}
|
||||
|
||||
// const arCorrectionFactor = this.getArCorrectionFactor();
|
||||
// correct factors, unless we're trying to reset
|
||||
// stretchFactors.xFactor *= arCorrectionFactor;
|
||||
// stretchFactors.yFactor *= arCorrectionFactor;
|
||||
stretchFactors.arCorrectionFactor = this.getArCorrectionFactor();
|
||||
|
||||
return stretchFactors;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"manifest_version": 2,
|
||||
"name": "Ultrawidify",
|
||||
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
||||
"version": "4.5.0.1",
|
||||
"version": "4.5.1.1",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
|
||||
@ -50,7 +50,8 @@
|
||||
"res/fonts/*",
|
||||
"res/css/*",
|
||||
"res/img/settings/about-bg.png",
|
||||
"res/icons/*"
|
||||
"res/icons/*",
|
||||
"res/img/*"
|
||||
],
|
||||
"permissions": [
|
||||
"storage",
|
||||
|
@ -210,6 +210,7 @@ import DefaultSettingsPanel from './panels/DefaultSettingsPanel';
|
||||
import AboutPanel from './panels/AboutPanel';
|
||||
import ExtensionMode from '../common/enums/extension-mode.enum';
|
||||
import Logger from '../ext/lib/Logger';
|
||||
import {ChromeShittinessMitigations as CSM} from '../common/js/ChromeShittinessMitigations';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
@ -219,7 +220,6 @@ export default {
|
||||
selectedSite: '',
|
||||
activeFrames: [],
|
||||
activeSites: [],
|
||||
port: BrowserDetect.firefox ? browser.runtime.connect({name: 'popup-port'}) : chrome.runtime.connect({name: 'popup-port'}),
|
||||
comms: new Comms(),
|
||||
frameStore: {},
|
||||
frameStoreCount: 0,
|
||||
@ -245,16 +245,19 @@ export default {
|
||||
allowLogging: true,
|
||||
});
|
||||
|
||||
this.settings = new Settings({updateCallback: () => this.updateConfig(), logger: this.logger});
|
||||
this.settings = new Settings({afterSettingsSaved: () => this.updateConfig(), logger: this.logger});
|
||||
await this.settings.init();
|
||||
this.settingsInitialized = true;
|
||||
|
||||
this.port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
|
||||
const port = BrowserDetect.firefox ? browser.runtime.connect({name: 'popup-port'}) : chrome.runtime.connect({name: 'popup-port'});
|
||||
port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
|
||||
CSM.setProperty('port', port);
|
||||
|
||||
this.execAction.setSettings(this.settings);
|
||||
|
||||
// ensure we'll clean player markings on popup close
|
||||
window.addEventListener("unload", () => {
|
||||
this.port.postMessage({
|
||||
CSM.port.postMessage({
|
||||
cmd: 'unmark-player',
|
||||
forwardToAll: true,
|
||||
});
|
||||
@ -314,7 +317,7 @@ export default {
|
||||
getSite() {
|
||||
try {
|
||||
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
|
||||
this.port.postMessage({cmd: 'get-current-site'});
|
||||
CSM.port.postMessage({cmd: 'get-current-site'});
|
||||
} catch (e) {
|
||||
this.logger.log('error','popup','[popup::getSite] sending get-current-site failed for some reason. Reason:', e);
|
||||
}
|
||||
@ -336,7 +339,14 @@ export default {
|
||||
async updateConfig() {
|
||||
// when this runs, a site could have been enabled or disabled
|
||||
// this means we must update canShowVideoTab
|
||||
const settings = this.settings;
|
||||
this.settings = null;
|
||||
this.updateCanShowVideoTab();
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.settings = settings;
|
||||
this.updateCanShowVideoTab();
|
||||
});
|
||||
},
|
||||
updateCanShowVideoTab() {
|
||||
let canShow = false;
|
||||
@ -370,9 +380,8 @@ export default {
|
||||
}
|
||||
}
|
||||
if (!this.site || this.site.host !== message.site.host) {
|
||||
this.port.postMessage({cmd: 'get-current-zoom'});
|
||||
CSM.port.postMessage({cmd: 'get-current-zoom'});
|
||||
}
|
||||
console.log("processing received message:", message)
|
||||
this.site = message.site;
|
||||
|
||||
// update activeSites
|
||||
@ -472,7 +481,7 @@ export default {
|
||||
|
||||
this.frameStore[frame] = fs;
|
||||
|
||||
this.port.postMessage({
|
||||
CSM.port.postMessage({
|
||||
cmd: 'mark-player',
|
||||
forwardToContentScript: true,
|
||||
targetTab: videoTab.id,
|
||||
@ -525,7 +534,6 @@ export default {
|
||||
this.selectedSite = host;
|
||||
},
|
||||
toggleSideMenu(visible) {
|
||||
console.warn('toggling side menu visible to:', visible ?? !this.sideMenuVisible, "arg:", visible )
|
||||
this.sideMenuVisible = visible ?? !this.sideMenuVisible;
|
||||
}
|
||||
}
|
||||
|
@ -2,30 +2,27 @@
|
||||
<div>
|
||||
<h2>What's new</h2>
|
||||
<p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
|
||||
<p class="label">4.5.0</p>
|
||||
<p class="label">4.5.1</p>
|
||||
<ul>
|
||||
<li>Fixed the misalignment issue on netflix ... hopefully.</li>
|
||||
<li>
|
||||
Under the hood: migrated from vue2 to vue3, because optional chaining in templates is too OP.
|
||||
'Site settings' tab should now work in Chrome as well (<a href="https://github.com/tamius-han/ultrawidify/issues/126">#126</a>)
|
||||
</li>
|
||||
<li>
|
||||
(On options page, section 'Action & shortcuts') Manual aspect ratio now supports entering custom ratios using '21/9' and '2.39:1' formats (as opposed to single number, e.g. '2.39') — <a href="https://github.com/tamius-han/ultrawidify/issues/121">#121</a>.
|
||||
Popup interface now refreshes properly (<a href="https://github.com/tamius-han/ultrawidify/issues/127">#127</a>)
|
||||
</li>
|
||||
<li>
|
||||
Added config for wakanim.tv (special thanks to <a href="https://github.com/saschanaz">@saschanaz</a> for doing the legwork — <a href="https://github.com/tamius-han/ultrawidify/issues/113">#113</a>)
|
||||
Videos should now be scaled correctly when the display is narrower than video's native aspect ratio (<a href="https://github.com/tamius-han/ultrawidify/issues/118">#118</a>)
|
||||
</li>
|
||||
<li>
|
||||
(In Firefox) When extension was placed in overflow menu, the popup was cut off. That should be fixed now. (<a href="https://github.com/tamius-han/ultrawidify/issues/119">#119</a>)
|
||||
Fullscreen videos on streamable are aligned correctly (<a href="https://github.com/tamius-han/ultrawidify/issues/118">#116</a>). Note that while this fix hasn't broken any sites I have access to and know of,
|
||||
there is a small possibility that this bugfix may break something somewhere. If this happens on a site you use, please notify me via github, email or PM me on reddit.
|
||||
</li>
|
||||
<li>
|
||||
The extension will now show a notification when autodetection can't run due to DRM.
|
||||
Edge users using CWS version of the extension get a very aggressive warning when trying to use the extension with Edge
|
||||
</li>
|
||||
<li>
|
||||
Videos on facebook and reddit no longer get shifted up and to the left for me (cropping most of the video off-screen), but I haven't been
|
||||
deliberately trying to fix that issue. If you experience that issue, please consider contacting me (via github or email) with a link to a
|
||||
problematic video.
|
||||
</li>
|
||||
<li>
|
||||
<b>[4.5.0.1]</b> Fixes for netflix alignment issues.
|
||||
<b>[4.5.1.1]</b> Streamable fix broke old.reddit + RES on embeds from v.redd.it and streamable.com. We're now using an alternative implementation. (<a href="https://github.com/tamius-han/ultrawidify/issues/128">#128</a>)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -17,7 +17,6 @@
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
font-size: 16px;
|
||||
|
||||
// Ensure we're display:block
|
||||
display: block;
|
||||
@ -44,4 +43,26 @@
|
||||
font-size: 1.42rem;
|
||||
margin: .25rem 0;
|
||||
}
|
||||
ul, ol {
|
||||
display: block;
|
||||
list-style: disc outside none;
|
||||
margin: 1em 0;
|
||||
padding: 0 0 0 40px;
|
||||
}
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
ul ul, ol ul {
|
||||
list-style-type: circle;
|
||||
// list-style-position: inside;
|
||||
margin-left: 15px;
|
||||
}
|
||||
ol ol, ul ol {
|
||||
list-style-type: lower-latin;
|
||||
// list-style-position: inside;
|
||||
margin-left: 15px;
|
||||
}
|
||||
li {
|
||||
display: list-item;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user