Merge branch 'master' into feature/player-ui

This commit is contained in:
Tamius Han 2020-12-29 18:33:54 +01:00
commit 0e0eb57fd9
23 changed files with 600 additions and 138 deletions

View File

@ -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
View File

@ -9,3 +9,7 @@ build/
*.pem
*.kate-swp
src/res/img/git-ignore/
test/debug-configs/

View File

@ -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

View File

@ -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
View File

@ -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",

View File

@ -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",

View 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;

View File

@ -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') {

View File

@ -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}'
};
}
}
];

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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();

View 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!")
}
}

View File

@ -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);
}
}

View File

@ -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'){

View File

@ -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}};

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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",

View File

@ -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;
}
}

View File

@ -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 &amp; 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>

View File

@ -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;
}
}