Merge branch 'master' into stable
This commit is contained in:
commit
cede86d759
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/
|
||||
|
27
CHANGELOG.md
27
CHANGELOG.md
@ -1,19 +1,32 @@
|
||||
# Changelog
|
||||
|
||||
## v4.x
|
||||
|
||||
|
||||
### Plans for the future
|
||||
|
||||
* WebGL
|
||||
* Native builds for Chromium Edge and Opera
|
||||
* Native builds for Chromium Edge
|
||||
* Settings page looks ugly af right now. Maybe fix it some time later
|
||||
* other bug fixes
|
||||
|
||||
QoL improvements for me:
|
||||
## v5.0 (planned major)
|
||||
|
||||
* logging: allow to enable logging at will and export said logs to a file
|
||||
* WebGL autodetection
|
||||
* in-player GUI
|
||||
* Fix UI logger
|
||||
|
||||
### v4.5.0
|
||||
## 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)).
|
||||
|
||||
|
||||
### v4.5.0 (Current)
|
||||
|
||||
* Under the hood: migrated from vue2 to vue3, because optional chaining in templates is too OP.
|
||||
* (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') — [#121](https://github.com/tamius-han/ultrawidify/issues/121).
|
||||
@ -22,7 +35,7 @@ QoL improvements for me:
|
||||
* 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.
|
||||
|
||||
### v4.4.10 (Current)
|
||||
### v4.4.10
|
||||
|
||||
* Video alignment should now work on Twitch — [#109](https://github.com/tamius-han/ultrawidify/issues/109)
|
||||
* Videos should now align properly on Hulu while cropped — [#111](https://github.com/tamius-han/ultrawidify/issues/111) & via email
|
||||
|
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;
|
219
src/csui/PlayerUiComponent.vue
Normal file
219
src/csui/PlayerUiComponent.vue
Normal file
@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<div v-if="uiVisible" class="uw-hover uv-hover-trigger-region">
|
||||
<div class="flex flex-row pad">
|
||||
<div class="text panel">
|
||||
<h1>Microsoft Edge's DRM implementation is too broken for this extension to work on this site</h1>
|
||||
<p><sup>2020-12-22</sup></p>
|
||||
<p>
|
||||
In October 2020, Microsoft Edge received an update that renders video playback completely broken on sites that utilize DRM. This extension relies on the browser implementing functional video playback,
|
||||
which means that this extension currently cannot work in Edge on sites that utilize DRM (and neither can other 21:9 extensions).
|
||||
</p>
|
||||
<p>
|
||||
<b>Using this extension (and its alternatives) on this site may make things worse</b> — even if you only set aspect ratio manually.
|
||||
</p>
|
||||
<p>
|
||||
I have attempted all possible workarounds and none of them work.
|
||||
</p>
|
||||
<p><small>Yes I do recognize the irony of getting pissed at Microsoft for their bugs while my extension is basically the Skyrim of CWS, but guys at Microsoft are getting paid for working on MS Edge and I'm not getting paid for writing this extension.</small></p>
|
||||
<p>
|
||||
<b>I am not keeping up with Edge updates as I primarily use Firefox and Chrome. If Edge has already fixed their broken video implementation,
|
||||
please open an issue on <a href="https://github.com/tamius-han/ultrawidify/issues" target="_blank">github</a>, <a href="mailto:tamius.han@gmail.com" target="_blank">shoot me an email</a> or
|
||||
<a href="https://www.reddit.com/message/compose?to=xternal7" target="_blank">PM me on reddit</a>. Please include this string in the message:
|
||||
</b>
|
||||
</p>
|
||||
<p>
|
||||
<i>{{userAgent}}</i>
|
||||
</p>
|
||||
<p>
|
||||
<b>Your help is much appreciated.</b>
|
||||
</p>
|
||||
<p> </p>
|
||||
<p>
|
||||
Further reading: <a href="https://stuff.tamius.net/sacred-texts/2020/12/22/ultrawidify-and-edge-2020-edition/" target="_blank">blog post with extra details</a>.
|
||||
</p>
|
||||
<p>
|
||||
I know better than you: <b><a @click="uiVisible=false">hide this popup</a></b>
|
||||
</p>
|
||||
<p>
|
||||
In order to disable this popup forever, open the ultrawidify popup, click on 'site settings' and disable automatic aspect ratio detection for this site.
|
||||
You should probably even disable the extension for this site altogether for the time being.
|
||||
</p>
|
||||
<p>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
</p>
|
||||
<h3>Help by reporting this issue to Microsoft</h3>
|
||||
<p><b>Go to the settings menu</b> <small>(upper right corner of the window, three dots)</small> <b>→ Help and feedback</b> <small>(second option from the bottom)</small> <b>→ Send feedback.</b> (Alternatively, press Alt + Shift + I)</p>
|
||||
<p>Enter this in the first box:</p>
|
||||
<p>
|
||||
<br/>
|
||||
<i>
|
||||
Videos on sites that utilize DRM protection schemes are not being scaled correctly. If a part of a DRM-protected video is being displayed outside the boundaries of the browser window,
|
||||
Edge will scale the video to only fit the portion of the video tag that is currently being displayed on the screen, rather than filling the entire video tag. This causes videos appear
|
||||
differently than website developers intended at best, and breaking certain websites at worst.
|
||||
</i>
|
||||
<br/>
|
||||
</p>
|
||||
<p>Or something along these lines. Click 'send' when you're done.</p>
|
||||
<p>Maybe if Edge developer team gets enough reports, they'll fix the problem.</p>
|
||||
</div>
|
||||
<div class="image-examples panel">
|
||||
<p>Follow-up questions</p>
|
||||
<h3>How can one tell when Edge has fixed their bugs?</h3>
|
||||
<p>
|
||||
When 21:9 movies on netflix look like this:
|
||||
</p>
|
||||
<p>
|
||||
<img :src="getUrl('res/img/git-ignore/edge-demo-working.jpg')" />
|
||||
</p>
|
||||
<p>
|
||||
And not like this:
|
||||
</p>
|
||||
<p>
|
||||
<img :src="getUrl('res/img/git-ignore/edge-demo.jpg')" />
|
||||
</p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import Icon from '../common/components/Icon';
|
||||
import BrowserDetect from '../ext/conf/BrowserDetect';
|
||||
import Settings from '../ext/lib/Settings';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Icon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uiVisible: true,
|
||||
userAgent: window.navigator.userAgent
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
showUi(visible) {
|
||||
if (visible !== undefined) {
|
||||
this.uiVisible = visible;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getUrl(url) {
|
||||
return BrowserDetect.firefox ? browser.runtime.getURL(url) : chrome.runtime.getURL(url);
|
||||
},
|
||||
async hidePopupForever() {
|
||||
const settings = new Settings();
|
||||
await settings.init();
|
||||
|
||||
if (!settings.active.mutedNotifications) {
|
||||
settings.active.mutedNotifications = {};
|
||||
}
|
||||
if (!settings.active.mutedNotifications?.browserSpecific) {
|
||||
settings.active.mutedNotifications.browserSpecific = {
|
||||
edge: {
|
||||
brokenDrm: {
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
settings.active.mutedNotifications.browserSpecific.edge.brokenDrm[window.location.hostname] = true;
|
||||
|
||||
await settings.saveWithoutReload();
|
||||
this.uiVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" src="../res/css/uwui-base.scss"></style>
|
||||
<style lang="scss" scoped>
|
||||
@import '../res/css/uwui-base.scss';
|
||||
@import '../res/css/colors.scss';
|
||||
@import '../res/css/font/overpass.css';
|
||||
@import '../res/css/font/overpass-mono.css';
|
||||
@import '../res/css/common.scss';
|
||||
|
||||
.uw-ultrawidify-container-root {
|
||||
font-family: 'Overpass';
|
||||
|
||||
.uw-hover {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
left: 5%;
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
color: #fff;
|
||||
background-color: rgba(84, 8, 8, 0.786);
|
||||
|
||||
pointer-events: auto;
|
||||
overflow: hidden;
|
||||
|
||||
p, h1, h2, h3 {
|
||||
margin: 0.75em;
|
||||
display: block;
|
||||
// display: inline-block;
|
||||
}
|
||||
|
||||
i {
|
||||
font-family: 'Overpass Mono', monospace;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
sup {
|
||||
vertical-align: super;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.text {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
max-width: 666px;
|
||||
min-width: 420px;
|
||||
}
|
||||
|
||||
.image-examples {
|
||||
flex-grow: auto;
|
||||
flex-shrink: 1;
|
||||
min-width: 720px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pad {
|
||||
padding: 16px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
// padding-bottom: 10%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.flex-row {
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
@ -9,6 +9,7 @@ const BrowserDetect = {
|
||||
edge: process.env.BROWSER === 'edge',
|
||||
processEnvBrowser: process.env.BROWSER,
|
||||
processEnvChannel: process.env.CHANNEL,
|
||||
isEdgeUA: () => /Edg\/(\.?[0-9]*)*$/.test(window.navigator.userAgent)
|
||||
}
|
||||
|
||||
if (process.env.CHANNEL !== 'stable') {
|
||||
|
@ -406,6 +406,18 @@ const ExtensionConfPatch = [
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '4.5.1',
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
for (const site in userOptions.sites) {
|
||||
try {
|
||||
delete userOptions[sites].autoarPreventConditions
|
||||
} catch (e) {
|
||||
// doesn't matter if site doesn't have that option,
|
||||
// everything is still fine
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -1032,26 +1032,13 @@ 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,
|
||||
videoAlignment: VideoAlignment.Default,
|
||||
keyboardShortcutsEnabled: ExtensionMode.Default,
|
||||
arPersistence: true, // persist aspect ratio between different videos
|
||||
autoarPreventConditions: { // prevents autoar on following conditions
|
||||
videoStyleString: { // if video style string thing does anything of what follows
|
||||
containsProperty: { // if video style string has any of these properties (listed as keys)
|
||||
'height': { // if 'height' property is present in style attribute, we prevent autoar from running
|
||||
allowedValues: [ // unless attribute is equal to anything in here. Optional.
|
||||
'100%'
|
||||
]
|
||||
}
|
||||
// 'width': true // this would prevent aard from running if <video> had a 'width' property in style, regardless of value
|
||||
// could also be an empty object, in theory.
|
||||
}
|
||||
}
|
||||
},
|
||||
"DOM": {
|
||||
"player": {
|
||||
"manual": true,
|
||||
@ -1071,19 +1058,6 @@ var ExtensionConf = {
|
||||
videoAlignment: VideoAlignment.Default,
|
||||
keyboardShortcutsEnabled: ExtensionMode.Default,
|
||||
arPersistence: true, // persist aspect ratio between different videos
|
||||
autoarPreventConditions: { // prevents autoar on following conditions
|
||||
videoStyleString: { // if video style string thing does anything of what follows
|
||||
containsProperty: { // if video style string has any of these properties (listed as keys)
|
||||
'height': { // if 'height' property is present in style attribute, we prevent autoar from running
|
||||
allowedValues: [ // unless attribute is equal to anything in here. Optional.
|
||||
'100%'
|
||||
]
|
||||
}
|
||||
// 'width': true // this would prevent aard from running if <video> had a 'width' property in style, regardless of value
|
||||
// could also be an empty object, in theory.
|
||||
}
|
||||
}
|
||||
},
|
||||
DOM: {
|
||||
"player": {
|
||||
"manual": true,
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
98
src/ext/lib/uwui/PlayerUI.js
Normal file
98
src/ext/lib/uwui/PlayerUI.js
Normal file
@ -0,0 +1,98 @@
|
||||
import UI from './UI';
|
||||
import VuexWebExtensions from 'vuex-webextensions';
|
||||
import PlayerUiComponent from '../../../csui/PlayerUiComponent.vue';
|
||||
|
||||
if (process.env.CHANNEL !== 'stable'){
|
||||
console.info("Loading: PlayerUi");
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that handles in-player UI
|
||||
*/
|
||||
class PlayerUi extends UI {
|
||||
|
||||
/**
|
||||
* Creates new in-player UI for ultrawidify
|
||||
* @param {*} playerElement PlayerUI will be created as a child of this element
|
||||
* @param {*} settings Extension settings (instanceof Settings)
|
||||
*/
|
||||
constructor (
|
||||
playerElement,
|
||||
settings
|
||||
) {
|
||||
super(
|
||||
'ultrawidifyUi',
|
||||
PlayerUi.getStoreConfig(),
|
||||
PlayerUi.getUiConfig(playerElement),
|
||||
PlayerUi.getCommsConfig()
|
||||
);
|
||||
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
|
||||
//#region constructor helpers
|
||||
// we will move some things out of the constructor in order to keep things clean
|
||||
static getStoreConfig() {
|
||||
// NOTE: these are sample values and can be deleted. Currently, they're commented out
|
||||
// so we won't have to look up the documentation in order to get them working
|
||||
return {
|
||||
plugins: [
|
||||
VuexWebExtensions({
|
||||
persistentStates: [
|
||||
'showUi'
|
||||
],
|
||||
}),
|
||||
],
|
||||
state: {
|
||||
showUi: true,
|
||||
},
|
||||
mutations: {
|
||||
'uw-toggle-ui'(state) {
|
||||
state['showUi'] = !state['showUi'];
|
||||
},
|
||||
'uw-set-ui-visible'(state, payload) {
|
||||
state['showUi'] = payload;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
'uw-set-ui-visible'({commit}, payload) {
|
||||
commit('uw-set-ui-visible', payload);
|
||||
},
|
||||
'uw-toggle-ui'({commit}) {
|
||||
commit('uw-toggle-ui');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static getUiConfig(playerElement) {
|
||||
return {
|
||||
parentElement: playerElement,
|
||||
component: PlayerUiComponent
|
||||
}
|
||||
}
|
||||
|
||||
static getCommsConfig() {
|
||||
// NOTE: these are sample values and can be deleted. Currently, they're commented out
|
||||
// so we won't have to look up the documentation in order to get them working
|
||||
return {
|
||||
handlers: {
|
||||
// 'show-notification': [(message) => this.showNotification(message)],
|
||||
}
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region lifecycle
|
||||
replace(playerElement) {
|
||||
super.replace(this.getUiConfig(playerElement));
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
if (process.env.CHANNEL !== 'stable'){
|
||||
console.info("PlayerUi loaded");
|
||||
}
|
||||
|
||||
export default PlayerUi;
|
@ -42,7 +42,9 @@ class UI {
|
||||
|
||||
const rootDiv = document.createElement('div');
|
||||
|
||||
rootDiv.setAttribute('style', `pointer-events: none; position: ${this.uiConfig.style?.position ?? 'absolute'}; width: ${this.uiConfig.style?.width ?? '100%'}; height: ${this.uiConfig.style?.height ?? '100%'}; top: ${this.uiConfig.style?.height ?? '0'}; ${this.uiConfig.additionalStyle ?? ''}`);
|
||||
if (this.uiConfig.additionalStyle) {
|
||||
rootDiv.setAttribute('style', this.uiConfig.additionalStyle);
|
||||
}
|
||||
rootDiv.setAttribute('id', uwid);
|
||||
rootDiv.classList.add('uw-ultrawidify-container-root');
|
||||
|
||||
|
@ -2,6 +2,8 @@ import Debug from '../../conf/Debug';
|
||||
import ExtensionMode from '../../../common/enums/extension-mode.enum'
|
||||
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
||||
import PlayerNotificationUi from '../uwui/PlayerNotificationUI';
|
||||
import PlayerUi from '../uwui/PlayerUI';
|
||||
import BrowserDetect from '../../conf/BrowserDetect';
|
||||
|
||||
if (process.env.CHANNEL !== 'stable'){
|
||||
console.info("Loading: PlayerData.js");
|
||||
@ -44,7 +46,9 @@ class PlayerData {
|
||||
this.extensionMode = videoData.extensionMode;
|
||||
this.invalid = false;
|
||||
this.element = this.getPlayer();
|
||||
|
||||
this.notificationService = new PlayerNotificationUi(this.element, this.settings);
|
||||
|
||||
this.dimensions = undefined;
|
||||
this.overlayNode = undefined;
|
||||
|
||||
@ -476,6 +480,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)) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
@ -675,7 +672,7 @@ 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
|
||||
styleArray.push("top: 0px !important; left: 0px !important; bottom: 0px !important; right: 0px;");
|
||||
styleArray.push("position: absolute; 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
|
||||
// restrictions. If site has dumb shit like 'max-width: 100%' and 'max-height: 100vh' in their CSS, that
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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",
|
||||
"version": "4.5.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,27 +2,24 @@
|
||||
<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.
|
||||
</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.
|
||||
Edge users using CWS version of the extension get a very aggressive warning when trying to use the extension with Edge
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -1,6 +1,46 @@
|
||||
.uw-ultrawidify-container-root {
|
||||
|
||||
// here's the defaults:
|
||||
all: initial;
|
||||
* {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
// here's things that we don't want as defaults
|
||||
// (must come after the all: declaration, otherwise
|
||||
// all: declaration overrides everything.)
|
||||
|
||||
// we put our UI _over_ site's player:
|
||||
z-index: 999999;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
// Ensure we're display:block
|
||||
display: block;
|
||||
|
||||
// we are click-through by default:
|
||||
pointer-events: none;
|
||||
|
||||
// defaults for some common elements:
|
||||
p,h1,h2,h3,h4,h5,h6,div {
|
||||
display: block;
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6,b {
|
||||
font-weight: bold;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin: .5rem 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.69em;
|
||||
margin: .42rem 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.42rem;
|
||||
margin: .25rem 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user