Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8ff061371d |
27
.babelrc
@ -1,27 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
],
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
"useBuiltIns": false,
|
||||
"targets": {
|
||||
"esmodules": true
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
// {
|
||||
// "plugins": [
|
||||
// "@babel/plugin-proposal-optional-chaining"
|
||||
// ],
|
||||
// "presets": [
|
||||
// ["@babel/preset-env", {
|
||||
// "useBuiltIns": "usage",
|
||||
// "targets": {
|
||||
// // https://jamie.build/last-2-versions
|
||||
// "browsers": ["> 0.25%", "not ie 11", "not op_mini all"]
|
||||
// }
|
||||
// }]
|
||||
// ]
|
||||
// }
|
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,25 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
Describe what happened. Don't forget to mention which site you were on (reddit, netflix, youtube). If issue only happens with certain videos, please provide links with timestamps.
|
||||
|
||||
**To Reproduce**
|
||||
What did you do to make it happen?
|
||||
|
||||
**Expected behavior**
|
||||
What do you think should happen instead?
|
||||
|
||||
**Screenshots**
|
||||
A picture is worth a thousand words. If Ultrawidify scales a video in an improper way, please include a screenshot of that.
|
||||
|
||||
**Browser and OS**
|
||||
* Browser/browser version:
|
||||
* Operating system:
|
||||
* Ultrawidify version:
|
||||
|
||||
**Additional info**
|
||||
Any other things you want to say.
|
18
.gitignore
vendored
@ -1,17 +1 @@
|
||||
old/
|
||||
build/
|
||||
/node_modules
|
||||
/*.log
|
||||
/dist*
|
||||
/uw-git_keys
|
||||
/untracked-assets
|
||||
|
||||
*.pem
|
||||
|
||||
*.kate-swp
|
||||
|
||||
src/res/img/git-ignore/
|
||||
|
||||
test/debug-configs/
|
||||
|
||||
debugging-resources/
|
||||
ultrawidify.zip
|
||||
|
8
.vscode/extensions.json
vendored
@ -1,8 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"hollowtree.vue-pack",
|
||||
"msjsdiag.debugger-for-chrome",
|
||||
"firefox-devtools.vscode-firefox-debug",
|
||||
"msjsdiag.debugger-for-edge"
|
||||
]
|
||||
}
|
52
.vscode/launch.json
vendored
@ -1,52 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "attach",
|
||||
"name": "Attach to Chrome",
|
||||
"port": 9222,
|
||||
"urlFilter": "http://*/*",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "firefox",
|
||||
"request": "attach",
|
||||
"name": "Attach (firefox)",
|
||||
"pathMappings": [
|
||||
{
|
||||
"url": "webpack:///ext",
|
||||
"path": "${workspaceFolder}/src/ext"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Launch addon (firefox)",
|
||||
"type": "firefox",
|
||||
"request": "launch",
|
||||
"port": 6000,
|
||||
"reAttach": true,
|
||||
"addonType": "webExtension",
|
||||
"addonPath": "${workspaceFolder}/dist-ff",
|
||||
"pathMappings": [
|
||||
{
|
||||
"url": "webpack:///ext",
|
||||
"path": "${workspaceFolder}/src/ext"
|
||||
},
|
||||
]
|
||||
}
|
||||
],
|
||||
"firefox": {
|
||||
"executable": "/usr/bin/firefox-developer-edition",
|
||||
"firefoxArgs": [
|
||||
"--start-debugger-server"
|
||||
]
|
||||
},
|
||||
"chrome": {
|
||||
"executable": "/usr/bin/google-chrome-stable --remote-debugging-port=9222",
|
||||
}
|
||||
}
|
86
.vscode/settings.json
vendored
@ -1,86 +0,0 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"aard",
|
||||
"ardetector",
|
||||
"autodetect",
|
||||
"autodetection",
|
||||
"beforeunload",
|
||||
"blackbar",
|
||||
"blackbars",
|
||||
"blackframe",
|
||||
"canvas",
|
||||
"clickthrough",
|
||||
"com",
|
||||
"comms",
|
||||
"csui",
|
||||
"decycle",
|
||||
"dinked",
|
||||
"dinks",
|
||||
"disneyplus",
|
||||
"endregion",
|
||||
"equalish",
|
||||
"fith",
|
||||
"fitw",
|
||||
"fuckup",
|
||||
"gfycat",
|
||||
"gmail",
|
||||
"guardline",
|
||||
"han",
|
||||
"haram",
|
||||
"iframe",
|
||||
"imgur",
|
||||
"insta",
|
||||
"letterboxed",
|
||||
"manjaro",
|
||||
"mdicon",
|
||||
"mdijs",
|
||||
"minification",
|
||||
"mitigations",
|
||||
"nogrow",
|
||||
"noshrink",
|
||||
"outro",
|
||||
"PILLARBOX",
|
||||
"PILLARBOXED",
|
||||
"polyfill",
|
||||
"recursing",
|
||||
"reddit",
|
||||
"rescan",
|
||||
"resizer",
|
||||
"scrollbar",
|
||||
"shitiness",
|
||||
"smallcaps",
|
||||
"suboption",
|
||||
"tabitem",
|
||||
"tablist",
|
||||
"tamius",
|
||||
"textbox",
|
||||
"ultrawide",
|
||||
"ultrawidify",
|
||||
"unmark",
|
||||
"unmarking",
|
||||
"unshift",
|
||||
"uwid",
|
||||
"uwui",
|
||||
"videodata",
|
||||
"vids",
|
||||
"vuejs",
|
||||
"vuex",
|
||||
"webextension",
|
||||
"webextensions",
|
||||
"youtube"
|
||||
],
|
||||
"cSpell.ignoreWords": [
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"autoar",
|
||||
"cheight",
|
||||
"cwidth",
|
||||
"fcstart",
|
||||
"fctime",
|
||||
"legacycd",
|
||||
"ncol",
|
||||
"nrow",
|
||||
"tickrate",
|
||||
"undisable",
|
||||
"vdid"
|
||||
]
|
||||
}
|
584
CHANGELOG.md
@ -1,584 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
|
||||
### Plans for the future
|
||||
|
||||
* Native builds for Chromium Edge
|
||||
* Settings page looks ugly af right now. Maybe fix it some time later
|
||||
* other bug fixes
|
||||
|
||||
## v7.0 (planned major)
|
||||
* WebGL autodetection
|
||||
|
||||
## v6.0 (current major)
|
||||
|
||||
### v6.0.1
|
||||
|
||||
* Fixed external links
|
||||
|
||||
### v6.0.0
|
||||
|
||||
Chrome only, because I needed to rush manifest v3 migration before ensuring things work in Firefox.
|
||||
|
||||
* In player UI
|
||||
* New alignment options (can align video both vertically, as well as horizontally)
|
||||
* Extension does a little bit of a better job differentiating between levels of support for a given site
|
||||
* Changed how cropping and panning works. This should lead to fewer problems and better generic support.
|
||||
* REGRESSION: no manual panning with shift + mouse movement
|
||||
* "Player select" screen, which provides a GUI way for picking HTML element that acts as the video player area
|
||||
|
||||
Regressions and potential issues:
|
||||
* Settings were largely not migrated from previous versions. This is as intended, since changes to cropping (and some other aspects)
|
||||
rendered certain old settings obsolete.
|
||||
* Extension can no longer discriminate between iframes — extension popup commands get sent to ALL iframes on page
|
||||
* Extension probably can't discriminate between multiple videos on a single page
|
||||
|
||||
## v5.x
|
||||
|
||||
### v5.1.7
|
||||
|
||||
Firefox-only.
|
||||
|
||||
* When cropping and panning video, CSS' `transform: translate(x,y)` now uses integers _always_. Before that fix, `translate(x,y)` could be offset by x.5 px, and that half of a pixel introduced a 1px thick line on the portion of the left edge of the video.
|
||||
|
||||
### v5.1.7
|
||||
|
||||
* When aligning videos, ensure video is never translated by a fractional value
|
||||
* As of recent nVidia driver update in Edge, Angle detection fails in a way that prevents popup from showing up. This problem should be fixed now.
|
||||
|
||||
The angle detection problem was fixed by disabling the angle detection check for now, as Chrome, et al. appear to have fixed buggy video hardware acceleration.
|
||||
|
||||
### v5.1.6
|
||||
|
||||
* Added new config for disney+ (courtesy of @MStefan99)
|
||||
* Chrome hardware acceleration is bugged and cannot be worked around in-extension. Only way to fix this is for users to change their Google Chrome settings. Added naggathon with instructions into the extension popup.
|
||||
|
||||
### v5.1.5
|
||||
|
||||
* Fixed laginess in Chromium-based browsers on Windows. Details in [#199](https://github.com/tamius-han/ultrawidify/issues/199#issuecomment-1221383134)
|
||||
|
||||
### v5.1.4
|
||||
|
||||
* Fixed some problems with autodetection not returning to 16:9 when necessary if autodetection already changed aspect ratio ([#198](https://github.com/tamius-han/ultrawidify/issues/198))
|
||||
|
||||
### v5.1.3
|
||||
|
||||
* Fixed some problems with autodetection sometimes briefly resetting on dark frames ([#195](https://github.com/tamius-han/ultrawidify/issues/195), [#196](https://github.com/tamius-han/ultrawidify/issues/196))
|
||||
|
||||
### v5.1.2
|
||||
|
||||
* `set-extension-mode` turned into `set-ExtensionMode` at some point. This caused in "Enable this extension" options to vanish on certain setups.
|
||||
* Blackframe tests now run on same data as main algorithm as opposed on a smaller sample (`drawImage()` calls are _very_ expensive even for a 16x9 sample).
|
||||
|
||||
### v5.1.1
|
||||
|
||||
* Fixed autodetection
|
||||
|
||||
### v5.1.0
|
||||
|
||||
* Re-enable logger
|
||||
* Move aspect ratio autodetection to requestAnimationFrame
|
||||
* Fix netflix
|
||||
|
||||
### v5.0.7
|
||||
|
||||
* Videos of square-ish aspect ratios on 1440p (and lower) resolutions now no longer get misaligned ([#162](https://github.com/tamius-han/ultrawidify/issues/162))
|
||||
* Alignment of featured videos on youtube channel page should now also be fixed
|
||||
|
||||
### v5.0.6
|
||||
* Added configuration for metaivi.com based on user feedback ([#160](https://github.com/tamius-han/ultrawidify/issues/160))
|
||||
* Removed ExtConfPatches for versions < 4.5.0, because nobody should be using a build of this extension that's over a year old
|
||||
|
||||
### v5.0.5
|
||||
|
||||
* improved UX a bit
|
||||
* Fixed white background on app.plex.tv ([#158](https://github.com/tamius-han/ultrawidify/issues/158))
|
||||
|
||||
### v5.0.4
|
||||
* Attempt to fix disney+ again, courtesy of [@jwannebo](https://github.com/tamius-han/ultrawidify/issues/84#issuecomment-846334005) on github.
|
||||
|
||||
|
||||
### v5.0.3
|
||||
|
||||
* Fixed the issue where the videos were sometimes offset up and left. Again.
|
||||
* Fix the issue where correcting source stretch was squished incorrectly ([#153](https://github.com/tamius-han/ultrawidify/issues/153))
|
||||
|
||||
### v5.0.2
|
||||
|
||||
* When in full screen, the extension will assume player element dimensions are the same as the screen resolution. This should help with sites where ultrawidify doesn't correctly identify the player, as cropping generally doesn't work if player element is not identified. Old behaviour can be restored in advanced extension settings by toggling the "use player aspect ratio in fullscreen" checkbox under 'player detection settings'.
|
||||
* Extension should now respect 'disable extension' option for real.
|
||||
* Fixed the issue where player wouldn't get detected if video was wider than the player.
|
||||
|
||||
|
||||
### v5.0.1
|
||||
* Added an option for users to turn off (and/or configure) Chrome/Edge's zoom limiter.
|
||||
|
||||
### v5.0.0
|
||||
|
||||
There's been some big-ish changes under the hood:
|
||||
|
||||
* Migrate main scripts to typescript (vue is currently not included).
|
||||
* webextension-polyfill is now used everywhere (if only because typescript throws a hissy fit with `browser` and `chrome` otherwise) ([#114](https://github.com/tamius-han/ultrawidify/issues/114))
|
||||
* Fix some bugs that I didn't even know I had, but typescript kinda shone some light on them
|
||||
* Manual zoom (Z/U unless sites override the two) should now work again (without automatic AR constantly overriding it). Same goes for panning. ([#135](https://github.com/tamius-han/ultrawidify/issues/135) & [#138](https://github.com/tamius-han/ultrawidify/issues/138))
|
||||
* Fix issue when video would be scaled incorrectly if video element uses `height:auto`.
|
||||
* **[5.0.0.1]** Fixed the issue where settings were reset on page load.
|
||||
* **[5.0.0.1]** Fixed the issue where settings page wouldn't load.
|
||||
## v4.x (current major)
|
||||
|
||||
### v4.5.3
|
||||
|
||||
* Provides workaround for the fullscreen stretching bug Chrome 88 (or a recent Windows 10 update) introduced for nVidia users using hardware acceleration on Windows 10. In order to mitigate this bug, Ultrawidify needs to keep a 5-10 px wide black border while watching videos in full screen. This bug is also present in Edge.
|
||||
* **[4.5.3.1]** Fixed letterbox misalignment binding in settings (#134)
|
||||
* **[4.5.3.2]** Fixed false 'autodetection not supported' notifications.
|
||||
|
||||
### v4.5.2
|
||||
|
||||
* Fixed the issue where videos would sometimes get misaligned while using hybrid stretch, except for real this time. ([#125](https://github.com/tamius-han/ultrawidify/issues/125))
|
||||
* Improved DRM detection (the 'autodetection cannot work on this site' popup should now no longer show up on the sites where autodetection _can_ work)
|
||||
|
||||
### 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))
|
||||
* 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))
|
||||
* **[4.5.1.2]** Fixed the issue where videos would sometimes get misaligned while using hybrid stretch. ([#125](https://github.com/tamius-han/ultrawidify/issues/125))
|
||||
* **[4.5.1.3]** Added fix for disney plus
|
||||
* **[4.5.1.3]** Microsoft Edge has fixed the bugs that prevented the extension from working properly. Popup should no longer be shown.
|
||||
|
||||
|
||||
### 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).
|
||||
* Added config for wakanim.tv (special thanks to @saschanaz for doing the legwork — [#113](https://github.com/tamius-han/ultrawidify/issues/113))
|
||||
* (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.
|
||||
|
||||
### 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
|
||||
* Fixed a problem where changing certain settings would cause multiple instances of Ultrawidify to run on a page, effectively preventing some crop options to be set until reload. (possibly [#112](https://github.com/tamius-han/ultrawidify/issues/112)?)
|
||||
* Fixed a problem where embedded videos would be misaligned after switching from full screen
|
||||
* **[4.4.10.1]** Fixed cruncyhroll regression — [#109](https://github.com/tamius-han/ultrawidify/issues/115)
|
||||
|
||||
### v4.4.9
|
||||
|
||||
* Fixed the youtube alignment issue (previously fixed in v4.4.7.1-2), but this time for real (and in a bit more proper way)
|
||||
* Fixed the bug where extension wouldn't work when URL specified a port (e.g. www.example.com:80)
|
||||
* **[4.4.9.1]** removed source files from extension build in order to decrease package size
|
||||
* **[4.4.9.2]** updated dependencies and stuff
|
||||
|
||||
In addition to that, as of 4.4.9.1 the build process ensures removal of `node_modules` before building the extension so we can have reproducible builds except for real this time. Hopefully.
|
||||
|
||||
### v4.4.8
|
||||
|
||||
* Fixed the bug where on pages with more than one video, the list of available videos in the extension popup wouldn't remove videos that are no longer displayed on site. This resulted in extension listing videos that were no longer on the page. Reboot or navigation would also not clear the list if navigating between various pages on the same host.
|
||||
* Fixed the chrome-only bug where on sites with more than one video, the number wouldn't get hidden when the extension popup closed.
|
||||
|
||||
### v4.4.7
|
||||
|
||||
* Removed unnecessary font files and image files from the package.
|
||||
* LoggerUI is now functional.
|
||||
* **[4.4.7.1]** Additional CSS fixes
|
||||
* **[4.4.7.1]** Bruteforce fix for youtube alignment issue
|
||||
* **[4.4.7.2]** Bruteforce fix for youtube alignment issue — increase number of retries
|
||||
|
||||
### v4.4.6
|
||||
|
||||
* Ensured that Vue part of the content script (logger UI) only loads when necessary in order to fix breakage on certain sites (#96).
|
||||
* Disabling (or enabling, if running in whitelist-only mode) specific sites used to not work (#91). This issue appears to have been fixed.
|
||||
* Default stretch mode for sites is now probably being observed, too (#94).
|
||||
* Fixed netflix (and possibly disney+ )
|
||||
* It's been almost a month and Chrome Web Store still hasn't finished the review of the 4.4.4.1 (and 4.4.4.2) revisions because when it comes to incompetence, it's hard to expect anything less from Google. I've did some proverbial yelling at the support in hopes that Chrome version will finally see an update (disclaimer: when I said yelling I really mean a polite request, because support staff doesn't deserve abuse because a different department is utter shite at doing their jobs).
|
||||
|
||||
### v4.4.5
|
||||
|
||||
* Extension no longer requires `allTabs` and `webNavigation` permissions
|
||||
* Some CSS on the debugger popup was not scoped, causing issues with some sites.
|
||||
* Fix some additional issues with video alignment when changing video on autoplay
|
||||
|
||||
### v4.4.4
|
||||
|
||||
* Tab detection in extension popup has been made more accurate
|
||||
* QoL: Added user-accessible logger (to make fixing sites I can't access a bit easier)
|
||||
* Changed links to reflect my github username change
|
||||
* **[4.4.4.1]** Fix broken extension popup.
|
||||
* **[4.4.4.1]** Fix global/site settings not getting applied immediately/only getting applied after page reload.
|
||||
* **[4.4.4.2]** Fix problem with video being offset while switching between full screen and non-fullscreen non-theater mode on Youtube
|
||||
|
||||
### v4.4.3
|
||||
|
||||
* Fixed conf patch for disney+ (hopefully) (v4.4.3.1: but for real)
|
||||
* `Settings.save()` adds missing values to site config when saving extension configuration.
|
||||
|
||||
### v4.4.2
|
||||
|
||||
* New stretching modes that squish video to a specified aspect ratio. One of the two modes correct aspect ratio before cropping, the other corrects after cropping.
|
||||
* Potential fix for disney+ — added an option that forces extension to force player re-detection.
|
||||
* Fixed bug where certain custom actions that should be removable weren't removable
|
||||
|
||||
### v4.4.1
|
||||
|
||||
* Changes to player detection that fix issues with vk
|
||||
* Extension tries to avoid setting aspect ratio pointlessly
|
||||
* (Hopefully) fixed mailto: and reddit compose links.
|
||||
* When reporting bugs, email/reddit template now automatically gathers browser, extension version and OS.
|
||||
|
||||
### v4.4.0
|
||||
|
||||
* Russian users (and users of other non-latin keyboard layouts) can now use keyboard shortcuts by default, without having to rebind them manually. (NOTE: if you've changed keyboard shortcuts manually, this change will ***NOT*** be applied to your configuration.)
|
||||
* NOTE: when using non-latin layouts, 'zoom' shortcut (`z` by default) uses the position of 'Y' on QWERTY layout.
|
||||
* Ability to preserve aspect ratio between different videos (applies to current page and doesn't survive proper page reloads)
|
||||
* Changing aspect ratio now resets zooming and panning.
|
||||
* Fixed bug where keyboard shortcuts would work while typing in certain text fields
|
||||
* Fixed minor bug with autodetection
|
||||
* **[4.4.0.1]** fixed mailto and reddit compose links. When reporting issues via e-mail or reddit, extension version, browser
|
||||
and OS are automatically included in email/reddit template.
|
||||
|
||||
### v4.3.1
|
||||
|
||||
* Minor rework of settings page (actions & shortcuts section)
|
||||
* Fixed bug that prevented settings page from opening
|
||||
* **[4.3.1.1]** quick patch for twitch.tv
|
||||
|
||||
### v4.3.0
|
||||
|
||||
* Fixed some issues with incorrect alignment after window resize
|
||||
* Fixed all sorts of issues for videos hosted on v.reddit for new (and old) reddit
|
||||
* Fixed the issue where setting extension to 'whitelist only' would disable 'site settings' in popup.
|
||||
* Added user-friendly way to export/import settings (export requires 'download' permissions)
|
||||
* Reworked logging
|
||||
* Started using mutation observers to watch for changes in player size as well. Since mutation observers aren't entirely reliable, old way of doing things is still somewhat present as a backup way, but runs less frequently.
|
||||
* Implemented/improved/fixed settings patching
|
||||
* **[4.3.0.1]** Removed some console.logs that I missed the first time around.
|
||||
* **[4.3.0.2]** Extension would not work for new users. (Special thanks to [ezzak](https://github.com/ezzak) for finding and submitting a patch)
|
||||
|
||||
### v4.2.4 / 4.2.4.x
|
||||
|
||||
* Improvements to player detection. More details in the [blog post](https://stuff.tamius.net/sacred-texts/2019/08/31/ultrawidify-and-the-improper-cropping/).
|
||||
* **[4.2.4.1]** Fixed default video settings for reddit
|
||||
* **[4.2.4.1]** Manually specified query selectors will also be checked for compliance with player detection rules.
|
||||
* **[4.2.4.2]** Additional bugfixes. Updated/fixed default settings.
|
||||
|
||||
### v4.2.3 / 4.2.3.x
|
||||
* Fixed twitchy behaviour on Twitch, Facebook and Twatter. Here's a [blog post](https://stuff.tamius.net/sacred-texts/2019/08/24/ultrawidify-the-twitchy-twitch-problem/) that covers the issue in more detail.
|
||||
* Cropping now uses user styles (as opposed to modifying element's style attribute)
|
||||
* Fixed the issue where one-pixel letterbox would result in constant aspect ratio corrections.
|
||||
* Started using mutation observers to watch for anything modifying the size of our video.
|
||||
* **[4.2.3.1]** fixed some bugs in popup.
|
||||
|
||||
### v4.2.2
|
||||
|
||||
* Fixed player detection on reddit (for videos from v.reddit)
|
||||
|
||||
### v4.2.1
|
||||
* Fixed bug where custom CSS didn't get applied to pages
|
||||
|
||||
### v4.2.0
|
||||
|
||||
* Slightly improved popup design. (Design change suggested by PortaTrekos)
|
||||
* Player detection: youtube and twitch now have manual player element detection, with strictly defined players.
|
||||
* Improved site settings control in extension popup. It's possible to enable extension for previously disabled embedded sites.
|
||||
* Improved incompatibilities with reddit, where videos would be vertically misaligned when not using RES
|
||||
* Fixed imcompatibilities with Iridium. Flicker when clicking play/pause or switching between big and popup player is caused by either Youtube or Iridium trying to apply their styles over mine.
|
||||
* Issues with inconsistent alignment that some people reported are potentially fixed
|
||||
|
||||
### v4.1.2
|
||||
|
||||
* Fixed video alignment issues on www.reddit as well (for people who use old reddit without going to old.reddit)
|
||||
* Fixed bug with 'player detection' tab
|
||||
|
||||
### v4.1.1
|
||||
|
||||
* Disabled gfycat
|
||||
|
||||
### v4.1.0
|
||||
|
||||
* Added ability to add custom CSS to page
|
||||
* Fixed video alignment issues on old.reddit. Disabled extension on imgur by default.
|
||||
* Extension now works on vimeo again
|
||||
* **UX:** Renamed 'about' to 'report a problem' in order to make contact info more discoverable
|
||||
|
||||
|
||||
### v4.0.1
|
||||
|
||||
* Fixed bug where sites using 'default' option in 'Extension mode' settings would be disabled, even if extension was not.
|
||||
* Fixed bug where extension sometimes wouldn't work on Netflix.
|
||||
|
||||
### v4.0.0
|
||||
|
||||
* Fixed the bug where saving settings wouldn't work
|
||||
* Massive under-the-hood changes. The extension popup and settings page use VueJS
|
||||
* **Autodetection improvements:**
|
||||
* Autodetection tries to differentiate between gradients and hard edge and avoids correcting on gradients. This should help with videos that are similar to [IGN's review of Hollow Knight](https://www.youtube.com/watch?v=hg25ONutphA).
|
||||
* Black frame detection has been implemented and improved. Some cases (but not all) of text on black background causing aspect ratio corrections have also been fixed.
|
||||
* Autodetection frequency increased from roughly once every 0.6 seconds to about 3 checks per second.
|
||||
* Fixed the bug where autodetectin didn't calculate aspect ratio correctly. This bug would manifest in extension cropping too much even though the edge was clearly defined. It most commonly occured in videos of aspect ratio <1 that contained letterbox. [ex 1]( https://www.youtube.com/watch?v=9DP0TbOQcOw), [ex 2](https://www.reddit.com/r/videos/comments/a137pj/daily_reminder_that_shelly_miscavige_wife_of/)
|
||||
* **Settings page was re-added**
|
||||
* This includes a page for adding new aspect ratios and keyboard shortcuts. This feature is experimental.
|
||||
* It's possible to tweak autodetection sensitivity and frequency — in slightly more user-friendly way as well
|
||||
* It's also possible to tweak autodetection settings in detail.
|
||||
* It's now possible to reset settings to default
|
||||
* Rewrote keyboard shortcuts and changed how they're handled. Massively.
|
||||
* You can now select which specific video on the page you control, provided each video is in its separate iframe
|
||||
* While I wasn't looking, Netflix started supporting ultrawide monitors on its own. Netflix' implementation clashes with my own, though, so I've decided to disable autodetection on videos that netflix already cropped on their own. Manual aspect ratio changes are still possible, but they're off. You've been warned.
|
||||
|
||||
## v3.x
|
||||
|
||||
~~### v3.3.0~~
|
||||
|
||||
~~This will probably get promoted to 4.0, continuing the trend of version something. 3 not happening. Eulul~~
|
||||
|
||||
* ~~Basic mode added~~
|
||||
* ~~Per-site controls in popup (to control embedded videos)~~
|
||||
* ~~Rewrote keyboard shortcuts and changed how they're handled. Massively.~~
|
||||
|
||||
Never happened, got bumped to 4.0.0.
|
||||
|
||||
### v3.2.2
|
||||
|
||||
* Pan event listener now gets properly unbound
|
||||
* Fixed 'reset zoom' button in popup
|
||||
|
||||
### v3.2.1
|
||||
|
||||
* Fixed issue where global video alignment setting didn't get saved properly
|
||||
|
||||
### v3.2.0
|
||||
|
||||
* Zoom and panning
|
||||
* Reorganized popup
|
||||
* Various bug fixes
|
||||
|
||||
### v3.1.1 (Chrome-only)
|
||||
|
||||
* Logging was accidentally left on in release version. This was fixed.
|
||||
|
||||
### v3.1.0
|
||||
|
||||
* Fixed the issue where aspect ratio change wouldn't survive switching between fullscreen and non-fullscreen modes
|
||||
* Fixed the issue where settings wouldn't survive browser restarts in Firefox
|
||||
|
||||
Under the hood:
|
||||
|
||||
* rewrote how settings work, swapped Comms with storage.onChanged where it made sense & as much as possible
|
||||
* enabling/disabling extension (either globally or for a given site) has now instant effect (consequence of above)
|
||||
|
||||
### v3.0.1
|
||||
|
||||
Minor fixes.
|
||||
|
||||
### v3.0.0
|
||||
|
||||
Pretty much rewrote extension in more object-oriented way and sorted out spaghetti a little. Site settings and keybinds have been merged with the rest of the extension settings. Rewrote messageing.
|
||||
|
||||
User-facing changes:
|
||||
* Extension can be enabled/disabled globally or on per-site basis
|
||||
* Automatic aspect ratio can be turned off, either globally or on per-site basis
|
||||
* Stretching mode implemented
|
||||
* Popup has been pimped up to reflect those changes
|
||||
|
||||
## v2.x
|
||||
|
||||
### v2.2.5 (AMO, Chrome)
|
||||
|
||||
Added some anti-lag measures. This seems to be an issue affecting _only_ Chrome (and only then some installs), where canvas.drawImage() won't work properly for some reason.
|
||||
|
||||
### v2.2.4
|
||||
|
||||
Lots of mostly incredibly minor stuff.
|
||||
|
||||
* Fixed issue where 21:9 videos with no letterbox would be zoomed in incorrectly in theater mode
|
||||
* Added pillarbox basic pillarbox detection: extension will avoid zooming in a video if both letterbox and pillarbox are detected. This should fix the issues with incorrect zooming on certain kinds of images (such as movie titles and studio logos, e.g. [lucasfilm](https://i.ytimg.com/vi/H368H5cTqVM/maxresdefault.jpg) was one of the offenders).
|
||||
* Fixed an issue where automatic detection would sometimes _not_ unzoom the video in cases where it clearly should
|
||||
* Implemented some debugging tools for me. It's not much.
|
||||
* Fixed some under-the-hood bugs nobody knew they even existed
|
||||
* A lil bit of refactoring
|
||||
|
||||
### v2.2.3
|
||||
|
||||
* Fixed automatic aspect ratio detection on DRM-protected sites.
|
||||
|
||||
### v2.2.2
|
||||
|
||||
* Fixes problems with switching from normal to fullscreen player on youtube. If 2.2.1 didn't fix the font issue, this version should have.
|
||||
|
||||
### v2.2.1
|
||||
|
||||
* Fixes few chrome-specific fixes/bugs that v2.2.0 introduced. Maybe fixed the font problem.
|
||||
|
||||
|
||||
### v2.2.0
|
||||
|
||||
Various improvements to automatic aspect ratio detection:
|
||||
|
||||
* **Fixed the situation with insane memory usage due to the automatic aspect ratio detection (#25, #32) and lag that appeared in certain cases after the extension has been running for a while.** There's still fun stuff going on — see notes below.
|
||||
* Improved accuracy of automatic detection. This should fix the issue of rapid switching in dark videos or videos with otherwise uneven edges (#12 - [video](https://www.youtube.com/watch?v=NaTGwlfRB_c); #24 - [video](https://www.youtube.com/watch?v=xvZqHgFz51I) (see the car at the beginning))
|
||||
|
||||
Improved accuracy has increased the base RAM usage, and not by a small amount (I seem to have fixed my blunders, so that could _actually_ be on Firefox). As a result, I've reduced both resolution of the sample as well as polling frequency.
|
||||
|
||||
Polling of 1 check per second shouldn't use too much RAM. If you want automatic aspect ratio detection to react faster, you can up that number to 30 in the settings. 30 checks per second can be expensive: up to 400 MB if you've just started Firefox and went to youtube. Can go north of 2 gigs if you've been running Firefox for longer than that (seems to be a problem with Javascript garbage collection).
|
||||
|
||||
Videos that aren't playing (e.g. videos that are paused or ended) do (should) ***not*** use any meaningful amount of RAM.
|
||||
|
||||
* Overpass font is now bundled with this extension, meaning the popup should appear the way it was meant to appear™.
|
||||
|
||||
|
||||
### v2.1.4
|
||||
|
||||
* Extension has been disabled on imgur (it was breaking gifs)
|
||||
|
||||
### v2.1.3
|
||||
|
||||
* Youtube pushed an update that broke this extension on Firefox (but not on Chrome?). This update fixes it.
|
||||
* Extension disabled on reddit by default
|
||||
|
||||
Youtube fix seems to have broken Chrome compatibility (again), so any quick fix for this point forward will land in Chrome version along with v2.2.
|
||||
|
||||
### v2.1.2
|
||||
|
||||
* Fixed some bugs with autodetection sometimes not working properly on Youtube.
|
||||
|
||||
Problem: there's this bit of code that keeps aspect ratio from changing when the difference between 'previous' and 'current' aspect ratio is too small. Unfortunately, the 'previous' value was _not_ updated on every aspect ratio switch for some reason. Also `ArDetect.init()` — for some reason — didn't always clean the 'previous' value even though it should.
|
||||
|
||||
### v2.1.1
|
||||
|
||||
* Fixed issue #20 — aspect ratio autodetection should now start on subsequent videos as well.
|
||||
* Netflix sometimes always showed 'no video detected' warning. Popup and background script now periodically poll for `hasVideos` property.
|
||||
|
||||
### v2.1.0 (Chrome)
|
||||
|
||||
* Popup should work more reliably now
|
||||
* Twitch works ... kinda but not always
|
||||
|
||||
### v2.0.3
|
||||
|
||||
* Fixed the bug where Netflix videos weren't vertically centered in Firefox 57+ (not present in Chrome or FF 56 or earlier)
|
||||
|
||||
### v2.0.2
|
||||
|
||||
v2.0.1, but UI in the extension button now also works in Chrome.
|
||||
|
||||
### v2.0.1
|
||||
|
||||
* Autodetection: aspect ratio is no longer corrected if the detected difference is too small to make a meaningful difference
|
||||
|
||||
### v2.0
|
||||
|
||||
* Completely rewritten
|
||||
* Automatic aspect ratio detection works on Youtube _and_ Netflix
|
||||
* Added popup for quick actions (serves as a replacement for player UI)
|
||||
* Restored settings page for keybinds.
|
||||
|
||||
Getting automatic aspect ratio detection required some hacks, not sure how easy will be to port to chrome.
|
||||
|
||||
### v2.0a1
|
||||
|
||||
The extension is being rewritten almost ground-up, around automatic aspect ratio detection. By default, this extension now only works in fullscreen, but due to some simplification it should work on most sites. As direct result of this simplification:
|
||||
|
||||
* The UI is completely gone
|
||||
* Ability to add custom sites has been scrapped (might get implemented later on if some sites are a bit more problematic
|
||||
* Extension broken up between smaller files, this time the proper way
|
||||
* Added "the impossible aspect ratio autodetection"
|
||||
* Zoom/unzoom options are gone
|
||||
* Can't customize keybinds yet
|
||||
|
||||
# v1.x
|
||||
|
||||
### v1.3a1
|
||||
|
||||
* Adding ability to add custom sites (in progress)
|
||||
* Most of the extension is being completely rewritten to accomodate that feature, which means there's a serious regression with Netflix support (no netflix at the moment)
|
||||
* I'm also trying to break the 1500 line behemoth into smaller files.
|
||||
|
||||
### v1.2.1
|
||||
|
||||
* Fixed the bugs which caused aspect ratio to not be calculated properly.
|
||||
* Introduced further changes that allow me to not keep two separate version for Firefox and Chrome.
|
||||
|
||||
### v1.2.0
|
||||
|
||||
* Auto-aspect ratio detection on netflix
|
||||
* initial port to Chrome
|
||||
|
||||
### v1.1.1
|
||||
|
||||
* Fixed zooming issue on netflix
|
||||
* Ultrawidify shortcuts > youtube/netflix shortcuts
|
||||
* Fixed 'settings' page
|
||||
* Fixed 'settings' (wrench button) popup on youtube (it was broken by one of the previous updates)
|
||||
|
||||
### v1.1.0
|
||||
|
||||
* Introduced Netflix support.
|
||||
|
||||
As Netflix relies on extension re-initializing at least the UI ***a lot***, the optimization introduced in 1.0.2 was reversed (as waiting 2 seconds for the UI to appear is just too much).
|
||||
|
||||
Furthermore, triggering UI re-initialisation on onUpdated events turned out to not be the proper way to go: immediately after the extension is initialized, onUpdated gets triggered even more often than your average Buzzfeed writer/reader. But change the episode on Netflix and suddenly, onUpdated gets barely triggered at all — which means that more often than not, the UI extension injects into the page wasn't visible. (the fuck, really)
|
||||
|
||||
This is why Netflix uses another function that manually checks whether the player bar is present. Ideally that check happens every tenth of a second, but Firefox may be limiting that to one per second.
|
||||
|
||||
### v1.0.2
|
||||
|
||||
The 'extension sometimes not working' bug was fixed (by having extension try to setup every time a page got updated), but the fix had some problems. Namely, the extension would re-initiate (complete with re-adding the entire UI) itself very _very_ often.
|
||||
|
||||
This could be a problem, so it was fixed. Extension is notified of updates only every ~2 seconds (which absorbs most of the "page was updated" events on page load) and doesn't attempt to reload the UI if the UI was already loaded. (Unless `debugmsg` is set to true. It's generally not, but any commits to this repo could potentially still have it enabled).
|
||||
|
||||
### v1.0.1
|
||||
|
||||
Fixed the bug where sometimes the extension would fail to work. (example: you opened youtube's search page in a brand new tab. You then opened a video from the search results (_not_ in a new tab). Extension wouldn't work at all in videos opened in that manner).
|
||||
|
||||
### v1.0.0
|
||||
|
||||
* Is pretty much rc1, except slightly different background image.
|
||||
|
||||
### v1.0-rc1
|
||||
|
||||
* Settings page is added and mostly working.
|
||||
|
||||
### v0.9.9.6
|
||||
|
||||
* The issue with buttons not fitting in the control bar was resolved.
|
||||
|
||||
### v0.9.9.5
|
||||
|
||||
* Played with settings and localstorage a bit, but no clear implementation yet.
|
||||
* Fixed some bugs caused by event propagation.
|
||||
* All buttons in the player's control bar are now also in the settings popup.
|
||||
* Had to scrap settings page in its current form
|
||||
* TODO: sometimes not all buttons can fit in the control bar. Such occurences should be detected.
|
||||
|
||||
### v0.9.9.1
|
||||
|
||||
* Keybinds `a` and `w` now work.
|
||||
* Some changes under the bonnet, mostly regarding the way keypresses are handled.
|
||||
* 'Settings' page is ~15% done.
|
||||
|
||||
### v0.9.9
|
||||
|
||||
* The aspect ratio thingy is now also in GUI
|
||||
* Fixed code for forcing aspect ratio. At least I think it's fixed now.
|
||||
|
||||
### v0.9.8
|
||||
|
||||
* Added GUI/buttons on the player.
|
||||
* Script now only loads on youtube pages (iframes included) (before, this script would run on any page)
|
||||
|
||||
### v0.9.7
|
||||
|
||||
* No new features added. Version number got incremented due to an attempt at autoupdating (which got foiled due to lack of HTTPS)
|
||||
|
||||
### v0.9.6
|
||||
|
||||
* Added experimental feature that tries to force an aspect ratio
|
||||
|
||||
### v0.9.1
|
||||
|
||||
* First version on GitHub (and on AMO) with basic features (zoom, fit to width, fit to height)
|
@ -1,6 +0,0 @@
|
||||
# Implementation details
|
||||
|
||||
## Enabling/disabling aspect ratio corrections
|
||||
|
||||
* Aspect ratios are changed by proxy. Extension attaches **a custom CSS class** to `video` and `player` elements.
|
||||
* To prevent extension from affecting the appearance of a webpage, **it's sufficient to remove our custom CSS classes from `video` and `player` elements.**
|
32
Jenkinsfile
vendored
@ -1,32 +0,0 @@
|
||||
// required jenkins plugins:
|
||||
// * https://plugins.jenkins.io/git/
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
|
||||
// stage('Check for changes') {
|
||||
// sh "env.GIT_COMMIT != env.GIT_PREVIOUS_COMMIT"
|
||||
// }
|
||||
|
||||
stage('Install dependencies') {
|
||||
steps {
|
||||
sh 'npm ci'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'npm run build-all'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Push to release server') {
|
||||
steps {
|
||||
sh "echo 'implement me pls!'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
Microsoft edge extension store requires notes for certification. Because I'm too lazy to whip this text over and over and over and over and over and over again, I'm making it a copypasta.
|
||||
|
||||
|
||||
---------------------------------------------------------------------------------------------
|
||||
This extension is targeted at users of 21:9 monitors. If using 16:9 monitor, use youtube in THEATER MODE.
|
||||
|
||||
Not all videos need to have their aspect ratio corrected. Here is few examples of videos with problems this extension is trying to solve:
|
||||
|
||||
* Variable aspect ratio — autodetection testing grounds: https://www.youtube.com/watch?v=-IHzprfs6tw
|
||||
* Static (but incorrect) aspect ratio: https://www.youtube.com/watch?v=BTETsm79D3A
|
||||
|
||||
Twitch example (collapse subscription & chat sidebars on 16:9, do not fullscreen) — aspect ratio switch happens at around 1:50:00 mark:
|
||||
* https://www.twitch.tv/videos/330639009?t=1h49m45s
|
||||
|
||||
Autodetect has technological limitations and can incorrectly detect aspect ratio. This is acceptable — user should override it in such cases.
|
||||
|
||||
Functions labelled 'experimental' are experimental and may not function correctly.
|
||||
|
||||
Websites may interfere with keyboard shortcuts.
|
||||
|
||||
Brief video flicker when changing between fullscreen, non-fullscreen or when changing browser is inherent artifact caused by sites not being aware of extension and is thus considered acceptable.
|
||||
|
||||
Logger option does nothing (except give you a popup) unless you have a logger config handy. It is designed for debugging in case of bug reports.
|
@ -1,31 +0,0 @@
|
||||
# Build guide for AMO
|
||||
|
||||
## Build platform
|
||||
|
||||
The extension is built on a PC running Manjaro Linux. npm and node are installed from repositories/aur.
|
||||
|
||||
### Software versions:
|
||||
|
||||
Node/npm versions:
|
||||
|
||||
```
|
||||
node: %%NODE_VERSION%%
|
||||
npm: %%NPM_VERSION%%
|
||||
```
|
||||
|
||||
Linux (`uname -a`):
|
||||
|
||||
```
|
||||
%%LINUX_VERSION%%
|
||||
```
|
||||
|
||||
## Reproducing build
|
||||
|
||||
Run the following commands to install dependencies and compile the firefox build:
|
||||
|
||||
```
|
||||
npm ci
|
||||
npm run build
|
||||
```
|
||||
|
||||
The compiled code pops up in `/dist-ff`.
|
@ -1,17 +0,0 @@
|
||||
#Permissions
|
||||
|
||||
This extension requires some permissions. Here's why.
|
||||
|
||||
#TL;DR version:
|
||||
|
||||
* **All tabs** — allows this extension to work on any site (By default, you need to enable sites other than those supported by default manually). Automatic detection on Netflix also [requires this permission](https://discourse.mozilla.org/t/drawwindow-in-webextension/13811) (or at least it did as of January 2018).
|
||||
* **Access browser tabs** — required for the popup to work (and it still doesn't always).
|
||||
* **Access browser activity during navigation** — makes some stuff with displaying popup easier. Most notably, it's used to ask the tab you're switching to whether it contains any videos, so this information is known before you need to open the popup.
|
||||
|
||||
#Technical mumbo-jumbo
|
||||
|
||||
todo
|
||||
|
||||
#This extension asks for permission that isn't listed above.
|
||||
|
||||
Sometimes (and by 'sometimes' I mean 'way too often') I forget to update README files. If there's a permission that I haven't wrote an explanation for, please [open an issue](https://github.com/tamius-han/ultrawidify/issues).
|
391
README.md
@ -1,284 +1,191 @@
|
||||
This is the v1 of the project. This branch is the original source for the extension, which is now obsolete (due to the code rewrite started in october 2017). See main (stable) and v2 (current) branches for something that's still getting maintained.
|
||||
|
||||
# Ultrawidify — aspect ratio fixer for youtube and netflix
|
||||
|
||||
## 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/ultrawidify/lmpgpgechmkkkehkihpiddbcbgibokbi).
|
||||
|
||||
There's also [nightly "builds"](https://stuff.lionsarch.tamius.net/ultrawidify/nightly/).
|
||||
|
||||
## TL;DR
|
||||
|
||||
If you own an ultrawide monitor, you have probably noticed that sometimes videos aren't encoded properly — they feature black bars on all four sides. This could happen because someone was incompetent (note: as far as youtube is concerned, improperly rendered videos might be due to youtube's implementation of certain new features). The extension kinda fixes that by doing this:
|
||||
|
||||
![Demo](img-demo/example-httyd2.png "Should these black bars be here? No [...] But an ultrawide user never forgets.")
|
||||
|
||||
Works on Youtube and Netflix. Available for [Firefox (v1.2.1)](https://addons.mozilla.org/en/firefox/addon/ultrawidify/) and [Chrome (v1.2.1)](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi).
|
||||
|
||||
## Known issues
|
||||
## The long version
|
||||
|
||||
* Netflix autodetection not working in Chrome and working poorly in Firefox. This problem happens because DRM, and happens on other sites utilizing DRM protection schemes. Don't expect Chrome support any time soon.
|
||||
* Everything reported in [issues](https://github.com/tamius-han/ultrawidify/issues)
|
||||
|
||||
### Limitations
|
||||
|
||||
* Unclear how extension handles sites with more than one video per page.
|
||||
* Autodetection is only correct 95% of the time, most of the time.
|
||||
* That new stretching mode wasn't thoroughly tested yet. Issues may be present. (Same with zoom)
|
||||
* Enabling extension everywhere (as opposed to whitelisted sites) could break some websites.
|
||||
|
||||
### Features
|
||||
|
||||
* **Can be enabled or disabled on per-site basis**
|
||||
* **Crop video to fit screen** (no stretching. Supported aspect ratios: 21/9 (1:2.39), 16:9, 16:10. It's possible to set additional aspect ratios, but settings GUI currently contains some mildly annoying bugs)
|
||||
* **Automatic aspect ratio detection** (can be enabled/disabled entirely or on a per-site basis, separately of the extension. May not work on sites utilizing DRM schemes, such as Netflix et. al.). Autodetection in action: [youtube](https://www.youtube.com/watch?v=j2xn1WpbtCQ))
|
||||
* **Supports Youtube theater mode**
|
||||
* **[EXPERIMENTAL!]** Stretch video to fit the screen
|
||||
* **[EXPERIMENTAL!]** custom zooming and panning
|
||||
|
||||
|
||||
### Officially supported sites
|
||||
|
||||
* Youtube
|
||||
* Netflix
|
||||
* Twitch
|
||||
|
||||
### Other sites
|
||||
|
||||
I am not actively testing extension on other sites. You can try your luck and enable extension for any unsupported site you stumble across via extension popup, but I make no guarantees it will work everywhere.
|
||||
|
||||
If extension doesn't work for a site I'm not testing on out of the box, follow [this wiki](https://github.com/tamius-han/ultrawidify/wiki/Fixing-site-incompatibilites-('Advanced-settings')). The 'quick and dirty' approach should work for most sites. (If you try doing things the proper way, you should really know what you're doing.)
|
||||
|
||||
### Installing this extension
|
||||
|
||||
You can download this extension from the relevant extension stores:
|
||||
|
||||
* [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/ultrawidify/lmpgpgechmkkkehkihpiddbcbgibokbi)
|
||||
|
||||
Other browsers are not officially supported. If you're using a different Chromium-based browser, you can try installing the addon from the Chrome Web Store — but if things don't work, you're on your own.
|
||||
|
||||
### Nightly builds
|
||||
|
||||
* Nightly builds can be downloaded [here](https://stuff.lionsarch.tamius.net/ultrawidify/) as an unpacked extension that can
|
||||
only be installed temporarily.
|
||||
|
||||
If I did anything during the day, the nightly version will be sorta-built at whatever my VPS provider thinks is 4AM CE(S)T.
|
||||
|
||||
# Beggathon (donations)
|
||||
|
||||
If you want to support this project, please consider a donation. Working on this extension takes time, money, coffee and motivation. Sometimes also [a very precise amount of alco](https://xkcd.com/323/).
|
||||
|
||||
You can make a donation [via Paypal](https://www.paypal.me/tamius).
|
||||
|
||||
**Any donation — no matter how big or small — is well appreciated. Thanks.**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# The long version
|
||||
|
||||
The technology has been here for a while, but plenty of people don't know how to properly encode a video (despite the fact [youtube has an article that explains aspect ratios](https://support.google.com/youtube/answer/6375112)). Plenty of people surprisingly includes major Hollywood studios, such as [Marvel](https://www.youtube.com/watch?v=Ke1Y3P9D0Bc), [Disney](https://www.youtube.com/watch?v=yCOPJi0Urq4), [Dreamworks](https://www.youtube.com/watch?v=oKiYuIsPxYk), [Warner Brothers](https://www.youtube.com/watch?v=VYZ3U1inHA4), [Sony](https://www.youtube.com/watch?v=7BWWWQzTpNU), et cetera. You'd think that this is the one thing Hollywood studios and people who make [music videos for a living](https://www.youtube.com/watch?v=c6Mx2mxpaCY) would know how to do right, but they don't. This extension is here to fix that.
|
||||
The technology has been here for a while, but plenty of people don't know how to properly encode a video (despite the fact [youtube has an article that explains aspect ratios](https://support.google.com/youtube/answer/6375112)). Plenty of people surprisingly includes major Holywood studios, such as [Marvel](https://www.youtube.com/watch?v=Ke1Y3P9D0Bc), [Disney](https://www.youtube.com/watch?v=yCOPJi0Urq4), [Dreamworks](https://www.youtube.com/watch?v=oKiYuIsPxYk), [Warner Brothers](https://www.youtube.com/watch?v=VYZ3U1inHA4), [Sony](https://www.youtube.com/watch?v=7BWWWQzTpNU), et cetera. You'd think that this is the one thing Holywood studios and people who make [music videos for a living](https://www.youtube.com/watch?v=c6Mx2mxpaCY) would know how to do right, but they don't. This extension is here to fix that.
|
||||
|
||||
![Jesus Christ.](img-demo/example-jasonbourne.png "This is indeed worse than Snowden.")
|
||||
|
||||
## Features
|
||||
|
||||
Most settings are self-explanatory, but we'll get into details anyway.
|
||||
* **Adds UI to the player's controls**
|
||||
* **Fit video to width/height**
|
||||
* **Zoom/unzoom video**
|
||||
* **Force specific aspect ratio**
|
||||
* **(Attempt to) autodetect aspect ratio** (Netflix only)
|
||||
* **Rebindable shortcuts**
|
||||
|
||||
### Limitations:
|
||||
### User interface
|
||||
|
||||
Before we go on to features, let's discuss limitations.
|
||||
![UI](img-demo/example-ui-general.png "If I ever found out that the video I'm in is 21:9, but encoded as 16:9 + black bars, I'd probably consider killing myself as well. To be completely fair, Blender institute did good job encoding the video properly. But of course there's some repost channels to fuck it up.")
|
||||
|
||||
* Currently, this extension is only tested on Youtube and Netflix. It should work on other sites as well, but you'll need to manually enable extension on other sites via the popup.
|
||||
* It's unclear how extension handles sites displaying multiple videos per site. Having multiple videos on the same page is a very tricky case that hasn't been given much thought.
|
||||
* Autodetection is a very hard problem to solve. Despite various improvements, it's still not 100% correct. In cases where aspect ratio is hard to determine, extension tends to err on the side of caution and tries to avoid changing aspect ratios. However, sometimes aspect ratio changes will still trigger too eagerly.
|
||||
To be entirely fair to the blender foundation, the video featured above is properly encoded. (However, few accounts that reposted it didn't sport the same levels of competence).
|
||||
|
||||
The 'more settings' menu contains all the buttons on the control bar, plus an option to force a specific aspect ratio — in case you're trying to watch a 16:9 video, that's encoded as 4:3 video, on a 21:9 monitor.
|
||||
|
||||
### Automatic aspect ratio detection
|
||||
![UI](img-demo/example-ui-more-settings.png "If you know me and came looking for the obligatory »it's a wyvern, not a dragon« comment ... well, you just found it.")
|
||||
|
||||
By default, automatic detection will run on every site this extension is enabled for. It does what it says on the tin: it attempts to detect aspect ratio of the video by periodically looking at a video frame.
|
||||
|
||||
Some caveats apply:
|
||||
* autodetection is very easy in 99% of cases and very tricky in the 1%. Sometimes, autodetection will be too eager. Sometimes it won't be eager enough.
|
||||
* Some sites use DRM. DRM measures are designed specifically to prevent scripts from looking at video frames. Since that's exactly what this extension uses to determine aspect ratio of a video, **autodetection is not possible on sites that use DRM** (Netflix and the likes). Firefox is slight exception to this.
|
||||
* Firefox offers an API that can be used to take screenshots of the page. Turns out that you can use this API to work around the above limitation. Usage of this API has its own limitations. Due to those limitations, automatic detection on DRM-protected sites in Firefox keeps a thin black bar at the top and the bottom of the video.
|
||||
|
||||
Autodetection can be enabled or disabled globally, per site or per video.
|
||||
|
||||
### Popup
|
||||
|
||||
Most of the extension settings can be accessed and modified via the popup. If extension is enabled for the site you're currently on, the popup will display options for the video you're currently watching.
|
||||
|
||||
![Demo](img-demo/ui/popup/popup_video_settings.png)
|
||||
|
||||
|
||||
### Cropping video
|
||||
|
||||
![Demo](img-demo/ui/popup/crop.png)
|
||||
|
||||
Extension can crop videos to the desired aspect ratio. Options offered by the extension are (keyboard shortcuts in **bold**):
|
||||
|
||||
* Automatic — **A**
|
||||
* Reset (default) — **R**
|
||||
* 21:9 (2.39:1) — **D**
|
||||
* 18:9 (2:1) — **X**
|
||||
* 16:9 (1.77) — **S**
|
||||
* Custom — **Q**
|
||||
|
||||
In addition to that, you can crop video to fit width (**W**) or height (**E**).
|
||||
|
||||
**Note:** manually adjusting aspect ratio _disables_ autodetection for current video. Manual adjustments are temporary and should last for only one video.
|
||||
|
||||
You can set custom aspect ratio by clicking 'set custom aspect ratio' link under the buttons, changing the value in the box and clicking 'save'. Aspect ratio can be in any of the following formats:
|
||||
* `width/height` (e.g. `16/9`, `21/9` - even `2560/1080`)
|
||||
* `1:ratio` (e.g. `1:2.39`. You can omit the `1:` part, too — e.g. `2.39` is equivalent to `1:2.39`)
|
||||
'Save' button saves your custom aspect ratio. If you don't save changes, they'll be forgotten by the time you close the popup.
|
||||
|
||||
![Demo](img-demo/ui/popup/crop_custom.png)
|
||||
|
||||
### Zoom
|
||||
|
||||
Keys 'Z' and 'U' manually zoom the video. You can use those to zoom farther than merely adjusting aspect ratio would. At high magnification, you can pan the video by moving mouse over it. Panning is off by default and can be activated by holding 'shift' or toggled by pressing 'P' key.
|
||||
|
||||
You can also zoom video by using the slider in the popup:
|
||||
|
||||
![Demo](img-demo/ui/popup/zoom.png)
|
||||
|
||||
### Align video
|
||||
|
||||
If you watch 16:9 videos in full screen on a 21:9 monitor, there's obviously going to be black bars on either side of the video. The video will be centered, though. Some people don't want video to be centered in such situations, instead preferring having the video aligned to either side. **Video alignment** option does that.
|
||||
|
||||
### Stretching videos
|
||||
|
||||
![Demo](img-demo/ui/popup/stretch.png)
|
||||
|
||||
When you watch a 16:9 content on a 21:9 monitor, you can deal with this issue in three ways: A) you don't, B) you crop or C) you stretch the 16:9 video to fit a 21:9 container. Obviously not everyone is a person of culture, some people prefer to choose the greater evil of the three: they prefer their videos stretched!
|
||||
|
||||
Ultrawidify offers you several ways of dealing with the issue:
|
||||
* **Never** — don't stretch at all
|
||||
* **Basic** — stretch the video to fit screen. Doesn't remove black bars encoded in the video. While this option is active, automatic aspect ratio detection is disabled.
|
||||
* **Hybrid** — this mode first crops away the black bars encoded in the video file. If the video doesn't fit your monitor after being cropped, the extension will proceed to stretch it in a smart way. Automatic detection remains active with this option.
|
||||
* **Thin borders** — this mode only applies stretching only when borders around video are thin (less than 5% of total width or height).
|
||||
|
||||
## Global and per-site default settings
|
||||
|
||||
You can change default settings for extension or site you're currently on by visiting 'Extension settings' and 'Site settings' tabs in the popup. Per-site settings override extension defaults, video settings override both. Both tabs also have the same options:
|
||||
|
||||
![Demo](img-demo/ui/popup/extension_settings.png)
|
||||
|
||||
Quick rundown of the options:
|
||||
|
||||
* **Enable this extension** (Extension settings)
|
||||
|
||||
Whether the extension is enabled. Options:
|
||||
|
||||
`Always` — allow this extension to run on every site (unless the site is blacklisted)
|
||||
`On whitelisted sites` — allow this extension to run only on sites you manually enabled
|
||||
`Never` — this extension won't work. At all.
|
||||
|
||||
* **Enable autodetection** (Extension settings)
|
||||
|
||||
Whether extension should automatically detect aspect ratio. Uses same options as _Enable this extension_ options.
|
||||
|
||||
* **Enable this extension** (Site settings)
|
||||
|
||||
Whether the extension is enabled on current site. Options:
|
||||
|
||||
`Whitelist` — allow this extension to run on current site.
|
||||
`Default` — follow global settings (allow if global option is set to 'always', don't allow if global option is set to any of the other two)
|
||||
`Blacklist` — never allow extension to run on current site.
|
||||
|
||||
* **Enable autodetection** (Site settings)
|
||||
|
||||
Whether extension should automatically detect aspect ratio on current site. Uses same options as _Enable this extension_ options.
|
||||
|
||||
* **Default stretching mode**
|
||||
|
||||
How, if at all, should extension stretch the video by default.
|
||||
|
||||
* **Video alignment**
|
||||
|
||||
How to align the video by default.
|
||||
|
||||
## Keyboard shortcuts
|
||||
|
||||
The keyboard shortcuts have already been listed, but let's list them all again in the same, handy place.
|
||||
These options might show some benefit for people not using 21:9 monitors, as they would allow you to crop a (proper) 21:9 to 16:9 (remove black bars at the cost of some video). 'Fit to height' would often do the same job, though.
|
||||
|
||||
### Default keyboard shortcuts
|
||||
|
||||
`w` - fit to width
|
||||
`e` - fit to height
|
||||
`r` - reset
|
||||
w - fit to width
|
||||
e - fit to height
|
||||
r - reset
|
||||
z - zoom
|
||||
u - unzoom
|
||||
|
||||
a - attempt to automatically determine the aspect ratio (netflix only)
|
||||
|
||||
s - force 21:9
|
||||
d - force 16:9
|
||||
x - force 16:10
|
||||
c - force 4:3
|
||||
|
||||
`a` - attempt to automatically determine the aspect ratio
|
||||
### About Netflix aspect ratio autodetection
|
||||
|
||||
`s` - force 16:9
|
||||
`d` - force 21:9
|
||||
`x` - force 18:9
|
||||
`q` - force custom aspect ratio
|
||||
Automatic aspect ratio detection on Netflix works by grabbing the title of the video off Netflix' control bar and throws it at some third party services. First, it takes the title and throws it at OMDB. OMDB replies with IMDB id. We then throw that id at IMDB, which replies with 1700+ lines (and aspect ratio information is hopefully somewhere among them). If OMDB doesn't find the movie — or if the IMDB doesn't have information about aspect ratio for that particular title — automatic detection fails. There's also a posibility that this method returns the wrong data, as there's a possibility that multiple movies share the same title.
|
||||
|
||||
`z` - zoom
|
||||
`u` - unzoom
|
||||
`p` - toggle video panning
|
||||
`shift`- pan video (while holding)
|
||||
|
||||
### Rebinding keyboard shortcuts
|
||||
|
||||
is currently not possible. Settings page for this extension has been disabled sometime with 2.0 release (because it [broke](https://github.com/tamius-han/ultrawidify/issues/16)), and fixing the setting page has been very low priority as I've had more important issues to work on.
|
||||
|
||||
However, I do plan on implementing this feature. Hopefully by the end of the year, but given how consistently I've been breaking self-imposed deadlines and goals for this extension don't hold your breath. After all, [Hofstadter's a bitch](https://en.wikipedia.org/wiki/Hofstadter%27s_law).
|
||||
|
||||
|
||||
|
||||
## Plans for the future
|
||||
|
||||
1. Handle porting of extension settings between versions.
|
||||
2. ~~Reintroduce gradual zoom on z and u and provide a way to 'scroll' the zoomed in video up/down left/right.~~ (v3.2.0)
|
||||
3. reintroduce settings page (rebindable keys, blacklist/whitelist management, some settings for automatic aspect ratio detection)
|
||||
4. site-specific options for sites that require additional CSS classes or other hacks
|
||||
5. figure the best way to do GUI (injecting buttons into the player bar is not a good way. Been there, done that, each site has its own way and some appear to be impossible). ~~Might get bumped to be released alongside #2~~no it wont lol
|
||||
6. Improvements to automatic aspect ratio detection
|
||||
For best results with autodetection, please make sure the following requirements are met:
|
||||
|
||||
* Netflix, not youtube
|
||||
* Netflix must be in English
|
||||
* Movie title must be in English/the original title
|
||||
* Movie must be known by OMDB
|
||||
* Movie must have aspect ratio info on IMDB
|
||||
|
||||
## Installing
|
||||
|
||||
### Permanent install / stable
|
||||
|
||||
[Latest stable for Firefox — download from AMO](https://addons.mozilla.org/en/firefox/addon/ultrawidify/)
|
||||
[v1.2.1 — Regular version — download from AMO](https://addons.mozilla.org/en/firefox/addon/ultrawidify/)
|
||||
|
||||
[Latest stable for Chrome — download from Chrome store](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi)
|
||||
|
||||
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) -->
|
||||
[v1.2.1 — Regular version — download from Chrome store](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi)
|
||||
|
||||
### Installing the current, github version
|
||||
|
||||
## Get pre-built version:
|
||||
|
||||
TODO
|
||||
|
||||
## Build from source
|
||||
|
||||
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`.
|
||||
|
||||
TODO: see if #3 already loads the extension in FF
|
||||
|
||||
2. Open up Firefox (or Chrome)
|
||||
3. Go to `about:debugging` (or Chrome equivalent)
|
||||
2. Open up Firefox
|
||||
3. Go to `about:debugging`
|
||||
4. Add temporary addon
|
||||
5. Select `${ultrawidify_folder}/dist/manifest.json`
|
||||
5. Browse to wherever you saved it and select manifest.json
|
||||
|
||||
# Changelog
|
||||
## Known issues (in stable versions)
|
||||
|
||||
see changelog.md
|
||||
'More settings' button actually doesn't work at the moment.
|
||||
|
||||
todo: add link to changelog.md here
|
||||
## Plans for the future
|
||||
|
||||
* ~~Adding custom keybinds~~ (done at lastest)
|
||||
* ~~Adding a proper settings page~~ (done at last)
|
||||
* ~~Adding buttons for actions in youtube's player~~ (kinda done)
|
||||
* ~~Adding an option to force specific aspect ratio~~ (now it's "good enough")
|
||||
* ~~Port to Chrome~~
|
||||
* ~~Have extension remember the last setting when switching between fullscreen and not fullscreen.~~ (kinda done)
|
||||
* Have an option to remember last selected aspect ratio.
|
||||
* Option to hide UI
|
||||
* ~~Netflix support~~ (done)
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
###v1.3a1 (git/current version)
|
||||
|
||||
* Adding ability to add custom sites (in progress)
|
||||
* Most of the extension is being completely rewritten to accomodate that feature, which means there's a serious regression with Netflix support (no netflix at the moment)
|
||||
* I'm also trying to break the 1500 line behemoth into smaller files.
|
||||
|
||||
###v1.2.1 (AMO + Chrome)
|
||||
|
||||
* Fixed the bugs which caused aspect ratio to not be calculated properly.
|
||||
* Introduced further changes that allow me to not keep two separate version for Firefox and Chrome.
|
||||
|
||||
###v1.2.0
|
||||
|
||||
* Auto-aspect ratio detection on netflix
|
||||
* initial port to Chrome
|
||||
|
||||
###v1.1.1
|
||||
|
||||
* Fixed zooming issue on netflix
|
||||
* Ultrawidify shortcuts > youtube/netflix shortcuts
|
||||
* Fixed 'settings' page
|
||||
* Fixed 'settings' (wrench button) popup on youtube (it was broken by one of the previous updates)
|
||||
|
||||
###v1.1.0
|
||||
|
||||
* Introduced Netflix support.
|
||||
|
||||
As Netflix relies on extension re-initializing at least the UI ***a lot***, the optimization introduced in 1.0.2 was reversed (as waiting 2 seconds for the UI to appear is just too much).
|
||||
|
||||
Furthermore, triggering UI re-initialisation on onUpdated events turned out to not be the proper way to go: immediately after the extension is initialized, onUpdated gets triggered even more often than your average Buzzfeed writer/reader. But change the episode on Netflix and suddenly, onUpdated gets barely triggered at all — which means that more often than not, the UI extension injects into the page wasn't visible. (the fuck, really)
|
||||
|
||||
This is why Netflix uses another function that manually checks whether the player bar is present. Ideally that check happens every tenth of a second, but Firefox may be limiting that to one per second.
|
||||
|
||||
###v1.0.2
|
||||
|
||||
The 'extension sometimes not working' bug was fixed (by having extension try to setup every time a page got updated), but the fix had some problems. Namely, the extension would re-initiate (complete with re-adding the entire UI) itself very _very_ often.
|
||||
|
||||
This could be a problem, so it was fixed. Extension is notified of updates only every ~2 seconds (which absorbs most of the "page was updated" events on page load) and doesn't attempt to reload the UI if the UI was already loaded. (Unless `debugmsg` is set to true. It's generally not, but any commits to this repo could potentially still have it enabled).
|
||||
|
||||
###v1.0.1
|
||||
|
||||
Fixed the bug where sometimes the extension would fail to work. (example: you opened youtube's search page in a brand new tab. You then opened a video from the search results (_not_ in a new tab). Extension wouldn't work at all in videos opened in that manner).
|
||||
|
||||
###v1.0.0
|
||||
|
||||
* Is pretty much rc1, except slightly different background image.
|
||||
|
||||
###v1.0-rc1
|
||||
|
||||
* Settings page is added and mostly working.
|
||||
|
||||
###v0.9.9.6
|
||||
|
||||
* The issue with buttons not fitting in the control bar was resolved.
|
||||
|
||||
###v0.9.9.5
|
||||
|
||||
* Played with settings and localstorage a bit, but no clear implementation yet.
|
||||
* Fixed some bugs caused by event propagation.
|
||||
* All buttons in the player's control bar are now also in the settings popup.
|
||||
* Had to scrap settings page in its current form
|
||||
* TODO: sometimes not all buttons can fit in the control bar. Such occurences should be detected.
|
||||
|
||||
###v0.9.9.1
|
||||
|
||||
* Keybinds `a` and `w` now work.
|
||||
* Some changes under the bonnet, mostly regarding the way keypresses are handled.
|
||||
* 'Settings' page is ~15% done.
|
||||
|
||||
###v0.9.9
|
||||
|
||||
* The aspect ratio thingy is now also in GUI
|
||||
* Fixed code for forcing aspect ratio. At least I think it's fixed now.
|
||||
|
||||
###v0.9.8
|
||||
|
||||
* Added GUI/buttons on the player.
|
||||
* Script now only loads on youtube pages (iframes included) (before, this script would run on any page)
|
||||
|
||||
###v0.9.7
|
||||
|
||||
* No new features added. Version number got incremented due to an attempt at autoupdating (which got foiled due to lack of HTTPS)
|
||||
|
||||
###v0.9.6
|
||||
|
||||
* Added experimental feature that tries to force an aspect ratio
|
||||
|
||||
###v0.9.1
|
||||
|
||||
* First version on GitHub (and on AMO) with basic features (zoom, fit to width, fit to height)
|
||||
|
84
buildext.sh
Executable file
@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Takes all the files from 'src' and compiles it intro a single content script.
|
||||
# Also compiles background scripts and settings pages.
|
||||
#
|
||||
# I'm using this over something like requirejs so my extension doesn't need even more
|
||||
# dependencies.
|
||||
#
|
||||
# How does this work?
|
||||
# 0. You're supposed to run this in the root directory of the extension.
|
||||
|
||||
# 1. see if file has any #include [filename] comments. If so, merge [filename] file
|
||||
# into the current file (after checking if that file has any #include comments
|
||||
# Compiled files are saved to /tmp.
|
||||
#
|
||||
# 2. After compiling file and its dependencies, check for presence of #location [directory]
|
||||
# comments. [directory] is relative to the root directory of the extension
|
||||
# 2.1 also check for #out, which defines filename.
|
||||
#
|
||||
# 3. Use '-nodebug' to remove all calls of console.log (to be implemented)
|
||||
|
||||
function flattenFileName {
|
||||
echo $1 | sed 's/\//_/g'
|
||||
}
|
||||
|
||||
fileList="";
|
||||
|
||||
function compileFile {
|
||||
local file=$1
|
||||
local flatfile=$(flattenFileName $file);
|
||||
|
||||
|
||||
if [ -f /tmp/$flatfile ] ; then
|
||||
return 0
|
||||
fi;
|
||||
|
||||
fileList="$fileList $flatfile"
|
||||
|
||||
# let's take all the #included files and put them at the top
|
||||
for f in $(grep "#include" $file | awk '{print $NF}') ; do
|
||||
|
||||
local lf=$f
|
||||
fflat=$(flattenFileName $lf);
|
||||
|
||||
compileFile $lf
|
||||
|
||||
printf "\n//BEGIN included from $lf\n" >> /tmp/$flatfile
|
||||
grep -Ev "#include|#location|#out" /tmp/$fflat >> /tmp/$flatfile
|
||||
printf "//END included from $lf\n\n" >> /tmp/$flatfile
|
||||
|
||||
done
|
||||
|
||||
grep -Ev "#include|#location|#out" $file >> /tmp/$flatfile
|
||||
}
|
||||
|
||||
cd src;
|
||||
|
||||
for file in *.js ; do
|
||||
echo "main loop, we're looking at this file: $file"
|
||||
compileFile $file
|
||||
echo "Files compiled. Moving to location (if specified)"
|
||||
|
||||
outFile=$file
|
||||
|
||||
if grep -q "#out" $file ; then
|
||||
outFile=$( grep "#out" $file | awk '{print $NF}')
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if grep -q "#location" $file ; then
|
||||
location=$( grep "#location" $file | awk '{print $NF}')
|
||||
echo "File will be saved to $location as $outFile"
|
||||
cd ..
|
||||
echo "// Autogenerated using buildext. This file should not be modified — modify source files instead." > $location/$outFile
|
||||
grep -Ev "#location|#include|#out" /tmp/$(flattenFileName $file) >> $location/$outFile
|
||||
cd src
|
||||
fi
|
||||
done
|
||||
|
||||
# perform cleanup
|
||||
for file in $fileList ; do
|
||||
rm /tmp/$file
|
||||
done
|
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 6.0 KiB |
10220
js/jquery-3.1.1.js
vendored
Normal file
181
js/uw-bg.js
Normal file
@ -0,0 +1,181 @@
|
||||
var browser_autodetect = true;
|
||||
var usebrowser = "chrome";
|
||||
|
||||
debugmsg = false;
|
||||
debugmsg_imdb = false;
|
||||
url_changed = false;
|
||||
if(debugmsg){
|
||||
console.log(". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ");
|
||||
console.log("\nLoading ultrawidify background script (uw-bg)\nIf you can see this, extension at least tried to load\n\nRandom number: ",Math.floor(Math.random() * 20) + 1,"\n");
|
||||
console.log(". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ");
|
||||
}
|
||||
|
||||
if(browser_autodetect){
|
||||
if(typeof browser === "undefined"){ // This means we're probably not on Firefox, but on nazi chrome
|
||||
if(chrome){
|
||||
browser = chrome;
|
||||
usebrowser = "chrome";
|
||||
}
|
||||
}
|
||||
else
|
||||
usebrowser = "firefox";
|
||||
}
|
||||
else{
|
||||
if(usebrowser == "chrome")
|
||||
browser = chrome;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************
|
||||
**** script-related stuff starts here ****
|
||||
********************************************/
|
||||
|
||||
function gibActiveTab(){
|
||||
return browser.tabs.query({active: true, currentWindow: true});
|
||||
}
|
||||
|
||||
var page_change_msg_count = 0;
|
||||
|
||||
function notifyChange(){
|
||||
|
||||
if(debugmsg)
|
||||
console.log("uw-bg::tab updated. seq:", page_change_msg_count++);
|
||||
|
||||
browser.tabs.query({active: true, currentWindow: true}, function(tabs){
|
||||
browser.tabs.sendMessage(tabs[0].id, {message: "page-change"});
|
||||
});
|
||||
}
|
||||
|
||||
browser.tabs.onUpdated.addListener(notifyChange);
|
||||
|
||||
//BEGIN Goldberg machine that gets aspect ratio data off imdb
|
||||
|
||||
function getAspectRatio(title, sender_tab){
|
||||
// presledki morajo biti zamenjani s +
|
||||
// spaces need to be replaced with +
|
||||
var rektitle = title.replace(/ /g, '+');
|
||||
|
||||
// Zdaj lahko pošljemo zahtevek na omdbapi
|
||||
// now we can send a request to omdbapi
|
||||
httpGET("http://www.omdbapi.com/?t=" + rektitle,
|
||||
function(response, sender_tab) {
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::getAspectRatio | omdbapi gave us this: ", response);
|
||||
|
||||
var info = JSON.parse(response);
|
||||
|
||||
if(!info || !info.Title)
|
||||
return;
|
||||
|
||||
if(debugmsg || debugmsg_imdb){
|
||||
console.log("uw-bg::getAspectRatio | movie title: »»", info.Title, "«« | imdb ID:", info.imdbID,"\nTrying to get technical specs off IMDB");
|
||||
}
|
||||
httpGET("https://www.imdb.com/title/" + info.imdbID + "/technical",
|
||||
function(response, sender_tab){
|
||||
if(!response)
|
||||
return;
|
||||
var lines = response.split('\n');
|
||||
if(debugmsg || debugmsg_imdb){
|
||||
console.log("uw-bg::getAspectRatio | we just got something off IMDB, it's",lines.length,"long. Here's what we got:\n",response);
|
||||
}
|
||||
|
||||
// IMDB nam zraven da veliko nepotrebnega sranja. Na testni strani je bil relevanten podatek
|
||||
// 700+ (!) vrstic globoko. Stvar, ki nam jo da IMDB ima 1500+ vrstic. Iskanje bomo zato začeli
|
||||
// od sredine
|
||||
//
|
||||
// IMDB gives us a lot of unnecessary shit along with the data we want. On our test page the
|
||||
// relevant data was buried 700+ lines deep (1500+ lines total). Because we don't want to
|
||||
// pointlessly search half the page, the best place to start seems to be the middle.
|
||||
|
||||
var lines_nr = lines.length;
|
||||
if(lines_nr % 2 == 1)
|
||||
++lines_nr;
|
||||
var i = lines_nr / 2;
|
||||
var j = i;
|
||||
var ar_found = 0;
|
||||
|
||||
while(i > 400 && j < lines_nr){
|
||||
|
||||
if(lines[i].indexOf("Aspect Ratio") != -1){
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::getAspectRatio | »Aspect Ratio« has been found on line",i," — searching for aspect ratio ...");
|
||||
|
||||
ar_found = i;
|
||||
break;
|
||||
}
|
||||
if(lines[j].indexOf("Aspect Ratio") != -1){
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::getAspectRatio | »Aspect Ratio« has been found on line",j," — searching for aspect ratio ...");
|
||||
|
||||
ar_found = j;
|
||||
break;
|
||||
}
|
||||
--i;
|
||||
++j;
|
||||
}
|
||||
|
||||
|
||||
if(ar_found){
|
||||
var ar_limit = ar_found + 5;
|
||||
for(var i = ar_found; i < ar_limit; ++i){
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::getAspectRatio | scanning lines for aspect ratio number. Line:",lines[i],"has ar:", lines[i].indexOf(":"));
|
||||
if(lines[i].indexOf(":") != -1){
|
||||
// To pomeni, da smo našli razmerje stranic. gg ez
|
||||
// This means we found our aspect ratio, gg ez
|
||||
|
||||
var ar = lines[i].trim().split(":");
|
||||
ar[0] = ar[0].trim();
|
||||
ar[1] = ar[1].trim();
|
||||
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::getAspectRatio | Aspect ratio found:",ar[0],":",ar[1]);
|
||||
|
||||
// Pa povejmo to naši strani:
|
||||
// Let's break the news:
|
||||
browser.tabs.sendMessage(sender_tab.id, {type:"arInfo", arx:ar[0], ary:ar[1]});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::getAspectRatio | Aspect ratio hasn't been found");
|
||||
|
||||
},
|
||||
sender_tab
|
||||
); //httpGET end
|
||||
},
|
||||
sender_tab
|
||||
); //httpGET end
|
||||
}
|
||||
|
||||
function httpGET(url, callback, callback_args){
|
||||
var rek = new XMLHttpRequest();
|
||||
rek.onreadystatechange = function(){
|
||||
if(rek.readyState == 4 && rek.status == 200){
|
||||
callback(rek.responseText, callback_args);
|
||||
}
|
||||
}
|
||||
rek.open("GET", url, true);
|
||||
rek.send(null);
|
||||
}
|
||||
//END 3rd party snooping for aspect ratios
|
||||
browser.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
|
||||
//Stvari delamo samo, če ima naše sporočilce tip
|
||||
//We only do stuff if our message has a type
|
||||
if(request.type){
|
||||
if(request.type == "debug"){
|
||||
console.log("uw-bg::onMessage | got a message. It was a debugging message. Here's the full message:",request);
|
||||
}
|
||||
if(request.type == "gibAspectRatio"){
|
||||
if(debugmsg || debugmsg_imdb)
|
||||
console.log("uw-bg::onMessage | got a message, we want to set aspect ratio. message:",request,"sender:",sender);
|
||||
var result = getAspectRatio(request.title, sender.tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
50
manifest.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Ultrawidify-git",
|
||||
"version": "1.3a1",
|
||||
|
||||
"icons": {
|
||||
"32":"res/icons/uw-32.png",
|
||||
"64":"res/icons/uw-64.png"
|
||||
},
|
||||
|
||||
"description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.",
|
||||
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://*/*"],
|
||||
"js": [ "js/jquery-3.1.1.js", "js/uw_libbuttons.js", "js/uw.js" ],
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
|
||||
"background": {
|
||||
"scripts": ["js/jquery-3.1.1.js", "js/uw-bg.js"]
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"tabs", "storage", "activeTab", "*://*.youtube.com/*", "*://youtube.com/*", "*://imdb.com/*", "*://*.imdb.com/*"
|
||||
],
|
||||
|
||||
"web_accessible_resources": [
|
||||
"res/img/ytplayer-icons/zoom.png",
|
||||
"res/img/ytplayer-icons/unzoom.png",
|
||||
"res/img/ytplayer-icons/fitw.png",
|
||||
"res/img/ytplayer-icons/fith.png",
|
||||
"res/img/ytplayer-icons/reset.png",
|
||||
"res/img/ytplayer-icons/settings.png",
|
||||
|
||||
"res/img/settings/about-bg.png",
|
||||
|
||||
"res/css/uw_common.css",
|
||||
"res/css/uw_yt.css",
|
||||
"res/css/uw_netflix.css",
|
||||
"res/css/uw_settings.css"
|
||||
],
|
||||
|
||||
"options_ui" : {
|
||||
"page": "res/settings.html",
|
||||
"open_in_tab": true
|
||||
}
|
||||
}
|
16616
package-lock.json
generated
78
package.json
@ -1,78 +0,0 @@
|
||||
{
|
||||
"name": "ultrawidify",
|
||||
"version": "6.0.2",
|
||||
"description": "Aspect ratio fixer for youtube and other sites, with automatic aspect ratio detection. Supports ultrawide and other ratios.",
|
||||
"author": "Tamius Han <tamius.han@gmail.com>",
|
||||
"scripts": {
|
||||
"build": "npm run pre-build; cross-env NODE_ENV=production BROWSER=firefox CHANNEL=stable webpack --hide-modules",
|
||||
"build-all": "bash ./scripts/build-all.sh",
|
||||
"build-chrome": "cross-env NODE_ENV=production BROWSER=chrome CHANNEL=stable webpack --hide-modules",
|
||||
"build-chrome:dev": "cross-env NODE_ENV=development BROWSER=chrome webpack --hide-modules",
|
||||
"build-edge": "cross-env NODE_ENV=production BROWSER=edge CHANNEL=stable webpack --hide-modules",
|
||||
"build-nightly": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=nightly webpack --hide-modules",
|
||||
"build-nightly-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=nightly webpack --hide-modules",
|
||||
"build-testing": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=testing webpack --hide-modules",
|
||||
"build-testing-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=testing webpack --hide-modules",
|
||||
"build-zip": "node scripts/build-zip.js",
|
||||
"build:dev": "webpack --hide-modules",
|
||||
"dev": "cross-env NODE_ENV=development CHANNEL=dev concurrently \"cross-env BROWSER=firefox npm run build:dev -- --watch\" \"cross-env BROWSER=chrome npm run build:dev -- --watch\" \"cross-env BROWSER=edge npm run build:dev -- --watch\"",
|
||||
"dev:windows": "cross-env NODE_ENV=development CHANNEL=dev concurrently \"cross-env BROWSER=firefox npm run build:dev -- -w --watch-poll\" \"cross-env BROWSER=chrome npm run build:dev -- -w --watch-poll\" \"cross-env BROWSER=edge npm run build:dev -- -w --watch-poll\"",
|
||||
"dev-ff": "rm -rf ./dist-ff && cross-env NODE_ENV=development CHANNEL=dev BROWSER=firefox npm run build:dev -- --watch",
|
||||
"dev-chrome": "rm -rf ./dist-chrome && cross-env NODE_ENV=development CHANNEL=dev BROWSER=chrome npm run build:dev -- --watch",
|
||||
"dev-edge": "rm -rf ./dist-edge && cross-env NODE_ENV=development CHANNEL=dev BROWSER=edge npm run build:dev -- --watch",
|
||||
"pre-build": "rm -rf ./dist-ff; rm -rf ./dist-chrome; rm -rf ./dist-edge; rm -rf ./node_modules; npm ci",
|
||||
"start": "npm run dev",
|
||||
"start:windows": "npm run dev:windows"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.0",
|
||||
"@mdi/font": "^6.5.95",
|
||||
"@mdi/js": "^6.4.95",
|
||||
"@types/resize-observer-browser": "^0.1.6",
|
||||
"concurrently": "^5.3.0",
|
||||
"fs-extra": "^7.0.1",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"json-cyclic": "0.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"mdi-vue": "^3.0.11",
|
||||
"typescript": "^4.4.4",
|
||||
"vue": "^3.2.21",
|
||||
"vue-style-loader": "^4.1.3",
|
||||
"vuex": "^4.0.2",
|
||||
"vuex-webextensions": "^1.3.3",
|
||||
"webextension-polyfill": "^0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/preset-env": "^7.16.0",
|
||||
"@types/chrome": "0.0.240",
|
||||
"@types/core-js": "^2.5.5",
|
||||
"@types/es6-promise": "^3.3.0",
|
||||
"@types/firefox": "0.0.31",
|
||||
"@types/lodash": "^4.14.176",
|
||||
"@types/node": "^14.17.32",
|
||||
"@vue/cli": "^4.5.15",
|
||||
"@vue/cli-plugin-typescript": "^4.5.15",
|
||||
"@vue/compiler-sfc": "^3.2.21",
|
||||
"archiver": "^3.0.0",
|
||||
"babel-loader": "^8.2.3",
|
||||
"babel-preset-es2020": "^1.0.2",
|
||||
"copy-webpack-plugin": "^4.5.3",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"ejs": "^2.7.4",
|
||||
"file-loader": "^1.1.11",
|
||||
"mini-css-extract-plugin": "^0.4.4",
|
||||
"node-sass": "^4.14.1",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"ts-loader": "^8.3.0",
|
||||
"vue-cli-plugin-vue-next": "~0.1.4",
|
||||
"vue-loader": "^16.8.2",
|
||||
"web-ext-types": "^2.3.0",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-chrome-extension-reloader": "^0.8.3",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-shell-plugin": "^0.5.0"
|
||||
}
|
||||
}
|
57
res/css/uw_common.css
Normal file
@ -0,0 +1,57 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Oxygen:300,400&subset=latin-ext');
|
||||
|
||||
.show{
|
||||
display: block !important;
|
||||
}
|
||||
.uw_hide{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.uw_submenu{
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: rgba(0,0,0,0.66);
|
||||
}
|
||||
/*
|
||||
.uw-setmenu{
|
||||
padding-left: 2em !important;
|
||||
padding-right: 2em !important;
|
||||
}*/
|
||||
|
||||
.uw_submenu_bottom0{
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.display_relative{
|
||||
display: relative;
|
||||
}
|
||||
|
||||
.uw-setmenu-item{
|
||||
padding-right: 2em !important;
|
||||
padding-left: 2em !important;
|
||||
}
|
||||
|
||||
.common_anchor {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uw_button{
|
||||
display: inline-block;
|
||||
/* height: 100% !important; */
|
||||
background-size: 75% 75%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.uw_ui_anchor{
|
||||
display: inline-block;
|
||||
}
|
||||
#uw_ui_anchor{
|
||||
display: inline-block;
|
||||
|
||||
}
|
39
res/css/uw_netflix.css
Normal file
@ -0,0 +1,39 @@
|
||||
.uw-button{
|
||||
display: inline-block;
|
||||
/* height: 100% !important; */
|
||||
background-size: 75% 75%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.uw-button-row {
|
||||
display: inline-block !important;
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
right: 0 !important;
|
||||
width: 99% !important;
|
||||
height: 100% !important;
|
||||
z-index: 1337 !important;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.uw-button:hover{
|
||||
background-color: rgba(192,0,0,0.66);
|
||||
}
|
||||
.uw-setmenu{
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: rgba(0,0,0,0.66);
|
||||
right: 0px;
|
||||
}
|
||||
.uw-setmenu-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "Oxygen";
|
||||
color: #ffffff !important;
|
||||
width: 90%;
|
||||
padding-left: 10%;
|
||||
}
|
||||
.uw-setmenu-item:hover{
|
||||
background-color: rgba(192,0,0,0.66);
|
||||
}
|
1
res/css/uw_settings.css
Normal file
@ -0,0 +1 @@
|
||||
/* yeah this is also a placeholder file, this time for 'settings' page */
|
28
res/css/uw_yt.css
Normal file
@ -0,0 +1,28 @@
|
||||
.uw-button{
|
||||
display: inline-block;
|
||||
height: 100% !important;
|
||||
background-size: 75% 75%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
.uw-button:hover{
|
||||
background-color: rgba(192,0,0,0.66);
|
||||
}
|
||||
.uw-setmenu{
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: rgba(0,0,0,0.66);
|
||||
right: 0px;
|
||||
}
|
||||
.uw-setmenu-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "Oxygen";
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.uw-setmenu-item:hover{
|
||||
background-color: rgba(192,0,0,0.66);
|
||||
}
|
||||
.uw_top{
|
||||
z-index: 1337;
|
||||
}
|
BIN
res/icons/uw-32.png
Normal file
After Width: | Height: | Size: 317 B |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
BIN
res/img/settings/about-bg.png
Normal file
After Width: | Height: | Size: 783 KiB |
BIN
res/img/ytplayer-icons/fith.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
res/img/ytplayer-icons/fitw.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
res/img/ytplayer-icons/reset.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
res/img/ytplayer-icons/settings.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
res/img/ytplayer-icons/unzoom.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
res/img/ytplayer-icons/zoom.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
387
res/settings.html
Normal file
@ -0,0 +1,387 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Ultrawidify :: settings</title>
|
||||
<meta charset="UTF-8">
|
||||
<base target="_blank">
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css?family=Oxygen:300,400&subset=latin-ext');
|
||||
|
||||
body{
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoYRxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==);
|
||||
background-size: 75px;
|
||||
background-color: #000000;
|
||||
color: #ddd;
|
||||
font-family: 'Oxygen', serif;
|
||||
font-size: 1.2em;
|
||||
width: 100%;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
text-align: center;
|
||||
z-index: -1000;
|
||||
}
|
||||
|
||||
a, a:visited{
|
||||
color: #fa6607;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover{
|
||||
color: #fa6;
|
||||
}
|
||||
|
||||
.show{
|
||||
display: block !important;
|
||||
}
|
||||
.hide{
|
||||
display: none !important;
|
||||
}
|
||||
head{
|
||||
width: 100%;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
h1,h2{
|
||||
color: #ff9;
|
||||
font-weight: 300;
|
||||
}
|
||||
h1{
|
||||
font-size: 3.3em;
|
||||
}
|
||||
h2{
|
||||
font-size: 2.2em;
|
||||
}
|
||||
.sites_header{
|
||||
font-size: 1.6em;
|
||||
color: #ff9;
|
||||
}
|
||||
.content{
|
||||
display: inline-block;
|
||||
width: 52em;
|
||||
}
|
||||
.center{
|
||||
margin: 0 auto;
|
||||
}
|
||||
.basecolor: {
|
||||
color: #ddd !important;
|
||||
}
|
||||
.red{
|
||||
color: #ff3a00;
|
||||
}
|
||||
.disabled: {
|
||||
opacity: 0.69;
|
||||
}
|
||||
.left{
|
||||
text-align: left;
|
||||
}
|
||||
.block{
|
||||
display: inline-block;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.tabline{
|
||||
background-color: #000;
|
||||
width: 100%;
|
||||
margin-bottom: 1.5em;
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.4em;
|
||||
z-index: -200;
|
||||
}
|
||||
.tab{
|
||||
color: #fa6607;
|
||||
}
|
||||
.tab:hover{
|
||||
text-shadow: #aa5 0px 0px 0.02em,#aa5 0px 0px 0.02em;
|
||||
}
|
||||
.tab-selected {
|
||||
color: #ff9 !important;
|
||||
}
|
||||
#all{
|
||||
min-width: 100%;
|
||||
min-height: 100vh;
|
||||
background-image: url('img/settings/about-bg.png');
|
||||
background-position: calc(50vw + 20em) 10vh;
|
||||
background-attachment: fixed;
|
||||
background-size: auto 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.dup_keybinds{
|
||||
background-color: #720 !important;
|
||||
}
|
||||
input[type=text]{
|
||||
font-size: 1em;
|
||||
padding-left: 0.6em;
|
||||
margin-left: 1em;
|
||||
width: 2em;
|
||||
background-color: #000;
|
||||
border: 1px #442 solid;
|
||||
}
|
||||
.uw_shortcuts_line{
|
||||
padding-top: 0.25em;
|
||||
padding-left: 5em;
|
||||
}
|
||||
.uw_shortcuts_label{
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
width: 17.5em;
|
||||
}
|
||||
.uw_options_line{
|
||||
margin-top: 0.75em;
|
||||
font-size: 1.1em;
|
||||
width: 80%;
|
||||
margin-left: 5%;
|
||||
}
|
||||
.uw_options_option{
|
||||
margin-left: 5%;
|
||||
}
|
||||
.uw_suboption{
|
||||
margin-left: 5em;
|
||||
margin-top: 0.75em;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.uw_options_desc, .uw_suboption_desc{
|
||||
margin-top: 0.33em;
|
||||
font-size: 0.69em;
|
||||
color: #aaa;
|
||||
}
|
||||
.uw_suboption_desc{
|
||||
margin-left: 5em;
|
||||
}
|
||||
|
||||
.buttonbar{
|
||||
/* width: 100%; */
|
||||
padding-left: 20em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
.button{
|
||||
display: inline-block;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
padding-top: 0.4em;
|
||||
width: 4em;
|
||||
text-align: center;
|
||||
background-color: rgba(0,0,0,0.66);
|
||||
color: #ffc;
|
||||
height: 1.7em;
|
||||
}optionsoptions
|
||||
Shortcuts
|
||||
About
|
||||
Official
|
||||
Shortcuts
|
||||
About
|
||||
Official
|
||||
|
||||
/** site options css **/
|
||||
.site_name {
|
||||
padding-left: 1em;
|
||||
padding-bottom: 0.3em;
|
||||
color: #fff;
|
||||
font-size: 1.1em;
|
||||
height: 13em !important;
|
||||
|
||||
}
|
||||
.site_details {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.site_title_ebox {
|
||||
width: 10em !important;
|
||||
font-size: 1.5em !important;
|
||||
background-color: rgba(0,0,0,0) !important;
|
||||
margin-left: 0px !important;
|
||||
border: 0px !important;
|
||||
color: #ffc !important;
|
||||
}
|
||||
.details_ebox {
|
||||
width: 12em !important;
|
||||
background-color: rgba(0,0,0,0) !important;
|
||||
border: 0px !important;
|
||||
color: #ffc !important;
|
||||
margin-left: 0em !important;
|
||||
}
|
||||
.details_ebox:disabled {
|
||||
color: #aaa !important;
|
||||
}
|
||||
.inline_button {
|
||||
display: inline-block;
|
||||
margin-top: -1.42em;
|
||||
}
|
||||
.inline_button:hover {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="all">
|
||||
<header>
|
||||
<div class="content center">
|
||||
<div class="left">
|
||||
<h1>Ultrawidify :: settings</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabline center">
|
||||
<div class="content left">
|
||||
<div id="tab_general_settings" class="block tab tab-selected">General settings</div>
|
||||
<div id="tab_sites" class="block tab">Site options</div>
|
||||
<div id="tab_shortcuts" class="block tab">Shortcuts</div>
|
||||
<div id="tab_about" class="block tab">About</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<div id="general_settings">
|
||||
<div class="content left">
|
||||
<div class="uw_options_line">
|
||||
<div class="uw_options_option"><input type="checkbox" id='enable_autoar'> Enable automatic aspect ratio detection</div>
|
||||
<div class="uw_options_desc">This option uses 3rd party websites to determine aspect ratio. It may not work all the time or even properly. It only works with Netflix. <span class="red">This option is <b>NOT</b> available on Youtube.</span></div>
|
||||
</div>
|
||||
<div class="uw_options_line">
|
||||
<div class="uw_options_option"><input type="checkbox" id="enable_ui"> Show UI in the player bar</div>
|
||||
<div class="uw_options_desc">If this option is enabled, the extension will add some extra buttons to the player bar. If this option is disabled, setting video fit and aspect ratio is only possible via keyboard shortcuts.</div>
|
||||
<div class="uw_suboption_line" id="compact_ui_suboption">
|
||||
<div class="uw_suboption"><input type="checkbox" id="enable_ui_compact"> If possible, use compact UI</div>
|
||||
<div class="uw_suboption_desc">With this option enabled, only 'more settings' button is enabled. Note that this option doesn't work on every site.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="uw_sites" class="hide">
|
||||
<div id="uw_sites_body" class="content left">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="uw_shortcuts" class="hide">
|
||||
<div class="content left">
|
||||
<form>
|
||||
<!-- BEGIN FORM -->
|
||||
<!-- fit width -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Fit to width</div>
|
||||
<input type='checkbox' id='fitw_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='fitw_shift' > Shift +
|
||||
<input type='checkbox' id='fitw_alt' > Alt +
|
||||
<input type='text' id='fitw_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- fit height -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Fit to height</div>
|
||||
<input type='checkbox' id='fith_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='fith_shift' > Shift +
|
||||
<input type='checkbox' id='fith_alt' > Alt +
|
||||
<input type='text' id='fith_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- reset -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Reset</div>
|
||||
<input type='checkbox' id='reset_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='reset_shift' > Shift +
|
||||
<input type='checkbox' id='reset_alt' > Alt +
|
||||
<input type='text' id='reset_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- zoom -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Zoom</div>
|
||||
<input type='checkbox' id='zoom_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='zoom_shift' > Shift +
|
||||
<input type='checkbox' id='zoom_alt' > Alt +
|
||||
<input type='text' id='zoom_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- unzoom -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Unzoom</div>
|
||||
<input type='checkbox' id='unzoom_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='unzoom_shift' > Shift +
|
||||
<input type='checkbox' id='unzoom_alt' > Alt +
|
||||
<input type='text' id='unzoom_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- force 21:9 -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Force 21:9</div>
|
||||
<input type='checkbox' id='ar219_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='ar219_shift' > Shift +
|
||||
<input type='checkbox' id='ar219_alt' > Alt +
|
||||
<input type='text' id='ar219_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- force 16:9 -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Force 16:9</div>
|
||||
<input type='checkbox' id='ar169_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='ar169_shift' > Shift +
|
||||
<input type='checkbox' id='ar169_alt' > Alt +
|
||||
<input type='text' id='ar169_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- force 16:10 -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Force 16:10</div>
|
||||
<input type='checkbox' id='ar1610_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='ar1610_shift' > Shift +
|
||||
<input type='checkbox' id='ar1610_alt' > Alt +
|
||||
<input type='text' id='ar1610_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- force 4:3 -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Force 4:3</div>
|
||||
<input type='checkbox' id='ar43_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='ar43_shift' > Shift +
|
||||
<input type='checkbox' id='ar43_alt' > Alt +
|
||||
<input type='text' id='ar43_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
|
||||
<!-- try autoar -->
|
||||
<div class="uw_shortcuts_line">
|
||||
<div class="uw_shortcuts_label">Autodetect aspect ratio (Netflix only)</div>
|
||||
<input type='checkbox' id='autoar_ctrl' > Ctrl +
|
||||
<input type='checkbox' id='autoar_shift' > Shift +
|
||||
<input type='checkbox' id='autoar_alt' > Alt +
|
||||
<input type='text' id='autoar_letter' maxlength='1' class='shortcut_input'>
|
||||
</div>
|
||||
<!-- END FORM -->
|
||||
</form>
|
||||
<div class="buttonbar"><div class="button" id="kb_cancel">Cancel</div><div class="button" id="kb_save">Save</div></div>
|
||||
<div id="errbox"></div>
|
||||
<div><small><b>Note:</b> keyboard shortcut conflicts aren't handled by this extension. You must know your shortcuts.<br/><b>Pro tip:</b> If you don't want to have a keybind for a shortcut, just uncheck all boxes for the action and remove the letter</small></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="about" class="hide">
|
||||
<div class="content left">
|
||||
<h2>Ultrawidify - an aspect ratio fixer for youtube <small>(and netflix)</small></h2>
|
||||
<p>Created by Tamius Han (me). If something is broken, you can shout at me on <a href="https://github.com/xternal7/ultrawidify">github</a> (shout nicely, though. Open an issue or bug report or something). If you're curious to see the source code, <a href="https://github.com/xternal7/ultrawidify">github's here</a>. If you're looking at this page because you're bored and want to be bored some more, <a href="http://tamius.net">my website's here</a>.</p>
|
||||
<h2>So you want to help?</h2>
|
||||
<p>There's a lot of sites where you can stream videos. A lot of these sites keep failing to handle aspect ratios correctly, which means it would be great if this extension worked elsewhere. Unfortunately, a lot of these sites require me to pony up some money (ayy lmao) OR just flat out block anyone who's not from the US (or their small selection of approved regions). Some sites even do both.</p>
|
||||
<p>This means I'd need some help. There's two ways. One of them is to use 'inspect element' option of your browser to pick up IDs (or classnames) of certain elements. More detail here(TODO: add a link to quick tutorial).</p>
|
||||
<p>The second one is, well. I won't shy away from donations either. <small>Bonus respect for dank amounts!</small></p>
|
||||
<p>Needless to say, I'll be happy and thankful regardless of the way you contribute.</p>
|
||||
<h2>Plans for the future</h2>
|
||||
<p>Support for more sizes. More flexible/customizable UI. Maybe (but absolutely no promises here) a bit more advanced autodetection.</p>
|
||||
<h2>Acknowledgements</h2>
|
||||
<p>This extension uses font <a href="https://fonts.google.com/specimen/Oxygen">Oxygen</a>.</p>
|
||||
<p>Special thanks to CD Project Red (The Witcher 2), Anet (Guild Wars 2), and Valve (CS:GO), which made it possible for me to untrigger myself after seeing so many improperly encoded videos.</p>
|
||||
<small><p>More or less.</p>
|
||||
<!-- <p>GW2 is also roughly how the avatar was obtained. Noone tell Anet, though.</p> --></small>
|
||||
<p>Special one-finger salute to all incompetent people who don't know how to properly encode videos and upload them to youtube (to word it most nicely).</p>
|
||||
<p>Special thanks to me for making this extension. You're welcome.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./settings.js"></script>
|
||||
</body>
|
||||
</html>
|
860
res/settings.js
Normal file
@ -0,0 +1,860 @@
|
||||
// Autogenerated using buildext. This file should not be modified — modify source files instead.
|
||||
|
||||
//BEGIN included from lib/libopts.js
|
||||
// setopt, getopt, delopt. Shrani oz. dobi oz. briše stvari iz skladišča
|
||||
// setopt, getopt, delopt. They set/get/delete stuff from the storage
|
||||
|
||||
function setopt(item){
|
||||
browser.storage.local.set(item);
|
||||
}
|
||||
function getopt(prop, callback){
|
||||
if(usebrowser == "chrome")
|
||||
browser.storage.local.get(prop, callback);
|
||||
else
|
||||
browser.storage.local.get(prop).then(callback);
|
||||
}
|
||||
function delopt(item){
|
||||
browser.storage.local.remove(item);
|
||||
}
|
||||
//END included from lib/libopts.js
|
||||
|
||||
|
||||
//BEGIN included from lib/uiutils.js
|
||||
|
||||
//END included from lib/uiutils.js
|
||||
|
||||
|
||||
//BEGIN included from conf/sitesconf.js
|
||||
var UW_SITES = {
|
||||
youtube: {
|
||||
enabled: true,
|
||||
type: "official",
|
||||
urlRules: ["youtu"],
|
||||
player: {
|
||||
name: "movie_player",
|
||||
isClass: false,
|
||||
},
|
||||
iframe: {
|
||||
name: "player",
|
||||
isClass: false
|
||||
},
|
||||
ui: {
|
||||
uiMode: "native",
|
||||
uiconf: {
|
||||
sampleButton: {
|
||||
class: "ytp-button ytp-settings-button",
|
||||
index: 0,
|
||||
buttonSizeBase: "x",
|
||||
},
|
||||
uiParent: {
|
||||
name: "ytp-right-controls",
|
||||
isClass: true,
|
||||
insertStrat: "prepend",
|
||||
},
|
||||
uiOffset: {
|
||||
offsetBy: "10vh",
|
||||
offsetType: "css"
|
||||
}
|
||||
}
|
||||
},
|
||||
autoar_imdb:{
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
netflix: {
|
||||
enabled: true,
|
||||
type: "official",
|
||||
urlRules: ["netflix"],
|
||||
player: {
|
||||
name: "placeholder",
|
||||
isClass: true,
|
||||
},
|
||||
ui: {
|
||||
uiMode: "native",
|
||||
uiconf: {
|
||||
sampleButton: {
|
||||
class: "ytp-button ytp-settings-button",
|
||||
index: 0,
|
||||
buttonSizeBase: "x",
|
||||
},
|
||||
uiParent: {
|
||||
name: "player-controls-wrapper",
|
||||
isClass: true,
|
||||
insertStrat: "append"
|
||||
},
|
||||
uiOffset: {
|
||||
offsetBy: "0px",
|
||||
offsetType: "css"
|
||||
}
|
||||
}
|
||||
},
|
||||
autoar_imdb:{
|
||||
enabled: true,
|
||||
title: "player-status-main-title",
|
||||
isClass: true
|
||||
}
|
||||
},
|
||||
dummy: {
|
||||
type: "add new site",
|
||||
urlRules: [""],
|
||||
player: {
|
||||
name: "",
|
||||
isClass: false,
|
||||
},
|
||||
sampleButton: {
|
||||
class: "ytp-button ytp-settings-button",
|
||||
index: 0,
|
||||
buttonSizeBase: "x",
|
||||
},
|
||||
uiParent: {
|
||||
name: "",
|
||||
isClass: false,
|
||||
insertStrat: "prepend",
|
||||
},
|
||||
autoar_imdb:{
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
//END included from conf/sitesconf.js
|
||||
|
||||
|
||||
|
||||
var browser_autodetect = true;
|
||||
var usebrowser = "chrome";
|
||||
var debugmsg = true;
|
||||
|
||||
if(browser_autodetect){
|
||||
if(typeof browser === "undefined"){
|
||||
if(chrome){
|
||||
browser = chrome;
|
||||
usebrowser = "chrome";
|
||||
}
|
||||
}
|
||||
else
|
||||
usebrowser = "firefox";
|
||||
}
|
||||
else{
|
||||
if(usebrowser == "chrome")
|
||||
browser = chrome;
|
||||
}
|
||||
|
||||
var UW_SITES = {};
|
||||
|
||||
function showAbout(){
|
||||
clearPage();
|
||||
|
||||
document.getElementById("about").classList.remove("hide");
|
||||
document.getElementById("tab_about").classList.add("tab-selected");
|
||||
}
|
||||
function showShortcuts(){
|
||||
clearPage();
|
||||
|
||||
document.getElementById("uw_shortcuts").classList.remove("hide");
|
||||
document.getElementById("tab_shortcuts").classList.add("tab-selected");
|
||||
}
|
||||
function showGeneralSettings(){
|
||||
clearPage();
|
||||
|
||||
document.getElementById("general_settings").classList.remove("hide");
|
||||
document.getElementById("tab_general_settings").classList.add("tab-selected");
|
||||
}
|
||||
|
||||
function showSites(){
|
||||
clearPage();
|
||||
document.getElementById("uw_sites").classList.remove("hide");
|
||||
document.getElementById("tab_sites").classList.add("tab-selected");
|
||||
}
|
||||
|
||||
function clearPage(){
|
||||
// Hide you sections
|
||||
document.getElementById("uw_shortcuts").classList.add("hide");
|
||||
document.getElementById("about").classList.add("hide");
|
||||
document.getElementById("general_settings").classList.add("hide");
|
||||
document.getElementById("uw_sites").classList.add("hide");
|
||||
|
||||
// Hide you tabs
|
||||
document.getElementById("tab_shortcuts").classList.remove("tab-selected");
|
||||
document.getElementById("tab_about").classList.remove("tab-selected");
|
||||
document.getElementById("tab_general_settings").classList.remove("tab-selected");
|
||||
document.getElementById("tab_sites").classList.remove("tab-selected");
|
||||
|
||||
}
|
||||
|
||||
function saveopts(){
|
||||
|
||||
var actions = ["fitw", "fith", "reset", "zoom", "unzoom", "ar219", "ar169", "ar1610", "ar43", "autoar"];
|
||||
var new_keybinds = {};
|
||||
|
||||
// Preberemo naš obrazec in iz njega naredimo nov objekt z bližnjicami.
|
||||
// Let's read our form and make a new object with keybinds.
|
||||
|
||||
for(var i = 0; i < actions.length; i++){
|
||||
var action = actions[i];
|
||||
var targetAR = "";
|
||||
|
||||
if(action == "ar219"){
|
||||
action = "char";
|
||||
targetAR = (21/9);
|
||||
}
|
||||
if(action == "ar169"){
|
||||
action = "char";
|
||||
targetAR = (16/9);
|
||||
}
|
||||
if(action == "ar1610"){
|
||||
action = "char";
|
||||
targetAR = (16/10);
|
||||
}
|
||||
if(action == "ar43"){
|
||||
action = "char";
|
||||
targetAR = (4/3);
|
||||
}
|
||||
|
||||
if(targetAR != ""){
|
||||
var keybind = {
|
||||
action: action,
|
||||
targetAR: targetAR,
|
||||
key: document.querySelector("#" + actions[i] + "_letter").value.toLowerCase().replace(/[^a-z0-9]/,""),
|
||||
modifiers: []
|
||||
}
|
||||
}
|
||||
else{
|
||||
var keybind = {
|
||||
action: action,
|
||||
key: document.querySelector("#" + actions[i] + "_letter").value.toLowerCase().replace(/[^a-z0-9]/,""),
|
||||
modifiers: []
|
||||
}
|
||||
}
|
||||
|
||||
if(document.querySelector("#" + actions[i] + "_ctrl").checked)
|
||||
keybind.modifiers.push("ctrl");
|
||||
if(document.querySelector("#" + actions[i] + "_alt").checked)
|
||||
keybind.modifiers.push("alt");
|
||||
if(document.querySelector("#" + actions[i] + "_shift").checked)
|
||||
keybind.modifiers.push("shift");
|
||||
|
||||
new_keybinds[i] = keybind;
|
||||
}
|
||||
|
||||
// Preveriti moramo, da nismo dvema možnostima dodali isto bližnjico.
|
||||
// We need to check if all keybinds are unique.
|
||||
|
||||
var fail = false;
|
||||
|
||||
for(var i = 0; i < actions.length; i++)
|
||||
document.querySelector("#" + actions[i] + "_letter").classList.remove("dup_keybinds");
|
||||
|
||||
for(var i = 0; i < actions.length; i++){
|
||||
if(new_keybinds[i].key == "")
|
||||
continue;
|
||||
|
||||
for(var j = i + 1; j < actions.length; j++){
|
||||
if(new_keybinds[i].key == new_keybinds[j].key){
|
||||
if(compareModifiers(new_keybinds[i].modifiers, new_keybinds[j].modifiers)){
|
||||
fail = true;
|
||||
document.querySelector("#" + actions[i] + "_letter").classList.add("dup_keybinds");
|
||||
document.querySelector("#" + actions[j] + "_letter").classList.add("dup_keybinds");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fail){
|
||||
browser.storage.local.set({ultrawidify_keybinds:new_keybinds});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function saveAutoar(){
|
||||
setopt({ultrawidify_autoar: document.querySelector("#enable_autoar").checked});
|
||||
}
|
||||
|
||||
function saveUI(){
|
||||
var show_ui = document.querySelector("#enable_ui");
|
||||
var ui_compact = document.querySelector("#enable_ui_compact");
|
||||
var optionLine = document.getElementById("compact_ui_suboption");
|
||||
|
||||
if(show_ui.checked){
|
||||
ui_compact.disabled = false;
|
||||
optionLine.classList.remove("hide");
|
||||
setopt({ultrawidify_ui: ui_compact.checked ? "compact" : "all" });
|
||||
}
|
||||
else{
|
||||
ui_compact.disabled = true;
|
||||
optionLine.classList.add("hide");
|
||||
setopt({ultrawidify_ui: "none"});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function compareModifiers(a,b){
|
||||
//NOTE: to je precej slab in neprenoslijv način primerjanja dveh tabel, ampak za naš primer deluje dovolj
|
||||
// dobro, saj 'ctrl' vedno pride pred 'alt' in 'alt' vedno pride pred 'shift' (če se sploh pojavijo).
|
||||
//NOTE: this is bad and totally unfoolproof practice. In our example comparing arrays the way we do works
|
||||
// because values ALWAYS appear in the same order: 'ctrl' always appears before 'alt' (or it doesn't
|
||||
// appear at all). 'alt' always appears before 'shift' (or it doesn't appear at all).
|
||||
if(a.length != b.length)
|
||||
return false;
|
||||
|
||||
var match = true;
|
||||
for(var i = 0; i < a.length; i++)
|
||||
match &= a[i] == b[i]
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
function printerr(err){
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
function gotopts(opts){
|
||||
if(!opts.ultrawidify_keybinds){
|
||||
console.log("ultrawidify keybinds are undefined. the fuck?",opts);
|
||||
return;
|
||||
}
|
||||
var KEYBINDS = Object.keys(opts.ultrawidify_keybinds).map(function (key) { return opts.ultrawidify_keybinds[key];});
|
||||
// google chrome is really the untermensch browse // google chrome is really the untermensch browserr
|
||||
var actions = ["fitw", "fith", "reset", "zoom", "unzoom", "ar219", "ar169", "ar1610", "ar43", "autoar"];
|
||||
for(var i = 0; i < actions.length; i++){
|
||||
document.querySelector("#" + actions[i] + "_letter").classList.remove("dup_keybinds");
|
||||
document.querySelector("#" + actions[i] + "_letter").value = KEYBINDS[i].key;
|
||||
for(var j = 0; j < KEYBINDS[i].modifiers.length; j++){
|
||||
if(KEYBINDS[i].modifiers[j] == "ctrl")
|
||||
document.querySelector("#" + actions[i] + "_ctrl").checked = true;
|
||||
if(KEYBINDS[i].modifiers[j] == "alt")
|
||||
document.querySelector("#" + actions[i] + "_alt").checked = true;
|
||||
if(KEYBINDS[i].modifiers[j] == "shift")
|
||||
document.querySelector("#" + actions[i] + "_shift").checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function gotar(opts){
|
||||
|
||||
}
|
||||
|
||||
function gotui(opts){
|
||||
var show_ui = document.querySelector("#enable_ui");
|
||||
var ui_compact = document.querySelector("#enable_ui_compact");
|
||||
var optionLine = document.getElementById("compact_ui_suboption");
|
||||
|
||||
if(opts.ultrawidify_ui == "all"){
|
||||
show_ui.checked = true;
|
||||
ui_compact.checked = false;
|
||||
optionLine.classList.remove("hide");
|
||||
}
|
||||
else if(opts.ultrawidify_ui == "compact"){
|
||||
show_ui.checked = true;
|
||||
ui_compact.checked = true;
|
||||
optionLine.classList.remove("hide");
|
||||
}
|
||||
else if(opts.ultrawidify_ui == "none"){
|
||||
show_ui.checked = false;
|
||||
ui_compact.checked = false;
|
||||
optionLine.classList.add("hide");
|
||||
}
|
||||
}
|
||||
|
||||
function gotsites(opts){
|
||||
|
||||
var list = document.getElementById("uw_sites_list");
|
||||
|
||||
if(list)
|
||||
list.remove();
|
||||
|
||||
var anchor = document.getElementById("uw_sites_body");
|
||||
|
||||
// at the top of the list, there is this option to reset site config
|
||||
resetLink = document.createElement("a");
|
||||
resetLink.onclick = function(){ delopt("ultrawidify_siterules"); setopt({"ultrawidify_siterules":UW_SITES}); };
|
||||
resetLink.textContent = "Reset site options to default";
|
||||
anchor.appendChild(resetLink);
|
||||
|
||||
|
||||
list = document.createElement("div");
|
||||
list.id = "uw_sites_list";
|
||||
list.className = "uw_sites";
|
||||
|
||||
anchor.appendChild(list);
|
||||
|
||||
uw_sites = opts.ultrawidify_siterules;
|
||||
UW_SITES = uw_sites;
|
||||
if(debugmsg)
|
||||
console.log("uw settings::gotopts | site opts:",opts);
|
||||
|
||||
for (type in {"official":1,"non-official":1,"custom":1, "add new site":1} ) { // unparalleled laziness!
|
||||
if(debugmsg){
|
||||
console.log("uw settings::gotopts | adding sites of type" , type);
|
||||
}
|
||||
var head = document.createElement("div");
|
||||
head.className = "sites_header";
|
||||
head.textContent = type.charAt(0).toUpperCase() + type.slice(1);
|
||||
|
||||
var category_desc = document.createElement("div");
|
||||
if(type == "official"){
|
||||
category_desc.innerHTML = "These sites are officially supported by the extension developer. These sites should always work. <small>(Pro tip: if you don't want extension to run on some of the following sites, uncheck the checkbox for that site)</small>";
|
||||
}
|
||||
else if(type == "non-official"){
|
||||
category_desc.textContent = "Sites in this category have been contribued by third parties. These sites will probably work, but the developer couldn't test whether they work or not.";
|
||||
}
|
||||
else if(type == "custom"){
|
||||
category_desc.textContent = "In this section, you can define rules for sites that aren't supported either officially or non-officially. See [todo: link] contributing for details. If you define a custom site, please consider sharing configuration on github (see contributing for details).";
|
||||
}
|
||||
else if(type == "add new site"){
|
||||
category_desc.textContent = "Add a custom site by filling the form below.";
|
||||
}
|
||||
|
||||
list.append(head);
|
||||
list.append(category_desc);
|
||||
|
||||
var category_counter = 0;
|
||||
|
||||
for (site in uw_sites) {
|
||||
if(debugmsg)
|
||||
console.log("we're at site %s of type %s. We're %s this site.",site, uw_sites[site].type, uw_sites[site].type == type ? "processing" : "ignoring");
|
||||
|
||||
if(uw_sites[site].type == type){
|
||||
var entry = document.createElement("div");
|
||||
var header = document.createElement("div");
|
||||
|
||||
header.id = site + "_display";
|
||||
header.className = "uw_options_line site_details";
|
||||
|
||||
|
||||
var siteTitle = document.createElement("div");
|
||||
siteTitle.className = "site_name";
|
||||
{
|
||||
var sitecb = mkcb(site, uw_sites[site].enabled, "siteEnabled", true);
|
||||
var editTitle = mkebox(site, site, "title");
|
||||
editTitle.className = "site_title_ebox";
|
||||
siteTitle.append(sitecb);
|
||||
siteTitle.append(editTitle);
|
||||
|
||||
var editBtn = document.createElement("div");
|
||||
editBtn.textContent = "« edit »";
|
||||
editBtn.className = "inline_button";
|
||||
editBtn.id = site + "_edit_button";
|
||||
editBtn.addEventListener("click", function(){ var site = this.id; site = site.replace("_edit_button", ""); enableEditing(site)});
|
||||
|
||||
var saveBtn = document.createElement("div");
|
||||
saveBtn.textContent = "« save »";
|
||||
saveBtn.className = "inline_button hide";
|
||||
saveBtn.id = site + "_save_button";
|
||||
saveBtn.addEventListener("click", function(){ var site = this.id; site = site.replace("_save_button", ""); saveEdited(site)});
|
||||
|
||||
var cancelBtn = document.createElement("div");
|
||||
cancelBtn.textContent = "« cancel »";
|
||||
cancelBtn.className = "inline_button hide";
|
||||
cancelBtn.id = site + "_cancel_button";
|
||||
cancelBtn.addEventListener("click", function(){ var site = this.id; site = site.replace("_cancel_button", ""); cancelEditing(site)});
|
||||
|
||||
siteTitle.append(editBtn);
|
||||
siteTitle.append(saveBtn);
|
||||
siteTitle.append(cancelBtn);
|
||||
}
|
||||
header.appendChild(siteTitle);
|
||||
entry.appendChild(header);
|
||||
|
||||
var body = document.createElement("div");
|
||||
var jsonForm = document.createElement("textarea");
|
||||
jsonForm.cols = 64;
|
||||
jsonForm.rows = 32;
|
||||
|
||||
jsonForm.value = JSON.stringify(uw_sites[site], null, 2);
|
||||
|
||||
body.appendChild(jsonForm);
|
||||
// body.classNamež
|
||||
entry.appendChild(body);
|
||||
list.append(entry);
|
||||
|
||||
|
||||
category_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// for (site in uw_sites){
|
||||
// if(debugmsg)
|
||||
// console.log("we're at site %s of type %s. We're %s this site.",site, uw_sites[site].type, uw_sites[site].type == type ? "processing" : "ignoring");
|
||||
//
|
||||
// if(uw_sites[site].type == type){
|
||||
//
|
||||
// var entry = document.createElement("div");
|
||||
// var displayedInfo = document.createElement("div");
|
||||
// displayedInfo.id = site + "_display";
|
||||
// displayedInfo.className = "uw_options_line site_details";
|
||||
//
|
||||
// var siteTitle = document.createElement("div");
|
||||
// siteTitle.className = "site_name";
|
||||
//
|
||||
// {
|
||||
// var sitecb = mkcb(site, uw_sites[site].enabled, "siteEnabled", true);
|
||||
// var editTitle = mkebox(site, site, "title");
|
||||
// editTitle.className = "site_title_ebox";
|
||||
// siteTitle.append(sitecb);
|
||||
// siteTitle.append(editTitle);
|
||||
//
|
||||
// var editBtn = document.createElement("div");
|
||||
// editBtn.textContent = "« edit »";
|
||||
// editBtn.className = "inline_button";
|
||||
// editBtn.id = site + "_edit_button";
|
||||
// editBtn.addEventListener("click", function(){ var site = this.id; site = site.replace("_edit_button", ""); enableEditing(site)});
|
||||
//
|
||||
// var saveBtn = document.createElement("div");
|
||||
// saveBtn.textContent = "« save »";
|
||||
// saveBtn.className = "inline_button hide";
|
||||
// saveBtn.id = site + "_save_button";
|
||||
// saveBtn.addEventListener("click", function(){ var site = this.id; site = site.replace("_save_button", ""); saveEdited(site)});
|
||||
//
|
||||
// var cancelBtn = document.createElement("div");
|
||||
// cancelBtn.textContent = "« cancel »";
|
||||
// cancelBtn.className = "inline_button hide";
|
||||
// cancelBtn.id = site + "_cancel_button";
|
||||
// cancelBtn.addEventListener("click", function(){ var site = this.id; site = site.replace("_cancel_button", ""); cancelEditing(site)});
|
||||
//
|
||||
// siteTitle.append(editBtn);
|
||||
// siteTitle.append(saveBtn);
|
||||
// siteTitle.append(cancelBtn);
|
||||
// }
|
||||
//
|
||||
// var siteDetails = document.createElement("div");
|
||||
// siteDetails.id = site + "_conf_details";
|
||||
// siteDetails.classList = "hide";
|
||||
//
|
||||
// var urlRules = document.createElement("div");
|
||||
// {
|
||||
// var urlRulesLabel = document.createElement("span");
|
||||
// urlRulesLabel.textContent = "URL rule: ";
|
||||
//
|
||||
// urlRulesEbox = mkebox(site, uw_sites[site].urlRules[0], "url_rules");
|
||||
//
|
||||
// urlRules.append(urlRulesLabel);
|
||||
// urlRules.append(urlRulesEbox);
|
||||
// }
|
||||
//
|
||||
// var playerElement = document.createElement("div");
|
||||
//
|
||||
// {
|
||||
// var playerName = document.createElement("div");
|
||||
//
|
||||
// var playerNameLabel = document.createElement("span");
|
||||
//
|
||||
// playerNameLabel.textContent = "id of the player container:";
|
||||
// var playerNameEbox = mkebox(site, uw_sites[site].player.name, "player_name");
|
||||
//
|
||||
// playerName.append(playerNameLabel);
|
||||
// playerName.append(playerNameEbox);
|
||||
//
|
||||
// var playerClass = document.createElement("div");
|
||||
// var pcb = document.createElement("input");
|
||||
// pcb.className = site + "_ebox";
|
||||
// pcb.type = "checkbox";
|
||||
// pcb.name = site + "_pccb_name";
|
||||
// pcb.id = site + "_pccb_id";
|
||||
// pcb.checked = uw_sites[site].player.isClass;
|
||||
// pcb.disabled = true;
|
||||
//
|
||||
// var pcblabel = document.createElement("span");
|
||||
// pcblabel.textContent = " Name of the player container is a class";
|
||||
//
|
||||
// playerClass.append(pcb);
|
||||
// playerClass.append(pcblabel);
|
||||
// playerElement.append(playerName);
|
||||
// playerElement.append(playerClass);
|
||||
// }
|
||||
//
|
||||
// var iframe_playerName = document.createElement("div");
|
||||
// var ipn_label = document.createElement("span");
|
||||
// ipn_label.textContent = "id of the player container when in an iframe:";
|
||||
// ipn_ebox = mkebox(site, uw_sites[site].iframe ? uw_sites[site].iframe.name : "", "iframe_name");
|
||||
// iframe_playerName.append(ipn_label);
|
||||
// iframe_playerName.append(ipn_ebox);
|
||||
//
|
||||
// var iframe_playerClass = document.createElement("div");
|
||||
// var ipc_label = document.createElement("span");
|
||||
// ipc_label.textContent = " Name of the player container is a class";
|
||||
// var ipc_cb = mkcb(site, uw_sites[site].iframe ? uw_sites[site].iframe.isClass : false, "iframe_class");
|
||||
// iframe_playerClass.append(ipc_cb);
|
||||
// iframe_playerClass.append(ipc_label);
|
||||
//
|
||||
//
|
||||
// var sampleButton = document.createElement("div");
|
||||
// var sbc = document.createElement("div");
|
||||
// var sbi = document.createElement("div");
|
||||
// var sbo = document.createElement("div");
|
||||
// var sbc_label = document.createElement("span");
|
||||
// var sbi_label = document.createElement("span");
|
||||
// var sbo_label = document.createElement("span");
|
||||
// sbc_label.textContent = "Sample button class:";
|
||||
// sbi_label.textContent = "Sample button index:";
|
||||
// sbo_label.textContent = "Use height for UI scaling";
|
||||
// var sampleButtonClass = mkebox(site, uw_sites[site].sampleButton.class, "sample_button_class");
|
||||
// var sampleButtonIndex = mkebox(site, uw_sites[site].sampleButton.index, "sample_button_index");
|
||||
// var buttonSizeBase = mkcb(site, uw_sites[site].sampleButton.buttonSizeBase == "y", "sample_button_size_base");
|
||||
//
|
||||
// sbc.append(sbc_label);
|
||||
// sbc.append(sampleButtonClass);
|
||||
// sampleButton.append(sbc);
|
||||
//
|
||||
// sbi.append(sbi_label);
|
||||
// sbi.append(sampleButtonIndex);
|
||||
// sampleButton.append(sbi);
|
||||
//
|
||||
// sbo.append(buttonSizeBase);
|
||||
// sbo.append(sbo_label);
|
||||
// sampleButton.append(sbo);
|
||||
//
|
||||
// var imdbar = document.createElement("div");
|
||||
// var imdbar_cb = mkcb(site, uw_sites[site].autoar_imdb, "imdbar");
|
||||
// var imdbar_label = document.createElement("span");
|
||||
// imdbar_label.textContent = " This site supports automatic aspect ratio detection";
|
||||
// imdbar.append(imdbar_cb);
|
||||
// imdbar.append(imdbar_label);
|
||||
//
|
||||
// var imdbar_title = document.createElement("div");
|
||||
// var it_label = document.createElement("span");
|
||||
// it_label.textContent = "id of the element containing video title:";
|
||||
// it_ebox = mkebox(site, uw_sites[site].iframe ? uw_sites[site].iframe.name : "", "imdbar_title");
|
||||
// imdbar_title.append(it_label);
|
||||
// imdbar_title.append(it_ebox);
|
||||
//
|
||||
// var imdbar_class = document.createElement("div");
|
||||
// var ic_label = document.createElement("span");
|
||||
// ic_label.textContent = " Name of the title container is a class";
|
||||
// var ic_cb = mkcb(site, uw_sites[site].iframe ? uw_sites[site].iframe.isClass : false, "imdbar_class");
|
||||
// imdbar_class.append(ic_cb);
|
||||
// imdbar_class.append(ic_label);
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// var optionspad = document.createElement("div");
|
||||
// optionspad.textContent = "-------------";
|
||||
//
|
||||
//
|
||||
// siteDetails.append(urlRules);
|
||||
// siteDetails.append(playerElement);
|
||||
// siteDetails.append(optionspad);
|
||||
// siteDetails.append(iframe_playerName);
|
||||
// siteDetails.append(iframe_playerClass);
|
||||
// siteDetails.append(optionspad);
|
||||
//
|
||||
// siteDetails.append(sampleButton);
|
||||
//
|
||||
// siteDetails.append(imdbar);
|
||||
// siteDetails.append(imdbar_title);
|
||||
// siteDetails.append(imdbar_class);
|
||||
// // siteDetails.append(optionspad);
|
||||
//
|
||||
//
|
||||
// displayedInfo.append(siteTitle);
|
||||
// displayedInfo.append(siteDetails);
|
||||
//
|
||||
// entry.append(displayedInfo);
|
||||
//
|
||||
// list.append(entry);
|
||||
//
|
||||
// category_counter++;
|
||||
//
|
||||
// if(site == "dummy" && type == "add new site"){
|
||||
// if(debugmsg)
|
||||
// console.log("uw settings::gotsites | we are adding dummy site");
|
||||
// enableEditing("dummy");
|
||||
// document.getElementById("dummy_title_ebox").disabled = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if(! category_counter){
|
||||
var noEntriesMsg = document.createElement("div");
|
||||
noEntriesMsg.textContent = "There's no entries in this category yet";
|
||||
noEntriesMsg.classList = "red";
|
||||
list.append(noEntriesMsg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function mkebox(site, value, id){
|
||||
var ebox = document.createElement("input");
|
||||
ebox.className = "site_details details_ebox " + site + "_ebox",
|
||||
ebox.id = site + "_" + id + "_ebox";
|
||||
ebox.type = "text";
|
||||
ebox.value = value;
|
||||
ebox.disabled = true;
|
||||
|
||||
return ebox;
|
||||
}
|
||||
|
||||
function mkcb(site, checked, id, forceEnable){
|
||||
var cb = document.createElement("input");
|
||||
cb.type = "checkbox";
|
||||
cb.name = site + "_cb_name";
|
||||
cb.id = site + "_" + id + "_cb";
|
||||
cb.checked = checked;
|
||||
|
||||
if(!forceEnable){
|
||||
cb.disabled = true;
|
||||
cb.className = site + "_ebox";
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
|
||||
function enableEditing(site){
|
||||
showSiteDetails(site);
|
||||
if(debugmsg)
|
||||
console.log("uw settings :: enableEditing | enabling editing for",site);
|
||||
|
||||
var formElements = document.getElementsByClassName(site + "_ebox");
|
||||
|
||||
if(!formElements)
|
||||
return;
|
||||
|
||||
if(debugmsg)
|
||||
console.log("form elements: ", formElements);
|
||||
|
||||
for(var i = 0; i < formElements.length; i++){
|
||||
formElements[i].disabled = false;
|
||||
}
|
||||
|
||||
var editButton = document.getElementById(site + "_edit_button");
|
||||
if( editButton )
|
||||
editButton.classList.add("hide");
|
||||
else
|
||||
return;
|
||||
|
||||
try{
|
||||
document.getElementById(site + "_save_button").classList.remove("hide");
|
||||
document.getElementById(site + "_cancel_button").classList.remove("hide");
|
||||
} catch (e){};
|
||||
}
|
||||
|
||||
function disableEditing(site){
|
||||
var formElements = document.getElementsByClassName(site + "_ebox");
|
||||
|
||||
if(!formElements)
|
||||
return;
|
||||
|
||||
for(var i = 0; i < formElements.length; i++){
|
||||
formElements[i].disabled = true;
|
||||
}
|
||||
|
||||
var editButton = document.getElementById(site + "_edit_button");
|
||||
if( editButton )
|
||||
editButton.classList.remove("hide");
|
||||
else
|
||||
return;
|
||||
|
||||
try{
|
||||
document.getElementById(site + "_save_button").classList.add("hide");
|
||||
document.getElementById(site + "_cancel_button").classList.add("hide");
|
||||
} catch (e){};
|
||||
}
|
||||
|
||||
function cancelEditing(site){
|
||||
if(site != "dummy"){
|
||||
disableEditing(site);
|
||||
hideSiteDetails(site);
|
||||
}
|
||||
setSiteOpts(site, UW_SITES[site]);
|
||||
}
|
||||
|
||||
function saveEdited(site){
|
||||
|
||||
console.log("uw settings::saveEdited | this is our site:",site,"is this 'dummy'?", site == "dummy");
|
||||
|
||||
if(site == "dummy"){
|
||||
var newsite = getSiteOpts(site);
|
||||
newsite.type = "custom";
|
||||
newsite.enabled = true;
|
||||
UW_SITES[document.getElementById("dummy_title_ebox").value] = newsite;
|
||||
}
|
||||
else{
|
||||
UW_SITES[site] = getSiteOpts(site);
|
||||
// disableEditing(site);
|
||||
// hideSiteDetails(site);
|
||||
}
|
||||
setopt({ultrawidify_siterules: UW_SITES});
|
||||
|
||||
if(site == "dummy")
|
||||
gotsites({ultrawidify_siterules: UW_SITES});
|
||||
|
||||
}
|
||||
|
||||
function showSiteDetails(site){
|
||||
try{
|
||||
document.getElementById(site + "_conf_details").classList.remove("hide");
|
||||
}catch(me_outside_how_about_that){}
|
||||
}
|
||||
|
||||
function hideSiteDetails(site){
|
||||
try{
|
||||
document.getElementById(site + "_conf_details").classList.add("hide");
|
||||
}catch(me_outside_how_about_that){}
|
||||
}
|
||||
|
||||
|
||||
function getSiteOpts(site){
|
||||
var newOptions = {};
|
||||
|
||||
newOptions.urlRules = [ document.getElementById(site + "_url_rules_ebox").value ];
|
||||
newOptions.player = {};
|
||||
newOptions.player.name = document.getElementById(site + "_player_name_ebox").value;
|
||||
newOptions.player.isClass = document.getElementById(site + "_pccb_id").checked;
|
||||
newOptions.iframe = {};
|
||||
newOptions.iframe.name = document.getElementById(site + "_iframe_name_ebox").value;
|
||||
newOptions.iframe.isClass = document.getElementById(site + "_iframe_class_cb").checked;
|
||||
newOptions.autoar_imdb = {};
|
||||
newOptions.autoar_imdb.enabled = document.getElementById(site + "_imdbar_cb").value;
|
||||
newOptions.autoar_imdb.title = document.getElementById(site + "_imdbar_title_ebox").value;
|
||||
newOptions.autoar_imdb.isClass = document.getElementById(site + "_imdbar_class_cb").checked;
|
||||
|
||||
return newOptions;
|
||||
}
|
||||
|
||||
function setSiteOpts(site, opts){
|
||||
document.getElementById(site + "_url_rules_ebox").value = opts.urlRules[0];
|
||||
document.getElementById(site + "_player_name_ebox").value = opts.player.name;
|
||||
document.getElementById(site + "_pccb_id").checked = opts.player.isClass;
|
||||
if(opts.iframe){
|
||||
document.getElementById(site + "_iframe_name_ebox").value = opts.iframe.name;
|
||||
document.getElementById(site + "_iframe_class_cb").checked = opts.iframe.isClass;
|
||||
}
|
||||
if(opts.autoar_imdb){
|
||||
document.getElementById(site + "_imdbar_cb").checked = opts.autoar_imdb.enabled;
|
||||
if(opts.autoar_imdb.enabled){
|
||||
document.getElementById(site + "_imdbar_title_ebox").value = opts.autoar_imdb.title;
|
||||
document.getElementById(site + "_imdbar_class_cb").value = opts.autoar_imdb.isClass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadopts(){
|
||||
|
||||
getopt("ultrawidify_keybinds", gotopts);
|
||||
// getopt("ultrawidify_autoar", gotar)
|
||||
getopt("ultrawidify_ui", gotui);
|
||||
getopt("ultrawidify_siterules", gotsites);
|
||||
|
||||
// We build ui for 'site options' here
|
||||
// buildSites();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// page init
|
||||
document.addEventListener("DOMContentLoaded", loadopts);
|
||||
|
||||
document.querySelector("#tab_shortcuts").addEventListener("click", showShortcuts);
|
||||
document.querySelector("#tab_about").addEventListener("click", showAbout);
|
||||
document.querySelector("#tab_general_settings").addEventListener("click",showGeneralSettings);
|
||||
document.querySelector("#tab_sites").addEventListener("click", showSites);
|
||||
|
||||
document.querySelector("#kb_save").addEventListener("click", saveopts);
|
||||
document.querySelector("#kb_cancel").addEventListener("click",loadopts);
|
||||
|
||||
document.querySelector("#enable_autoar").addEventListener("click",saveAutoar);
|
||||
document.querySelector("#enable_ui").addEventListener("click", saveUI);
|
||||
document.querySelector("#enable_ui_compact").addEventListener("click", saveUI);
|
||||
getopt("ultrawidify_autoar",function(obj){document.querySelector("#enable_autoar").checked = obj.ultrawidify_autoar});
|
@ -1,42 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NOTE: this script needs to be run with the npm run build-all
|
||||
# command from the root directory of the project. Running it in
|
||||
# any other way probably isn't going to work.
|
||||
|
||||
# pre-build steps:
|
||||
mkdir -p ./build/old
|
||||
npm run pre-build
|
||||
rm ./dist-zip/uw-amo-source.zip
|
||||
mv -f ./dist-zip/*.zip ./build/old
|
||||
|
||||
# lets force raise ram limit, but the improper way
|
||||
# export NODE_OPTIONS=--max_old_space_size=4096
|
||||
|
||||
# build the version for each browser and create a zip afterwards
|
||||
# step 1: define build functions
|
||||
#function buildFF {
|
||||
npm run build
|
||||
node scripts/build-zip.js ff
|
||||
#}
|
||||
#function buildChrome {
|
||||
npm run build-chrome
|
||||
node scripts/build-zip.js chrome
|
||||
#}
|
||||
#function buildEdge {
|
||||
npm run build-edge
|
||||
node scripts/build-zip.js edge
|
||||
#}
|
||||
|
||||
# step 2: execute them all at once
|
||||
# buildFF &
|
||||
# buildChrome &
|
||||
# buildEdge &
|
||||
|
||||
# wait < <(jobs -p)
|
||||
|
||||
# prepare AMO source
|
||||
# source code needs to be prepared AFTER
|
||||
# the code has been built, to ensure that
|
||||
# package-lock.json remains unchanged
|
||||
./scripts/prepare-amo-source.sh
|
@ -1,94 +0,0 @@
|
||||
#!/bin/bash
|
||||
# env variables to set:
|
||||
#
|
||||
# FORCE_BUILD set this variable to "true" if you wanna force build, even if build was
|
||||
# triggered without any commits pushed to the directory
|
||||
#
|
||||
# BUILD_SCRIPT build-testing or build-nightly, could be any other from package.json tho
|
||||
#
|
||||
# RELEASE_SERVER target server (where to push built zips after they've been built)
|
||||
# RELEASE_DIRECTORY base directory on the target server
|
||||
# BUILD_CHANNEL_DIRECTORY directory for uploads, inside the release directory
|
||||
#
|
||||
# AMO_API_KEY needed if you want to sign and push extension to addons.mozilla.org
|
||||
# AMO_API_SECRET -||-
|
||||
|
||||
echo "============= STARTING BUILD SCRIPT ============="
|
||||
pwd
|
||||
whoami
|
||||
echo " ::: env dump"
|
||||
echo " -> FORCE_BUILD: $FORCE_BUILD"
|
||||
echo " -> BUILD_SCRIPT: $BUILD_SCRIPT"
|
||||
echo " -> RELEASE_SERVER: $RELEASE_SERVER"
|
||||
echo " -> RELEASE_DIRECTORY: $RELEASE_DIRECTORY"
|
||||
echo " -> BUILD_CHANNEL_DIRECTORY: $BUILD_CHANNEL_DIRECTORY"
|
||||
|
||||
# don't build if nothing has changed, unless overriden via env variable
|
||||
if [ ! -z "$GIT_COMMIT" ] ; then
|
||||
if [ ! -z "$GIT_PREVIOUS_COMMIT" ] ; then
|
||||
if [ "$GIT_COMMIT" == "$GIT_PREVIOUS_COMMIT" ] ; then
|
||||
if [ $FORCE_BUILD == false ] ; then
|
||||
echo "--------------------------------------------"
|
||||
echo " Nothing has changed. Aborting build."
|
||||
echo "--------------------------------------------"
|
||||
exit 0;
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# let's raise RAM limit for npm command globally
|
||||
NODE_OPTIONS=--max_old_space_size=4096
|
||||
|
||||
npm ci
|
||||
|
||||
rm -rf ./dist-zip || true # no big deal if ./dist-zip doesn't exist
|
||||
mkdir dist-zip # create it back
|
||||
|
||||
#
|
||||
# build firefox
|
||||
#
|
||||
npm run "${BUILD_SCRIPT}"
|
||||
node --max-old-space-size=2048 scripts/build-zip.js ff nightly
|
||||
# if [ ! -z "${AMO_API_KEY}" ] ; then
|
||||
# if [ ! -z "${AMO_API_SECRET}" ] ; then
|
||||
# web-ext sign --source-dir ./dist --api-key "${AMO_API_KEY}" --api-secret "${AMO_API_SECRET}"
|
||||
# fi
|
||||
# fi
|
||||
|
||||
#
|
||||
# build chrome
|
||||
#
|
||||
npm run "${BUILD_SCRIPT}-chrome"
|
||||
node --max-old-space-size=2048 scripts/build-zip.js chrome nightly
|
||||
#
|
||||
#./scripts/build-crx.sh
|
||||
#
|
||||
|
||||
#
|
||||
# build edge
|
||||
#
|
||||
npm run "${BUILD_SCRIPT}-edge"
|
||||
node --max-old-space-size=2048 scripts/build-zip.js chrome nightly
|
||||
|
||||
|
||||
######################################
|
||||
# UPLOAD TO WEB SERVER
|
||||
######################################
|
||||
|
||||
echo "--------------------------------------------"
|
||||
echo " files ready for upload"
|
||||
echo "--------------------------------------------"
|
||||
echo ""
|
||||
echo "Uploading to server ..."
|
||||
# push all built stuff to the server
|
||||
scp -i ~/.ssh/id_rsa -r ./dist-zip/* "ultrawidify-uploader@${RELEASE_SERVER}:${RELEASE_DIRECTORY}${BUILD_CHANNEL_DIRECTORY}"
|
||||
|
||||
|
||||
######################################
|
||||
# Build finished message
|
||||
######################################
|
||||
echo ""
|
||||
echo "--------------------------------------------"
|
||||
echo " BUILD FINISHED SUCCESSFULLY"
|
||||
echo "--------------------------------------------"
|
@ -1,45 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Purpose: Pack a Chromium extension directory into crx format
|
||||
# gotten from: https://web.archive.org/web/20180114090616/https://developer.chrome.com/extensions/crx#scripts
|
||||
#
|
||||
# Script assumes we're in basedir of the repository and that extension has been built and zipped to /dist-zip
|
||||
# using the crx name we want (same name as zip, except different extension)
|
||||
#
|
||||
# also this doesn't check for errors ever so
|
||||
#
|
||||
|
||||
echo "entering dist-zip"
|
||||
cd ./dist-zip
|
||||
|
||||
zip=`ls | grep chrome.zip`
|
||||
name="${zip%.*}"
|
||||
crx="$name.crx"
|
||||
key="../keys/chrome-nightly.pem" # this is also good for testing build
|
||||
pub="$name.pub"
|
||||
sig="$name.sig"
|
||||
trap 'rm -f "$pub" "$sig" "$zip"' EXIT
|
||||
|
||||
# signature
|
||||
openssl sha1 -sha1 -binary -sign "$key" < "$zip" > "$sig"
|
||||
|
||||
# public key
|
||||
openssl rsa -pubout -outform DER < "$key" > "$pub" 2>/dev/null
|
||||
|
||||
byte_swap () {
|
||||
# Take "abcdefgh" and return it as "ghefcdab"
|
||||
echo "${1:6:2}${1:4:2}${1:2:2}${1:0:2}"
|
||||
}
|
||||
|
||||
crmagic_hex="4372 3234" # Cr24
|
||||
version_hex="0200 0000" # 2
|
||||
pub_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$pub" | awk '{print $5}')))
|
||||
sig_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$sig" | awk '{print $5}')))
|
||||
(
|
||||
echo "$crmagic_hex $version_hex $pub_len_hex $sig_len_hex" | xxd -r -p
|
||||
cat "$pub" "$sig" "$zip"
|
||||
) > "$crx"
|
||||
echo "Wrote $crx"
|
||||
|
||||
echo "exiting dist-zip"
|
||||
cd ..
|
@ -1,76 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const archiver = require('archiver');
|
||||
|
||||
const extractExtensionData = (browserPostfix) => {
|
||||
const extPackageJson = require(`../dist-${browserPostfix}/manifest.json`);
|
||||
|
||||
return {
|
||||
name: extPackageJson.name,
|
||||
version: extPackageJson.version
|
||||
}
|
||||
};
|
||||
|
||||
const makeDirIfNotExists = (dir) => {
|
||||
if(!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir);
|
||||
}
|
||||
}
|
||||
|
||||
const buildZip = (src, dist, zipFilename) => {
|
||||
console.info(`Building ${zipFilename}...`);
|
||||
|
||||
const archive = archiver('zip', { zlib: { level: 9 }});
|
||||
const stream = fs.createWriteStream(path.join(dist, zipFilename));
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
archive
|
||||
.directory(src, false)
|
||||
.on('error', err => reject(err))
|
||||
.pipe(stream);
|
||||
|
||||
stream.on('close', () => resolve());
|
||||
archive.finalize();
|
||||
});
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
const browser = process.argv[2];
|
||||
const testingOrNightly = process.argv[3];
|
||||
let browserPostfix;
|
||||
if (browser == 'firefox') {
|
||||
browserPostfix = 'ff';
|
||||
} else {
|
||||
browserPostfix = browser;
|
||||
}
|
||||
const destDir = path.join(__dirname, `../dist-${browserPostfix}`);
|
||||
const zipDir = path.join(__dirname, '../dist-zip');
|
||||
const {name, version} = extractExtensionData(browserPostfix);
|
||||
|
||||
// collapse spaces and dashes into single dash
|
||||
const baseFilename = `${name.replace(/[ -]+/g, '-')}-${version}`;
|
||||
|
||||
let realZipDir;
|
||||
|
||||
if (!!testingOrNightly) {
|
||||
realZipDir = path.join(zipDir, version);
|
||||
} else {
|
||||
realZipDir = path.join(zipDir);
|
||||
}
|
||||
|
||||
const zipFilename = `${baseFilename}-${browser}.zip`;
|
||||
|
||||
try {
|
||||
makeDirIfNotExists(realZipDir, {recursive: true});
|
||||
} catch (e) {
|
||||
console.error('Failed to make directory.\nDirectory we wanted to make', realZipDir, '\nerror we got:\n', e)
|
||||
return 1;
|
||||
}
|
||||
buildZip(destDir, realZipDir, zipFilename)
|
||||
.then(() => console.info('OK'))
|
||||
.catch(console.err);
|
||||
};
|
||||
|
||||
main();
|
@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# makes a zip file with human-readable source code that we need to upload to AMO
|
||||
# since webpack minifies stuff
|
||||
|
||||
# first, we collect npm/node versions:
|
||||
# (NOTE: the last bit is necessary to remove ANSI color codes from output)
|
||||
NODE_VERSION=`node --version`
|
||||
NPM_VERSION=`npm --version`
|
||||
LINUX_VERSION="$(uname -a | sed 's/\//\\\//g')"
|
||||
|
||||
# copy REAMDE to /tmp for processing
|
||||
cp README-AMO.md /tmp/README-AMO.md
|
||||
|
||||
# replace placeholders with proper software versions
|
||||
sed -i "s/%%NODE_VERSION%%/${NODE_VERSION}/g" /tmp/README-AMO.md
|
||||
sed -i "s/%%NPM_VERSION%%/${NPM_VERSION}/g" /tmp/README-AMO.md
|
||||
sed -i "s/%%LINUX_VERSION%%/${LINUX_VERSION}/g" /tmp/README-AMO.md
|
||||
|
||||
# add files to archive
|
||||
zip -r dist-zip/uw-amo-source.zip /tmp/README-AMO.md .babelrc package.json package-lock.json webpack.config.js scripts/ src/
|
||||
|
||||
# rename /tmp/README-AMO.md to README.md
|
||||
printf "@ tmp/README-AMO.md\n@=README.md\n" | zipnote -w dist-zip/uw-amo-source.zip
|
||||
|
||||
# printout for debugging purposes:
|
||||
echo ""
|
||||
echo "—————— AMO SOURCE PREPARATION FINISHED ——————"
|
||||
echo " Debug info:"
|
||||
echo ""
|
||||
echo "node --version:"
|
||||
node --version
|
||||
echo ""
|
||||
echo "npm --version"
|
||||
npm --version
|
||||
echo ""
|
||||
echo "uname -a"
|
||||
uname -a
|
||||
echo ""
|
||||
echo ""
|
||||
echo "extracted variables:"
|
||||
echo "NODE_VERSION: ${NODE_VERSION}"
|
||||
echo "NPM_VERSION: ${NPM_VERSION}"
|
||||
echo "UNAME: ${LINUX_VERSION}"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "—————— EXTENSION PACKAGES READY FOR UPLOAD ——————"
|
@ -1,53 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const BUNDLE_DIR = path.join(__dirname, `../dist-${process.env.BROWSER === 'firefox' ? 'ff' : process.env.BROWSER}`);
|
||||
const bundles = [
|
||||
'csui/csui-popup.js',
|
||||
];
|
||||
|
||||
const evalRegexForProduction = /;([a-z])=function\(\){return this}\(\);try{\1=\1\|\|Function\("return this"\)\(\)\|\|\(0,eval\)\("this"\)}catch\(t\){"object"==typeof window&&\(\1=window\)}/g;
|
||||
const evalRegexForDevelopment = /;\\r\\n\\r\\n\/\/ This works in non-strict mode(?:.){1,304}/g;
|
||||
|
||||
const removeEvals = (file) => {
|
||||
console.info(`Removing eval() from ${file}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(file, 'utf8', (err, data) => {
|
||||
if(err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const regex = process.env.NODE_ENV === 'production' ? evalRegexForProduction : evalRegexForDevelopment;
|
||||
|
||||
if(!regex.test(data)) {
|
||||
reject(`No CSP specific code found in ${file}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
data = data.replace(regex, '=window;');
|
||||
|
||||
fs.writeFile(file, data, (err) => {
|
||||
if(err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
bundles.forEach(bundle => {
|
||||
removeEvals(path.join(BUNDLE_DIR, bundle))
|
||||
.then(() => console.info(`Bundle ${bundle}: OK`))
|
||||
.catch(console.error);
|
||||
});
|
||||
};
|
||||
|
||||
main();
|
@ -1,57 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
### VARIABLES
|
||||
|
||||
REPRODUCABILITY=5 # how many times we need to build with same hash
|
||||
|
||||
### TEST STARTS HERE ###
|
||||
|
||||
CURRENT_DIR=$(pwd)
|
||||
|
||||
if [[ $(echo $0 | awk -F"/" '{print NF-1}') -eq 1 ]] ; then
|
||||
# we need to go one directory up
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# cleanup after self if we already ran and previous test crashed or
|
||||
# something before it cleaned up after itself.
|
||||
rm -rf /tmp/uw-test-runs/* 2>/dev/null # we not interested if fails
|
||||
|
||||
# make new folder if it doesn't exist
|
||||
mkdir -p /tmp/uw-test-runs
|
||||
|
||||
for ((run=0;run<$REPRODUCABILITY;run++)) ; do
|
||||
echo ""
|
||||
echo "---- run ${run} ----"
|
||||
|
||||
# save hash and then run build. Save hash.
|
||||
OLD_HASH=$HASH
|
||||
HASH=$(npm run build 2>/dev/null | grep "Hash:")
|
||||
|
||||
# move build file to /tmp, where it'll be saved for later
|
||||
mv dist-ff /tmp/uw-test-runs/${run}
|
||||
|
||||
# skip comparisons with previous tests on first run,
|
||||
# cos we don't have anything to compare against yet
|
||||
if [[ $run -ne 0 ]] ; then
|
||||
if [[ "$OLD_HASH" == "$HASH" ]] ; then
|
||||
echo "Hashes ok${HASH##*:}"
|
||||
else
|
||||
echo "Webpack hashes do not match! (${OLD_HASH##*:} <---> ${HASH##*:})"
|
||||
fi
|
||||
|
||||
echo "Diff test (no output=ok):"
|
||||
diff -qr /tmp/uw-test-runs/${prev_run} /tmp/uw-test-runs/${run}
|
||||
else
|
||||
echo "Webpack hash: $HASH"
|
||||
fi
|
||||
|
||||
# save id of previous run
|
||||
prev_run=$run
|
||||
done
|
||||
|
||||
# clean up after self
|
||||
rm -rf /tmp/uw-test-runs
|
||||
|
||||
# restore dir
|
||||
cd "$CURRENT_DIR"
|
@ -1,14 +0,0 @@
|
||||
let Notifications = Object.freeze({
|
||||
'TEST_NOTIFICATION': {
|
||||
icon: 'card-text',
|
||||
text: 'This is a test notification.',
|
||||
timeout: -1,
|
||||
},
|
||||
'AARD_DRM': {
|
||||
icon: 'exclamation-triangle',
|
||||
text: '<b>Autodetection may not be able to run on this video.</b> On sites that utilize DRM you will have to set aspect ratio manually.',
|
||||
timeout: 5000,
|
||||
}
|
||||
});
|
||||
|
||||
export default Notifications;
|
@ -1,7 +0,0 @@
|
||||
enum AntiGradientMode {
|
||||
Disabled = 0,
|
||||
Lax = 1,
|
||||
Strict = 2
|
||||
}
|
||||
|
||||
export default AntiGradientMode;
|
@ -1,13 +0,0 @@
|
||||
enum AspectRatioType {
|
||||
Cycle = -2,
|
||||
Initial = -1, // page default
|
||||
Reset = 0, // reset to initial
|
||||
Automatic = 1, // we want to request automatic aspect ratio detection
|
||||
FitWidth = 2, // legacy/dynamic = fit to width
|
||||
FitHeight = 3, // legacy/dynamic = fit to height
|
||||
Fixed = 4, // pre-determined aspect ratio
|
||||
Manual = 5, // ratio achieved by zooming in/zooming out
|
||||
AutomaticUpdate = 6, // set by Aard
|
||||
}
|
||||
|
||||
export default AspectRatioType;
|
@ -1,9 +0,0 @@
|
||||
enum CropModePersistence {
|
||||
Default = -1,
|
||||
Disabled = 0,
|
||||
UntilPageReload = 1,
|
||||
CurrentSession = 2,
|
||||
Forever = 3,
|
||||
}
|
||||
|
||||
export default CropModePersistence;
|
@ -1,10 +0,0 @@
|
||||
enum ExtensionMode {
|
||||
AutoDisabled = -2,
|
||||
Disabled = -1,
|
||||
Default = 0,
|
||||
Whitelist = 1,
|
||||
Basic = 2,
|
||||
Enabled = 3,
|
||||
};
|
||||
|
||||
export default ExtensionMode;
|
@ -1,11 +0,0 @@
|
||||
enum StretchType {
|
||||
NoStretch = 0,
|
||||
Basic = 1,
|
||||
Hybrid = 2,
|
||||
Conditional = 3,
|
||||
Fixed = 4,
|
||||
FixedSource = 5,
|
||||
Default = -1
|
||||
};
|
||||
|
||||
export default StretchType;
|
@ -1,10 +0,0 @@
|
||||
enum VideoAlignmentType {
|
||||
Left = 0,
|
||||
Center = 1,
|
||||
Right = 2,
|
||||
Top = 3,
|
||||
Bottom = 4,
|
||||
Default = -1
|
||||
};
|
||||
|
||||
export default VideoAlignmentType;
|
@ -1,6 +0,0 @@
|
||||
import AspectRatioType from '../enums/AspectRatioType.enum';
|
||||
|
||||
export interface Ar {
|
||||
type: AspectRatioType,
|
||||
ratio?: number
|
||||
}
|
@ -1,418 +0,0 @@
|
||||
import { Action } from '../../../node_modules/vuex/types/index'
|
||||
import AntiGradientMode from '../enums/AntiGradientMode.enum'
|
||||
import AspectRatioType from '../enums/AspectRatioType.enum'
|
||||
import CropModePersistence from '../enums/CropModePersistence.enum'
|
||||
import ExtensionMode from '../enums/ExtensionMode.enum'
|
||||
import StretchType from '../enums/StretchType.enum'
|
||||
import VideoAlignmentType from '../enums/VideoAlignmentType.enum'
|
||||
|
||||
export interface KeyboardShortcutInterface {
|
||||
key?: string,
|
||||
code?: string,
|
||||
ctrlKey?: boolean,
|
||||
metaKey?: boolean,
|
||||
altKey?: boolean,
|
||||
shiftKey?: boolean,
|
||||
onKeyUp?: boolean,
|
||||
onKeyDown?: boolean,
|
||||
onMouseMove?: boolean,
|
||||
}
|
||||
|
||||
interface ActionScopeInterface {
|
||||
show: boolean,
|
||||
label?: string, // example override, takes precedence over default label
|
||||
shortcut?: KeyboardShortcutInterface[],
|
||||
}
|
||||
|
||||
interface RestrictionsSettings {
|
||||
disableOnSmallPlayers?: boolean; // Whether ultrawidify should disable itself when the player is small
|
||||
minAllowedWidth?: number; // if player is less than this many px wide, ultrawidify will disable itself
|
||||
minAllowedHeight?: number; // if player is less than this many px tall, ultrawidify will disable itself
|
||||
onlyAllowInFullscreen?: boolean; // if enabled, ultrawidify will be disabled when not in full screen regardless of what previous two options say
|
||||
onlyAllowAutodetectionInFullScreen?: boolean; // if enabled, autodetection will only start once in full screen
|
||||
}
|
||||
|
||||
interface ExtensionEnvironmentSettingsInterface {
|
||||
normal: ExtensionMode,
|
||||
theater: ExtensionMode,
|
||||
fullscreen: ExtensionMode,
|
||||
}
|
||||
|
||||
export interface CommandInterface {
|
||||
action: string,
|
||||
label: string,
|
||||
comment?: string,
|
||||
arguments?: any,
|
||||
shortcut?: KeyboardShortcutInterface,
|
||||
internalOnly?: boolean,
|
||||
actionId?: string,
|
||||
}
|
||||
|
||||
export type SettingsReloadComponent = 'PlayerData' | 'VideoData';
|
||||
export type SettingsReloadFlags = true | SettingsReloadComponent;
|
||||
|
||||
export interface AardSettings {
|
||||
aardType: 'webgl' | 'legacy' | 'auto';
|
||||
|
||||
disabledReason: string, // if automatic aspect ratio has been disabled, show reason
|
||||
allowedMisaligned: number, // top and bottom letterbox thickness can differ by this much.
|
||||
// Any more and we don't adjust ar.
|
||||
allowedArVariance: number, // amount by which old ar can differ from the new (1 = 100%)
|
||||
timers: { // autodetection frequency
|
||||
playing: number, // while playing
|
||||
paused: number, // while paused
|
||||
error: number, // after error
|
||||
minimumTimeout: number,
|
||||
tickrate: number, // 1 tick every this many milliseconds
|
||||
},
|
||||
autoDisable: { // settings for automatically disabling the extension
|
||||
maxExecutionTime: number, // if execution time of main autodetect loop exceeds this many milliseconds,
|
||||
// we disable it.
|
||||
consecutiveTimeoutCount: number, // we only do it if it happens this many consecutive times
|
||||
|
||||
// FOR FUTURE USE
|
||||
consecutiveArResets: number // if aspect ratio reverts immediately after AR change is applied, we disable everything
|
||||
},
|
||||
canvasDimensions: {
|
||||
blackframeCanvas: { // smaller than sample canvas, blackframe canvas is used to recon for black frames
|
||||
// it's not used to detect aspect ratio by itself, so it can be tiny af
|
||||
width: number,
|
||||
height: number,
|
||||
},
|
||||
sampleCanvas: { // size of image sample for detecting aspect ratio. Bigger size means more accurate results,
|
||||
// at the expense of performance
|
||||
width: number,
|
||||
height: number,
|
||||
},
|
||||
},
|
||||
|
||||
// NOTE: Black Frame is currently not in use.
|
||||
blackframe: {
|
||||
sufficientColorVariance: number, // calculate difference between average intensity and pixel, for every pixel for every color
|
||||
// component. Average intensity is normalized to where 0 is black and 1 is biggest value for
|
||||
// that component. If sum of differences between normalized average intensity and normalized
|
||||
// component varies more than this % between color components, we can afford to use less strict
|
||||
// cumulative threshold.
|
||||
cumulativeThresholdLax: number,
|
||||
cumulativeThresholdStrict: number,// if we add values of all pixels together and get more than this, the frame is bright enough.
|
||||
// (note: blackframe is 16x9 px -> 144px total. cumulative threshold can be reached fast)
|
||||
blackPixelsCondition: number, // How much pixels must be black (1 all, 0 none) before we consider frame as black. Takes
|
||||
// precedence over cumulative threshold: if blackPixelsCondition is met, the frame is dark
|
||||
// regardless of whether cumulative threshold has been reached.
|
||||
},
|
||||
|
||||
// Used by old aspect ratio detection algorithm. Pls remove.
|
||||
blackbar: {
|
||||
blackLevel: number, // everything darker than 10/255 across all RGB components is considered black by
|
||||
// default. blackLevel can decrease if we detect darker black.
|
||||
threshold: number, // if pixel is darker than the sum of black level and this value, we count it as black
|
||||
// on 0-255. Needs to be fairly high (8 might not cut it) due to compression
|
||||
// artifacts in the video itself
|
||||
frameThreshold: number, // threshold, but when doing blackframe test
|
||||
imageThreshold: number, // in order to detect pixel as "not black", the pixel must be brighter than
|
||||
// the sum of black level, threshold and this value.
|
||||
gradientThreshold: number, // When trying to determine thickness of the black bars, we take 2 values: position of
|
||||
// the last pixel that's darker than our threshold, and position of the first pixel that's
|
||||
// brighter than our image threshold. If positions are more than this many pixels apart,
|
||||
// we assume we aren't looking at letterbox and thus don't correct the aspect ratio.
|
||||
gradientSampleSize: number, // How far do we look to find the gradient
|
||||
maxGradient: number, // if two neighboring pixels in gradientSampleSize differ by more than this, then we aren't
|
||||
// looking at a gradient
|
||||
gradientNegativeTreshold: number,
|
||||
gradientMaxSD: number, // reserved for future use
|
||||
antiGradientMode: AntiGradientMode
|
||||
},
|
||||
// Also not in use, probs.
|
||||
variableBlackbarThresholdOptions: { // In case of poor bitrate videos, jpeg artifacts may cause us issues
|
||||
// FOR FUTURE USE
|
||||
enabled: boolean, // allow increasing blackbar threshold
|
||||
disableArDetectOnMax: boolean, // disable autodetection when threshold goes over max blackbar threshold
|
||||
maxBlackbarThreshold: number, // max threshold (don't increase past this)
|
||||
thresholdStep: number, // when failing to set aspect ratio, increase threshold by this much
|
||||
increaseAfterConsecutiveResets: number // increase if AR resets this many times in a row
|
||||
},
|
||||
blackLevels: {
|
||||
defaultBlack: number, // By default, pixels darker than this are considered black.
|
||||
// (If detection algorithm detects darker blacks, black is considered darkest detected pixel)
|
||||
blackTolerance: number, // If pixel is more than this much brighter than blackLevel, it's considered not black
|
||||
// It is not considered a valid image detection if gradient detection is enabled
|
||||
imageDelta: number, // When gradient detection is enabled, pixels this much brighter than black skip gradient detection
|
||||
}
|
||||
sampling: {
|
||||
edgePosition: number; // % of width (max 0.33). Pixels up to this far away from either edge may contain logo.
|
||||
staticCols: number, // we take a column at [0-n]/n-th parts along the width and sample it
|
||||
randomCols: number, // we add this many randomly selected columns to the static columns
|
||||
staticRows: number, // forms grid with staticSampleCols. Determined in the same way. For black frame checks,
|
||||
},
|
||||
guardLine: { // all pixels on the guardline need to be black, or else we trigger AR recalculation
|
||||
// (if AR fails to be recalculated, we reset AR)
|
||||
enabled: boolean,
|
||||
ignoreEdgeMargin: number, // we ignore anything that pokes over the black line this close to the edge
|
||||
// (relative to width of the sample)
|
||||
imageTestThreshold: number, // when testing for image, this much pixels must be over blackbarThreshold
|
||||
edgeTolerancePx: number, // black edge violation is performed this far from reported 'last black pixel'
|
||||
edgeTolerancePercent: null // unused. same as above, except use % of canvas height instead of pixels
|
||||
},
|
||||
arSwitchLimiter: { // to be implemented
|
||||
switches: number, // we can switch this many times
|
||||
period: number // per this period
|
||||
},
|
||||
|
||||
|
||||
// pls deprecate and move things used
|
||||
edgeDetection: {
|
||||
slopeTestWidth: number,
|
||||
gradientTestSamples: number, // we check this many pixels below (or above) the suspected edge to check for gradient
|
||||
gradientTestBlackThreshold: number, // if pixel in test sample is brighter than that, we aren't looking at gradient
|
||||
gradientTestDeltaThreshold: number, // if delta between two adjacent pixels in gradient test exceeds this, it's not gradient
|
||||
gradientTestMinDelta: number, // if last pixels of the test sample is less than this brighter than the first -> not gradient
|
||||
|
||||
thresholds: {
|
||||
edgeDetectionLimit: number, // during scanning of the edge, quit after edge gets detected at this many points
|
||||
minQualitySingleEdge: number, // At least one of the detected must reach this quality
|
||||
minQualitySecondEdge: number, // The other edge must reach this quality (must be smaller or equal to single edge quality)
|
||||
}
|
||||
|
||||
maxLetterboxOffset: 0.1, // Upper and lower letterbox can be different by this many (% of height)
|
||||
|
||||
// Previous iteration variables VVVV
|
||||
sampleWidth: number, // we take a sample this wide for edge detection
|
||||
detectionThreshold: number, // sample needs to have this many non-black pixels to be a valid edge
|
||||
confirmationThreshold: number, //
|
||||
singleSideConfirmationThreshold: number, // we need this much edges (out of all samples, not just edges) in order
|
||||
// to confirm an edge in case there's no edges on top or bottom (other
|
||||
// than logo, of course)
|
||||
logoThreshold: number, // if edge candidate sits with count greater than this*all_samples, it can't be logo
|
||||
// or watermark.
|
||||
edgeTolerancePx?: number, // we check for black edge violation this far from detection point
|
||||
edgeTolerancePercent?: number, // we check for black edge detection this % of height from detection point. unused
|
||||
middleIgnoredArea: number, // we ignore this % of canvas height towards edges while detecting aspect ratios
|
||||
minColsForSearch: number, // if we hit the edge of blackbars for all but this many columns (%-wise), we don't
|
||||
// continue with search. It's pointless, because black edge is higher/lower than we
|
||||
// are now. (NOTE: keep this less than 1 in case we implement logo detection)
|
||||
},
|
||||
pillarTest: {
|
||||
ignoreThinPillarsPx: number, // ignore pillars that are less than this many pixels thick.
|
||||
allowMisaligned: number // left and right edge can vary this much (%)
|
||||
},
|
||||
textLineTest: {
|
||||
nonTextPulse: number, // if a single continuous pulse has this many non-black pixels, we aren't dealing
|
||||
// with text. This value is relative to canvas width (%)
|
||||
pulsesToConfirm: number, // this is a threshold to confirm we're seeing text.
|
||||
pulsesToConfirmIfHalfBlack: number, // this is the threshold to confirm we're seeing text if longest black pulse
|
||||
// is over 50% of the canvas width
|
||||
testRowOffset: number // we test this % of height from detected edge
|
||||
}
|
||||
}
|
||||
|
||||
interface SettingsInterface {
|
||||
_updateFlags?: {
|
||||
requireReload?: SettingsReloadFlags,
|
||||
forSite?: string
|
||||
}
|
||||
|
||||
arDetect: AardSettings,
|
||||
|
||||
ui: {
|
||||
inPlayer: {
|
||||
enabled: boolean,
|
||||
enabledFullscreenOnly: boolean,
|
||||
popupAlignment: 'left' | 'right',
|
||||
minEnabledWidth: number, // don't show UI if player is narrower than % of screen width
|
||||
minEnabledHeight: number, // don't show UI if player is narrower than % of screen height
|
||||
activation: 'trigger-zone' | 'player', // what needs to be hovered in order for UI to be visible
|
||||
triggerZoneDimensions: { // how large the trigger zone is (relative to player size)
|
||||
width: number
|
||||
height: number,
|
||||
offsetX: number, // fed to translateX(offsetX + '%'). Valid range [-100, 0]
|
||||
offsetY: number // fed to translateY(offsetY + '%'). Valid range [-100, 100]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
restrictions?: RestrictionsSettings;
|
||||
|
||||
crop: {
|
||||
default: any;
|
||||
},
|
||||
stretch: {
|
||||
default: any;
|
||||
conditionalDifferencePercent: number // black bars less than this wide will trigger stretch
|
||||
// if mode is set to '1'. 1.0=100%
|
||||
},
|
||||
kbm: {
|
||||
enabled: boolean, // if keyboard/mouse handler service will run
|
||||
keyboardEnabled: boolean, // if keyboard shortcuts are processed
|
||||
mouseEnabled: boolean, // if mouse movement is processed
|
||||
}
|
||||
|
||||
zoom: {
|
||||
minLogZoom: number,
|
||||
maxLogZoom: number,
|
||||
announceDebounce: number // we wait this long before announcing new zoom
|
||||
},
|
||||
|
||||
miscSettings: {
|
||||
mousePan: {
|
||||
enabled: boolean
|
||||
},
|
||||
mousePanReverseMouse: boolean,
|
||||
defaultAr?: any
|
||||
},
|
||||
|
||||
resizer: {
|
||||
setStyleString: {
|
||||
maxRetries: number,
|
||||
retryTimeout: number
|
||||
}
|
||||
},
|
||||
pageInfo: {
|
||||
timeouts: {
|
||||
urlCheck: number,
|
||||
rescan: number
|
||||
}
|
||||
},
|
||||
pan?: any,
|
||||
version?: string,
|
||||
preventReload?: boolean,
|
||||
|
||||
// -----------------------------------------
|
||||
// ::: MITIGATIONS :::
|
||||
// -----------------------------------------
|
||||
// Settings for browser bug workarounds.
|
||||
mitigations?: {
|
||||
zoomLimit?: {
|
||||
enabled?: boolean,
|
||||
fullscreenOnly?: boolean,
|
||||
limit?: number,
|
||||
}
|
||||
}
|
||||
// -----------------------------------------
|
||||
// ::: ACTIONS :::
|
||||
// -----------------------------------------
|
||||
// Nastavitve za ukaze. Zamenja stare nastavitve za bližnične tipke.
|
||||
//
|
||||
// Polje 'shortcut' je tabela, če se slučajno lotimo kdaj delati choordov.
|
||||
actions: {
|
||||
name?: string, // name displayed in settings
|
||||
label?: string, // name displayed in ui (can be overridden in scope/playerUi)
|
||||
cmd?: {
|
||||
action: string,
|
||||
arg: any,
|
||||
customArg?: any,
|
||||
persistent?: boolean, // optional, false by default. If true, change doesn't take effect immediately.
|
||||
// Instead, this action saves stuff to settings
|
||||
}[],
|
||||
scopes?: {
|
||||
global?: ActionScopeInterface,
|
||||
site?: ActionScopeInterface,
|
||||
page?: ActionScopeInterface
|
||||
},
|
||||
playerUi?: {
|
||||
show: boolean,
|
||||
path?: string,
|
||||
},
|
||||
userAdded?: boolean,
|
||||
}[],
|
||||
// This object fulfills the same purpose as 'actions', but is written in less retarded and overly
|
||||
// complicated way. Hopefully it'll be easier to maintain it that way.
|
||||
commands?: {
|
||||
crop?: CommandInterface[],
|
||||
stretch?: CommandInterface[],
|
||||
zoom?: CommandInterface[],
|
||||
pan?: CommandInterface[],
|
||||
internal?: CommandInterface[],
|
||||
},
|
||||
whatsNewChecked: boolean,
|
||||
newFeatureTracker: any,
|
||||
// -----------------------------------------
|
||||
// ::: SITE CONFIGURATION :::
|
||||
// -----------------------------------------
|
||||
// Config for a given page:
|
||||
//
|
||||
// <hostname> : {
|
||||
// status: <option> // should extension work on this site?
|
||||
// arStatus: <option> // should we do autodetection on this site?
|
||||
//
|
||||
// defaultAr?: <ratio> // automatically apply this aspect ratio on this side. Use extension defaults if undefined.
|
||||
// stretch? <stretch mode> // automatically stretch video on this site in this manner
|
||||
// videoAlignment? <left|center|right>
|
||||
//
|
||||
// type: <official|community|user> // 'official' — blessed by Tam.
|
||||
// // 'community' — blessed by reddit.
|
||||
// // 'user' — user-defined (not here)
|
||||
// override: <true|false> // override user settings for this site on update
|
||||
// }
|
||||
//
|
||||
// Valid values for options:
|
||||
//
|
||||
// status, arStatus, statusEmbedded:
|
||||
//
|
||||
// * enabled — always allow, full
|
||||
// * basic — allow, but only the basic version without playerData
|
||||
// * default — allow if default is to allow, block if default is to block
|
||||
// * disabled — never allow
|
||||
//
|
||||
sites: {
|
||||
[x: string]: SiteSettingsInterface,
|
||||
}
|
||||
}
|
||||
|
||||
export interface SiteSettingsInterface {
|
||||
enable: ExtensionEnvironmentSettingsInterface;
|
||||
enableAard: ExtensionEnvironmentSettingsInterface;
|
||||
enableKeyboard: ExtensionEnvironmentSettingsInterface;
|
||||
|
||||
type?: 'official' | 'community' | 'user-defined' | 'testing' | 'officially-disabled' | 'unknown' | 'modified';
|
||||
defaultType: 'official' | 'community' | 'user-defined' | 'testing' | 'officially-disabled' | 'unknown' | 'modified';
|
||||
|
||||
// must be defined in @global and @empty
|
||||
persistCSA?: CropModePersistence, // CSA - crop, stretch, alignment
|
||||
|
||||
defaults?: { // must be defined in @global and @empty
|
||||
crop?: {type: AspectRatioType, [x: string]: any},
|
||||
stretch?: StretchType,
|
||||
alignment?: {x: VideoAlignmentType, y: VideoAlignmentType},
|
||||
}
|
||||
|
||||
cropModePersistence?: CropModePersistence;
|
||||
stretchModePersistence?: CropModePersistence;
|
||||
alignmentPersistence?: CropModePersistence;
|
||||
|
||||
|
||||
activeDOMConfig?: string;
|
||||
DOMConfig?: { [x: string]: SiteDOMSettingsInterface };
|
||||
|
||||
// the following script are for extension caching and shouldn't be saved.
|
||||
// if they _are_ saved, they will be overwritten
|
||||
currentDOMConfig?: SiteDOMSettingsInterface;
|
||||
|
||||
// the following fields are for use with extension update script
|
||||
override?: boolean; // whether settings for this site will be overwritten by extension upgrade script
|
||||
}
|
||||
|
||||
export interface SiteDOMSettingsInterface {
|
||||
type: 'official' | 'community' | 'user-defined' | 'modified' | undefined;
|
||||
elements?: {
|
||||
player?: SiteDOMElementSettingsInterface,
|
||||
video?: SiteDOMElementSettingsInterface,
|
||||
other?: { [x: number]: SiteDOMElementSettingsInterface }
|
||||
};
|
||||
customCss?: string;
|
||||
periodicallyRefreshPlayerElement?: boolean;
|
||||
|
||||
// the following script are for extension caching and shouldn't be saved.
|
||||
// if they _are_ saved, they will be overwritten
|
||||
anchorElementIndex?: number;
|
||||
anchorElement?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface SiteDOMElementSettingsInterface {
|
||||
manual?: boolean;
|
||||
querySelectors?: string;
|
||||
index?: number; // previously: useRelativeAncestor + videoAncestor
|
||||
mode?: 'index' | 'qs';
|
||||
nodeCss?: {[x: string]: string};
|
||||
}
|
||||
|
||||
export default SettingsInterface;
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* 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 choice, really.
|
||||
*/
|
||||
export class ChromeShittinessMitigations {
|
||||
static port = null;
|
||||
|
||||
static setProperty(property, value) {
|
||||
ChromeShittinessMitigations[property] = value;
|
||||
}
|
||||
}
|
||||
|
||||
export default ChromeShittinessMitigations;
|
@ -1,24 +0,0 @@
|
||||
class IO {
|
||||
/**
|
||||
* Export a (presumably json) string to file. Meant for use with content script.
|
||||
* @param {*} jsonString string to be saved
|
||||
*/
|
||||
static async csStringToFile(jsonString) {
|
||||
console.info("\n\n\n\n---------- Starting export of log to file ----------------");
|
||||
|
||||
console.info("[info] json string for exportObject:", jsonString.length);
|
||||
|
||||
const blob = new Blob([jsonString], {type: 'application/json'});
|
||||
const fileUrl = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = fileUrl;
|
||||
a.download = 'ultrawidify-log.log';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(fileUrl);
|
||||
}
|
||||
}
|
||||
|
||||
export default IO;
|
@ -1,40 +0,0 @@
|
||||
class KeyboardShortcutParser {
|
||||
static parseShortcut(keypress) {
|
||||
let shortcutCombo = '';
|
||||
|
||||
if (keypress.ctrlKey) {
|
||||
shortcutCombo += 'Ctrl + ';
|
||||
}
|
||||
if (keypress.shiftKey) {
|
||||
shortcutCombo += 'Shift + ';
|
||||
}
|
||||
if (keypress.metaKey) {
|
||||
shortcutCombo += 'Meta + ';
|
||||
}
|
||||
if (keypress.altKey) {
|
||||
shortcutCombo += 'Alt + ';
|
||||
}
|
||||
if (keypress.key) {
|
||||
shortcutCombo += keypress.key.toUpperCase();
|
||||
} else {
|
||||
shortcutCombo += '<mouse action>'
|
||||
}
|
||||
return shortcutCombo;
|
||||
}
|
||||
|
||||
static generateShortcutFromKeypress(event) {
|
||||
return {
|
||||
ctrlKey: event.ctrlKey,
|
||||
altKey: event.altKey,
|
||||
shiftKey: event.shiftKey,
|
||||
metaKey: event.metaKey,
|
||||
code: event.code,
|
||||
key: event.key,
|
||||
keyup: true,
|
||||
keydown: false,
|
||||
type: event.type, // only needed for purposes of EditShortcutButton
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default KeyboardShortcutParser;
|
@ -1,18 +0,0 @@
|
||||
export async function sleep(timeout) {
|
||||
return new Promise<void>( (resolve, reject) => setTimeout(() => resolve(), timeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates deep copy of an object
|
||||
* @param obj
|
||||
* @returns
|
||||
*/
|
||||
export function _cp(obj) {
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
} catch (e) {
|
||||
// console.error('Failed to parse json. This probably means that the data we received was not an object. Will return data as-is');
|
||||
// console.error('data in:', obj, 'error:', e);
|
||||
return obj;
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<p><i><a href="https://www.youtube.com/watch?v=Mn3YEJTSYs8&feature=youtu.be&t=770" target='_blank'>...</a> but as is normal, you can't use a free extensions without the developers begging for money. It's the bi-daily beggathon here on ... wherever here is.</i>
|
||||
</p>
|
||||
<p>
|
||||
Jokes and references few will get aside, developing this extension does take a decent amount of time, motivation, carefully calibrated quantities
|
||||
of alcohol and enough coffee to bankrupt a small nation.
|
||||
</p>
|
||||
<p>If you want to buy me a beer or bankroll my caffeine addiction, you can do so by <a href="https://paypal.me/tamius">clicking here</a>. All donations are appreciated.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
57
src/conf/keybinds.js
Normal file
@ -0,0 +1,57 @@
|
||||
// Yeah hi /r/badcode.
|
||||
// Anyway, because nazi localstorage flat out refuses to store arrays:
|
||||
var DEFAULT_KEYBINDINGS = {
|
||||
0:{ action: "fitw",
|
||||
key: 'w',
|
||||
modifiers: []
|
||||
},
|
||||
1:{
|
||||
action: "fith",
|
||||
key: 'e',
|
||||
modifiers: []
|
||||
},
|
||||
2: {
|
||||
action: "reset",
|
||||
key: 'r',
|
||||
modifiers: []
|
||||
},
|
||||
3: {
|
||||
action: "zoom",
|
||||
key: "z",
|
||||
modifiers: []
|
||||
},
|
||||
4: {
|
||||
action: "unzoom",
|
||||
key: "u",
|
||||
modifiers: []
|
||||
},
|
||||
5: {
|
||||
action: "char",
|
||||
targetAR: (21/9),
|
||||
key: "d",
|
||||
modifiers: []
|
||||
},
|
||||
6: {
|
||||
action: "char",
|
||||
targetAR: (16/9),
|
||||
key: "s",
|
||||
modifiers: []
|
||||
},
|
||||
7: {
|
||||
action: "char",
|
||||
targetAR: (16/10),
|
||||
key: "x",
|
||||
modifiers: []
|
||||
},
|
||||
8: {
|
||||
action: "char",
|
||||
targetAR: (4/3),
|
||||
key: "c",
|
||||
modifiers: []
|
||||
},
|
||||
9: {
|
||||
action: "autoar",
|
||||
key: "a",
|
||||
modifiers: []
|
||||
}
|
||||
};
|
91
src/conf/sitesconf.js
Normal file
@ -0,0 +1,91 @@
|
||||
var UW_SITES = {
|
||||
youtube: {
|
||||
enabled: true,
|
||||
type: "official",
|
||||
urlRules: ["youtu"],
|
||||
player: {
|
||||
name: "movie_player",
|
||||
isClass: false,
|
||||
},
|
||||
iframe: {
|
||||
name: "player",
|
||||
isClass: false
|
||||
},
|
||||
ui: {
|
||||
uiMode: "native",
|
||||
uiconf: {
|
||||
sampleButton: {
|
||||
class: "ytp-button ytp-settings-button",
|
||||
index: 0,
|
||||
buttonSizeBase: "x",
|
||||
},
|
||||
uiParent: {
|
||||
name: "ytp-right-controls",
|
||||
isClass: true,
|
||||
insertStrat: "prepend",
|
||||
},
|
||||
uiOffset: {
|
||||
offsetBy: "10vh",
|
||||
offsetType: "css"
|
||||
}
|
||||
}
|
||||
},
|
||||
autoar_imdb:{
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
netflix: {
|
||||
enabled: true,
|
||||
type: "official",
|
||||
urlRules: ["netflix"],
|
||||
player: {
|
||||
name: "placeholder",
|
||||
isClass: true,
|
||||
},
|
||||
ui: {
|
||||
uiMode: "native",
|
||||
uiconf: {
|
||||
sampleButton: {
|
||||
class: "ytp-button ytp-settings-button",
|
||||
index: 0,
|
||||
buttonSizeBase: "x",
|
||||
},
|
||||
uiParent: {
|
||||
name: "player-controls-wrapper",
|
||||
isClass: true,
|
||||
insertStrat: "append"
|
||||
},
|
||||
uiOffset: {
|
||||
offsetBy: "0px",
|
||||
offsetType: "css"
|
||||
}
|
||||
}
|
||||
},
|
||||
autoar_imdb:{
|
||||
enabled: true,
|
||||
title: "player-status-main-title",
|
||||
isClass: true
|
||||
}
|
||||
},
|
||||
dummy: {
|
||||
type: "add new site",
|
||||
urlRules: [""],
|
||||
player: {
|
||||
name: "",
|
||||
isClass: false,
|
||||
},
|
||||
sampleButton: {
|
||||
class: "ytp-button ytp-settings-button",
|
||||
index: 0,
|
||||
buttonSizeBase: "x",
|
||||
},
|
||||
uiParent: {
|
||||
name: "",
|
||||
isClass: false,
|
||||
insertStrat: "prepend",
|
||||
},
|
||||
autoar_imdb:{
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
116
src/conf/uiconf.js
Normal file
@ -0,0 +1,116 @@
|
||||
var UW_UI_BUTTONS = {
|
||||
fitw: {
|
||||
native_bar: true,
|
||||
has_submenu: false,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/fitw.png",
|
||||
text: "Fit to width",
|
||||
onclick: function(){ changeCSS("fit", "fitw") }
|
||||
},
|
||||
fith: {
|
||||
native_bar: true,
|
||||
has_submenu: false,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/fith.png",
|
||||
text: "Fit to height",
|
||||
onclick: function(){ changeCSS("fit", "fith") }
|
||||
},
|
||||
reset: {
|
||||
native_bar: true,
|
||||
has_submenu: false,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/reset.png",
|
||||
text: "Reset",
|
||||
onclick: function(){ changeCSS("reset", "reset") }
|
||||
},
|
||||
zoom: {
|
||||
native_bar: true,
|
||||
has_submenu: false,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/zoom.png",
|
||||
text: "Zoom",
|
||||
onclick: function(){ changeCSS("fit", "zoom") }
|
||||
},
|
||||
unzoom: {
|
||||
native_bar: true,
|
||||
has_submenu: false,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/unzoom.png",
|
||||
text: "Unzoom",
|
||||
onclick: function(){ changeCSS("fit", "unzoom") }
|
||||
},
|
||||
zoom: {
|
||||
native_bar: true,
|
||||
has_submenu: false,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/zoom.png",
|
||||
text: "Reset",
|
||||
onclick: function(){ changeCSS("fit", "zoom") }
|
||||
},
|
||||
autoar: {
|
||||
native_bar: false,
|
||||
has_submenu: false,
|
||||
button: false,
|
||||
text: "Detect aspect ratio via 3rd party",
|
||||
onclick: function(){ manual_autoar()}
|
||||
},
|
||||
settings: {
|
||||
native_bar: true,
|
||||
button: true,
|
||||
icon: "/res/img/ytplayer-icons/settings.png",
|
||||
text: "Settings",
|
||||
has_submenu: true,
|
||||
submenu: [ "fitw","fith","reset","zoom","unzoom","autoar","ar" ],
|
||||
top_level: true,
|
||||
submenu_id: "uw_settings_menu",
|
||||
onclick: function(){ toggleMenu("uw_settings_menu") }
|
||||
},
|
||||
ar: {
|
||||
native_bar: false,
|
||||
button: false,
|
||||
text: "Force aspect ratio",
|
||||
has_submenu: true,
|
||||
submenu: [ "ar219", "ar169", "ar1610", "ar43" ],
|
||||
submenu_id: "uw_force_ar_menu",
|
||||
onclick: function(){ showMenu("uw_force_ar_menu") }
|
||||
},
|
||||
ar219: {
|
||||
native_bar: false,
|
||||
button: false,
|
||||
text: "21:9",
|
||||
has_submenu: false,
|
||||
onclick: function(){ changeCSS("char", ( 21/9 )); }
|
||||
},
|
||||
ar169: {
|
||||
native_bar: false,
|
||||
button: false,
|
||||
text: "16:9",
|
||||
has_submenu: false,
|
||||
onclick: function(){ changeCSS("char", ( 16/9 )); }
|
||||
},
|
||||
ar1610: {
|
||||
native_bar: false,
|
||||
button: false,
|
||||
text: "16:10",
|
||||
has_submenu: false,
|
||||
onclick: function(){ changeCSS("char", ( 1.6 )); }
|
||||
},
|
||||
ar43: {
|
||||
native_bar: false,
|
||||
button: false,
|
||||
text: "4:3",
|
||||
has_submenu: false,
|
||||
onclick: function(){ changeCSS("char", ( 4/3 )); }
|
||||
}
|
||||
}
|
||||
|
||||
var UW_UI_BANLIST = {
|
||||
youtube: {
|
||||
autoar: "all"
|
||||
},
|
||||
netflix: {
|
||||
settings: "all"
|
||||
}
|
||||
}
|
||||
|
||||
|
1
src/conf/uwvars.js
Normal file
@ -0,0 +1 @@
|
||||
|
@ -1,69 +0,0 @@
|
||||
<template>
|
||||
<div class="uw-clickthrough relative w-100 h-100">
|
||||
<template v-for="rectangle of drawnRectangles" :key="rectangle.id ?? rectangle">
|
||||
|
||||
<!-- Player element overlays -->
|
||||
<div class="absolute z-index-overlay"
|
||||
:style="rectangle.style"
|
||||
>
|
||||
<!-- used for drawing player element overlay rectangles - keep this section empty -->
|
||||
</div>
|
||||
|
||||
<!-- Notification overlay -->
|
||||
<div class="absolute z-index-notification notification-area">
|
||||
<template v-for="notification of displayedNotifications" :key="notification.id">
|
||||
<div class="notification d-flex flex-row">
|
||||
<div class="notification-icon">
|
||||
<mdicon :name="notification.icon ?? 'alert'" :size="128"></mdicon>
|
||||
</div>
|
||||
<div class="notification-text">
|
||||
<h3 class="notification-title">{{ notification.title }}</h3>
|
||||
<p class="notification-verbose">{{ notification.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UIProbeMixin from './src/utils/UIProbeMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
mixins: [
|
||||
UIProbeMixin
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
drawnRectangles: [],
|
||||
displayedNotifications: [],
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
this.logger = new Logger();
|
||||
|
||||
// this prolly needs to be taken out
|
||||
await this.logger.init({
|
||||
allowLogging: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* Setup the "companion" onMouseMove handler to the one in the content script.
|
||||
* We can handle events with the same function we use to handle events from
|
||||
* the content script.
|
||||
*/
|
||||
document.addEventListener('mousemove', (event) => {
|
||||
this.handleProbe({
|
||||
coords: {
|
||||
x: event.clientX,
|
||||
y: event.clientY
|
||||
}
|
||||
}, this.origin);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,687 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="context-spawn uw-ui-area"
|
||||
style="z-index: 1000;"
|
||||
v-if="!triggerZoneEditorVisible"
|
||||
>
|
||||
<div
|
||||
class="spawn-container uw-ui-trigger"
|
||||
:style="triggerZoneStyles"
|
||||
>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="contextMenuActive || settingsInitialized && uwTriggerZoneVisible && !isGlobal"
|
||||
class="context-spawn uw-clickable uw-ui-area"
|
||||
style="z-index: 1001"
|
||||
|
||||
>
|
||||
<GhettoContextMenu
|
||||
alignment="right" class="uw-menu"
|
||||
@mouseenter="() => {preventContextMenuHide(); newFeatureViewUpdate('uw6.ui-popup')}"
|
||||
@mouseleave="allowContextMenuHide()"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div class="context-item">
|
||||
Ultrawidify
|
||||
</div>
|
||||
</template>
|
||||
<slot>
|
||||
|
||||
<!--
|
||||
Didn't manage to ensure that extension status pops up above other menu items in less than 3 minutes with z-index,
|
||||
so wrapping 'status' and 'real menu items' in two different divs, ordering them in the opposite way, and then
|
||||
ensuring correct ordering with flex-direction: column-reverse ended up being easier and faster.
|
||||
-->
|
||||
<div class="menu-width flex-reverse-order">
|
||||
<div style="z-index: 1000">
|
||||
<GhettoContextMenu alignment="right">
|
||||
<template v-slot:activator>
|
||||
Crop
|
||||
</template>
|
||||
<slot>
|
||||
<GhettoContextMenuOption
|
||||
v-for="(command, index) of settings?.active.commands.crop"
|
||||
:key="index"
|
||||
:label="command.label"
|
||||
:shortcut="getKeyboardShortcutLabel(command)"
|
||||
@click="execAction(command)"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
</slot>
|
||||
</GhettoContextMenu>
|
||||
<GhettoContextMenu alignment="right">
|
||||
<template v-slot:activator>
|
||||
Stretch
|
||||
</template>
|
||||
<slot>
|
||||
<GhettoContextMenuOption
|
||||
v-for="(command, index) of settings?.active.commands.stretch"
|
||||
:key="index"
|
||||
:label="command.label"
|
||||
:shortcut="getKeyboardShortcutLabel(command)"
|
||||
@click="execAction(command)"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
</slot>
|
||||
</GhettoContextMenu>
|
||||
<GhettoContextMenu alignment="right">
|
||||
<template v-slot:activator>
|
||||
<div class="context-item">
|
||||
Align
|
||||
</div>
|
||||
</template>
|
||||
<slot>
|
||||
<GhettoContextMenuItem :disableHover="true" :css="{'reduced-padding': true}">
|
||||
<AlignmentOptionsControlComponent
|
||||
:eventBus="eventBus"
|
||||
>
|
||||
</AlignmentOptionsControlComponent>
|
||||
</GhettoContextMenuItem>
|
||||
</slot>
|
||||
</GhettoContextMenu>
|
||||
|
||||
<!-- shortcut for configuring UI -->
|
||||
<GhettoContextMenuOption
|
||||
v-if="settings.active.newFeatureTracker?.['uw6.ui-popup']?.show > 0"
|
||||
@click="showUwWindow('playerUiSettings')"
|
||||
>
|
||||
<span style="color: #fa6;">Change when and if<br/>this popup appears</span>
|
||||
<span style="font-size: 0.8rem">
|
||||
<span style="font-size: 0.8rem; opacity: 0.5">This menu option will show {{settings.active.newFeatureTracker?.['uw6.ui-popup']?.show}} more<br/> times; or until clicked or dismissed.<br/>
|
||||
Also accessible via:<br/> <span style="font-size: 0.85em">EXTENSION SETTINGS > UI AND KEYBOARD</span>.
|
||||
</span>
|
||||
<br/>
|
||||
<a style="color: #fa6; cursor: pointer;" @click="() => acknowledgeNewFeature('uw6.ui-popup')">Dismiss this option</a>
|
||||
</span>
|
||||
</GhettoContextMenuOption>
|
||||
|
||||
<!-- -->
|
||||
<GhettoContextMenuOption
|
||||
@click="showUwWindow()"
|
||||
label="Extension settings"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
<GhettoContextMenuOption
|
||||
@click="showUwWindow('playerDetection')"
|
||||
label="Incorrect cropping?"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
<GhettoContextMenuOption
|
||||
@click="showUwWindow('about')"
|
||||
label="Not working?"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
</div>
|
||||
|
||||
<div style="z-index: 10000">
|
||||
<GhettoContextMenuItem
|
||||
class="extension-status-messages"
|
||||
:disableHover="true"
|
||||
>
|
||||
Site compatibility:
|
||||
<SupportLevelIndicator
|
||||
:siteSupportLevel="siteSupportLevel"
|
||||
>
|
||||
</SupportLevelIndicator>
|
||||
<div v-if="statusFlags.hasDrm" class="aard-blocked">
|
||||
Autodetection potentially<br/>
|
||||
unavailable due to <a href="https://en.wikipedia.org/wiki/Digital_rights_management">DRM</a>.
|
||||
</div>
|
||||
<div v-else-if="statusFlags.aardErrors?.cors" class="aard-blocked">
|
||||
Autodetection blocked<br/>
|
||||
by site/browser (CORS).
|
||||
</div>
|
||||
<div v-else-if="statusFlags.aardErrors?.webglError" class="aard-blocked">
|
||||
Autodetection unavailable<br/>
|
||||
due to webgl error.
|
||||
</div>
|
||||
</GhettoContextMenuItem>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
</GhettoContextMenu>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="settingsInitialized && uwWindowVisible"
|
||||
class="uw-window flex flex-col uw-clickable uw-ui-area"
|
||||
:class="{'fade-out': uwWindowFadeOut}"
|
||||
>
|
||||
<PlayerUIWindow
|
||||
:settings="settings"
|
||||
:eventBus="eventBus"
|
||||
:logger="logger"
|
||||
:in-player="!isGlobal"
|
||||
:site="site"
|
||||
:defaultTab="defaultWindowTab"
|
||||
@close="uwWindowVisible = false"
|
||||
@preventClose="(event) => uwWindowFadeOutDisabled = event"
|
||||
></PlayerUIWindow>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="triggerZoneEditorVisible"
|
||||
class="context-spawn uw-ui-area"
|
||||
style="z-index: 1000;"
|
||||
>
|
||||
<TriggerZoneEditor
|
||||
:settings="settings"
|
||||
:eventBus="eventBus"
|
||||
:playerDimensions="playerDimensions"
|
||||
>
|
||||
</TriggerZoneEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PlayerUIWindow from './src/PlayerUIWindow.vue';
|
||||
import GhettoContextMenu from './src/components/GhettoContextMenu.vue';
|
||||
import GhettoContextMenuItem from './src/components/GhettoContextMenuItem.vue';
|
||||
import GhettoContextMenuOption from './src/components/GhettoContextMenuOption.vue';
|
||||
import AlignmentOptionsControlComponent from './src/PlayerUiPanels/AlignmentOptionsControlComponent.vue';
|
||||
import BrowserDetect from '../ext/conf/BrowserDetect';
|
||||
import Logger from '../ext/lib/Logger';
|
||||
import Settings from '../ext/lib/Settings';
|
||||
import EventBus from '../ext/lib/EventBus';
|
||||
import UIProbeMixin from './src/utils/UIProbeMixin';
|
||||
import KeyboardShortcutParserMixin from './src/utils/KeyboardShortcutParserMixin';
|
||||
import CommsMixin from './src/utils/CommsMixin';
|
||||
import SupportLevelIndicator from './src/components/SupportLevelIndicator.vue';
|
||||
import TriggerZoneEditor from './src/components/TriggerZoneEditor.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PlayerUIWindow,
|
||||
GhettoContextMenu,
|
||||
GhettoContextMenuItem,
|
||||
GhettoContextMenuOption,
|
||||
AlignmentOptionsControlComponent,
|
||||
SupportLevelIndicator,
|
||||
TriggerZoneEditor,
|
||||
},
|
||||
mixins: [
|
||||
UIProbeMixin,
|
||||
KeyboardShortcutParserMixin,
|
||||
CommsMixin
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
uwTriggerZoneVisible: false,
|
||||
uwTriggerZoneTimeout: undefined,
|
||||
uwTriggerRegionConf: {
|
||||
left: "10%",
|
||||
top: "10%",
|
||||
height: "30%",
|
||||
width: "30%",
|
||||
maxWidth: "24rem",
|
||||
maxHeight: "13.37rem",
|
||||
},
|
||||
|
||||
uwWindowFadeOutDisabled: false,
|
||||
uwWindowFadeOut: false,
|
||||
uwWindowCloseTimeout: undefined,
|
||||
uwWindowVisible: false,
|
||||
triggerZoneEditorVisible: false,
|
||||
|
||||
// component properties
|
||||
settings: {},
|
||||
BrowserDetect: BrowserDetect,
|
||||
settingsInitialized: false,
|
||||
eventBus: new EventBus(),
|
||||
logger: null,
|
||||
|
||||
// NOTE: chromium doesn't allow us to access window.parent.location
|
||||
// meaning we will have to correct this value from our uwui-probe
|
||||
// messages ... which is a bummer.
|
||||
site: null,
|
||||
origin: '*', // will be set appropriately once the first uwui-probe event is received
|
||||
lastProbeTs: null,
|
||||
|
||||
isGlobal: true,
|
||||
disabled: false,
|
||||
|
||||
contextMenuActive: false,
|
||||
triggerZoneActive: false,
|
||||
|
||||
uiVisible: true,
|
||||
debugData: {
|
||||
resizer: {},
|
||||
player: {},
|
||||
},
|
||||
debugDataPrettified: '',
|
||||
|
||||
// in global overlay, this property is used to determine
|
||||
// if closing the window should emit uw-set-ui-state
|
||||
// event on eventBus
|
||||
showPlayerUIAfterClose: false,
|
||||
|
||||
statusFlags: {
|
||||
hasDrm: undefined,
|
||||
aardErrors: undefined,
|
||||
},
|
||||
defaultWindowTab: 'videoSettings',
|
||||
|
||||
saveState: {},
|
||||
siteSettings: undefined,
|
||||
previewZoneVisible: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// LPT: NO ARROW FUNCTIONS IN COMPUTED,
|
||||
// IS SUPER HARAM
|
||||
// THINGS WILL NOT WORK IF YOU USE ARROWS
|
||||
windowWidth() {
|
||||
return window.innerWidth;
|
||||
},
|
||||
windowHeight() {
|
||||
return window.innerHeight;
|
||||
},
|
||||
// LPT: NO ARROW FUNCTIONS IN COMPUTED,
|
||||
// IS SUPER HARAM
|
||||
// THINGS WILL NOT WORK IF YOU USE ARROWS
|
||||
siteSupportLevel() {
|
||||
return (this.site && this.siteSettings) ? this.siteSettings.data.type || 'no-support' : 'waiting';
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showUi(visible) {
|
||||
if (visible !== undefined) {
|
||||
this.uiVisible = visible;
|
||||
}
|
||||
},
|
||||
resizerDebugData(newData) {
|
||||
this.debugData.resizer = newData;
|
||||
this.debugDataPrettified = JSON.stringify(this.debugData, null, 2);
|
||||
},
|
||||
playerDebugData(newData) {
|
||||
this.debugData.player = newData;
|
||||
this.debugDataPrettified = JSON.stringify(this.debugData, null, 2);
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
this.logger = new Logger();
|
||||
|
||||
// this prolly needs to be taken out
|
||||
await this.logger.init({
|
||||
allowLogging: true,
|
||||
});
|
||||
|
||||
this.settings = new Settings({afterSettingsSaved: this.updateConfig, logger: this.logger});
|
||||
this.settings.listenAfterChange(() => this.updateTriggerZones());
|
||||
|
||||
await this.settings.init();
|
||||
this.settingsInitialized = true;
|
||||
|
||||
// set up communication with client script.
|
||||
// NOTE: companion onmousemove is set up in UIProbeMixin
|
||||
window.addEventListener('message', event => {
|
||||
this.handleMessage(event);
|
||||
});
|
||||
|
||||
this.eventBus.subscribe('uw-config-broadcast', {function: (data) => {
|
||||
switch (data.type) {
|
||||
case 'drm-status':
|
||||
this.statusFlags.hasDrm = data.hasDrm;
|
||||
break;
|
||||
case 'aard-error':
|
||||
this.statusFlags.aardErrors = data.aardErrors;
|
||||
break;
|
||||
case 'player-dimensions':
|
||||
this.playerDimensionsUpdate(data.data);
|
||||
break;
|
||||
}
|
||||
}});
|
||||
|
||||
this.eventBus.subscribe('uw-set-ui-state', { function: (data) => {
|
||||
if (data.globalUiVisible !== undefined) {
|
||||
if (this.isGlobal) {
|
||||
if (data.globalUiVisible) {
|
||||
this.showUwWindow();
|
||||
} else {
|
||||
this.hideUwWindow(true);
|
||||
}
|
||||
// this.showPlayerUIAfterClose = data.showPlayerUIAfterClose;
|
||||
} else {
|
||||
// non global UIs are hidden while global overlay
|
||||
// is visible and vice versa
|
||||
// this.disabled = data.globalUiVisible;
|
||||
this.saveState = {
|
||||
uwWindowVisible: this.uwWindowVisible,
|
||||
uwWindowFadeOutDisabled: this.uwWindowFadeOutDisabled,
|
||||
uwWindowFadeOut: this.uwWindowFadeOut
|
||||
};
|
||||
this.uwWindowFadeOutDisabled = false;
|
||||
this.hideUwWindow(true);
|
||||
}
|
||||
}
|
||||
}});
|
||||
|
||||
this.eventBus.subscribe(
|
||||
'uw-restore-ui-state',
|
||||
{
|
||||
function: (data) => {
|
||||
if (this.saveState) {
|
||||
if (this.saveState.uwWindowVisible) {
|
||||
this.showUwWindow();
|
||||
}
|
||||
this.uwWindowFadeOutDisabled = this.saveState.uwWindowFadeOutDisabled;
|
||||
this.uwWindowFadeOut = this.saveState.uwWindowFadeOut;
|
||||
}
|
||||
this.saveState = {};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.eventBus.subscribe('ui-trigger-zone-update', {
|
||||
function: (data) => {
|
||||
this.showTriggerZonePreview = data.previewZoneVisible;
|
||||
// this.;
|
||||
}
|
||||
});
|
||||
|
||||
this.eventBus.subscribe(
|
||||
'start-trigger-zone-edit',
|
||||
{
|
||||
function: () => {
|
||||
this.triggerZoneEditorVisible = true;
|
||||
this.uwWindowVisible = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.eventBus.subscribe(
|
||||
'finish-trigger-zone-edit',
|
||||
{
|
||||
function: () => {
|
||||
this.triggerZoneEditorVisible = false;
|
||||
this.showUwWindow('playerUiSettings');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.sendToParentLowLevel('uwui-get-role', null);
|
||||
this.sendToParentLowLevel('uwui-get-theme', null);
|
||||
|
||||
this.sendToParentLowLevel('uw-bus-tunnel', {
|
||||
action: 'get-player-dimensions'
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Gets URL of the browser settings page (i think?)
|
||||
*/
|
||||
getUrl(url) {
|
||||
return BrowserDetect.getURL(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Mostly intended to process messages received via window.addEventListener('message').
|
||||
* This method should include minimal logic — instead, it should only route messages
|
||||
* to the correct function down the line.
|
||||
*/
|
||||
handleMessage(event) {
|
||||
switch (event.data.action) {
|
||||
case 'uwui-probe':
|
||||
if (!this.site) {
|
||||
this.origin = event.origin;
|
||||
this.site = event.origin.split('//')[1];
|
||||
this.siteSettings = this.settings.getSiteSettings(this.site);
|
||||
}
|
||||
return this.handleProbe(event.data, event.origin); // handleProbe is defined in UIProbeMixin
|
||||
case 'uw-bus-tunnel':
|
||||
return this.handleBusTunnelIn(event.data.payload);
|
||||
case 'uwui-set-role':
|
||||
this.isGlobal = event.data.payload.role === 'global';
|
||||
this.sendToParentLowLevel('uwui-interface-ready', true);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles trigger zone
|
||||
*/
|
||||
handleTriggerZone(mouseInside) {
|
||||
// this.triggerZoneActive = mouseInside;
|
||||
},
|
||||
|
||||
acknowledgeNewFeature(featureKey) {
|
||||
delete this.settings.active.newFeatureTracker[featureKey];
|
||||
this.settings.saveWithoutReload();
|
||||
},
|
||||
newFeatureViewUpdate(featureKey) {
|
||||
if (!this.settings.active.newFeatureTracker[featureKey]) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.settings.active.newFeatureTracker[featureKey].show--;
|
||||
this.settings.saveWithoutReload();
|
||||
|
||||
if (this.settings.active.newFeatureTracker[featureKey]?.show < 0) {
|
||||
this.acknowledgeNewFeature(featureKey);
|
||||
}
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends message to parent _without_ using event bus.
|
||||
*/
|
||||
sendToParentLowLevel(action, payload, lowLevelExtras = {}) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action, payload, ...lowLevelExtras
|
||||
},
|
||||
'*'
|
||||
);
|
||||
},
|
||||
|
||||
preventContextMenuHide() {
|
||||
this.contextMenuActive = true;
|
||||
},
|
||||
allowContextMenuHide() {
|
||||
this.contextMenuActive = false;
|
||||
},
|
||||
|
||||
setTriggerZoneActive(active, event) {
|
||||
this.triggerZoneActive = active;
|
||||
},
|
||||
|
||||
showUwWindow(tab) {
|
||||
this.defaultWindowTab = tab; // can be undefined
|
||||
|
||||
this.uwWindowFadeOut = false;
|
||||
this.uwWindowVisible = true;
|
||||
this.uwTriggerZoneVisible = false;
|
||||
this.allowContextMenuHide();
|
||||
|
||||
// refresh DRM status
|
||||
this.eventBus.send('get-drm-status');
|
||||
|
||||
// if (this.isGlobal) {
|
||||
// this.sendToParentLowLevel('uwui-clickable', undefined, {clickable: true});
|
||||
// }
|
||||
},
|
||||
|
||||
hideUwWindow(skipTimeout = false) {
|
||||
if (this.uwWindowFadeOutDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeout = skipTimeout ? 0 : 1100;
|
||||
|
||||
this.uwWindowCloseTimeout = setTimeout(
|
||||
() => {
|
||||
this.uwWindowVisible = false;
|
||||
|
||||
// Global UI has some extra housekeeping to do when window gets hidden
|
||||
if (this.isGlobal) {
|
||||
this.sendToParentLowLevel('uwui-global-window-hidden', {});
|
||||
}
|
||||
},
|
||||
timeout
|
||||
);
|
||||
this.uwWindowFadeOut = true;
|
||||
},
|
||||
|
||||
cancelUwWindowHide() {
|
||||
this.uwWindowFadeOut = false;
|
||||
clearTimeout(this.uwWindowCloseTimeout);
|
||||
},
|
||||
|
||||
handleBusTunnelIn(payload) {
|
||||
this.eventBus.send(payload.action, payload.config, payload.routingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.ard-blocked {
|
||||
color: rgb(219, 125, 48) !important;
|
||||
background-color: rgba(0,0,0,0.85) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" src="./src/res-common/panels.scss" scoped module></style>
|
||||
<style lang="scss" src="./src/res-common/common.scss" scoped module></style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.uw-hover {
|
||||
position: absolute;
|
||||
z-index: 999999999999999999;
|
||||
}
|
||||
|
||||
.reduced-padding {
|
||||
padding: 1rem !important;
|
||||
}
|
||||
|
||||
.uv-hover-trigger-region {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border: 0.5rem dashed #fff;
|
||||
color: #fff;
|
||||
backdrop-filter: blur(0.5rem) brightness(0.5);
|
||||
}
|
||||
|
||||
.uw-window {
|
||||
position: fixed;
|
||||
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
|
||||
z-index: 999999999999999999;
|
||||
|
||||
width: 2500px;
|
||||
height: 1200px;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
|
||||
pointer-events: all !important;
|
||||
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(16px) saturate(120%);
|
||||
|
||||
&.fade-out {
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s;
|
||||
transition-delay: 0.5s;
|
||||
}
|
||||
}
|
||||
|
||||
.gib-bg {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(16px) saturate(120%);
|
||||
|
||||
width: fit-content;
|
||||
block-size: fit-content;
|
||||
}
|
||||
|
||||
|
||||
.context-spawn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
|
||||
color: #fff;
|
||||
|
||||
// .context-item {
|
||||
// font-size: .95rem;
|
||||
// padding: 1rem 1.6rem;
|
||||
// background-color: rgba(0, 0, 0, 0.5);
|
||||
// backdrop-filter: blur(16px) saturate(120%);
|
||||
|
||||
// white-space: nowrap;
|
||||
// }
|
||||
|
||||
// .spawn-container {
|
||||
// border: 1px solid white;
|
||||
// }
|
||||
}
|
||||
|
||||
.extension-status-messages {
|
||||
z-index: 1000;
|
||||
text-transform: uppercase;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
||||
width: 112.25%;
|
||||
transform: translate(-12.5%, 12.5%) scale(0.75);
|
||||
|
||||
> * {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-reverse-order {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
}
|
||||
|
||||
.aard-blocked {
|
||||
color: #fa6;
|
||||
}
|
||||
|
||||
.trigger-zone-preview {
|
||||
border: 4px solid #fa4;
|
||||
}
|
||||
|
||||
.debug-1 {
|
||||
border: 1px solid yellow;
|
||||
|
||||
&:hover {
|
||||
background-color: rbba(255,255,0,0.5);
|
||||
}
|
||||
}
|
||||
.debug-2 {
|
||||
border: 1px solid blue;
|
||||
|
||||
&:hover {
|
||||
background-color: rbba(0,0,255,.5);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,535 +0,0 @@
|
||||
<template>
|
||||
<div class="popup-panel">
|
||||
<!--
|
||||
NOTE — the code that makes ultrawidify popup work in firefox regardless of whether the
|
||||
extension is being displayed in a normal or a small/overflow popup breaks the popup
|
||||
behaviour on Chrome (where the popup would never reach the full width of 800px)
|
||||
|
||||
Since I'm tired and the hour is getting late, we'll just add an extra CSS class for
|
||||
non-firefox builds of this extension and be done with it. No need to complicate things
|
||||
further than that.
|
||||
-->
|
||||
<div v-if="settingsInitialized"
|
||||
class="popup flex flex-col no-overflow"
|
||||
:class="{'popup-chrome': ! BrowserDetect?.firefox}"
|
||||
>
|
||||
<div class="flex-row flex-nogrow flex-noshrink relative header"
|
||||
>
|
||||
<div class="grow shrink">
|
||||
<h1>
|
||||
<span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div v-if="BrowserDetect?.processEnvChannel !== 'stable'" class="absolute channel-info version-info">
|
||||
Build channel: {{BrowserDetect?.processEnvChannel}} <br/>
|
||||
<label>Version:</label> <br/>
|
||||
{{ settings.getExtensionVersion() }}
|
||||
</div>
|
||||
<div v-else class="version-info">
|
||||
<label>Version:</label> <br/>
|
||||
{{ settings.getExtensionVersion() }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- CONTAINER ROOT -->
|
||||
<div class="flex flex-row body no-overflow flex-grow">
|
||||
|
||||
<!-- TABS -->
|
||||
<div class="flex flex-col tab-row" style="flex: 3 3; border-right: 1px solid #222;">
|
||||
<div
|
||||
v-for="tab of tabs"
|
||||
:key="tab.id"
|
||||
class="tab flex flex-row"
|
||||
:class="{'active': tab.id === selectedTab}"
|
||||
@click="selectTab(tab.id)"
|
||||
>
|
||||
<div class="icon-container">
|
||||
<mdicon
|
||||
:name="tab.icon"
|
||||
:size="32"
|
||||
/>
|
||||
</div>
|
||||
<div class="label">
|
||||
{{tab.label}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="scrollable" style="flex: 7 7; padding: 1rem;">
|
||||
<template v-if="settings && siteSettings">
|
||||
<InPlayerUIAdvertisement
|
||||
v-if="selectedTab === 'playerUiCtl'"
|
||||
:eventBus="eventBus"
|
||||
/>
|
||||
<PopupVideoSettings
|
||||
v-if="selectedTab === 'videoSettings'"
|
||||
:settings="settings"
|
||||
:eventBus="eventBus"
|
||||
:siteSettings="siteSettings"
|
||||
></PopupVideoSettings>
|
||||
<!-- <PlayerDetectionPanel
|
||||
v-if="selectedTab === 'playerDetection'"
|
||||
:settings="settings"
|
||||
:eventBus="eventBus"
|
||||
:siteSettings="siteSettings"
|
||||
:site="site.host"
|
||||
>
|
||||
</PlayerDetectionPanel> -->
|
||||
<BaseExtensionSettings
|
||||
v-if="selectedTab === 'extensionSettings'"
|
||||
:settings="settings"
|
||||
:eventBus="eventBus"
|
||||
:siteSettings="siteSettings"
|
||||
:site="site.host"
|
||||
>
|
||||
</BaseExtensionSettings>
|
||||
</template>
|
||||
<template v-else>No settings or site settings found.</template>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseExtensionSettings from './src/PlayerUiPanels/BaseExtensionSettings.vue'
|
||||
import PlayerDetectionPanel from './src/PlayerUiPanels/PlayerDetectionPanel.vue'
|
||||
import PopupVideoSettings from './src/popup/panels/PopupVideoSettings.vue'
|
||||
import InPlayerUIAdvertisement from './src/PlayerUiPanels/InPlayerUiAdvertisement.vue';
|
||||
import Debug from '../ext/conf/Debug';
|
||||
import BrowserDetect from '../ext/conf/BrowserDetect';
|
||||
import Comms from '../ext/lib/comms/Comms';
|
||||
import CommsClient, {CommsOrigin} from '../ext/lib/comms/CommsClient';
|
||||
import Settings from '../ext/lib/Settings';
|
||||
import Logger from '../ext/lib/Logger';
|
||||
import EventBus from '../ext/lib/EventBus';
|
||||
import {ChromeShittinessMitigations as CSM} from '../common/js/ChromeShittinessMitigations';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
comms: undefined,
|
||||
eventBus: new EventBus(),
|
||||
settings: {},
|
||||
settingsInitialized: false,
|
||||
narrowPopup: null,
|
||||
sideMenuVisible: null,
|
||||
logger: undefined,
|
||||
site: undefined,
|
||||
siteSettings: undefined,
|
||||
selectedTab: 'playerUiCtl',
|
||||
tabs: [
|
||||
// see this for icons: https://pictogrammers.com/library/mdi/
|
||||
{id: 'playerUiCtl', label: 'In-player UI', icon: 'artboard'},
|
||||
{id: 'videoSettings', label: 'Video settings', icon: 'crop'},
|
||||
// {id: 'playerDetection', label: 'Player detection', icon: 'television-play'},
|
||||
{id: 'extensionSettings', label: 'Site and Extension options', icon: 'cogs' },
|
||||
],
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.logger = new Logger();
|
||||
await this.logger.init({
|
||||
allowLogging: true,
|
||||
});
|
||||
|
||||
this.settings = new Settings({afterSettingsSaved: () => this.updateConfig(), logger: this.logger});
|
||||
await this.settings.init();
|
||||
this.settingsInitialized = true;
|
||||
|
||||
// const port = chrome.runtime.connect({name: 'popup-port'});
|
||||
// port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
|
||||
// CSM.setProperty('port', port);
|
||||
|
||||
this.eventBus = new EventBus();
|
||||
this.eventBus.subscribe(
|
||||
'set-current-site',
|
||||
{
|
||||
function: (config, context) => {
|
||||
if (this.site) {
|
||||
if (!this.site.host) {
|
||||
// dunno why this fix is needed, but sometimes it is
|
||||
this.site.host = config.site.host;
|
||||
}
|
||||
}
|
||||
this.site = config.site;
|
||||
// this.selectedSite = this.selectedSite || config.site.host;
|
||||
this.siteSettings = this.settings.getSiteSettings(this.site.host);
|
||||
|
||||
this.eventBus.setupPopupTunnelWorkaround({
|
||||
origin: CommsOrigin.Popup,
|
||||
comms: {
|
||||
forwardTo: 'active'
|
||||
}
|
||||
});
|
||||
|
||||
this.loadFrames(this.site);
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.comms = new CommsClient('popup-port', this.logger, this.eventBus);
|
||||
this.eventBus.setComms(this.comms);
|
||||
this.eventBus.setupPopupTunnelWorkaround({
|
||||
origin: CommsOrigin.Popup,
|
||||
comms: {forwardTo: 'active'}
|
||||
});
|
||||
|
||||
|
||||
// ensure we'll clean player markings on popup close
|
||||
window.addEventListener("unload", () => {
|
||||
CSM.port.postMessage({
|
||||
cmd: 'unmark-player',
|
||||
forwardToAll: true,
|
||||
});
|
||||
// if (BrowserDetect.anyChromium) {
|
||||
// chrome.extension.getBackgroundPage().sendUnmarkPlayer({
|
||||
// cmd: 'unmark-player',
|
||||
// forwardToAll: true,
|
||||
// });
|
||||
// }
|
||||
});
|
||||
|
||||
// get info about current site from background script
|
||||
while (true) {
|
||||
this.requestSite();
|
||||
await this.sleep(5000);
|
||||
}
|
||||
},
|
||||
async updated() {
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
|
||||
// ensure that narrowPopup only gets set the first time the popup renders
|
||||
// if popup was rendered before, we don't do anything because otherwise
|
||||
// we'll be causing an unwanted re-render
|
||||
//
|
||||
// another thing worth noting — the popup gets first initialized with
|
||||
// offsetWidth set to 0. This means proper popup will be displayed as a
|
||||
// mini popup if we don't check for that.
|
||||
if (this.narrowPopup === null && body.offsetWidth > 0) {
|
||||
this.narrowPopup = body.offsetWidth < 600;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Debug,
|
||||
BrowserDetect,
|
||||
PopupVideoSettings, PlayerDetectionPanel, BaseExtensionSettings, InPlayerUIAdvertisement
|
||||
},
|
||||
methods: {
|
||||
async sleep(t) {
|
||||
return new Promise( (resolve,reject) => {
|
||||
setTimeout(() => resolve(), t);
|
||||
});
|
||||
},
|
||||
toObject(obj) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
},
|
||||
requestSite() {
|
||||
try {
|
||||
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
|
||||
// CSM.port.postMessage({command: 'get-current-site'});
|
||||
this.eventBus.send(
|
||||
'get-current-site',
|
||||
{
|
||||
comms: {forwardTo: 'active'}
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.log('error','popup','[popup::getSite] sending get-current-site failed for some reason. Reason:', e);
|
||||
}
|
||||
},
|
||||
getRandomColor() {
|
||||
return `rgb(${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)})`;
|
||||
},
|
||||
selectTab(tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
processReceivedMessage(message, port) {
|
||||
this.logger.log('info', 'popup', '[popup::processReceivedMessage] received message:', message)
|
||||
|
||||
if (message.command === 'set-current-site'){
|
||||
if (this.site) {
|
||||
if (!this.site.host) {
|
||||
// dunno why this fix is needed, but sometimes it is
|
||||
this.site.host = site.tabHostname;
|
||||
}
|
||||
}
|
||||
this.site = message.site;
|
||||
|
||||
// update activeSites
|
||||
// this.activeSites = this.activeSites.filter(x => x.host !== message.site);
|
||||
|
||||
// add current site
|
||||
// this.activeSites = unshift({
|
||||
// host: message.site.host,
|
||||
// isIFrame: false, // currently unused
|
||||
// });
|
||||
this.selectedSite = this.selectedSite || message.site.host;
|
||||
|
||||
this.loadFrames(this.site);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
isDefaultFrame(frameId) {
|
||||
return frameId === '__playing' || frameId === '__all';
|
||||
},
|
||||
loadFrames() {
|
||||
this.activeSites = [{
|
||||
host: this.site.host,
|
||||
isIFrame: false, // not used tho. Maybe one day
|
||||
}];
|
||||
this.selectedSite = this.selectedSite || this.site.host;
|
||||
|
||||
// for (const frame in videoTab.frames) {
|
||||
// this.activeFrames.push({
|
||||
// id: `${this.site.id}-${frame}`,
|
||||
// label: videoTab.frames[frame].host,
|
||||
// ...this.frameStore[frame],
|
||||
// })
|
||||
|
||||
// // only add each host once at most
|
||||
// if (!this.activeSites.find(x => x.host === videoTab.frames[frame].host)) {
|
||||
// this.activeSites.push({
|
||||
// host: videoTab.frames[frame].host,
|
||||
// isIFrame: undefined // maybe one day
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// update whether video tab can be shown
|
||||
// this.updateCanShowVideoTab();
|
||||
},
|
||||
getRandomColor() {
|
||||
return `rgb(${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// @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';
|
||||
@import './src/res-common/_variables';
|
||||
|
||||
.header {
|
||||
background-color: rgb(90, 28, 13);
|
||||
color: #fff;
|
||||
padding: 8px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.version-info {
|
||||
text-align: right;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.8;
|
||||
label {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.site-support-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.site-support-site {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.site-support {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
margin-left: 1rem;
|
||||
border-radius: 8px;
|
||||
padding: 0rem 1.5rem 0rem 1rem;
|
||||
|
||||
position: relative;
|
||||
|
||||
.tooltip {
|
||||
padding: 1rem;
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
transform: translateY(110%);
|
||||
width: 42em;
|
||||
|
||||
background-color: rgba(0,0,0,0.90);
|
||||
color: #ccc;
|
||||
}
|
||||
&:hover {
|
||||
.tooltip {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.mdi {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
&.official {
|
||||
background-color: #fa6;
|
||||
color: #000;
|
||||
|
||||
.mdi {
|
||||
fill: #000 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.community {
|
||||
background-color: rgb(85, 85, 179);
|
||||
color: #fff;
|
||||
|
||||
.mdi {
|
||||
fill: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.no-support {
|
||||
background-color: rgb(138, 65, 126);
|
||||
color: #eee;
|
||||
|
||||
.mdi {
|
||||
fill: #eee !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.user-added {
|
||||
border: 1px solid #ff0;
|
||||
|
||||
color: #ff0;
|
||||
|
||||
.mdi {
|
||||
fill: #ff0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
|
||||
.warning-area {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
overflow-y: auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-box {
|
||||
background: rgb(255, 174, 107);
|
||||
color: #000;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.icon-container {
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(0,0,0,0.7);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.popup-panel {
|
||||
background-color: rgba(0,0,0,0.50);
|
||||
color: #fff;
|
||||
|
||||
overflow-y: auto;
|
||||
|
||||
.popup-window-header {
|
||||
padding: 1rem;
|
||||
background-color: rgba(5,5,5, 0.75);
|
||||
}
|
||||
.tab-row {
|
||||
background-color: rgba(11,11,11, 0.75);
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
padding: 1rem;
|
||||
font-size: 1.25rem;
|
||||
// height: rem;
|
||||
min-height: 3rem;
|
||||
|
||||
border-bottom: 1px solid rgba(128, 128, 128, 0.5);
|
||||
border-top: 1px solid rgba(128, 128, 128, 0.5);
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
&.active {
|
||||
opacity: 1.0;
|
||||
background-color: $primaryBg;
|
||||
color: rgb(255, 174, 107);
|
||||
border-bottom: 1px solid rgba(116, 78, 47, 0.5);
|
||||
border-top: 1px solid rgba(116, 78, 47, 0.5);
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
width: 64px;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.label {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-title, .popup-title h1 {
|
||||
font-size: 48px !important;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: 1px solid #222 !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0; padding: 0; font-weight: 400; font-size:24px;
|
||||
}
|
||||
</style>
|
@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"; style="position: relative">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<title>Ultrawidify - Content Script User Interface (global overlay)</title>
|
||||
<!-- <link rel="stylesheet" href="csui.css"> -->
|
||||
<% if (NODE_ENV === 'development') { %>
|
||||
<!-- Load some resources only in development environment -->
|
||||
<% } %>
|
||||
</head>
|
||||
<body class="uw-ultrawidify-container-root">
|
||||
<div id="app"></div>
|
||||
<script src="csui-global.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,11 +0,0 @@
|
||||
import { createApp } from 'vue';
|
||||
import GlobalFrame from './GlobalFrame';
|
||||
import mdiVue from 'mdi-vue/v3';
|
||||
import * as mdijs from '@mdi/js';
|
||||
|
||||
// NOTE — this is in-player interface for ultrawidify
|
||||
// it is injected into the page in UI.init()
|
||||
|
||||
createApp(GlobalFrame)
|
||||
.use(mdiVue, {icons: mdijs})
|
||||
.mount('#app');
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="position: relative">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="color-scheme" content="dark">
|
||||
<title>Ultrawidify - Content Script User Interface (in-player overlay)</title>
|
||||
<!-- <link rel="stylesheet" href="csui.css"> -->
|
||||
</head>
|
||||
<body class="uw-ultrawidify-container-root" style="background-color: transparent;">
|
||||
<div id="app"></div>
|
||||
<script src="csui.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="position: relative">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>Ultrawidify - Content Script User Interface (in-player overlay)</title>
|
||||
<!-- <link rel="stylesheet" href="csui.css"> -->
|
||||
</head>
|
||||
<body class="uw-ultrawidify-container-root" style="background-color: transparent;">
|
||||
<div id="app"></div>
|
||||
<script src="csui.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="position: relative">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Ultrawidify - Content Script User Interface (in-player overlay)</title>
|
||||
<!-- <link rel="stylesheet" href="csui.css"> -->
|
||||
</head>
|
||||
<body class="uw-ultrawidify-container-root" style="background-color: transparent;">
|
||||
<div id="app"></div>
|
||||
<script src="csui.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="position: relative">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<!-- <link rel="stylesheet" href="popup.css"> -->
|
||||
|
||||
<% if (NODE_ENV === 'development') { %>
|
||||
<!-- Load some resources only in development environment -->
|
||||
<% } %>
|
||||
</head>
|
||||
<body
|
||||
style="width: 100%; height: 100%; overflow-x: hidden; min-width: 750px"
|
||||
>
|
||||
<div id="app">
|
||||
|
||||
</div>
|
||||
<script src="csui-popup.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,8 +0,0 @@
|
||||
import { createApp } from 'vue'
|
||||
import Popup from './Popup';
|
||||
import mdiVue from 'mdi-vue/v3';
|
||||
import * as mdijs from '@mdi/js';
|
||||
|
||||
createApp(Popup)
|
||||
.use(mdiVue, {icons: mdijs})
|
||||
.mount('#app');
|
@ -1,11 +0,0 @@
|
||||
import { createApp } from 'vue';
|
||||
import PlayerOverlay from './PlayerOverlay';
|
||||
import mdiVue from 'mdi-vue/v3';
|
||||
import * as mdijs from '@mdi/js';
|
||||
|
||||
// NOTE — this is in-player interface for ultrawidify
|
||||
// it is injected into the page in UI.init()
|
||||
|
||||
createApp(PlayerOverlay)
|
||||
.use(mdiVue, {icons: mdijs})
|
||||
.mount('#app');
|
@ -1,18 +0,0 @@
|
||||
$text-normal: #ddd;
|
||||
$text-dim: #999;
|
||||
$text-dark: #666;
|
||||
$primary-color: #fb772a;
|
||||
$primary: $primary-color;
|
||||
$secondary-color: #e70c0c;
|
||||
|
||||
$input-background: #141414;
|
||||
$input-border: #4e3527;
|
||||
$page-background: #101010;
|
||||
$popup-header-background: #7f1416;
|
||||
|
||||
$background-primary: #101010;
|
||||
$selected-color: #f5cbaf;
|
||||
$background-selected: #412d20;
|
||||
|
||||
|
||||
$info-color: #bda9f3;
|
@ -1,396 +0,0 @@
|
||||
@import "colors.scss";
|
||||
@import "fonts.scss";
|
||||
@import "flex.scss";
|
||||
// @import "~/@mdi/font/css/materialdesignicons.css";
|
||||
|
||||
// @import "form.scss";
|
||||
|
||||
body {
|
||||
background-color: $background-primary;
|
||||
color: $text-normal;
|
||||
font-family: 'Overpass', sans-serif;
|
||||
font-size: 1.2em;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
height: 100vh;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* STANDARD WIDTHS AND HEIGHTS */
|
||||
.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.h100, .h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.w24 {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.m-t-0-33em {
|
||||
margin-top: 0.33em;
|
||||
}
|
||||
|
||||
.x-pad-1em {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* overflow stuff */
|
||||
.overflow-y-auto {
|
||||
overflow: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba($primary-color, 0.7) $background-primary;
|
||||
}
|
||||
.scrollbar-darker {
|
||||
scrollbar-color: rgba($primary-color, 0.5) $background-primary;
|
||||
}
|
||||
|
||||
|
||||
/* scrollbars for chrome/webkit */
|
||||
.overflow-y-auto::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
}
|
||||
.overflow-y-auto::-webkit-scrollbar-track {
|
||||
background: $background-primary;
|
||||
}
|
||||
.overflow-y-auto::-webkit-scrollbar-thumb {
|
||||
background: rgba($primary-color, 0.7);
|
||||
}
|
||||
.overflow-y-auto::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
.scrollbar-darker::-webkit-scrollbar-thumb {
|
||||
background: rgba($primary-color, 0.5);
|
||||
}
|
||||
|
||||
.no-overflow {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.no-overflow-x {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.no-overflow-y {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/* .SELECTED CLASSES */
|
||||
|
||||
.selected-tab {
|
||||
background-color: initial;
|
||||
border-left: $primary-color 5px solid;
|
||||
}
|
||||
|
||||
.selected-tab-secondary {
|
||||
background-color: initial;
|
||||
border-left: $secondary-color 3px solid !important;
|
||||
}
|
||||
|
||||
|
||||
/* BASIC STYLING */
|
||||
|
||||
.description {
|
||||
color: $text-dim;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.label {
|
||||
padding-top: 1.5rem;
|
||||
font-size: 1.5rem;
|
||||
font-variant: small-caps;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.label-secondary {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
padding-top: 0.69rem;
|
||||
padding-bottom: 0.69rem;
|
||||
}
|
||||
|
||||
.indent {
|
||||
padding-left: 4.2rem;
|
||||
}
|
||||
|
||||
.row-padding {
|
||||
padding-top: 0.69rem;
|
||||
padding-bottom: 0.69rem;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
color: $primary-color;
|
||||
}
|
||||
a:hover {
|
||||
color: lighten($primary-color, 10%);
|
||||
}
|
||||
|
||||
/* INPUT FORMATTING */
|
||||
input[type="number"], input[type="text"], input {
|
||||
outline: none;
|
||||
background-color: $input-background;
|
||||
color: $text-normal;
|
||||
padding: 0.1rem;
|
||||
padding-top: 0.2rem;
|
||||
padding-bottom: 0.1rem;
|
||||
margin-left: 1rem;
|
||||
border: 1px solid $input-border;
|
||||
}
|
||||
|
||||
input:disabled {
|
||||
background: #444444;
|
||||
color: darken($text-normal, 50%);
|
||||
}
|
||||
|
||||
/* ELEMENT POSITIONING */
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.float-left {
|
||||
float: left;
|
||||
}
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* TEXT FORMATTING (no colors) */
|
||||
|
||||
small {
|
||||
font-size: 0.75em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 0.75em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.medium-small {
|
||||
font-size: 0.85em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.smallcaps{
|
||||
font-variant: small-caps;
|
||||
}
|
||||
|
||||
.center{
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.invalid-input {
|
||||
border: 1px solid #720 !important;
|
||||
background-color: #410 !important;
|
||||
}
|
||||
|
||||
.button {
|
||||
/*display: inline-block;*/
|
||||
// padding-top: 8px;
|
||||
// padding-bottom: 3px;
|
||||
//padding-left: 5px;
|
||||
//padding-right: 5px;
|
||||
border: 1px solid rgb(39, 39, 39);
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
color: $text-dim;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
user-select: none;;
|
||||
}
|
||||
|
||||
|
||||
.selected, .setting-selected {
|
||||
color: $selected-color !important;
|
||||
background-color: $background-selected !important;
|
||||
}
|
||||
|
||||
.selected-tab {
|
||||
color: $selected-color;
|
||||
}
|
||||
|
||||
.setting-selected {
|
||||
border: 1px solid shade($selected-color, 25%);
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
color: lighten($selected-color, 10%);
|
||||
background-color: lighten($background-selected, 10%);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
/* color: #666; */
|
||||
filter: contrast(50%) brightness(40%) grayscale(100%);
|
||||
}
|
||||
|
||||
.disabled-button {
|
||||
color: #666 !important;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
.disabled-button:hover {
|
||||
color: #777 !important;
|
||||
background-color: #222 !important;
|
||||
}
|
||||
|
||||
/* BROWSER-SPECIFIC DISABLE */
|
||||
.disabled-edge {
|
||||
pointer-events: none !important;
|
||||
filter: contrast(50%) brightness(40%) grayscale(100%) !important;
|
||||
content: "NOT SUPPORTED IN THIS BROWSER";
|
||||
}
|
||||
.disabled-edge::after {
|
||||
background-color: #333272;
|
||||
color: #d8d9e6;
|
||||
display: inline-block;
|
||||
font-size: .75em;
|
||||
font-variant: small-caps;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** misc **/
|
||||
|
||||
.warning-color {
|
||||
color: #d6ba4a;
|
||||
}
|
||||
|
||||
.warning, .warning-lite {
|
||||
color: #d6ba4a;
|
||||
padding-left: 35px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.warning::before, .warning-lite::before {
|
||||
content: "⚠ ";
|
||||
display: inline-block;
|
||||
}
|
||||
.warning::before {
|
||||
font-weight: bold;
|
||||
font-size: 2.5em;
|
||||
margin-left: -35px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.info {
|
||||
color: $info-color;
|
||||
padding-left: 35px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info::before {
|
||||
content: "ⓘ";
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-left: -35px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.new {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.new::after {
|
||||
content: "ⓘ";
|
||||
color: $info-color !important;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.experimental::after {
|
||||
// content: "Experimental";
|
||||
content: "Ⓔ";
|
||||
color: #ffde12;
|
||||
// background-color: #1f1f1f;
|
||||
display: inline-block;
|
||||
font-size: .75em;
|
||||
font-variant: small-caps;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
margin-left: 10px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
.experimental:hover::after {
|
||||
content: "Ⓔ Experimental";
|
||||
// content: "";
|
||||
color: #ffde12;
|
||||
// background-color: #1f1f1f;
|
||||
display: inline-block;
|
||||
font-size: .75em;
|
||||
font-variant: small-caps;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
margin-left: 10px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.sticky-bottom {
|
||||
width: 100%;
|
||||
position: sticky;
|
||||
// position: fixed;
|
||||
bottom: 0px;
|
||||
background-color: rgba($background-primary, 0.7);
|
||||
}
|
||||
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.ltr {
|
||||
direction: ltr;
|
||||
}
|
||||
.monospace {
|
||||
font-family: 'Overpass Mono';
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-auto {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.flex-nogrow {
|
||||
flex-grow: 0;
|
||||
}
|
||||
.flex-shrink {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.flex-noshrink {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.flex-cross-center {
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
.flex-self-center {
|
||||
align-self: center;
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-thin.woff2') format('woff2'); /* Super Modern Browsers */
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-thin-italic.woff2') format('woff2');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-extralight.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-extralight-italic.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-light.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-light-italic.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-regular.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-italic.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-semibold.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-semibold-italic.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-bold.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'overpass';
|
||||
src: url('../../fonts/overpass-webfont/overpass-bold-italic.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/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('/csui/res/fonts/overpass-webfont/overpass-thin-italic.woff2') format('woff2');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-extralight.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-extralight-italic.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-light.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-light-italic.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-regular.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-italic.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-semibold.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-semibold-italic.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-bold.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('/csui/res/fonts/overpass-webfont/overpass-bold-italic.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass mono';
|
||||
src: url('/csui/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('/csui/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('/csui/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('/csui/res/fonts/overpass-mono-webfont/overpass-mono-bold.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
@import 'flex.scss';
|
||||
@import 'colors.scss';
|
||||
@import 'common.scss';
|
||||
|
||||
* {
|
||||
font-family: 'Overpass';
|
||||
}
|
||||
|
||||
.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;
|
||||
background-color: none transparent !important;
|
||||
|
||||
// Ensure we're display:block
|
||||
display: block;
|
||||
|
||||
// we are click-through by default:
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
## License
|
||||
|
||||
Copyright 2015 Red Hat, Inc.,
|
||||
This Font Software is dual licensed and available under the SIL Open Font License, Version 1.1. and also the LGPL 2.1
|
||||
|
||||
The Open Font license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
The GNU LGPL can be found at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
|
||||
|
||||
|
||||
|
||||
#### SIL OPEN FONT LICENSE
|
||||
Version 1.1 - 26 February 2007
|
||||
|
||||
---
|
||||
|
||||
#### PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
#### DEFINITIONS
|
||||
“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
“Reserved Font Name” refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
#### PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
#### TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
#### DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|