Compare commits
No commits in common. "master" and "v2" have entirely different histories.
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.
|
|
||||||
17
.gitignore
vendored
@ -1,17 +1,2 @@
|
|||||||
|
ultrawidify.zip
|
||||||
old/
|
old/
|
||||||
build/
|
|
||||||
/node_modules
|
|
||||||
/*.log
|
|
||||||
/dist*
|
|
||||||
/uw-git_keys
|
|
||||||
/untracked-assets
|
|
||||||
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
*.kate-swp
|
|
||||||
|
|
||||||
src/res/img/git-ignore/
|
|
||||||
|
|
||||||
test/debug-configs/
|
|
||||||
|
|
||||||
debugging-resources/
|
|
||||||
|
|||||||
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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
58
.vscode/launch.json
vendored
@ -1,52 +1,14 @@
|
|||||||
{
|
{
|
||||||
// Use IntelliSense to learn about possible attributes.
|
// Use IntelliSense to learn about possible attributes.
|
||||||
// Hover to view descriptions of existing attributes.
|
// Hover to view descriptions of existing attributes.
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"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",
|
"type": "node",
|
||||||
"path": "${workspaceFolder}/src/ext"
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"program": "${file}"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
113
.vscode/settings.json
vendored
@ -1,113 +0,0 @@
|
|||||||
{
|
|
||||||
"cSpell.words": [
|
|
||||||
"aard",
|
|
||||||
"allowtransparency",
|
|
||||||
"ardetector",
|
|
||||||
"autodetect",
|
|
||||||
"autodetection",
|
|
||||||
"beforeunload",
|
|
||||||
"blackbar",
|
|
||||||
"blackbars",
|
|
||||||
"blackframe",
|
|
||||||
"bruteforce",
|
|
||||||
"canvas",
|
|
||||||
"clickthrough",
|
|
||||||
"cmpa",
|
|
||||||
"cmpb",
|
|
||||||
"com",
|
|
||||||
"comms",
|
|
||||||
"csui",
|
|
||||||
"ctab",
|
|
||||||
"cycleable",
|
|
||||||
"decycle",
|
|
||||||
"dinked",
|
|
||||||
"dinks",
|
|
||||||
"disneyplus",
|
|
||||||
"endregion",
|
|
||||||
"equalish",
|
|
||||||
"fith",
|
|
||||||
"fitw",
|
|
||||||
"fuckup",
|
|
||||||
"fucky",
|
|
||||||
"geoblocked",
|
|
||||||
"geoblocking",
|
|
||||||
"gfycat",
|
|
||||||
"gmail",
|
|
||||||
"guardline",
|
|
||||||
"han",
|
|
||||||
"haram",
|
|
||||||
"Heebo",
|
|
||||||
"hoverable",
|
|
||||||
"iframe",
|
|
||||||
"imgur",
|
|
||||||
"insta",
|
|
||||||
"jsoneditor",
|
|
||||||
"jwplayer",
|
|
||||||
"kavin",
|
|
||||||
"letterboxed",
|
|
||||||
"manjaro",
|
|
||||||
"mdicon",
|
|
||||||
"mdijs",
|
|
||||||
"metaivi",
|
|
||||||
"minification",
|
|
||||||
"mitigations",
|
|
||||||
"mstefan",
|
|
||||||
"nogrow",
|
|
||||||
"noshrink",
|
|
||||||
"outro",
|
|
||||||
"PILLARBOX",
|
|
||||||
"PILLARBOXED",
|
|
||||||
"polyfill",
|
|
||||||
"problemo",
|
|
||||||
"recursing",
|
|
||||||
"reddit",
|
|
||||||
"rescan",
|
|
||||||
"resizer",
|
|
||||||
"resizers",
|
|
||||||
"SCPI",
|
|
||||||
"scrollbar",
|
|
||||||
"shitiness",
|
|
||||||
"smallcaps",
|
|
||||||
"spaghettified",
|
|
||||||
"suboption",
|
|
||||||
"subscan",
|
|
||||||
"tabitem",
|
|
||||||
"tablist",
|
|
||||||
"tamius",
|
|
||||||
"textbox",
|
|
||||||
"ultrawide",
|
|
||||||
"ultrawidify",
|
|
||||||
"unmark",
|
|
||||||
"unmarking",
|
|
||||||
"unsets",
|
|
||||||
"unshift",
|
|
||||||
"uwid",
|
|
||||||
"uwui",
|
|
||||||
"videodata",
|
|
||||||
"vids",
|
|
||||||
"vuejs",
|
|
||||||
"vuex",
|
|
||||||
"wakanim",
|
|
||||||
"webextension",
|
|
||||||
"webextensions",
|
|
||||||
"wuckies",
|
|
||||||
"wucky",
|
|
||||||
"ycenter",
|
|
||||||
"youtube",
|
|
||||||
"YYMM"
|
|
||||||
],
|
|
||||||
"cSpell.ignoreWords": [
|
|
||||||
"abcdefghijklmnopqrstuvwxyz",
|
|
||||||
"autoar",
|
|
||||||
"cheight",
|
|
||||||
"cwidth",
|
|
||||||
"fcstart",
|
|
||||||
"fctime",
|
|
||||||
"legacycd",
|
|
||||||
"ncol",
|
|
||||||
"nrow",
|
|
||||||
"tickrate",
|
|
||||||
"undisable",
|
|
||||||
"vdid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
462
CHANGELOG.md
@ -1,444 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v6.0 (current major)
|
|
||||||
|
|
||||||
### v6.4.0
|
|
||||||
* In-player UI now appears in full-screen even for websites that use top layer
|
|
||||||
* Embedded sites now inherit settings of the parent frame by default
|
|
||||||
* Setting inheritance/overriding is not thoroughly tested and may be full of edge cases.
|
|
||||||
* Added validation to custom aspect ratio entry menu. Corrected parsing of aspect ratios given in the X:Y format, even though aspect ratios should be ideally given as a single number.
|
|
||||||
* Autodetection can now scan for subtitles.
|
|
||||||
* New experimental autodetection (which is secretly just slightly modified subtitle check)
|
|
||||||
|
|
||||||
### v6.3.0
|
|
||||||
* Added zoom segment to in-player UI and popup.
|
|
||||||
* Fixed keyboard zoom
|
|
||||||
* Added additional zoom options. If you wonder how zoom options differ from crop, mess around and find out.
|
|
||||||
* Subdomains now inherit same settings as their parent domain by default
|
|
||||||
* Extension popup detects embedded content
|
|
||||||
* Added `www.youtube-nocookie.com` to "officially supported" list
|
|
||||||
|
|
||||||
### v6.2.5
|
|
||||||
|
|
||||||
* Popup appearance changed — UI advertisement panel was moved to the popup header
|
|
||||||
* Fixed the bug where popup wouldn't be showing the correct settings
|
|
||||||
* Fixed the bug where site settings would default to 'disabled', even if Extension default setting was not disabled.
|
|
||||||
* Added ability to export and import settings from file (ft. developer mode editor)
|
|
||||||
* [dev goodies] Added debug overlay for aard
|
|
||||||
* Fixed an issue where aspect ratio wouldn't get calculated correctly on youtube videos with native aspect ratios other than 16:9
|
|
||||||
* Fixed an issue that would crash the extension if video element didn't have a player element associated with it
|
|
||||||
* Fixed an issue where extension sometimes wouldn't work if video element was grafted/re-parented to a different element
|
|
||||||
|
|
||||||
### v6.2.4
|
|
||||||
* [#264](https://github.com/tamius-han/ultrawidify/issues/264) — fixed issue with white screen that affected some youtube users. Special thanks to [SnowyOwlNugget](https://github.com/SnowyOwlNugget">SnowyOwlNugget), who instead of whining provided the necessary information.
|
|
||||||
* Minor updates to the settings
|
|
||||||
* Switching between full screen, theater, and normal player now correctly enables and disables the extension according to the settings.
|
|
||||||
* Don't reset settings if updating conf patches fails.
|
|
||||||
* Darken in-player UI backgrounds until Chrome fixes its backdrop-filter bug
|
|
||||||
|
|
||||||
### v6.2.3
|
|
||||||
* Fixed default persistent mode
|
|
||||||
|
|
||||||
### v6.2.2
|
|
||||||
* Fixed the issue where stretching was not applied if no cropping was used
|
|
||||||
* Added way to manually enable or disable color scheme detection, as a compromise between #259 and #264
|
|
||||||
|
|
||||||
### v6.2.1
|
|
||||||
|
|
||||||
* Fixed offset issue on Netflix
|
|
||||||
* Fixed issue with overlay iframe not being transparent on twitter
|
|
||||||
|
|
||||||
### v6.2.0
|
|
||||||
|
|
||||||
* Parts of automatic aspect ratio detection use WebGL now. This should result in improved performance.
|
|
||||||
* In-player UI now indicates whether a site is having a problem with automatic aspect ratio detection.
|
|
||||||
* UI improvements
|
|
||||||
|
|
||||||
Since automatic aspect ratio detection had to be rewritten completely and since the new version needs to be out 5 days ago, there are some regressions in the automatic aspect ratio detection.
|
|
||||||
|
|
||||||
### v6.1.0
|
|
||||||
|
|
||||||
Was skipped due to how major the changes were.
|
|
||||||
|
|
||||||
### 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)
|
### 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.
|
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
|
### v2.2.4
|
||||||
|
|
||||||
Lots of mostly incredibly minor stuff.
|
Lots of mostly incredibly minor stuff.
|
||||||
|
|
||||||
@ -449,11 +15,11 @@ Lots of mostly incredibly minor stuff.
|
|||||||
* Fixed some under-the-hood bugs nobody knew they even existed
|
* Fixed some under-the-hood bugs nobody knew they even existed
|
||||||
* A lil bit of refactoring
|
* A lil bit of refactoring
|
||||||
|
|
||||||
### v2.2.3
|
### v2.2.3
|
||||||
|
|
||||||
* Fixed automatic aspect ratio detection on DRM-protected sites.
|
* Fixed automatic aspect ratio detection on DRM-protected sites.
|
||||||
|
|
||||||
### v2.2.2
|
### 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.
|
* 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.
|
||||||
|
|
||||||
@ -469,9 +35,9 @@ 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.
|
* **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 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.
|
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).
|
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.
|
Videos that aren't playing (e.g. videos that are paused or ended) do (should) ***not*** use any meaningful amount of RAM.
|
||||||
|
|
||||||
@ -489,11 +55,11 @@ Videos that aren't playing (e.g. videos that are paused or ended) do (should) **
|
|||||||
|
|
||||||
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.
|
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
|
### v2.1.2
|
||||||
|
|
||||||
* Fixed some bugs with autodetection sometimes not working properly on Youtube.
|
* 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.
|
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
|
### v2.1.1
|
||||||
|
|
||||||
@ -505,7 +71,7 @@ Problem: there's this bit of code that keeps aspect ratio from changing when the
|
|||||||
* Popup should work more reliably now
|
* Popup should work more reliably now
|
||||||
* Twitch works ... kinda but not always
|
* Twitch works ... kinda but not always
|
||||||
|
|
||||||
### v2.0.3
|
### 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)
|
* Fixed the bug where Netflix videos weren't vertically centered in Firefox 57+ (not present in Chrome or FF 56 or earlier)
|
||||||
|
|
||||||
@ -537,8 +103,6 @@ The extension is being rewritten almost ground-up, around automatic aspect ratio
|
|||||||
* Zoom/unzoom options are gone
|
* Zoom/unzoom options are gone
|
||||||
* Can't customize keybinds yet
|
* Can't customize keybinds yet
|
||||||
|
|
||||||
# v1.x
|
|
||||||
|
|
||||||
### v1.3a1
|
### v1.3a1
|
||||||
|
|
||||||
* Adding ability to add custom sites (in progress)
|
* Adding ability to add custom sites (in progress)
|
||||||
@ -566,15 +130,15 @@ The extension is being rewritten almost ground-up, around automatic aspect ratio
|
|||||||
|
|
||||||
* Introduced Netflix support.
|
* 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).
|
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)
|
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.
|
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
|
### 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.
|
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).
|
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).
|
||||||
|
|
||||||
@ -588,7 +152,7 @@ Fixed the bug where sometimes the extension would fail to work. (example: you op
|
|||||||
|
|
||||||
### v1.0-rc1
|
### v1.0-rc1
|
||||||
|
|
||||||
* Settings page is added and mostly working.
|
* Settings page is added and mostly working.
|
||||||
|
|
||||||
### v0.9.9.6
|
### v0.9.9.6
|
||||||
|
|
||||||
@ -604,7 +168,7 @@ Fixed the bug where sometimes the extension would fail to work. (example: you op
|
|||||||
|
|
||||||
### v0.9.9.1
|
### v0.9.9.1
|
||||||
|
|
||||||
* Keybinds `a` and `w` now work.
|
* Keybinds `a` and `w` now work.
|
||||||
* Some changes under the bonnet, mostly regarding the way keypresses are handled.
|
* Some changes under the bonnet, mostly regarding the way keypresses are handled.
|
||||||
* 'Settings' page is ~15% done.
|
* 'Settings' page is ~15% done.
|
||||||
|
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
# Contributing to Ultrawidify
|
|
||||||
|
|
||||||
Thank you for considering contributing to this project! We welcome contributions from the community and are grateful for your efforts.
|
|
||||||
|
|
||||||
## How to Contribute
|
|
||||||
|
|
||||||
0. Open an issue, where you introduce the feature you want to add or thing you want to fix
|
|
||||||
1. Fork the repository.
|
|
||||||
2. Create a new branch for your contribution.
|
|
||||||
3. Write readable code
|
|
||||||
4. Check that your additions do not break existing features
|
|
||||||
5. Open a pull request
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
Please follow the code of conduct:
|
|
||||||
|
|
||||||
* don't be too much of an asshole
|
|
||||||
* language policing my code comments is not a worthwhile contribution, and is considered spam. If you're here to do that, fuck off. I'm looking at you, ScamOSS and co.
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
- Use formatting consistent with the rest of the project
|
|
||||||
- Write meaningful commit messages.
|
|
||||||
- Include comments where necessary to explain complex logic.
|
|
||||||
|
|
||||||
## Licensing & Contribution Agreement
|
|
||||||
|
|
||||||
By submitting a contribution (e.g., via pull request), you agree to the following:
|
|
||||||
|
|
||||||
- You grant the project maintainer(s) a non-exclusive, irrevocable, worldwide, royalty-free license to use, copy, modify, and distribute your contributions as part of the project.
|
|
||||||
- You certify that your contributions are your original work and that you have the right to submit them.
|
|
||||||
- You agree that your contributions are licensed under the same license as the rest of the project, unless explicitly stated otherwise.
|
|
||||||
|
|
||||||
**TL;DR:** once your code is in the project, there's no take-backsies.
|
|
||||||
|
|
||||||
## Questions?
|
|
||||||
|
|
||||||
The discussion board is right over there, three tabs to the right.
|
|
||||||
@ -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!'"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
35
LICENSE.MD
@ -1,35 +0,0 @@
|
|||||||
# License
|
|
||||||
|
|
||||||
Copyright (c) 2025 @tamius-han
|
|
||||||
|
|
||||||
The source code is provided on the "you can look, but you can't take" basis.
|
|
||||||
|
|
||||||
## Permissions
|
|
||||||
|
|
||||||
You are permitted to:
|
|
||||||
|
|
||||||
* You can view the code
|
|
||||||
* You can create forks and modify the code for personal use
|
|
||||||
* You can build and run modified versions of this project for personal use on your local machine
|
|
||||||
* Push modifications to your personal github fork
|
|
||||||
|
|
||||||
## Restrictions
|
|
||||||
|
|
||||||
You may NOT:
|
|
||||||
|
|
||||||
* Distribute this project or any modified versions outside of your personal Github fork
|
|
||||||
* Publish or distribute compiled binaries, builds, or packages of this project or any derivative work
|
|
||||||
* Use the code in commercial products, services, or other public-facing deployments.
|
|
||||||
* Sub-license, sell, or otherwise make the software or derivatives available to third parties.
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
|
|
||||||
By submitting a pull request or other contribution, you agree that:
|
|
||||||
|
|
||||||
- You grant the project maintainer(s) a non-exclusive, irrevocable, worldwide, royalty-free license to use, copy, modify, and distribute your contributions as part of the project.
|
|
||||||
- You certify that your contributions are your original work and that you have the right to submit them.
|
|
||||||
- You agree that your contributions are licensed under the same license as the rest of the project, unless explicitly stated otherwise.
|
|
||||||
|
|
||||||
## Disclaimer
|
|
||||||
|
|
||||||
This software is provided "as is", without warranty of any kind, express or implied. Use at your own risk.
|
|
||||||
@ -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`.
|
|
||||||
@ -14,4 +14,4 @@ todo
|
|||||||
|
|
||||||
#This extension asks for permission that isn't listed above.
|
#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).
|
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/xternal7/ultrawidify/issues).
|
||||||
269
README.md
@ -1,10 +1,4 @@
|
|||||||
# Ultrawidify — aspect ratio fixer for youtube and netflix
|
# 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
|
## TL;DR
|
||||||
|
|
||||||
@ -12,202 +6,34 @@ If you own an ultrawide monitor, you have probably noticed that sometimes videos
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Works (tested!) on Youtube and Netflix, but you can try your luck with other sites as well. Available for [Firefox](https://addons.mozilla.org/en/firefox/addon/ultrawidify/) and [Chrome](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi). Should support theater mode on youtube, iframes only supported on fullscreen.
|
||||||
|
|
||||||
## Known issues
|
Youtube demo of autodetection stuff can be found [here](https://www.youtube.com/watch?v=j2xn1WpbtCQ).
|
||||||
|
|
||||||
* 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.
|
## Beggathon
|
||||||
* Everything reported in [issues](https://github.com/tamius-han/ultrawidify/issues)
|
|
||||||
|
|
||||||
### Limitations
|
Working on this extension takes time, coffee and motivation. If you want to buy me a beer or something, you can [use this link to send me motivation](https://www.paypal.me/tamius). **Any donations are well appreciated.**
|
||||||
|
|
||||||
* Unclear how extension handles sites with more than one video per page.
|
## The long version
|
||||||
* 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
|
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.
|
||||||
|
|
||||||
* **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.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Most settings are self-explanatory, but we'll get into details anyway.
|
* **Fit video to width/height**
|
||||||
|
* **Force specific aspect ratio**
|
||||||
### Limitations:
|
* **Attempts to automatically detect aspect ratio**
|
||||||
|
* ~~**Rebindable shortcuts**~~ temporarily off
|
||||||
Before we go on to features, let's discuss limitations.
|
|
||||||
|
|
||||||
* 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.
|
|
||||||
|
|
||||||
|
|
||||||
### Automatic aspect ratio detection
|
### User interface
|
||||||
|
|
||||||
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.
|
Most quick options for a page are accessible through a button in the extension bar. The options are pretty self-explanatory.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### Cropping video
|
|
||||||
|
|
||||||

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

|
|
||||||
|
|
||||||
### 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:
|
|
||||||
|
|
||||||

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

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

|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
### Default keyboard shortcuts
|
### Default keyboard shortcuts
|
||||||
|
|
||||||
@ -220,30 +46,12 @@ The keyboard shortcuts have already been listed, but let's list them all again i
|
|||||||
`s` - force 16:9
|
`s` - force 16:9
|
||||||
`d` - force 21:9
|
`d` - force 21:9
|
||||||
`x` - force 18:9
|
`x` - force 18:9
|
||||||
`q` - force custom aspect ratio
|
|
||||||
|
|
||||||
`z` - zoom
|
### About aspect ratio autodetection
|
||||||
`u` - unzoom
|
|
||||||
`p` - toggle video panning
|
|
||||||
`shift`- pan video (while holding)
|
|
||||||
|
|
||||||
### Rebinding keyboard shortcuts
|
Aspect ratio autodetection is achieved by performing some black magic every 30-something milliseconds. This currently can't be turned off by default. If this extension makes video sites lag too much, open an issue and include your hardware and OS — **this is important for me to know in order to better optimize autodetection.**.
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
Manually triggering aspect ratio change will suspend automatic aspect ratio detection for until the page is refreshed, although it'll maybe unsuspend itself when video is changed. I don't know for certain.
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
@ -251,34 +59,33 @@ However, I do plan on implementing this feature. Hopefully by the end of the yea
|
|||||||
|
|
||||||
[Latest stable for Firefox — download from AMO](https://addons.mozilla.org/en/firefox/addon/ultrawidify/)
|
[Latest stable for Firefox — 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)
|
[Latest stafle 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) -->
|
|
||||||
|
|
||||||
### Installing the current, github version
|
### Installing the current, github version
|
||||||
|
|
||||||
## Get pre-built version:
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
## Build from source
|
|
||||||
|
|
||||||
Requirements: npm, node.
|
|
||||||
|
|
||||||
1. Clone this repo
|
1. Clone this repo
|
||||||
2. run `npm install`
|
2. Open up Firefox
|
||||||
3. If using **Firefox,** run: `npm run watch:dev`. If using **Chrome,** run: `npm run watch-chrome:dev`.
|
3. Go to `about:debugging`
|
||||||
|
|
||||||
TODO: see if #3 already loads the extension in FF
|
|
||||||
|
|
||||||
2. Open up Firefox (or Chrome)
|
|
||||||
3. Go to `about:debugging` (or Chrome equivalent)
|
|
||||||
4. Add temporary addon
|
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
|
||||||
|
|
||||||
|
* Netflix autodetection not working in Chrome, wontfix as issue is fundamentally unfixable. (Although a different kind of workaround could probably be put in place, but don't count on it)
|
||||||
|
* Everything reported in [issues](https://github.com/xternal7/ultrawidify/issues)
|
||||||
|
|
||||||
|
## Plans for the future
|
||||||
|
|
||||||
|
~~1. Handle porting of extension settings between versions. (Some people had some issues where extension broke until reinstalled, and corrupted settings seemed to be the problem.)~~ seems to work for me?
|
||||||
|
2. Reintroduce gradual zoom on z and u and provide a way to 'scroll' the zoomed in video up/down left/right
|
||||||
|
reintroduce settings page (rebindable keys, blacklist/whitelist management, some settings for automatic aspect ratio detection)
|
||||||
|
3. site-specific options for sites that require additional CSS classes or other hacks (see: vimeo, which is disabled)
|
||||||
|
4. 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
|
||||||
|
5. Stretch mode, because some people are very salty and toxic about the fact that this extension is here to solve a problem that's different than the one they want. More salty than me rn.
|
||||||
|
6. Improvements to automatic aspect ratio detection
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
see changelog.md
|
see changelog.md
|
||||||
|
|
||||||
todo: add link to changelog.md here
|
todo: add link to changelog.md here
|
||||||
|
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 |
42
js/conf/Debug.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Set prod to true when releasing
|
||||||
|
_prod = true;
|
||||||
|
// _prod = false;
|
||||||
|
|
||||||
|
Debug = {
|
||||||
|
debug: true,
|
||||||
|
keyboard: true,
|
||||||
|
debugResizer: true,
|
||||||
|
debugArDetect: true,
|
||||||
|
debugStorage: true,
|
||||||
|
// showArDetectCanvas: true,
|
||||||
|
flushStoredSettings: false,
|
||||||
|
playerDetectDebug: true,
|
||||||
|
arDetect: {
|
||||||
|
edgeDetect: true
|
||||||
|
},
|
||||||
|
canvas: {
|
||||||
|
debugDetection: true
|
||||||
|
},
|
||||||
|
debugCanvas: {
|
||||||
|
enabled: true,
|
||||||
|
guardLine: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_prod){
|
||||||
|
__disableAllDebug(Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __disableAllDebug(obj) {
|
||||||
|
for(key in obj) {
|
||||||
|
if (obj.hasOwnProperty(key) ){
|
||||||
|
if(obj[key] instanceof Object)
|
||||||
|
__disableAllDebug(obj[key]);
|
||||||
|
else
|
||||||
|
obj[key] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("Guess we're debugging ultrawidify then. Debug.js must always load first, and others must follow.\nLoading: Debug.js");
|
||||||
94
js/conf/ExtensionConf.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
if(Debug.debug)
|
||||||
|
console.log("Loading: ExtensionConf.js");
|
||||||
|
|
||||||
|
var ExtensionConf = {
|
||||||
|
extensionMode: "whitelist", // how should this extension work?
|
||||||
|
// 'blacklist' - work everywhere except blacklist
|
||||||
|
// 'whitelist' - only work on whitelisted sites
|
||||||
|
// 'disabled' - work nowhere
|
||||||
|
arDetect: {
|
||||||
|
mode: "blacklist", // how should autodetection work?
|
||||||
|
// 'blacklist' - work by default, problem sites need to be blocked
|
||||||
|
// 'whitelist' - only work if site has been specifically approved
|
||||||
|
// 'disabled' - don't work at all
|
||||||
|
disabledReason: "", // if automatic aspect ratio has been disabled, show reason
|
||||||
|
allowedMisaligned: 0.05, // top and bottom letterbox thickness can differ by this much.
|
||||||
|
// Any more and we don't adjust ar.
|
||||||
|
allowedArVariance: 0.075, // amount by which old ar can differ from the new (1 = 100%)
|
||||||
|
timer_playing: 666, // we trigger ar this often (in ms) under this conditions
|
||||||
|
timer_paused: 3000,
|
||||||
|
timer_error: 3000,
|
||||||
|
timer_minimumTimeout: 5, // but regardless of above, we wait this many msec before retriggering
|
||||||
|
autoDisable: { // settings for automatically disabling the extension
|
||||||
|
maxExecutionTime: 15, // if execution time of main autodetect loop exceeds this many milliseconds,
|
||||||
|
// we disable it.
|
||||||
|
consecutiveTimeoutCount: 5 // we only do it if it happens this many consecutive times
|
||||||
|
},
|
||||||
|
hSamples: 640,
|
||||||
|
vSamples: 360,
|
||||||
|
samplingInterval: 10, // we sample at columns at (width/this) * [ 1 .. this - 1]
|
||||||
|
blackLevel_default: 10, // everything darker than 10/255 across all RGB components is considered black by
|
||||||
|
// default. GlobalVars.blackLevel can decrease if we detect darker black.
|
||||||
|
blackbarTreshold: 16, // if pixel is darker than blackLevel + blackbarTreshold, 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
|
||||||
|
staticSampleCols: 9, // we take a column at [0-n]/n-th parts along the width and sample it
|
||||||
|
randomSampleCols: 0, // we add this many randomly selected columns to the static columns
|
||||||
|
staticSampleRows: 9, // 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: true,
|
||||||
|
ignoreEdgeMargin: 0.20, // we ignore anything that pokes over the black line this close to the edge
|
||||||
|
// (relative to width of the sample)
|
||||||
|
imageTestTreshold: 0.1, // when testing for image, this much pixels must be over blackbarTreshold
|
||||||
|
edgeTolerancePx: 3, // 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
|
||||||
|
},
|
||||||
|
fallbackMode: {
|
||||||
|
enabled: true,
|
||||||
|
safetyBorderPx: 5, // determines the thickness of safety border in fallback mode
|
||||||
|
noTriggerZonePx: 8 // if we detect edge less than this many pixels thick, we don't correct.
|
||||||
|
},
|
||||||
|
arSwitchLimiter: { // to be implemented
|
||||||
|
switches: 2, // we can switch this many times
|
||||||
|
period: 2.0 // per this period
|
||||||
|
},
|
||||||
|
edgeDetection: {
|
||||||
|
sampleWidth: 8, // we take a sample this wide for edge detection
|
||||||
|
detectionTreshold: 4, // sample needs to have this many non-black pixels to be a valid edge
|
||||||
|
singleSideConfirmationTreshold: 0.3, // 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)
|
||||||
|
logoTreshold: 0.15, // if edge candidate sits with count greater than this*all_samples, it can't be logo
|
||||||
|
// or watermark.
|
||||||
|
edgeTolerancePx: 2, // we check for black edge violation this far from detection point
|
||||||
|
edgeTolerancePercent: null, // we check for black edge detection this % of height from detection point. unused
|
||||||
|
middleIgnoredArea: 0.2, // we ignore this % of canvas height towards edges while detecting aspect ratios
|
||||||
|
minColsForSearch: 0.5, // 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)
|
||||||
|
edgeTolerancePx: 1, // tests for edge detection are performed this far away from detected row
|
||||||
|
},
|
||||||
|
pillarTest: {
|
||||||
|
ignoreThinPillarsPx: 5, // ignore pillars that are less than this many pixels thick.
|
||||||
|
allowMisaligned: 0.05 // left and right edge can vary this much (%)
|
||||||
|
},
|
||||||
|
textLineTest: {
|
||||||
|
nonTextPulse: 0.10, // 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: 10, // this is a treshold to confirm we're seeing text.
|
||||||
|
pulsesToConfirmIfHalfBlack: 5, // this is the treshold to confirm we're seeing text if longest black pulse
|
||||||
|
// is over 50% of the canvas width
|
||||||
|
testRowOffset: 0.02 // we test this % of height from detected edge
|
||||||
|
}
|
||||||
|
},
|
||||||
|
arChange: {
|
||||||
|
samenessTreshold: 0.025, // if aspect ratios are within 2.5% within each other, don't resize
|
||||||
|
},
|
||||||
|
miscFullscreenSettings: {
|
||||||
|
videoFloat: "center"
|
||||||
|
},
|
||||||
|
colors:{
|
||||||
|
// criticalFail: "background: #fa2; color: #000"
|
||||||
|
}
|
||||||
|
}
|
||||||
150
js/conf/Keybinds.js
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
if(Debug.debug)
|
||||||
|
console.log("Loading: Keybinds.js");
|
||||||
|
|
||||||
|
var _kbd_ModKeys = ["ctrlKey", "shiftKey", "altKey"];
|
||||||
|
var _kbd_keybinds = {};
|
||||||
|
|
||||||
|
var DEFAULT_KEYBINDINGS = {
|
||||||
|
"w": {
|
||||||
|
action: "fitw"
|
||||||
|
},
|
||||||
|
"e": {
|
||||||
|
action: "fith"
|
||||||
|
},
|
||||||
|
"r": {
|
||||||
|
action: "reset"
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
action: "autoar"
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
action: "char",
|
||||||
|
targetAr: 1.78
|
||||||
|
},
|
||||||
|
"d": {
|
||||||
|
action: "char",
|
||||||
|
targetAr: 2.39
|
||||||
|
},
|
||||||
|
"x": {
|
||||||
|
action: "char",
|
||||||
|
targetAr: 2.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _kbd_process = function (event) { // Tukaj ugotovimo, katero tipko smo pritisnili
|
||||||
|
|
||||||
|
if(Debug.debug && Debug.keyboard ){
|
||||||
|
console.log("%c[Keybinds::_kbd_process] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tipke upoštevamo samo, če smo v celozaslonskem načinu oz. če ne pišemo komentarja
|
||||||
|
// v nasprotnem primeru ne naredimo nič.
|
||||||
|
// We only take actions if we're in full screen or not writing a comment
|
||||||
|
if( !(PlayerDetect.isFullScreen() || (
|
||||||
|
(document.activeElement.getAttribute("role") != "textbox") &&
|
||||||
|
(document.activeElement.getAttribute("type") != "text")
|
||||||
|
))){
|
||||||
|
if(Debug.debug && Debug.keyboard)
|
||||||
|
console.log("[Keybinds::_kbd_process] We're writing a comment or something. Doing nothing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// building modifiers list:
|
||||||
|
var modlist = "";
|
||||||
|
for(var mod of _kbd_ModKeys){
|
||||||
|
if(event[mod])
|
||||||
|
modlist += (mod + "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug && Debug.keyboard ){
|
||||||
|
if(modlist)
|
||||||
|
console.log("[Keybinds::_kbd_process] there's been modifier keys. Modlist:", modlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
var keypress = modlist + event.key.toLowerCase();
|
||||||
|
|
||||||
|
if(Debug.debug && Debug.keyboard )
|
||||||
|
console.log("[Keybinds::_kbd_process] our full keypress is this", keypress, "_kbd_keybinds:", {kb: _kbd_keybinds} );
|
||||||
|
|
||||||
|
|
||||||
|
if(_kbd_keybinds[keypress]){
|
||||||
|
var conf = _kbd_keybinds[keypress];
|
||||||
|
|
||||||
|
if(Debug.debug && Debug.keyboard)
|
||||||
|
console.log("[Keybinds::_kbd_process] there's an action associated with this keypress. conf:", conf);
|
||||||
|
|
||||||
|
if(conf.action != "autoar")
|
||||||
|
ArDetect.stop();
|
||||||
|
|
||||||
|
if(conf.action == "char"){
|
||||||
|
Resizer.setAr(conf.targetAr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Resizer.legacyAr(conf.action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _kbd_load = async function() {
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Keybinds::_kbd_setup_init] Setting up keybinds");
|
||||||
|
|
||||||
|
var ret = await StorageManager.getopt_async("keybinds");
|
||||||
|
|
||||||
|
// var keybinds = ret.keybinds;
|
||||||
|
var keybinds = {};
|
||||||
|
|
||||||
|
if(Array.isArray(keybinds)){
|
||||||
|
StorageManager.delopt("keybinds");
|
||||||
|
keybinds = DEFAULT_KEYBINDINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Keybinds::_kbd_setup_init] loaded keybinds from storage. Do they exist?", keybinds, $.isEmptyObject(keybinds));
|
||||||
|
|
||||||
|
if( $.isEmptyObject(keybinds) ){
|
||||||
|
keybinds = DEFAULT_KEYBINDINGS;
|
||||||
|
StorageManager.setopt({"keybinds":keybinds});
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Keybinds::_kbd_setup_init] setting keybinds to default", keybinds);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keybinds = keybinds;
|
||||||
|
_kbd_keybinds = keybinds;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _kbd_setup = async function() {
|
||||||
|
await _kbd_load();
|
||||||
|
|
||||||
|
document.addEventListener('keydown', _kbd_process);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _kbd_fetch = async function(){
|
||||||
|
if($.isEmptyObject(_kbd_keybinds)){
|
||||||
|
await _kbd_load();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Keybinds::_kbd_fetch] We'll be returning this:", _kbd_keybinds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _kbd_keybinds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var _kbd_getKeybinds = function(){
|
||||||
|
return _kbd_keybinds;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Keybinds = {
|
||||||
|
init: _kbd_setup,
|
||||||
|
fetch: _kbd_fetch,
|
||||||
|
mods: _kbd_ModKeys,
|
||||||
|
getKeybinds: _kbd_getKeybinds,
|
||||||
|
keybinds: _kbd_keybinds
|
||||||
|
}
|
||||||
107
js/conf/Settings.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// This file handles saving and loading of settings.
|
||||||
|
// Actual settings are in ExtensionConf
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("Loading: Settings.js");
|
||||||
|
|
||||||
|
var _se_init = async function(isSlave){
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Settings::_se_init()] -------- starting init! ---------");
|
||||||
|
|
||||||
|
if(isSlave === undefined)
|
||||||
|
isSlave = false;
|
||||||
|
|
||||||
|
if(isSlave){
|
||||||
|
// request settings from background script. Yes, this is supposed to be global.
|
||||||
|
var res = await Comms.sendToBackgroundScript({cmd: "gib-settings"});
|
||||||
|
|
||||||
|
ExtensionConf = res.response;
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Settings::_se_init()] received settings from the background script. ExtensionConf:",ExtensionConf,"response message was this:",res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var newSettings = await StorageManager.getopt_async("uw-settings");
|
||||||
|
var uwVersion = browser.runtime.getManifest().version;
|
||||||
|
|
||||||
|
if (Debug.debug)
|
||||||
|
console.log("[Settings::_se_init()] settings saved in localstorage are:", newSettings, " - if that's empty, it's gonna be replaced by this:", ExtensionConf, ")");
|
||||||
|
|
||||||
|
if ((Object.keys(newSettings).length === 0 && newSettings.constructor === Object)){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Settings::_se_init()] no saved settings, saving default");
|
||||||
|
StorageManager.setopt({"uw-settings": ExtensionConf});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
var actualSettings = newSettings["uw-settings"];
|
||||||
|
if(actualSettings.version === undefined || actualSettings.version != uwVersion){
|
||||||
|
ExtensionConf['version'] = uwVersion;
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Settings::_se_init()] extension was updated, replacing settings", ExtensionConf);
|
||||||
|
|
||||||
|
StorageManager.setopt({"uw-settings": ExtensionConf});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_se_patchUserSettings(actualSettings, ExtensionConf);
|
||||||
|
}
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Settings::_se_init()] parsed settings:", actualSettings, "were they copied to ExtensionConf?",ExtensionConf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Settings::_se_init] settings have been loaded/reloaded. Current state: ", ExtensionConf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _se_patchUserSettings = function(saved, extDefaults){
|
||||||
|
for(var k in extDefaults){
|
||||||
|
if(extDefaults[k] != null && typeof extDefaults[k] === 'object' && extDefaults[k].constructor === Object){
|
||||||
|
if(typeof saved[k] !== 'object' || saved[k].constructor !== Object)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_se_patchUserSettings(saved[k], extDefaults[k]);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
extDefaults[k] = saved[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _se_save = function(settings){
|
||||||
|
StorageManager.delopt("uw-settings");
|
||||||
|
|
||||||
|
if(settings !== undefined){
|
||||||
|
StorageManager.setopt({"uw-settings": settings});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
StorageManager.setopt({"uw-settings": ExtensionConf});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Debug.debug)
|
||||||
|
console.log("[Settings::_se_save()] saving settings:", settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _se_reload = function(){
|
||||||
|
this.init(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _se_isBlacklisted = function(site){
|
||||||
|
return this.blacklist.indexOf(site) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _se_isWhitelisted = function(site){
|
||||||
|
return this.whitelist.indexOf(site) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Settings = {
|
||||||
|
init: _se_init,
|
||||||
|
save: _se_save,
|
||||||
|
reload: _se_reload,
|
||||||
|
}
|
||||||
274
js/conf/SitesConf.js
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
if(Debug.debug){
|
||||||
|
console.log("Loading: SitesConf.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nastavitve za posamezno stran
|
||||||
|
// Config for a given page:
|
||||||
|
//
|
||||||
|
// <hostname> : {
|
||||||
|
// status: <option> // should extension work on this site?
|
||||||
|
// arStatus: <option> // should we do autodetection on this site?
|
||||||
|
// statusEmbedded: <option> // should we do autodetection on this site?
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Veljavne vrednosti za možnosti
|
||||||
|
// Valid values for options:
|
||||||
|
//
|
||||||
|
// status, arStatus, statusEmbedded:
|
||||||
|
//
|
||||||
|
// * whitelisted — always allow
|
||||||
|
// * follow-global — allow if default is to allow, block if default is to block
|
||||||
|
// * blacklisted — never allow
|
||||||
|
//
|
||||||
|
|
||||||
|
var _sc_sites = {
|
||||||
|
"www.youtube.com" : {
|
||||||
|
status: "whitelisted", // should extension work on this site?
|
||||||
|
arStatus: "follow-global", // should we enable autodetection
|
||||||
|
statusEmbedded: "whitelisted", // should extension work for this site when embedded on other sites?
|
||||||
|
override: false // ignore value localStorage in favour of this
|
||||||
|
},
|
||||||
|
"www.netflix.com" : {
|
||||||
|
status: "whitelisted",
|
||||||
|
arStatus: "blacklisted",
|
||||||
|
statusEmbedded: "whitelisted",
|
||||||
|
override: false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// var _sc_SITES = {
|
||||||
|
// "vimeo.com" : {
|
||||||
|
// extraCss: [],
|
||||||
|
// bannedCss: [],
|
||||||
|
// nonfsPlayerMod: function(){
|
||||||
|
// // hack player to take all the width
|
||||||
|
// $("head").append('<style type="text/css">.uw_forceFullWidth {width: 100% !important} .uw_forceCenter{text-align: center;}</style>');
|
||||||
|
//
|
||||||
|
// var e = document.getElementsByClassName("player_outro_area")[0];
|
||||||
|
// e.classList.add("uw_forceFullWidth");
|
||||||
|
// e.classList.add("uw_forceCenter");
|
||||||
|
// e = document.getElementsByClassName("player_container")[0];
|
||||||
|
// e.classList.add("uw_forceFullWidth");
|
||||||
|
// e.classList.add("uw_forceCenter");
|
||||||
|
//
|
||||||
|
// $("video")[0].style.display = "inline-block";
|
||||||
|
// },
|
||||||
|
// fsPlayerMod: function(){
|
||||||
|
// // hack player to take all the width
|
||||||
|
// $("head").append('<style type="text/css">.uw_forceFullWidth {width: 100% !important} .uw_forceCenter{text-align: center;}</style>');
|
||||||
|
//
|
||||||
|
// var e = document.getElementsByClassName("player_outro_area")[0];
|
||||||
|
// e.classList.add("uw_forceFullWidth");
|
||||||
|
// e.classList.add("uw_forceCenter");
|
||||||
|
// e = document.getElementsByClassName("player_container")[0];
|
||||||
|
// e.classList.add("uw_forceFullWidth");
|
||||||
|
// e.classList.add("uw_forceCenter");
|
||||||
|
//
|
||||||
|
// $("video")[0].style.display = "inline-block";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
var _sc_init = async function(){
|
||||||
|
|
||||||
|
var newSettings = await StorageManager.getopt_async("uw-siteopts");
|
||||||
|
|
||||||
|
if (Debug.debug)
|
||||||
|
console.log("[SitesConf::_sc_init()] settings saved in localstorage are:", newSettings, " - if that's empty, it's gonna be replaced by this:", JSON.stringify(_sc_sites), ")");
|
||||||
|
|
||||||
|
if ((Object.keys(newSettings).length === 0 && newSettings.constructor === Object)){
|
||||||
|
console.log("[SitesConf::_sc_init()] replacing settings");
|
||||||
|
StorageManager.setopt({"uw-siteopts": JSON.stringify(_sc_sites)});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
var actualSettings = JSON.parse(newSettings["uw-siteopts"]);
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[SitesConf::_sc_init()] parsed settings:", actualSettings);
|
||||||
|
|
||||||
|
var overrides = 0;
|
||||||
|
|
||||||
|
for (var k in actualSettings){
|
||||||
|
|
||||||
|
// let sites with override=true override saved sites
|
||||||
|
if( _sc_sites[k] != undefined && _sc_sites[k].override ){
|
||||||
|
++overrides;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sc_sites[k] = actualSettings[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(overrides > 0)
|
||||||
|
_sc_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[SitesConf::_sc_init()] settings have been loaded/reloaded. Current state: ", this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_reset = function(){
|
||||||
|
StoreManager.delopt("uw-siteopts");
|
||||||
|
_sc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_reload = function(){
|
||||||
|
_sc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_save = function(){
|
||||||
|
StorageManager.delopt("uw-siteopts");
|
||||||
|
StorageManager.setopt({"uw-siteopts": JSON.stringify(_sc_sites)});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _sc_createEmptySite = function(){
|
||||||
|
return {
|
||||||
|
status: "follow-global",
|
||||||
|
arStatus: "follow-global",
|
||||||
|
statusEmbedded: "follow-global",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function inIframe(){
|
||||||
|
try {
|
||||||
|
return window.self !== window.top;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_isEnabled = function(site){
|
||||||
|
// console.log(".... — _sc_sites[", site, "].status:", (_sc_sites[site] == undefined ? "<default>" : _sc_sites[site].status), "; ExtensionConf.extensionMode:", ExtensionConf.extensionMode)
|
||||||
|
if( inIframe ) {
|
||||||
|
return _sc_siteEnableEmbedded(site);
|
||||||
|
}
|
||||||
|
return _sc_siteEnabled(site);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_siteEnabled = function(site){
|
||||||
|
|
||||||
|
// če za stran nismo določili načina delovanja, potem storimo privzeto stvar
|
||||||
|
// if we haven't defined options for a site, we do the default thing
|
||||||
|
if( _sc_sites[site] == undefined || _sc_sites[site].status == "follow-global"){
|
||||||
|
|
||||||
|
console.log(".... this site is undefined!");
|
||||||
|
|
||||||
|
if ( ExtensionConf.extensionMode == "blacklist" ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _sc_sites[site].status == "whitelisted" )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( _sc_sites[site].status == "blacklisted" )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// sem ne bi smeli priti, vendar pa za varnost naredimo en return
|
||||||
|
// we shouldn't come here but let's do a safety return
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_siteStatus = function(site){
|
||||||
|
if( _sc_sites[site] == undefined)
|
||||||
|
return "follow-global";
|
||||||
|
return _sc_sites[site].status;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_arEnabled = function(site){
|
||||||
|
|
||||||
|
if( _sc_sites[site] == undefined || _sc_sites[site].arStatus == "follow-global" ){
|
||||||
|
if(ExtensionConf.extensionMode == "blacklist" ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _sc_sites[site].arStatus == "whitelisted" )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( _sc_sites[site].arStatus == "blacklisted" )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_arStatus = function(site){
|
||||||
|
if( _sc_sites[site] == undefined )
|
||||||
|
return "follow-global";
|
||||||
|
return _sc_sites[site].arStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_siteEnableEmbedded = function(site) {
|
||||||
|
|
||||||
|
if( _sc_sites[site] == undefined || _sc_sites[site].statusEmbedded == "follow-global" ){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[SitesConf::_sc_siteEnableEmbedded] site", site, "is not defined in settings.");
|
||||||
|
|
||||||
|
if(ExtensionConf.extensionMode == "blacklist" ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _sc_sites[site].statusEmbedded == "whitelisted" )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( _sc_sites[site].statusEmbedded == "blacklisted" )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sc_updateSiteStatus = function(site, status){
|
||||||
|
// status: {}
|
||||||
|
// status.status - optional
|
||||||
|
// status.arStatus - optional
|
||||||
|
// status.statusEmbedded - optional
|
||||||
|
//
|
||||||
|
// <==[ Valid values for options: ]==>
|
||||||
|
//
|
||||||
|
// status, arStatus, statusEmbedded:
|
||||||
|
//
|
||||||
|
// * whitelisted — always allow
|
||||||
|
// * follow-global — allow if default is to allow, block if default is to block
|
||||||
|
// * blacklisted — never allow
|
||||||
|
|
||||||
|
if( _sc_sites[site] == undefined ){
|
||||||
|
_sc_sites[site] = _sc_createEmptySite();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.status != undefined ){
|
||||||
|
_sc_sites[site].status = status.status;
|
||||||
|
}
|
||||||
|
if(status.arStatus != undefined ){
|
||||||
|
_sc_sites[site].arStatus = status.arStatus;
|
||||||
|
}
|
||||||
|
if(status.statusEmbedded != undefined ){
|
||||||
|
_sc_sites[site].statusEmbedded = status.statusEmbedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sc_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SitesConf = {
|
||||||
|
siteopts: _sc_sites,
|
||||||
|
init: _sc_init,
|
||||||
|
reset: _sc_reset,
|
||||||
|
reload: _sc_reload,
|
||||||
|
save: _sc_save,
|
||||||
|
updateSiteStatus: _sc_updateSiteStatus,
|
||||||
|
updateSite: _sc_updateSiteStatus,
|
||||||
|
getSiteStatus: _sc_siteStatus,
|
||||||
|
getArStatus: _sc_arStatus,
|
||||||
|
siteEnabled: _sc_siteEnabled,
|
||||||
|
isEnabled: _sc_isEnabled,
|
||||||
|
siteEnableEmbedded: _sc_siteEnableEmbedded,
|
||||||
|
arEnabled: _sc_arEnabled,
|
||||||
|
isArEnabled: _sc_arEnabled
|
||||||
|
}
|
||||||
3
js/conf/Status.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
var Status = {
|
||||||
|
arStrat: "auto"
|
||||||
|
}
|
||||||
250
js/dep/chrome/chrome-extension-async.js
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/** Wrap an API that uses callbacks with Promises
|
||||||
|
* This expects the pattern function withCallback(arg1, arg2, ... argN, callback)
|
||||||
|
* @author Keith Henry <keith.henry@evolutionjobs.co.uk>
|
||||||
|
* @license MIT */
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
// before we start: don't do shit in browsers that aren't Google Chrome.
|
||||||
|
// We might need to modify this for use in IE at a later date tho
|
||||||
|
if(chrome === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** Wrap a function with a callback with a Promise.
|
||||||
|
* @param {function} f The function to wrap, should be pattern: withCallback(arg1, arg2, ... argN, callback).
|
||||||
|
* @param {function} parseCB Optional function to parse multiple callback parameters into a single object.
|
||||||
|
* @returns {Promise} Promise that resolves when the callback fires. */
|
||||||
|
function promisify(f, parseCB) {
|
||||||
|
return (...args) => {
|
||||||
|
let safeArgs = args;
|
||||||
|
let callback;
|
||||||
|
// The Chrome API functions all use arguments, so we can't use f.length to check
|
||||||
|
|
||||||
|
// If there is a last arg
|
||||||
|
if (args && args.length > 0) {
|
||||||
|
|
||||||
|
// ... and the last arg is a function
|
||||||
|
const last = args[args.length - 1];
|
||||||
|
if (typeof last === 'function') {
|
||||||
|
// Trim the last callback arg if it's been passed
|
||||||
|
safeArgs = args.slice(0, args.length - 1);
|
||||||
|
callback = last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a promise
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
// Try to run the original function, with the trimmed args list
|
||||||
|
f(...safeArgs, (...cbArgs) => {
|
||||||
|
|
||||||
|
// If a callback was passed at the end of the original arguments
|
||||||
|
if (callback) {
|
||||||
|
// Don't allow a bug in the callback to stop the promise resolving
|
||||||
|
try { callback(...cbArgs); }
|
||||||
|
catch (cbErr) { reject(cbErr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chrome extensions always fire the callback, but populate chrome.runtime.lastError with exception details
|
||||||
|
if (chrome.runtime.lastError)
|
||||||
|
// Return as an error for the awaited catch block
|
||||||
|
reject(new Error(chrome.runtime.lastError.message || `Error thrown by API ${chrome.runtime.lastError}`));
|
||||||
|
else {
|
||||||
|
if (parseCB) {
|
||||||
|
const cbObj = parseCB(...cbArgs);
|
||||||
|
resolve(cbObj);
|
||||||
|
}
|
||||||
|
else if (!cbArgs || cbArgs.length === 0)
|
||||||
|
resolve();
|
||||||
|
else if (cbArgs.length === 1)
|
||||||
|
resolve(cbArgs[0]);
|
||||||
|
else
|
||||||
|
resolve(cbArgs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) { reject(err); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Promisify all the known functions in the map
|
||||||
|
* @param {object} api The Chrome native API to extend
|
||||||
|
* @param {Array} apiMap Collection of sub-API and functions to promisify */
|
||||||
|
function applyMap(api, apiMap) {
|
||||||
|
if (!api)
|
||||||
|
// Not supported by current permissions
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (let funcDef of apiMap) {
|
||||||
|
let funcName;
|
||||||
|
if (typeof funcDef === 'string')
|
||||||
|
funcName = funcDef;
|
||||||
|
else {
|
||||||
|
funcName = funcDef.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!api.hasOwnProperty(funcName))
|
||||||
|
// Member not in API
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const m = api[funcName];
|
||||||
|
if (typeof m === 'function')
|
||||||
|
// This is a function, wrap in a promise
|
||||||
|
api[funcName] = promisify(m, funcDef.cb);
|
||||||
|
else
|
||||||
|
// Sub-API, recurse this func with the mapped props
|
||||||
|
applyMap(m, funcDef.props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Apply promise-maps to the Chrome native API.
|
||||||
|
* @param {object} apiMaps The API to apply. */
|
||||||
|
function applyMaps(apiMaps) {
|
||||||
|
for (let apiName in apiMaps) {
|
||||||
|
const callbackApi = chrome[apiName];
|
||||||
|
if (!callbackApi)
|
||||||
|
// Not supported by current permissions
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const apiMap = apiMaps[apiName];
|
||||||
|
applyMap(callbackApi, apiMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// accessibilityFeatures https://developer.chrome.com/extensions/accessibilityFeatures
|
||||||
|
const knownA11ySetting = ['get', 'set', 'clear'];
|
||||||
|
|
||||||
|
// ContentSetting https://developer.chrome.com/extensions/contentSettings#type-ContentSetting
|
||||||
|
const knownInContentSetting = ['clear', 'get', 'set', 'getResourceIdentifiers'];
|
||||||
|
|
||||||
|
// StorageArea https://developer.chrome.com/extensions/storage#type-StorageArea
|
||||||
|
const knownInStorageArea = ['get', 'getBytesInUse', 'set', 'remove', 'clear'];
|
||||||
|
|
||||||
|
/** Map of API functions that follow the callback pattern that we can 'promisify' */
|
||||||
|
applyMaps({
|
||||||
|
accessibilityFeatures: [ // Todo: this should extend AccessibilityFeaturesSetting.prototype instead
|
||||||
|
{ n: 'spokenFeedback', props: knownA11ySetting },
|
||||||
|
{ n: 'largeCursor', props: knownA11ySetting },
|
||||||
|
{ n: 'stickyKeys', props: knownA11ySetting },
|
||||||
|
{ n: 'highContrast', props: knownA11ySetting },
|
||||||
|
{ n: 'screenMagnifier', props: knownA11ySetting },
|
||||||
|
{ n: 'autoclick', props: knownA11ySetting },
|
||||||
|
{ n: 'virtualKeyboard', props: knownA11ySetting },
|
||||||
|
{ n: 'animationPolicy', props: knownA11ySetting }],
|
||||||
|
alarms: ['get', 'getAll', 'clear', 'clearAll'],
|
||||||
|
bookmarks: [
|
||||||
|
'get', 'getChildren', 'getRecent', 'getTree', 'getSubTree',
|
||||||
|
'search', 'create', 'move', 'update', 'remove', 'removeTree'],
|
||||||
|
browser: ['openTab'],
|
||||||
|
browserAction: [
|
||||||
|
'getTitle', 'setIcon', 'getPopup', 'getBadgeText', 'getBadgeBackgroundColor'],
|
||||||
|
browsingData: [
|
||||||
|
'settings', 'remove', 'removeAppcache', 'removeCache',
|
||||||
|
'removeCookies', 'removeDownloads', 'removeFileSystems',
|
||||||
|
'removeFormData', 'removeHistory', 'removeIndexedDB',
|
||||||
|
'removeLocalStorage', 'removePluginData', 'removePasswords',
|
||||||
|
'removeWebSQL'],
|
||||||
|
commands: ['getAll'],
|
||||||
|
contentSettings: [ // Todo: this should extend ContentSetting.prototype instead
|
||||||
|
{ n: 'cookies', props: knownInContentSetting },
|
||||||
|
{ n: 'images', props: knownInContentSetting },
|
||||||
|
{ n: 'javascript', props: knownInContentSetting },
|
||||||
|
{ n: 'location', props: knownInContentSetting },
|
||||||
|
{ n: 'plugins', props: knownInContentSetting },
|
||||||
|
{ n: 'popups', props: knownInContentSetting },
|
||||||
|
{ n: 'notifications', props: knownInContentSetting },
|
||||||
|
{ n: 'fullscreen', props: knownInContentSetting },
|
||||||
|
{ n: 'mouselock', props: knownInContentSetting },
|
||||||
|
{ n: 'microphone', props: knownInContentSetting },
|
||||||
|
{ n: 'camera', props: knownInContentSetting },
|
||||||
|
{ n: 'unsandboxedPlugins', props: knownInContentSetting },
|
||||||
|
{ n: 'automaticDownloads', props: knownInContentSetting }],
|
||||||
|
contextMenus: ['create', 'update', 'remove', 'removeAll'],
|
||||||
|
cookies: ['get', 'getAll', 'set', 'remove', 'getAllCookieStores'],
|
||||||
|
debugger: ['attach', 'detach', 'sendCommand', 'getTargets'],
|
||||||
|
desktopCapture: ['chooseDesktopMedia'],
|
||||||
|
// TODO: devtools.*
|
||||||
|
documentScan: ['scan'],
|
||||||
|
downloads: [
|
||||||
|
'download', 'search', 'pause', 'resume', 'cancel',
|
||||||
|
'getFileIcon', 'erase', 'removeFile', 'acceptDanger'],
|
||||||
|
enterprise: [{ n: 'platformKeys', props: ['getToken', 'getCertificates', 'importCertificate', 'removeCertificate'] }],
|
||||||
|
extension: ['isAllowedIncognitoAccess', 'isAllowedFileSchemeAccess'], // mostly deprecated in favour of runtime
|
||||||
|
fileBrowserHandler: ['selectFile'],
|
||||||
|
fileSystemProvider: ['mount', 'unmount', 'getAll', 'get', 'notify'],
|
||||||
|
fontSettings: [
|
||||||
|
'setDefaultFontSize', 'getFont', 'getDefaultFontSize', 'getMinimumFontSize',
|
||||||
|
'setMinimumFontSize', 'getDefaultFixedFontSize', 'clearDefaultFontSize',
|
||||||
|
'setDefaultFixedFontSize', 'clearFont', 'setFont', 'clearMinimumFontSize',
|
||||||
|
'getFontList', 'clearDefaultFixedFontSize'],
|
||||||
|
gcm: ['register', 'unregister', 'send'],
|
||||||
|
history: ['search', 'getVisits', 'addUrl', 'deleteUrl', 'deleteRange', 'deleteAll'],
|
||||||
|
i18n: ['getAcceptLanguages', 'detectLanguage'],
|
||||||
|
identity: [
|
||||||
|
'getAuthToken', 'getProfileUserInfo', 'removeCachedAuthToken',
|
||||||
|
'launchWebAuthFlow', 'getRedirectURL'],
|
||||||
|
idle: ['queryState'],
|
||||||
|
input: [{
|
||||||
|
n: 'ime', props: [
|
||||||
|
'setMenuItems', 'commitText', 'setCandidates', 'setComposition', 'updateMenuItems',
|
||||||
|
'setCandidateWindowProperties', 'clearComposition', 'setCursorPosition', 'sendKeyEvents',
|
||||||
|
'deleteSurroundingText']
|
||||||
|
}],
|
||||||
|
management: [
|
||||||
|
'setEnabled', 'getPermissionWarningsById', 'get', 'getAll',
|
||||||
|
'getPermissionWarningsByManifest', 'launchApp', 'uninstall', 'getSelf',
|
||||||
|
'uninstallSelf', 'createAppShortcut', 'setLaunchType', 'generateAppForLink'],
|
||||||
|
networking: [{ n: 'config', props: ['setNetworkFilter', 'finishAuthentication'] }],
|
||||||
|
notifications: ['create', 'update', 'clear', 'getAll', 'getPermissionLevel'],
|
||||||
|
pageAction: ['getTitle', 'setIcon', 'getPopup'],
|
||||||
|
pageCapture: ['saveAsMHTML'],
|
||||||
|
permissions: ['getAll', 'contains', 'request', 'remove'],
|
||||||
|
platformKeys: ['selectClientCertificates', 'verifyTLSServerCertificate',
|
||||||
|
{ n: "getKeyPair", cb: (publicKey, privateKey) => { return { publicKey, privateKey }; } }],
|
||||||
|
runtime: [
|
||||||
|
'getBackgroundPage', 'openOptionsPage', 'setUninstallURL',
|
||||||
|
'restartAfterDelay', 'sendMessage',
|
||||||
|
'sendNativeMessage', 'getPlatformInfo', 'getPackageDirectoryEntry',
|
||||||
|
{ n: "requestUpdateCheck", cb: (status, details) => { return { status, details }; } }],
|
||||||
|
scriptBadge: ['getPopup'],
|
||||||
|
sessions: ['getRecentlyClosed', 'getDevices', 'restore'],
|
||||||
|
storage: [ // Todo: this should extend StorageArea.prototype instead
|
||||||
|
{ n: 'sync', props: knownInStorageArea },
|
||||||
|
{ n: 'local', props: knownInStorageArea },
|
||||||
|
{ n: 'managed', props: knownInStorageArea }],
|
||||||
|
socket: [
|
||||||
|
'create', 'connect', 'bind', 'read', 'write', 'recvFrom', 'sendTo',
|
||||||
|
'listen', 'accept', 'setKeepAlive', 'setNoDelay', 'getInfo', 'getNetworkList'],
|
||||||
|
sockets: [
|
||||||
|
{ n: 'tcp', props: [
|
||||||
|
'create','update','setPaused','setKeepAlive','setNoDelay','connect',
|
||||||
|
'disconnect','secure','send','close','getInfo','getSockets'] },
|
||||||
|
{ n: 'tcpServer', props: [
|
||||||
|
'create','update','setPaused','listen','disconnect','close','getInfo','getSockets'] },
|
||||||
|
{ n: 'udp', props: [
|
||||||
|
'create','update','setPaused','bind','send','close','getInfo',
|
||||||
|
'getSockets','joinGroup','leaveGroup','setMulticastTimeToLive',
|
||||||
|
'setMulticastLoopbackMode','getJoinedGroups','setBroadcast'] }],
|
||||||
|
system: [
|
||||||
|
{ n: 'cpu', props: ['getInfo'] },
|
||||||
|
{ n: 'memory', props: ['getInfo'] },
|
||||||
|
{ n: 'storage', props: ['getInfo', 'ejectDevice', 'getAvailableCapacity'] }],
|
||||||
|
tabCapture: ['capture', 'getCapturedTabs'],
|
||||||
|
tabs: [
|
||||||
|
'get', 'getCurrent', 'sendMessage', 'create', 'duplicate',
|
||||||
|
'query', 'highlight', 'update', 'move', 'reload', 'remove',
|
||||||
|
'detectLanguage', 'captureVisibleTab', 'executeScript',
|
||||||
|
'insertCSS', 'setZoom', 'getZoom', 'setZoomSettings',
|
||||||
|
'getZoomSettings', 'discard'],
|
||||||
|
topSites: ['get'],
|
||||||
|
tts: ['isSpeaking', 'getVoices', 'speak'],
|
||||||
|
types: ['set', 'get', 'clear'],
|
||||||
|
vpnProvider: ['createConfig', 'destroyConfig', 'setParameters', 'sendPacket', 'notifyConnectionStateChanged'],
|
||||||
|
wallpaper: ['setWallpaper'],
|
||||||
|
webNavigation: ['getFrame', 'getAllFrames', 'handlerBehaviorChanged'],
|
||||||
|
windows: ['get', 'getCurrent', 'getLastFocused', 'getAll', 'create', 'update', 'remove']
|
||||||
|
});
|
||||||
|
})();
|
||||||
10220
js/dep/jquery-3.1.1.js
vendored
Normal file
30
js/lib/BrowserDetect.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
var _bd_usebrowser = "firefox";
|
||||||
|
|
||||||
|
var _bd_isFirefox = false;
|
||||||
|
var _bd_isChrome = false;
|
||||||
|
var _bd_isEdge = true; // we'll see if FF
|
||||||
|
|
||||||
|
try{
|
||||||
|
// this will fail in Edge
|
||||||
|
|
||||||
|
var promise = browser.runtime.getBrowserInfo();
|
||||||
|
_bd_isFirefox = true;
|
||||||
|
_bd_isEdge = false;
|
||||||
|
}
|
||||||
|
catch (e) {};
|
||||||
|
|
||||||
|
if(typeof browser === "undefined"){ // This is a good sign we're in chrome or chromium-based browsers
|
||||||
|
if(chrome){
|
||||||
|
browser = chrome;
|
||||||
|
_bd_usebrowser = "chrome";
|
||||||
|
_bd_isChrome = true;
|
||||||
|
_bd_isEdge = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var BrowserDetect = {
|
||||||
|
usebrowser: _bd_usebrowser,
|
||||||
|
firefox: _bd_isFirefox,
|
||||||
|
chrome: _bd_isChrome,
|
||||||
|
edge: _bd_isEdge
|
||||||
|
}
|
||||||
184
js/lib/Comms.js
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
var _com_chrome_tabquery_wrapper = async function(tabInfo){
|
||||||
|
return new Promise(function (resolve, reject){
|
||||||
|
browser.tabs.query(tabInfo, function(response){
|
||||||
|
browser.tabs.query(tabInfo);
|
||||||
|
// Chrome/js shittiness mitigation — remove this line and an empty array will be returned
|
||||||
|
var r = response;
|
||||||
|
resolve(r);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _com_queryTabs = async function(tabInfo){
|
||||||
|
if(BrowserDetect.usebrowser != "firefox"){
|
||||||
|
return await _com_chrome_tabquery_wrapper(tabInfo);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return browser.tabs.query(tabInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _com_getActiveTab = async function(tabInfo){
|
||||||
|
if(BrowserDetect.firefox){
|
||||||
|
return await browser.tabs.query({currentWindow: true, active: true});
|
||||||
|
}
|
||||||
|
return _com_chrome_tabquery_wrapper({currentWindow: true, active: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _com_chrome_tabs_sendmsg_wrapper = async function(tab, message, options){
|
||||||
|
return new Promise(function (resolve, reject){
|
||||||
|
try{
|
||||||
|
browser.tabs.sendMessage(tab, message, /*options, */function(response){
|
||||||
|
console.log("TESTING what is this owo? (response)", response);
|
||||||
|
|
||||||
|
// Chrome/js shittiness mitigation — remove this line and an empty array will be returned
|
||||||
|
var r = response;
|
||||||
|
|
||||||
|
resolve(r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var _com_sendMessage = async function(tab, message, options){
|
||||||
|
if(BrowserDetect.usebrowser != "firefox"){
|
||||||
|
var r = await _com_chrome_tabs_sendmsg_wrapper(tab, message, options);
|
||||||
|
console.log("TESTING what is this owo? (should be a promise)", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return browser.tabs.sendMessage(tab, message, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _com_chrome_tabs_sendmsgrt_wrapper = async function(message){
|
||||||
|
return new Promise(function (resolve, reject){
|
||||||
|
try{
|
||||||
|
browser.runtime.sendMessage(message, function(response){
|
||||||
|
|
||||||
|
// Chrome/js shittiness mitigation — remove this line and an empty array will be returned
|
||||||
|
var r = response;
|
||||||
|
|
||||||
|
resolve(r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var _com_sendMessageRuntime = async function(message){
|
||||||
|
if(BrowserDetect.usebrowser != "firefox"){
|
||||||
|
return _com_chrome_tabs_sendmsgrt_wrapper(message);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return browser.runtime.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pošlje sporočilce vsem okvirjem v trenutno odprtem zavihku. Vrne tisti odgovor od tistega okvira, ki prispe prvi.
|
||||||
|
// sends a message to all frames in the currently opened tab. Returns the response of a frame that replied first
|
||||||
|
var _com_sendToAllFrames = async function(message) {
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms::_com_sendToAllFrames] sending message to all frames of currenntly active tab");
|
||||||
|
|
||||||
|
var tabs = await browser.tabs.query({currentWindow: true, active: true});
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms::_com_sendToAllFrames] trying to send message", message, " to tab ", tabs[0], ". (all tabs:", tabs,")");
|
||||||
|
|
||||||
|
var response = await browser.tabs.sendMessage(tabs[0].id, message);
|
||||||
|
console.log("[Comms::_com_sendToAllFrames] response is this:",response);
|
||||||
|
return response;
|
||||||
|
|
||||||
|
// if(BrowserDetect.firefox){
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// pošlje sporočilce vsem okvirjem v trenutno odprtem zavihku in vrne _vse_ odgovore
|
||||||
|
// sends a message to all frames in currently opened tab and returns all responses
|
||||||
|
var _com_sendToEachFrame = async function(message, tabId) {
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms::_com_sendToEveryFrame] sending message to every frames of currenntly active tab");
|
||||||
|
|
||||||
|
if(tabId === undefined){
|
||||||
|
var tabs = await browser.tabs.query({currentWindow: true, active: true});
|
||||||
|
tabId = tabs[0].id;
|
||||||
|
}
|
||||||
|
var frames = await browser.webNavigation.getAllFrames({tabId: tabId});
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms::_com_sendToEveryFrame] we have this many frames:", frames.length, "||| tabId:", tabId ,"frames:",frames);
|
||||||
|
|
||||||
|
|
||||||
|
// pošlji sporočilce vsakemu okvirju, potisni obljubo v tabelo
|
||||||
|
// send message to every frame, push promise to array
|
||||||
|
var promises = [];
|
||||||
|
for(var frame of frames){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms:_com_sendToEachFrame] we sending message to tab with id", tabId, ", frame with id", frame.frameId);
|
||||||
|
try{
|
||||||
|
promises.push(browser.tabs.sendMessage(tabId, message, {frameId: frame.frameId}));
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms:_com_sendToEachFrame] we sending message to tab with id", tabId, ", frame with id", frame.frameId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// počakajmo, da so obljube izpolnjene.
|
||||||
|
// wait for all promises to be kept
|
||||||
|
|
||||||
|
var responses = [];
|
||||||
|
|
||||||
|
for(var promise of promises){
|
||||||
|
var response = await promise;
|
||||||
|
if(response !== undefined)
|
||||||
|
responses.push(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms::_com_sendToEveryFrame] we received responses from all frames", responses);
|
||||||
|
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _com_sendToMainFrame = async function(message, tabId){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Comms::_com_sendToMainFrame] sending message to every frames of currenntly active tab");
|
||||||
|
|
||||||
|
if(tabId === undefined){
|
||||||
|
var tabs = await browser.tabs.query({currentWindow: true, active: true});
|
||||||
|
tabId = tabs[0].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pošlji sporočilce glavnemu okvirju. Glavni okvir ima id=0
|
||||||
|
// send message to the main frame. Main frame has id=0
|
||||||
|
try{
|
||||||
|
var response = await browser.tabs.sendMessage(tabId, message, {frameId: 0});
|
||||||
|
console.log("[Comms::_com_sendToMainFrame] response is this:",response);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
console.log("[Comms:_com_sendToEachFrame] failed sending message to tab with id", tabId, ", frame with id", 0, "\nerror:",e);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Comms = {
|
||||||
|
getActiveTab: _com_getActiveTab,
|
||||||
|
sendToBackgroundScript: _com_sendMessageRuntime,
|
||||||
|
queryTabs: _com_queryTabs,
|
||||||
|
sendMessage: _com_sendMessage,
|
||||||
|
sendMessageRuntime: _com_sendMessageRuntime,
|
||||||
|
sendToEach: _com_sendToEachFrame,
|
||||||
|
sendToAll: _com_sendToAllFrames,
|
||||||
|
sendToMain: _com_sendToMainFrame,
|
||||||
|
}
|
||||||
173
js/lib/PlayerDetect.js
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
if(Debug.debug)
|
||||||
|
console.log("Loading: FullScreenDetect.js");
|
||||||
|
|
||||||
|
var _pd_isFullScreen = function(){
|
||||||
|
return ( window.innerHeight == window.screen.height && window.innerWidth == window.screen.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* sprejme <video> tag (element) in seznam imen, ki se lahko pojavijo v razredih oz. id staršev.
|
||||||
|
// vrne dimenzije predvajalnika (širina, višina)
|
||||||
|
//
|
||||||
|
// Na youtube v theater mode je razširitev rahlo pokvarjena. Video tag ostane večji od predvajalnika, ko se zapusti
|
||||||
|
// celozaslonski način. Ta funkcija skuša to težavo rešiti tako, da poišče element predvajalnika, ki je zavit okoli videa.
|
||||||
|
//
|
||||||
|
// Funkcija izkorišča lastnost, da bi načeloma moral biti vsak zunanji element večji od notranjega. Najmanjši element od
|
||||||
|
// <video> značke pa do korena drevesa bi tako moral biti predvajalnik.
|
||||||
|
//
|
||||||
|
// Če je podan seznam imen, potem funkcija vrne dimenzije prvega elementa, ki v id oz. razredu vsebuje katerokoli ime iz seznama
|
||||||
|
//
|
||||||
|
// | EN |
|
||||||
|
//
|
||||||
|
// accepts <video> tag (element) and list of names that can appear in id or class
|
||||||
|
// returns player dimensions (width, height)
|
||||||
|
//
|
||||||
|
// Theater mode is mildly broken on youtube. <video> tag remains bigger than the player after leaving the fullscreen mode, and
|
||||||
|
// there's nothing we can do about that. This function aims to solve the problem by finding the player element that's wrapped around
|
||||||
|
// the <video> tag.
|
||||||
|
//
|
||||||
|
// In general, an outer tag should be bigger than the inner tag. Therefore the smallest element between <video> tag and the document
|
||||||
|
// root should be the player.
|
||||||
|
//
|
||||||
|
// If list of names is provided, the function returns dimensions of the first element that contains any name from the list in either
|
||||||
|
// id or class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var _pd_getPlayerDimensions = function(startElement, elementNames){
|
||||||
|
var element = startElement;
|
||||||
|
|
||||||
|
if(element == null || element == undefined){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[PlayerDetect::_pd_getPlayerDimensions] element is not valid, doing nothing.", element)
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isFullScreen = _pd_isFullScreen();
|
||||||
|
|
||||||
|
var trustCandidateAfterGrows = 2; // if candidate_width or candidate_height increases in either dimensions this many
|
||||||
|
// times, we say we found our player. (This number ignores weird elements)
|
||||||
|
// in case our <video> is bigger than player in one dimension but smaller in the other
|
||||||
|
// if site is coded properly, player can't be wider than that
|
||||||
|
var candidate_width = Math.max(element.offsetWidth, window.innerWidth);
|
||||||
|
var candidate_height = Math.max(element.offsetHeight, window.innerHeight);
|
||||||
|
var playerCandidateNode = startElement;
|
||||||
|
|
||||||
|
// <video> can't be root in a document, so we can do this
|
||||||
|
element = element.parentNode;
|
||||||
|
|
||||||
|
try{
|
||||||
|
var grows = trustCandidateAfterGrows;
|
||||||
|
while(element != undefined){
|
||||||
|
// odstranimo čudne elemente, ti bi pokvarili zadeve
|
||||||
|
// remove weird elements, those would break our stuff
|
||||||
|
if ( element.offsetWidth == 0 || element.offsetHeight == 0){
|
||||||
|
element = element.parentNode;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( element.offsetHeight <= candidate_height &&
|
||||||
|
element.offsetWidth <= candidate_width ){
|
||||||
|
|
||||||
|
// if we're in fullscreen, we only consider elements that are exactly as big as the monitor.
|
||||||
|
if( ! isFullScreen ||
|
||||||
|
(element.offsetWidth == window.innerWidth && element.offsetHeight == window.innerHeight) ){
|
||||||
|
|
||||||
|
playerCandidateNode = element;
|
||||||
|
candidate_width = element.offsetWidth;
|
||||||
|
candidate_height = element.offsetHeight;
|
||||||
|
|
||||||
|
grows = trustCandidateAfterGrows;
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("Found new candidate for player. Dimensions: w:", candidate_width, "h:",candidate_height, "node:", playerCandidateNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(grows --<= 0){
|
||||||
|
|
||||||
|
if(Debug.debug && Debug.playerDetect){
|
||||||
|
console.log("Current element grew in comparrison to the child. We probably found the player. breaking loop, returning current result");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element.parentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
console.log("pdeeee,",e);
|
||||||
|
}
|
||||||
|
var dims;
|
||||||
|
|
||||||
|
if(isFullScreen && playerCandidateNode == startElement){
|
||||||
|
dims = {
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight,
|
||||||
|
element: null,
|
||||||
|
fullscreen: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
dims = {
|
||||||
|
width: candidate_width,
|
||||||
|
height: candidate_height,
|
||||||
|
element: playerCandidateNode,
|
||||||
|
fullscreen: isFullScreen
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return dims;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns 'true' if there was a change.
|
||||||
|
var _pd_checkPlayerSizeChange = function(){
|
||||||
|
|
||||||
|
// console.log("Player:", GlobalVars.playerDimensions, "Node:", GlobalVars.playerDimensions.element)
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
if(GlobalVars.playerDimensions.element == undefined)
|
||||||
|
console.log("[PlayerDetect] player size changed. reason: player element undefined");
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions.fullscreen){
|
||||||
|
if(! _pd_isFullScreen()){
|
||||||
|
console.log("[PlayerDetect] player size changed. reason: exited fullscreen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(! GlobalVars.playerDimensions.element)
|
||||||
|
console.log("[PlayerDetect] player element isnt defined");
|
||||||
|
|
||||||
|
if ( GlobalVars.playerDimensions.element &&
|
||||||
|
( GlobalVars.playerDimensions.width != GlobalVars.playerDimensions.element.offsetWidth ||
|
||||||
|
GlobalVars.playerDimensions.height != GlobalVars.playerDimensions.element.offsetHeight )
|
||||||
|
){
|
||||||
|
console.log("[PlayerDetect] player size changed. reason: dimension change. Old dimensions?", GlobalVars.playerDimensions.width, GlobalVars.playerDimensions.height, "new dimensions:", GlobalVars.playerDimensions.element.offsetWidth, GlobalVars.playerDimensions.element.offsetHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions.element == undefined)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions.width != GlobalVars.playerDimensions.element.offsetWidth || GlobalVars.playerDimensions.height != GlobalVars.playerDimensions.element.offsetHeight ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(GlobalVars.playerDimensions.fullscreen){
|
||||||
|
// return ! _pd_isFullScreen();
|
||||||
|
// }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var PlayerDetect = {
|
||||||
|
getPlayerDimensions: _pd_getPlayerDimensions,
|
||||||
|
checkPlayerSizeChange: _pd_checkPlayerSizeChange,
|
||||||
|
isFullScreen: _pd_isFullScreen
|
||||||
|
}
|
||||||
50
js/lib/StorageManager.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// setopt, getopt, delopt. Shrani oz. dobi oz. briše stvari iz skladišča
|
||||||
|
// setopt, getopt, delopt. They set/get/delete stuff from the storage
|
||||||
|
|
||||||
|
var _sm_setopt = function(item){
|
||||||
|
return browser.storage.local.set(item);
|
||||||
|
}
|
||||||
|
var _sm_getopt = function(prop, callback){
|
||||||
|
if(BrowserDetect.usebrowser == "chrome")
|
||||||
|
return browser.storage.local.get(prop, callback);
|
||||||
|
else
|
||||||
|
return browser.storage.local.get(prop).then(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sm_chrome_getopt_wrapper = async function(prop){
|
||||||
|
return new Promise(function (resolve, reject){
|
||||||
|
browser.storage.local.get(prop, function(response){
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _sm_getopt_async = async function(prop){
|
||||||
|
if(Debug.debug && Debug.debugStorage)
|
||||||
|
console.log("[StorageManager::_sm_getopt_async] requesting prop",prop,"from localStorage.");
|
||||||
|
|
||||||
|
if(BrowserDetect.usebrowser == "chrome"){
|
||||||
|
var ret = await _sm_chrome_getopt_wrapper(prop);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
var ret = await browser.storage.local.get(prop);
|
||||||
|
|
||||||
|
if(Debug.debug && Debug.debugStorage)
|
||||||
|
console.log("[StorageManager::_sm_getopt_async] got prop", prop, "; value: ", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _sm_delopt = function(item){
|
||||||
|
return browser.storage.local.remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
var StorageManager = {
|
||||||
|
setopt: _sm_setopt,
|
||||||
|
getopt: _sm_getopt,
|
||||||
|
delopt: _sm_delopt,
|
||||||
|
getopt_async: _sm_getopt_async
|
||||||
|
}
|
||||||
1423
js/modules/ArDetect.js
Normal file
220
js/modules/DebugCanvas.js
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
var _dbgc_canvas;
|
||||||
|
var _dbgc_context;
|
||||||
|
var _dbgc_timer;
|
||||||
|
var _dbgc_clearTimeoutCount = 0;
|
||||||
|
var _dbgc_imageBuffer;
|
||||||
|
|
||||||
|
// drawQueue vsebuje stvari, ki jih bomo risali na platno
|
||||||
|
// Je tabela objektov, ki naj bi zgledali takole:
|
||||||
|
// {
|
||||||
|
// id: (id elementa)
|
||||||
|
// class: (razred elementa)
|
||||||
|
// type: (črta, kvardat, whatever)
|
||||||
|
// startPosition: (kje se začne risati)
|
||||||
|
// dimensions: {width, height}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// drawqueue contains stuff we're gonna draw onto canvas
|
||||||
|
|
||||||
|
var _dbgc_drawQueue = [];
|
||||||
|
|
||||||
|
var _dbgc_classes = {
|
||||||
|
guardLine_blackbar: "#000099",
|
||||||
|
guardLine_imageTest: "#5555FF",
|
||||||
|
guardLine_blackbar_violation: "#FF0000",
|
||||||
|
|
||||||
|
test: "#FF0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_traceColors = {
|
||||||
|
guardLine_blackbar: [0, 0, 96],
|
||||||
|
guardLine_imageTest: [72, 72, 255],
|
||||||
|
guardLine_blackbar_violation: [255, 0, 0],
|
||||||
|
guardLine_imageTest_noimage: [69, 42, 42]
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_init = async function(canvasSize, canvasPosition){
|
||||||
|
console.log("initiating DebugCanvas")
|
||||||
|
|
||||||
|
var body = document.getElementsByTagName('body')[0];
|
||||||
|
|
||||||
|
if(!canvasPosition){
|
||||||
|
canvasPosition = {
|
||||||
|
top: 1200,
|
||||||
|
left: 800
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!_dbgc_canvas){
|
||||||
|
_dbgc_canvas = document.createElement("canvas");
|
||||||
|
body.appendChild(_dbgc_canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbgc_canvas.style.position = "absolute";
|
||||||
|
_dbgc_canvas.style.left = `${canvasPosition.left}px`;
|
||||||
|
_dbgc_canvas.style.top = `${canvasPosition.top}px`;
|
||||||
|
_dbgc_canvas.style.zIndex = 10002;
|
||||||
|
_dbgc_canvas.style.transform = "scale(2.5, 2.5)";
|
||||||
|
_dbgc_canvas.id = "uw_debug_canvas";
|
||||||
|
|
||||||
|
_dbgc_context = _dbgc_canvas.getContext("2d");
|
||||||
|
|
||||||
|
_dbgc_canvas.width = canvasSize.width;
|
||||||
|
_dbgc_canvas.height = canvasSize.height;
|
||||||
|
|
||||||
|
console.log("debug canvas is:", _dbgc_canvas, "context:", _dbgc_context)
|
||||||
|
|
||||||
|
// _dbgc_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_removeFromQueue = function(element){
|
||||||
|
var ind = _dbgc_drawQueue.indexOf(element);
|
||||||
|
if(ind > -1){
|
||||||
|
_dbgc_drawQueue.splice(ind, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_removeByAttribute = function(attribute, value){
|
||||||
|
var i = 0;
|
||||||
|
while(i < _dbgc_drawQueue.length){
|
||||||
|
if( _dbgc_drawQueue[i][attribute] == value){
|
||||||
|
_dbgc_drawQueue.splice(i, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_remove = function(id){
|
||||||
|
_dbgc_removeByAttribute('id', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_removeClass = function(className) {
|
||||||
|
_dbgc_removeByAttribute('class', className);
|
||||||
|
}
|
||||||
|
|
||||||
|
// good thing javascript is single threaded because this would be haram as fuck
|
||||||
|
var _dbgc_autoremove = async function(timeout, element){
|
||||||
|
setTimeout( _dbgc_removeFromQueue, timeout, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_start = function(){
|
||||||
|
_dbgc_scheduleUpdate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_scheduleUpdate = function (timeout, force_reset){
|
||||||
|
// don't allow more than 1 instance
|
||||||
|
if(_dbgc_timer){
|
||||||
|
++_dbgc_clearTimeoutCount;
|
||||||
|
clearTimeout(_dbgc_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbgc_timer = setTimeout(function(){
|
||||||
|
_dbgc_timer = null;
|
||||||
|
_dbgc_update();
|
||||||
|
},
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_draw = function(id, className, type, startPosition, dimensions, removeAfter){
|
||||||
|
/**
|
||||||
|
* @param id element id
|
||||||
|
* @param className element class
|
||||||
|
* @param type type of element (line, rectangle)
|
||||||
|
* @param startPosition start position on canvas. {x,y}
|
||||||
|
* @param dimensions dimensions of object
|
||||||
|
* @param removeAfter if defined, element will be removed after this many milliseconds. Leave 0 or undefined to avoid automatic removal (manual removal still possible)
|
||||||
|
*/
|
||||||
|
var element = {
|
||||||
|
id: id,
|
||||||
|
class: className,
|
||||||
|
type: type,
|
||||||
|
startPosition: startPosition,
|
||||||
|
dimensions: dimensions
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbgc_drawQueue.push(element);
|
||||||
|
|
||||||
|
if(removeAfter){
|
||||||
|
_dbgc_autoremove(removeAfter, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_update = function(){
|
||||||
|
// get frame off video
|
||||||
|
|
||||||
|
if(GlobalVars.video){
|
||||||
|
_dbgc_context.drawImage(GlobalVars.video, 0,0, _dbgc_canvas.width, _dbgc_canvas.height);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// console.log("[DebugCanvas] NO VIDEO DETECTED, DOING NOTHIGN");
|
||||||
|
_dbgc_scheduleUpdate(100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var element of _dbgc_drawQueue) {
|
||||||
|
_dbgc_context.fillStyle = _dbgc_classes[element.class];
|
||||||
|
|
||||||
|
// if(element.type == "rect"){
|
||||||
|
_dbgc_context.fillRect(element.startPosition.x, element.startPosition.y, element.dimensions.width, element.dimensions.height);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbgc_scheduleUpdate(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_setBuffer = function(buffer) {
|
||||||
|
// _dbgc_imageBuffer = buffer.splice(0);
|
||||||
|
_dbgc_imageBuffer = new Uint8ClampedArray(buffer);
|
||||||
|
// console.log(buffer, "<--buf")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_trace = function(className, arrayIndex){
|
||||||
|
_dbgc_imageBuffer[arrayIndex ] = _dbgc_traceColors[className][0];
|
||||||
|
_dbgc_imageBuffer[arrayIndex+1] = _dbgc_traceColors[className][1];
|
||||||
|
_dbgc_imageBuffer[arrayIndex+2] = _dbgc_traceColors[className][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// because (context.putImageData) doesnt work
|
||||||
|
function putImageData(ctx, imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
|
||||||
|
var data = imageData.data;
|
||||||
|
var height = imageData.height;
|
||||||
|
var width = imageData.width;
|
||||||
|
dirtyX = dirtyX || 0;
|
||||||
|
dirtyY = dirtyY || 0;
|
||||||
|
dirtyWidth = dirtyWidth !== undefined? dirtyWidth: width;
|
||||||
|
dirtyHeight = dirtyHeight !== undefined? dirtyHeight: height;
|
||||||
|
var limitBottom = Math.min(dirtyHeight, height);
|
||||||
|
var limitRight = Math.min(dirtyWidth, width);
|
||||||
|
for (var y = dirtyY; y < limitBottom; y++) {
|
||||||
|
for (var x = dirtyX; x < limitRight; x++) {
|
||||||
|
var pos = y * width + x;
|
||||||
|
ctx.fillStyle = 'rgba(' + data[pos*4+0]
|
||||||
|
+ ',' + data[pos*4+1]
|
||||||
|
+ ',' + data[pos*4+2]
|
||||||
|
+ ',' + (data[pos*4+3]/255) + ')';
|
||||||
|
ctx.fillRect(x + dx, y + dy, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dbgc_showTraces = function(){
|
||||||
|
if(_dbgc_context && _dbgc_imageBuffer instanceof Uint8ClampedArray){
|
||||||
|
var idata = new ImageData(_dbgc_imageBuffer, _dbgc_canvas.width, _dbgc_canvas.height);
|
||||||
|
putImageData(_dbgc_context, idata, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var DebugCanvas = {
|
||||||
|
events: {
|
||||||
|
|
||||||
|
},
|
||||||
|
init: _dbgc_init,
|
||||||
|
// start: _dbgc_start,
|
||||||
|
// draw: _dbgc_draw,
|
||||||
|
// remove: _dbgc_remove,
|
||||||
|
// removeClass: _dbgc_removeClass,
|
||||||
|
|
||||||
|
setBuffer: _dbgc_setBuffer,
|
||||||
|
trace: _dbgc_trace,
|
||||||
|
showTraces: _dbgc_showTraces
|
||||||
|
}
|
||||||
19
js/modules/PageInfo.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
if(Debug.debug)
|
||||||
|
console.log("Loading: PageInfo.js");
|
||||||
|
|
||||||
|
var _pi_hasVideos = function(){
|
||||||
|
// return true;
|
||||||
|
var videos = document.getElementsByTagName("video");
|
||||||
|
if(videos.length == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// if(videos[0].style.display == "none") // in this case ultrawidify doesn't even work
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var PageInfo = {
|
||||||
|
hasVideos: _pi_hasVideos
|
||||||
|
}
|
||||||
458
js/modules/Resizer.js
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
if(Debug.debug)
|
||||||
|
console.log("Loading: Resizer.js");
|
||||||
|
|
||||||
|
// restore watchdog. While true, _res_applyCss() tries to re-apply new css until this value becomes false again
|
||||||
|
// value becomes false when width and height of <video> tag match with what we want to set. Only necessary when
|
||||||
|
// calling _res_restore() for some weird reason.
|
||||||
|
var _res_restore_wd = false;
|
||||||
|
|
||||||
|
var _res_char = function(newAr, video, player){
|
||||||
|
|
||||||
|
// Kot vhodni argument dobimo razmerje stranic. Problem je, ker pri nekaterih ločljivostih lahko razmerje stranic
|
||||||
|
// videa/našega zaslona minimalno odstopa od idealnega razmerja — npr 2560x1080 ni natanko 21:9, 1920x1080 ni
|
||||||
|
// natanko 16:9. Zato ob podanem razmerju stranic izračunamo dejansko razmerje stranic.
|
||||||
|
//
|
||||||
|
// The aspect ratio we get as an argument is an ideal aspect ratio. Some (most) resolutions' aspect ratios differ
|
||||||
|
// from that ideal aspect ratio (by a minimal amount) — e.g. 2560x1080 isn't exactly 21:9, 1920x1080 isn't exactly
|
||||||
|
// 16:9. What is more, both 3440x1440 and 2560x1080 are considered "21:9", but their aspect ratios are slightly
|
||||||
|
// different. This has the potential to result in annoying black bars, so we correct the aspect ratio we're given
|
||||||
|
// to something that's slightly more correct.
|
||||||
|
|
||||||
|
var ar;
|
||||||
|
var res_219 = [ [2560,1080], [3440,1440] ];
|
||||||
|
var res_169 = [ [1920,1080], [1280,720], [1366,768] ];
|
||||||
|
|
||||||
|
if(newAr == (21/9)){
|
||||||
|
for (var i = 0; i < res_219.length; i++){
|
||||||
|
if( player.height == res_219[i][1]){
|
||||||
|
ar = res_219[i][0]/res_219[i][1];
|
||||||
|
set_video_ar( ar, video, player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(new_ar == (16/9)){
|
||||||
|
for (var i = 0; i < res_169.length; i++){
|
||||||
|
if( player.height == res_169[i][1]){
|
||||||
|
ar = res_169[i][0]/res_169[i][1];
|
||||||
|
setVideoAr( ar, video, player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_res_setVideoAr(new_ar, video, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skrbi za "stare" možnosti, kot na primer "na širino zaslona", "na višino zaslona" in "ponastavi".
|
||||||
|
// Približevanje opuščeno.
|
||||||
|
// handles "legacy" options, such as 'fit to widht', 'fit to height' and 'reset'. No zoom tho
|
||||||
|
var _res_legacyAr = function(action){
|
||||||
|
var vid = GlobalVars.video;
|
||||||
|
var ar;
|
||||||
|
|
||||||
|
if (!vid) {
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer.js::_res_legacyAr] No video??",vid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! GlobalVars.playerDimensions ){
|
||||||
|
ar = screen.width / screen.height;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ar = GlobalVars.playerDimensions.width / GlobalVars.playerDimensions.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// POMEMBNO: GlobalVars.lastAr je potrebno nastaviti šele po tem, ko kličemo _res_setAr(). _res_setAr() predvideva,
|
||||||
|
// da želimo nastaviti statično (type: 'static') razmerje stranic — tudi, če funkcijo kličemo tu oz. v ArDetect.
|
||||||
|
//
|
||||||
|
// IMPORTANT NOTE: GlobalVars.lastAr needs to be set after _res_setAr() is called, as _res_setAr() assumes we're
|
||||||
|
// setting a static aspect ratio (even if the function is called from here or ArDetect).
|
||||||
|
|
||||||
|
var fileAr = vid.videoWidth / vid.videoHeight;
|
||||||
|
|
||||||
|
if (action == "fitw"){
|
||||||
|
_res_setAr( ar > fileAr ? ar : fileAr);
|
||||||
|
}
|
||||||
|
else if(action == "fith"){
|
||||||
|
_res_setAr( ar < fileAr ? ar : fileAr);
|
||||||
|
}
|
||||||
|
else if(action == "reset"){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer.js::_res_legacyAr] Resetting aspect ratio to", fileAr)
|
||||||
|
}
|
||||||
|
|
||||||
|
_res_setAr(fileAr);
|
||||||
|
GlobalVars.lastAr = {type: "original"};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(action == "autoar" || action == "auto"){
|
||||||
|
GlobalVars.lastAr = {type: "auto", ar: null};
|
||||||
|
ArDetect.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVars.lastAr = {type: "legacy", action: action};
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_setAr = function(ar){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setAr] trying to set ar. args are: ar->",ar,"; playerDimensions->",GlobalVars.playerDimensions.width, "×", GlobalVars.playerDimensions.height, "| obj:", GlobalVars.playerDimensions);
|
||||||
|
|
||||||
|
GlobalVars.lastAr = {type: "static", ar: ar};
|
||||||
|
|
||||||
|
var vid = GlobalVars.video;
|
||||||
|
if(vid == null || vid==undefined || vid.videoWidth == 0 || vid.videoHeight == 0){
|
||||||
|
vid = document.getElementsByTagName("video")[0];
|
||||||
|
GlobalVars.video = vid;
|
||||||
|
|
||||||
|
if(vid == null || vid==undefined || vid.videoWidth == 0 || vid.videoHeight == 0){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setAr] I lied. Tricked you! You thought there's gonna be a video, didn't you? Never would be.", vid); // of course that's thorin reference -> https://youtu.be/OY5gGkeQn1c?t=1m20s
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setAr] video:",vid,"width:", vid.videoWidth, "height:", vid.videoHeight);
|
||||||
|
|
||||||
|
if(! GlobalVars.playerDimensions || GlobalVars.playerDimensions.width === 0 || GlobalVars.playerDimensions.height){
|
||||||
|
GlobalVars.playerDimensions = PlayerDetect.getPlayerDimensions(vid);
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setAr] playerDimensions are undefined, trying to determine new ones ... new dimensions:", GlobalVars.playerDimensions.width, "×", GlobalVars.playerDimensions.height, "| obj:", GlobalVars.playerDimensions);
|
||||||
|
|
||||||
|
if(! GlobalVars.playerDimensions || GlobalVars.playerDimensions.width === 0 || GlobalVars.playerDimensions.height === 0){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setAr] failed to get player dimensions. Doing nothing. Here's the object:", GlobalVars.playerDimensions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dejansko razmerje stranic datoteke/<video> značke
|
||||||
|
// Actual aspect ratio of the file/<video> tag
|
||||||
|
var fileAr = vid.videoWidth / vid.videoHeight;
|
||||||
|
var playerAr = GlobalVars.playerDimensions.width / GlobalVars.playerDimensions.height;
|
||||||
|
|
||||||
|
if(ar == "default" || !ar)
|
||||||
|
ar = fileAr;
|
||||||
|
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setAr] ar is " ,ar, ", file ar is", fileAr, ", playerDimensions are ", GlobalVars.playerDimensions.width, "×", GlobalVars.playerDimensions.height, "| obj:", GlobalVars.playerDimensions);
|
||||||
|
|
||||||
|
var videoDimensions = {
|
||||||
|
width: 0,
|
||||||
|
height: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_setAr] Player dimensions?", GlobalVars.playerDimensions.width, "×", GlobalVars.playerDimensions.height, "| obj:", GlobalVars.playerDimensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( fileAr < ar ){
|
||||||
|
// imamo letterbox zgoraj in spodaj -> spremenimo velikost videa (a nikoli širše od ekrana)
|
||||||
|
// letterbox -> change video size (but never to wider than monitor width)
|
||||||
|
|
||||||
|
videoDimensions.width = Math.min(GlobalVars.playerDimensions.height * ar, GlobalVars.playerDimensions.width);
|
||||||
|
videoDimensions.height = videoDimensions.width * (1/fileAr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
videoDimensions.height = Math.min(GlobalVars.playerDimensions.width * (1/ar), GlobalVars.playerDimensions.height);
|
||||||
|
videoDimensions.width = videoDimensions.height * fileAr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_setAr] Video dimensions: ", videoDimensions.width, "×", videoDimensions.height, "(obj:", videoDimensions, "); playerDimensions:",GlobalVars.playerDimensions.width, "×", GlobalVars.playerDimensions.height, "(obj:", GlobalVars.playerDimensions, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
var cssValues = _res_computeOffsets(videoDimensions, GlobalVars.playerDimensions);
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_setAr] Offsets for css are: ",cssValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
_res_applyCss(cssValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_computeOffsets = function(vidDim, playerDim){
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_computeOffsets] video will be aligned to ", ExtensionConf.miscFullscreenSettings.videoFloat);
|
||||||
|
|
||||||
|
var offsets = {
|
||||||
|
width: vidDim.width,
|
||||||
|
height: vidDim.height,
|
||||||
|
left: 0,
|
||||||
|
top: ((playerDim.height - vidDim.height) / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ExtensionConf.miscFullscreenSettings.videoFloat == "center" ){
|
||||||
|
offsets.left = (playerDim.width - vidDim.width ) / 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if( ExtensionConf.miscFullscreenSettings.videoFloat == "right" ){
|
||||||
|
offsets.left = (playerDim.width - vidDim.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVars.correctedVideoDimensions.width = parseInt(offsets.width);
|
||||||
|
GlobalVars.correctedVideoDimensions.height= parseInt(offsets.height);
|
||||||
|
GlobalVars.correctedVideoDimensions.left = parseInt(offsets.left);
|
||||||
|
GlobalVars.correctedVideoDimensions.top = parseInt(offsets.top);
|
||||||
|
|
||||||
|
return offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_align = function(float){
|
||||||
|
if(! float)
|
||||||
|
float = ExtensionConf.miscFullscreenSettings.videoFloat;
|
||||||
|
|
||||||
|
var dimensions = {left: 0};
|
||||||
|
|
||||||
|
if(float == "left"){
|
||||||
|
_res_applyCss(dimensions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(float == "center"){
|
||||||
|
// dimensions.left =
|
||||||
|
// _res_applyCss(
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_setStyleString_maxRetries = 3;
|
||||||
|
|
||||||
|
var _res_setStyleString = function(vid, styleString, count){
|
||||||
|
vid.setAttribute("style", styleString);
|
||||||
|
|
||||||
|
if(_res_restore_wd){
|
||||||
|
var vid2 = GlobalVars.video;
|
||||||
|
|
||||||
|
if(vid2 == undefined || vid2 == null){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setStyleString] Video element went missing, nothing to do here.")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(
|
||||||
|
styleString.indexOf("width: " + vid2.style.width) == -1 ||
|
||||||
|
styleString.indexOf("height: " + vid2.style.height) == -1) {
|
||||||
|
// css ni nastavljen?
|
||||||
|
// css not set?
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setStyleString] Style string not set ???");
|
||||||
|
|
||||||
|
if(count++ < _res_setStyleString_maxRetries){
|
||||||
|
setTimeout( _res_setStyleString, 200, count);
|
||||||
|
}
|
||||||
|
else if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_setStyleString] we give up. css string won't be set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_res_restore_wd = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_setStyleString] css applied. Style string:", styleString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _res_applyCss(dimensions){
|
||||||
|
|
||||||
|
if(GlobalVars.video == undefined || GlobalVars.video == null){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_applyCss] Video went missing, doing nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_applyCss] Starting to apply css. this is what we're getting in:", dimensions);
|
||||||
|
|
||||||
|
if(dimensions.top !== undefined)
|
||||||
|
dimensions.top = "top: " + Math.round(dimensions.top) + "px !important";
|
||||||
|
|
||||||
|
if(dimensions.left !== undefined)
|
||||||
|
dimensions.left = "left: " + Math.round(dimensions.left) + "px !important";
|
||||||
|
|
||||||
|
if(dimensions.width !== undefined)
|
||||||
|
dimensions.width = "width: " + Math.round(dimensions.width) + "px !important";
|
||||||
|
|
||||||
|
if(dimensions.height !== undefined)
|
||||||
|
dimensions.height = "height: " + Math.round(dimensions.height) + "px !important";
|
||||||
|
|
||||||
|
// misc.
|
||||||
|
dimensions.position = "position: absolute !important";
|
||||||
|
dimensions.margin = "margin: 0px !important";
|
||||||
|
|
||||||
|
// save values for left and top to GlobalVars
|
||||||
|
GlobalVars.currentCss.top = dimensions.top;
|
||||||
|
GlobalVars.currentCss.left = dimensions.left;
|
||||||
|
|
||||||
|
var vid = GlobalVars.video;
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[Resizer::_res_applyCss] trying to apply css. Css strings: ", dimensions, "video tag: ", vid);
|
||||||
|
|
||||||
|
var styleArrayStr = vid.getAttribute('style');
|
||||||
|
|
||||||
|
if (styleArrayStr !== null && styleArrayStr !== undefined){
|
||||||
|
|
||||||
|
var styleArray = styleArrayStr.split(";");
|
||||||
|
for(var i in styleArray){
|
||||||
|
|
||||||
|
styleArray[i] = styleArray[i].trim();
|
||||||
|
|
||||||
|
if (styleArray[i].startsWith("top:")){
|
||||||
|
styleArray[i] = dimensions.top;
|
||||||
|
delete dimensions.top;
|
||||||
|
}
|
||||||
|
else if(styleArray[i].startsWith("left:")){
|
||||||
|
styleArray[i] = dimensions.left;
|
||||||
|
delete dimensions.left;
|
||||||
|
}
|
||||||
|
else if(styleArray[i].startsWith("width:")){
|
||||||
|
styleArray[i] = dimensions.width;
|
||||||
|
delete dimensions.width;
|
||||||
|
}
|
||||||
|
else if(styleArray[i].startsWith("height:")){
|
||||||
|
styleArray[i] = dimensions.height;
|
||||||
|
delete dimensions.height;
|
||||||
|
}
|
||||||
|
else if(styleArray[i].startsWith("position:")){
|
||||||
|
styleArray[i] = dimensions.position;
|
||||||
|
delete dimensions.position;
|
||||||
|
}
|
||||||
|
else if(styleArray[i].startsWith("margin:")){
|
||||||
|
styleArray[i] = dimensions.margin;
|
||||||
|
delete dimensions.margin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
var styleArray = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add remaining elements
|
||||||
|
for(var key in dimensions)
|
||||||
|
styleArray.push( dimensions[key] );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// build style string back
|
||||||
|
var styleString = "";
|
||||||
|
for(var i in styleArray)
|
||||||
|
if(styleArray[i] !== undefined && styleArray[i] !== "")
|
||||||
|
styleString += styleArray[i] + "; ";
|
||||||
|
|
||||||
|
_res_setStyleString(vid, styleString);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_antiCssOverride = function(){
|
||||||
|
|
||||||
|
// this means we haven't set our CSS yet, or that we changed video.
|
||||||
|
if(GlobalVars.currentCss.top === null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// this means video went missing.
|
||||||
|
if(GlobalVars.video == undefined || GlobalVars.video == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// // our current css is fucky? Null, undefined and 0 are invalid values.
|
||||||
|
// if(! GlobalVars.currentCss.width || ! GlobalVars.currentCss.height )
|
||||||
|
// return;
|
||||||
|
|
||||||
|
var styleArrayStr = GlobalVars.video.getAttribute('style');
|
||||||
|
|
||||||
|
if (styleArrayStr !== null && styleArrayStr !== undefined){
|
||||||
|
var styleArray = styleArrayStr.split(";");
|
||||||
|
|
||||||
|
var stuffChecked = 0;
|
||||||
|
var stuffToCheck = 2;
|
||||||
|
|
||||||
|
for(var i in styleArray){
|
||||||
|
styleArray[i] = styleArray[i].trim();
|
||||||
|
|
||||||
|
if (styleArray[i].startsWith("top:")){
|
||||||
|
// don't force css restore if currentCss.top is not defined
|
||||||
|
if(GlobalVars.currentCss.top && styleArray[i] != GlobalVars.currentCss.top){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_antiCssOverride] SOMEBODY TOUCHED MA SPAGHETT (our CSS got overriden, restoring our css)");
|
||||||
|
console.log("[Resizer::_res_antiCssOverride] MA SPAGHETT: top:", GlobalVars.currentCss.top, "left:", GlobalVars.currentCss.left, "thing that touched ma spaghett", styleArrayStr);
|
||||||
|
}
|
||||||
|
_res_restore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stuffChecked++;
|
||||||
|
}
|
||||||
|
else if(styleArray[i].startsWith("left:")){
|
||||||
|
// don't force css restore if currentCss.left is not defined
|
||||||
|
if(GlobalVars.currentCss.left && styleArray[i] != GlobalVars.currentCss.left){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_antiCssOverride] SOMEBODY TOUCHED MA SPAGHETT (our CSS got overriden, restoring our css)");
|
||||||
|
console.log("[Resizer::_res_antiCssOverride] MA SPAGHETT: width:", GlobalVars.currentCss.width, "height:", GlobalVars.currentCss.height, "thing that touched ma spaghett", styleArrayStr);
|
||||||
|
}
|
||||||
|
_res_restore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stuffChecked++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stuffChecked == stuffToCheck){
|
||||||
|
// if(Debug.debug){
|
||||||
|
// console.log("[Resizer::_res_antiCssOverride] My spaghett rests untouched. (nobody overrode our CSS, doing nothing)");
|
||||||
|
// }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_restore = function(){
|
||||||
|
if(! GlobalVars.video)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[Resizer::_res_restore] attempting to restore aspect ratio. this & settings:", {'this': this, "settings": Settings} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is true until we verify that css has actually been applied
|
||||||
|
_res_restore_wd = true;
|
||||||
|
|
||||||
|
if(GlobalVars.lastAr.type == "legacy"){
|
||||||
|
_res_legacyAr(GlobalVars.lastAr.action);
|
||||||
|
}
|
||||||
|
else if(GlobalVars.lastAr.type == "static"){
|
||||||
|
_res_setAr(GlobalVars.lastAr.ar);
|
||||||
|
}
|
||||||
|
else if(GlobalVars.lastAr.type == "original"){
|
||||||
|
_res_legacyAr("reset");
|
||||||
|
}
|
||||||
|
else if(GlobalVars.lastAr.type == "auto"){
|
||||||
|
// do same as static, except keep lastAr to 'auto'. If we're here, this means video probably changed
|
||||||
|
// and there's something broken that prevents AR from working properly
|
||||||
|
var storeLastAr = {type: GlobalVars.lastAr.type, ar: GlobalVars.lastAr.ar};
|
||||||
|
_res_setAr(GlobalVars.lastAr.ar);
|
||||||
|
GlobalVars.lastAr = storeLastAr;
|
||||||
|
// ArDetect.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _res_reset = function(){
|
||||||
|
_res_legacyAr("reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
var Resizer = {
|
||||||
|
_currentAr: -1,
|
||||||
|
align: _res_align,
|
||||||
|
setAr: _res_setAr,
|
||||||
|
legacyAr: _res_legacyAr,
|
||||||
|
reset: _res_reset,
|
||||||
|
restore: _res_restore,
|
||||||
|
antiCssOverride: _res_antiCssOverride
|
||||||
|
}
|
||||||
46
js/run/GlobalVars.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
var GlobalVars = {
|
||||||
|
video: null,
|
||||||
|
player: null,
|
||||||
|
playerDimensions: null,
|
||||||
|
playerElement: null,
|
||||||
|
lastAr: null,
|
||||||
|
lastUrl: "",
|
||||||
|
currentCss: {
|
||||||
|
top: null,
|
||||||
|
left: null
|
||||||
|
},
|
||||||
|
canvas: {
|
||||||
|
context: null,
|
||||||
|
width: null,
|
||||||
|
height: null,
|
||||||
|
imageDataRowLength: null
|
||||||
|
},
|
||||||
|
correctedVideoDimensions: {
|
||||||
|
width: null,
|
||||||
|
height: null,
|
||||||
|
top: null,
|
||||||
|
left: null
|
||||||
|
},
|
||||||
|
arDetect: {
|
||||||
|
autoDisable: {
|
||||||
|
eventCount: 0
|
||||||
|
},
|
||||||
|
canvas: null,
|
||||||
|
blackLevel: 10,
|
||||||
|
sampleCols_current: 0,
|
||||||
|
noLetterboxCanvasReset: false,
|
||||||
|
guardLine: {
|
||||||
|
top: null,
|
||||||
|
bottom: null,
|
||||||
|
logo: {
|
||||||
|
detected: false,
|
||||||
|
top_left: null,
|
||||||
|
top_right: null,
|
||||||
|
bottom_left: null,
|
||||||
|
bottom_right: null
|
||||||
|
},
|
||||||
|
start: null,
|
||||||
|
end: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
262
js/uw-bg.js
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
var BgVars = {
|
||||||
|
arIsActive: true,
|
||||||
|
hasVideos: false,
|
||||||
|
currentSite: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractHostname(url){
|
||||||
|
// extract hostname
|
||||||
|
if (url.indexOf("://") > -1) { //find & remove protocol (http, ftp, etc.) and get hostname
|
||||||
|
hostname = url.split('/')[2];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hostname = url.split('/')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname = hostname.split(':')[0]; //find & remove port number
|
||||||
|
hostname = hostname.split('?')[0]; //find & remove "?"
|
||||||
|
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main(){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::main] setting up background script");
|
||||||
|
|
||||||
|
await Settings.init();
|
||||||
|
await Keybinds.init();
|
||||||
|
Keybinds.keybinds = await Keybinds.fetch();
|
||||||
|
|
||||||
|
|
||||||
|
// Poslušalci za dogodke | event listeners here
|
||||||
|
// {===]///[-------------------------------------]\\\[===}
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener(_uwbg_rcvmsg);
|
||||||
|
browser.tabs.onActivated.addListener(_uwbg_onTabSwitched);
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::main] listeners registered");
|
||||||
|
|
||||||
|
// add currentSite
|
||||||
|
var tabs = await Comms.getActiveTab();
|
||||||
|
BgVars.currentSite = extractHostname(tabs[0].url);
|
||||||
|
|
||||||
|
//
|
||||||
|
setInterval(_uwbg_check4videos, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _uwbg_onTabSwitched(activeInfo){
|
||||||
|
BgVars.hasVideos = false;
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::onTabSwitched] TAB CHANGED, GETTING INFO FROM MAIN TAB");
|
||||||
|
|
||||||
|
|
||||||
|
var tabId = activeInfo.tabId; // just for readability
|
||||||
|
|
||||||
|
var tab = await browser.tabs.get(tabId);
|
||||||
|
|
||||||
|
BgVars.currentSite = extractHostname(tab.url);
|
||||||
|
|
||||||
|
// this can fail. This might also not return a promise? Check that.
|
||||||
|
var videoFrameList = await Comms.sendToEach({"cmd":"has-videos"}, tabId);
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::onTabSwitched] got list of frames and whether they have videos", videoFrameList);
|
||||||
|
|
||||||
|
// Pogledamo, če kateri od okvirjev vsebuje video. Da omogočimo pojavno okno je zadosti že
|
||||||
|
// en okvir z videom.
|
||||||
|
// <===[///]----------------------------[\\\]===>
|
||||||
|
// Check if any frame has a video in it. To enable the popup there only needs to be at least one,
|
||||||
|
// but the popup controls all frames.
|
||||||
|
|
||||||
|
var hasVideos = false;
|
||||||
|
for(frame of videoFrameList){
|
||||||
|
hasVideos |= frame.response.hasVideos;
|
||||||
|
}
|
||||||
|
|
||||||
|
BgVars.hasVideos = hasVideos;
|
||||||
|
|
||||||
|
Settings.reload();
|
||||||
|
// todo: change extension icon depending on whether there's a video on the page or not
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _uwbg_check4videos(){
|
||||||
|
if(BgVars.hasVideos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var videoFrameList = Comms.sendToEach({"cmd":"has-videos"});
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::check4videos] got updated list of frames and whether they have videos", videoFrameList);
|
||||||
|
|
||||||
|
var hasVideos = false;
|
||||||
|
for(frame of videoFrameList){
|
||||||
|
hasVideos |= frame.response.hasVideos;
|
||||||
|
}
|
||||||
|
|
||||||
|
BgVars.hasVideos = hasVideos;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _uwbg_registerVideo(tabId){
|
||||||
|
var tabs = await Comms.getActiveTab();
|
||||||
|
|
||||||
|
// če ukaz pride iz zavihka, na katerem se trenunto ne nahajamo, potem se za zahtevo ne brigamo
|
||||||
|
// if command originated from a tab that's _not_ currently active, we ignore the request
|
||||||
|
if(tabId != tabs[0].id){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw-bg::_uwbg_registerVideo] request didn't come from currently active tab, ignoring");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("%c[uw-bg::_uwbg_registerVideo] request came from currently active tab!", "color: #afd, background: #000");
|
||||||
|
}
|
||||||
|
BgVars.hasVideos = true;
|
||||||
|
|
||||||
|
// todo: change extension icon depending on whether there's a video on the page or not
|
||||||
|
}
|
||||||
|
|
||||||
|
function _uwbg_rcvmsg(message, sender, sendResponse){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw-bg::_uwbg_rcvmsg] received message", message, "from sender", sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
message.sender = "uwbg";
|
||||||
|
message.receiver = "uw";
|
||||||
|
|
||||||
|
if(message.cmd == "has-videos"){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw-bg::_uwbg_rcvmsg] does this tab or any of its subframes have videos?", BgVars.hasVideos );
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = {response: {hasVideos: BgVars.hasVideos}};
|
||||||
|
if(BrowserDetect.firefox){
|
||||||
|
return Promise.resolve(res);
|
||||||
|
}
|
||||||
|
sendResponse(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message.cmd == "get-config"){
|
||||||
|
var config = {};
|
||||||
|
config.videoAlignment = ExtensionConf.miscFullscreenSettings.videoFloat;
|
||||||
|
config.arConf = {};
|
||||||
|
config.arConf.enabled_global = ExtensionConf.arDetect.enabled == "blacklist";
|
||||||
|
|
||||||
|
config.site = {};
|
||||||
|
config.site.status = SitesConf.getSiteStatus(BgVars.currentSite);
|
||||||
|
config.site.arStatus = SitesConf.getArStatus(BgVars.currentSite);
|
||||||
|
|
||||||
|
config.mode = ExtensionConf.extensionMode;
|
||||||
|
config.arMode = ExtensionConf.arDetect.mode;
|
||||||
|
config.arDisabledReason = ExtensionConf.arDetect.disabledReason;
|
||||||
|
config.arTimerPlaying = ExtensionConf.arDetect.timer_playing;
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::_uwbg_rcvmsg] Keybinds.getKeybinds() returned this:", Keybinds.getKeybinds());
|
||||||
|
|
||||||
|
config.keyboardShortcuts = Keybinds.getKeybinds();
|
||||||
|
|
||||||
|
|
||||||
|
// predvidevajmo, da je enako. Če je drugače, bomo popravili ko dobimo odgovor
|
||||||
|
// assume current is same as global & change that when you get response from content script
|
||||||
|
config.arConf.enabled_current = ExtensionConf.arDetect.enabled == "blacklist";
|
||||||
|
|
||||||
|
var res = {response: config}
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw-bg::_uwbg_rcvmsg] get-config: returning this to popup script:", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(BrowserDetect.firefox){
|
||||||
|
return Promise.resolve(res);
|
||||||
|
}
|
||||||
|
sendResponse(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message.cmd == "register-video"){
|
||||||
|
// dobili smo sporočilce, ki pravi: "hej jaz imam video, naredi cahen" — ampak preden naredimo cahen,
|
||||||
|
// se je potrebno prepričati, da je sporočilce prišlo iz pravilnega zavihka. Trenutno odprt zavihek
|
||||||
|
// lahko dobimo to. ID zavihka, iz katerega je prišlo sporočilo, se skriva v sender.tab.id
|
||||||
|
// ~<><\\\][=================][///><>~
|
||||||
|
// we got a message that says: "hey I have a video, make a mark or something" — but before we do the
|
||||||
|
// mark, we should check if the message has truly arrived from currently active tab. We can get the
|
||||||
|
// id of currently active tab here. ID of the sender tab is ‘hidden’ in sender.tab.id.
|
||||||
|
|
||||||
|
_uwbg_registerVideo(sender.tab.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(message.cmd == "uw-enabled-for-site"){
|
||||||
|
|
||||||
|
var mode = SitesConf.getSiteStatus(BgVars.currentSite);
|
||||||
|
|
||||||
|
if(BrowserDetect.usebrowser == "firefox")
|
||||||
|
return Promise.resolve({response: mode});
|
||||||
|
|
||||||
|
try{
|
||||||
|
sendResponse({response: mode});
|
||||||
|
}
|
||||||
|
catch(chromeIsShitError){};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(message.cmd == "enable-for-site"){
|
||||||
|
SitesConf.updateSite(BgVars.currentSite, {status: message.option, statusEmbedded: message.option});
|
||||||
|
}
|
||||||
|
else if(message.cmd == "enable-autoar"){
|
||||||
|
ExtensionConf.arDetect.mode = "blacklist";
|
||||||
|
Settings.save(ExtensionConf);
|
||||||
|
// Comms.sendToAll({cmd: "reload-settings", sender: "uwbg"})
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw-bg] autoar set to enabled (blacklist). evidenz:", ExtensionConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(message.cmd == "disable-autoar"){
|
||||||
|
ExtensionConf.arDetect.mode = "disabled";
|
||||||
|
if(message.reason){
|
||||||
|
ExtensionConf.arDetect.disabledReason = message.reason;
|
||||||
|
} else {
|
||||||
|
ExtensionConf.arDetect.disabledReason = '';
|
||||||
|
}
|
||||||
|
Settings.save(ExtensionConf);
|
||||||
|
// Comms.sendToAll({cmd: "reload-settings", sender: "uwbg"});
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw-bg] autoar set to disabled. evidenz:", ExtensionConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(message.cmd == "gib-settings"){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg] we got asked for settings. Returning this:", ExtensionConf);
|
||||||
|
|
||||||
|
if(BrowserDetect.usebrowser == "firefox")
|
||||||
|
return Promise.resolve({response: ExtensionConf});
|
||||||
|
|
||||||
|
try{
|
||||||
|
sendResponse({response: ExtensionConf});
|
||||||
|
}
|
||||||
|
catch(chromeIsShitError){};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(message.cmd = "autoar-set-timer-playing"){
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg] trying to set new interval for autoAr. New interval is",message.timeout,"ms");
|
||||||
|
|
||||||
|
var timeout = message.timeout;
|
||||||
|
|
||||||
|
if(timeout < 1)
|
||||||
|
timeout = 1;
|
||||||
|
if(timeout > 999)
|
||||||
|
timeout = 999;
|
||||||
|
|
||||||
|
ExtensionConf.arDetect.timer_playing = timeout;
|
||||||
|
Settings.save(ExtensionConf);
|
||||||
|
Comms.sendToAll({cmd: "update-settings", sender: "uwbg", newConf: ExtensionConf});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main();
|
||||||
302
js/uw.js
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
if(Debug.debug){
|
||||||
|
console.log("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀᴡɪᴅɪꜰʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n");
|
||||||
|
try {
|
||||||
|
if(window.self !== window.top){
|
||||||
|
console.log("%cWe aren't in an iframe.", "color: #afc, background: #174");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log("%cWe are in an iframe!", "color: #fea, background: #d31", window.self, window.top);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("%cWe are in an iframe!", "color: #fea, background: #d31");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all settings from localStorage:
|
||||||
|
|
||||||
|
async function main(){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::main] loading configuration ...");
|
||||||
|
|
||||||
|
// load settings
|
||||||
|
var isSlave = true;
|
||||||
|
await Settings.init(isSlave);
|
||||||
|
var scpromise = SitesConf.init();
|
||||||
|
var kbpromise = Keybinds.init();
|
||||||
|
|
||||||
|
// reset current css stuff in GlobalVars
|
||||||
|
GlobalVars.correctedVideoDimensions.top = null;
|
||||||
|
GlobalVars.correctedVideoDimensions.left = null;
|
||||||
|
GlobalVars.correctedVideoDimensions.width = null;
|
||||||
|
GlobalVars.correctedVideoDimensions.height = null;
|
||||||
|
|
||||||
|
GlobalVars.currentCss = {top: null, left: null};
|
||||||
|
|
||||||
|
// počakamo, da so nastavitve naložene
|
||||||
|
// wait for settings to load
|
||||||
|
await scpromise;
|
||||||
|
await kbpromise;
|
||||||
|
|
||||||
|
// globalVars: lastAr type = original
|
||||||
|
GlobalVars.lastAr = {type: "original"};
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::main] configuration should be loaded now");
|
||||||
|
// start autoar and setup everything
|
||||||
|
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::main] | document is ready. Starting ar script ...");
|
||||||
|
|
||||||
|
if(! SitesConf.isEnabled(window.location.hostname)){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw:main] | site", window.location.hostname, "is blacklisted.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(SitesConf.isArEnabled(window.location.hostname)){
|
||||||
|
// if(Debug.debug)
|
||||||
|
// console.log("[uw::main] Aspect ratio detection is enabled. Starting ArDetect");
|
||||||
|
// ArDetect.arSetup();
|
||||||
|
// }
|
||||||
|
// console.log("[uw::main] ExtensionConf:", ExtensionConf);
|
||||||
|
|
||||||
|
if(ExtensionConf.arDetect.mode == "blacklist"){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::main] Aspect ratio detection is enabled (mode=",ExtensionConf.arDetect.mode,"). Starting ArDetect");
|
||||||
|
ArDetect.arSetup();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::main] Aspect ratio detection is disabled. Mode:", ExtensionConf.arDetect.mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener(receiveMessage);
|
||||||
|
setInterval( ghettoOnChange, 100);
|
||||||
|
setInterval( ghettoUrlWatcher, 500);
|
||||||
|
|
||||||
|
// ko se na ticevki zamenja video, console.log pravi da ultrawidify spremeni razmerje stranic. preglej element
|
||||||
|
// in pogled na predvajalnik pravita, da se to ni zgodilo. Iz tega sledi, da nam ticevka povozi css, ki smo ga
|
||||||
|
// vsilili. To super duper ni kul, zato uvedemo nekaj protiukrepov.
|
||||||
|
//
|
||||||
|
// when you change a video on youtube, console.log says that ultrawidify changes aspect ratio. inspect element
|
||||||
|
// and a look at youtube player, on the other hand, say this didn't happen. It seems that youtube overrides our
|
||||||
|
// css, and this is super duper uncool. Therefore, extra checks and measures.
|
||||||
|
setInterval( Resizer.antiCssOverride, 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// tukaj gledamo, ali se je velikost predvajalnika spremenila. Če se je, ponovno prožimo resizer
|
||||||
|
// here we check (in the most ghetto way) whether player size has changed. If it has, we retrigger resizer.
|
||||||
|
|
||||||
|
var _video_recheck_counter = 5;
|
||||||
|
var _video_recheck_period = 1; // on this many retries
|
||||||
|
|
||||||
|
function ghettoOnChange(){
|
||||||
|
|
||||||
|
if(_video_recheck_counter++ > _video_recheck_period){
|
||||||
|
_video_recheck_counter = 0;
|
||||||
|
|
||||||
|
if ( GlobalVars.video == null ||
|
||||||
|
GlobalVars.video == undefined ||
|
||||||
|
GlobalVars.video.videoWidth == 0 ||
|
||||||
|
GlobalVars.video.videoHeight == 0 ){
|
||||||
|
|
||||||
|
var video = document.getElementsByTagName("video")[0];
|
||||||
|
if ( video !== undefined &&
|
||||||
|
video !== null &&
|
||||||
|
video.videoWidth > 0 &&
|
||||||
|
video.videoHeight > 0 ){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("%c[uw::ghettoOnChange] detected video. registering!", "color: #99f, background: #000");
|
||||||
|
console.log("[uw::ghettoOnChange] just for shits and giggles, let's see what's happened with GlobalVars.playerDimensions:", GlobalVars.playerDimensions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// zaznali smo novo <video> značko. Zaradi tega bomo resetirali GlobalVars.playerDimensions
|
||||||
|
// a new <video> has been detected. We'll be resetting GlobalVars.playerDimensions
|
||||||
|
GlobalVars.playerDimensions = PlayerDetect.getPlayerDimensions(video);
|
||||||
|
|
||||||
|
GlobalVars.video = video;
|
||||||
|
Comms.sendToBackgroundScript({"cmd":"register-video"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! GlobalVars.video)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions == null){
|
||||||
|
GlobalVars.playerDimensions = PlayerDetect.getPlayerDimensions( GlobalVars.video );
|
||||||
|
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions == undefined){
|
||||||
|
GlobalVars.playerDimensions = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(PlayerDetect.checkPlayerSizeChange()){
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw::ghettoOnChange] change detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GlobalVars.playerDimensions = PlayerDetect.getPlayerDimensions( GlobalVars.video );
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions == undefined){
|
||||||
|
GlobalVars.playerDimensions = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resizer.restore(); // note: this returns true if change goes through, false otherwise.
|
||||||
|
}
|
||||||
|
|
||||||
|
// sometimes, checkPlayerSizeChange might not detect a change to fullscreen. This means we need to
|
||||||
|
// trick it into doing that
|
||||||
|
|
||||||
|
if(GlobalVars.playerDimensions.fullscreen != PlayerDetect.isFullScreen()){
|
||||||
|
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw::ghettoOnChange] fullscreen switch detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVars.playerDimensions = PlayerDetect.getPlayerDimensions(GlobalVars.video);
|
||||||
|
if(GlobalVars.playerDimensions == undefined){
|
||||||
|
GlobalVars.playerDimensions = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resizer.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function ghettoUrlWatcher(){
|
||||||
|
if (GlobalVars.lastUrl != window.location.href){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw::ghettoUrlWatcher] URL has changed. Trying to retrigger autoAr");
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVars.video = null;
|
||||||
|
GlobalVars.lastUrl = window.location.href;
|
||||||
|
// Resizer.reset();
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// comms
|
||||||
|
function receiveMessage(message, sender, sendResponse) {
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::receiveMessage] we received a message.", message);
|
||||||
|
|
||||||
|
if(message.cmd == "has-videos"){
|
||||||
|
var anyVideos = GlobalVars.video != null;
|
||||||
|
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::receiveMessage] are there any videos on this page?", anyVideos, GlobalVars.video, this);
|
||||||
|
|
||||||
|
if(BrowserDetect.usebrowser == "firefox")
|
||||||
|
return Promise.resolve({response: {"hasVideos": anyVideos }});
|
||||||
|
|
||||||
|
try{
|
||||||
|
sendResponse({response: {"hasVideos":anyVideos}});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(chromeIsShitError){}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(message.cmd == "get-config"){
|
||||||
|
|
||||||
|
var config = {};
|
||||||
|
config.videoAlignment = ExtensionConf.miscFullscreenSettings.videoFloat;
|
||||||
|
config.arConf = {};
|
||||||
|
config.arConf.enabled_global = ExtensionConf.arDetect.enabled == "global";
|
||||||
|
|
||||||
|
|
||||||
|
var keybinds = Keybinds.getKeybinds();
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw-bg::_uwbg_rcvmsg] Keybinds.fetch returned this:", keybinds);
|
||||||
|
|
||||||
|
config.keyboardShortcuts = keybinds;
|
||||||
|
|
||||||
|
// predvidevajmo, da je enako. Če je drugače, bomo popravili ko dobimo odgovor
|
||||||
|
// assume current is same as global & change that when you get response from content script
|
||||||
|
config.arConf.enabled_current = ArDetect.isRunning();
|
||||||
|
|
||||||
|
if(BrowserDetect.usebrowser == "firefox")
|
||||||
|
return Promise.resolve({response: config});
|
||||||
|
|
||||||
|
try{
|
||||||
|
sendResponse({response: config});
|
||||||
|
}
|
||||||
|
catch(chromeIsShitError){};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(message.cmd == "force-ar"){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::receiveMessage] we're being commanded to change aspect ratio to", message.newAr);
|
||||||
|
|
||||||
|
if(message.arType == "legacy"){
|
||||||
|
ArDetect.stop();
|
||||||
|
Resizer.legacyAr(message.newAr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ArDetect.stop();
|
||||||
|
Resizer.setAr(message.newAr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(message.cmd == "force-video-float"){
|
||||||
|
if(Debug.debug)
|
||||||
|
console.log("[uw::receiveMessage] we're aligning video to", message.newFloat);
|
||||||
|
|
||||||
|
ExtensionConf.miscFullscreenSettings.videoFloat = message.newFloat;
|
||||||
|
Settings.save(ExtensionConf);
|
||||||
|
}
|
||||||
|
else if(message.cmd == "stop-autoar"){
|
||||||
|
ArDetect.stop();
|
||||||
|
}
|
||||||
|
else if(message.cmd == "update-settings"){
|
||||||
|
if(Debug.debug){
|
||||||
|
console.log("[uw] we got sent new ExtensionConf to abide by:", cmd.newConf);
|
||||||
|
}
|
||||||
|
ExtensionConf = cmd.newConf;
|
||||||
|
}
|
||||||
|
// else if(message.cmd == "enable-autoar"){
|
||||||
|
// if(Debug.debug){
|
||||||
|
// console.log("[uw] enabling autoar.");
|
||||||
|
// }
|
||||||
|
// ExtensionConf.autoAr.mode == "blacklist";
|
||||||
|
// Settings.save(ExtensionConf);
|
||||||
|
// }
|
||||||
|
// else if(message.cmd == "disable-autoar"){
|
||||||
|
// if(Debug.debug){
|
||||||
|
// console.log("[uw] disabling autoar.");
|
||||||
|
// }
|
||||||
|
// ExtensionConf.autoAr.mode == "disabled";
|
||||||
|
// Settings.save(ExtensionConf);
|
||||||
|
// }
|
||||||
|
if(message.cmd == "testing"){
|
||||||
|
if(Browserdetect.usebrowser = "firefox")
|
||||||
|
return Promise.resolve({response: "test response hier"});
|
||||||
|
|
||||||
|
sendResponse({response: "test response hier"});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// $(document).ready(function() {
|
||||||
|
main();
|
||||||
|
// });
|
||||||
87
manifest.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "Ultrawidify",
|
||||||
|
"version": "2.2.5",
|
||||||
|
|
||||||
|
"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/dep/jquery-3.1.1.js",
|
||||||
|
"js/dep/chrome/chrome-extension-async.js",
|
||||||
|
|
||||||
|
"js/run/GlobalVars.js",
|
||||||
|
"js/lib/BrowserDetect.js",
|
||||||
|
"js/lib/StorageManager.js",
|
||||||
|
"js/lib/Comms.js",
|
||||||
|
|
||||||
|
"js/conf/Debug.js",
|
||||||
|
"js/conf/Settings.js",
|
||||||
|
"js/conf/SitesConf.js",
|
||||||
|
"js/conf/Status.js",
|
||||||
|
|
||||||
|
"js/lib/PlayerDetect.js",
|
||||||
|
|
||||||
|
"js/modules/PageInfo.js",
|
||||||
|
"js/modules/DebugCanvas.js",
|
||||||
|
"js/modules/ArDetect.js",
|
||||||
|
"js/modules/Resizer.js",
|
||||||
|
|
||||||
|
"js/conf/Keybinds.js",
|
||||||
|
|
||||||
|
"js/uw.js" ],
|
||||||
|
"all_frames": true
|
||||||
|
}],
|
||||||
|
|
||||||
|
"background": {
|
||||||
|
"scripts": [
|
||||||
|
"js/dep/jquery-3.1.1.js",
|
||||||
|
"js/dep/chrome/chrome-extension-async.js",
|
||||||
|
|
||||||
|
"js/lib/BrowserDetect.js",
|
||||||
|
"js/lib/StorageManager.js",
|
||||||
|
"js/lib/Comms.js",
|
||||||
|
|
||||||
|
"js/conf/Debug.js",
|
||||||
|
"js/conf/ExtensionConf.js",
|
||||||
|
"js/conf/Settings.js",
|
||||||
|
"js/conf/SitesConf.js",
|
||||||
|
"js/conf/Status.js",
|
||||||
|
|
||||||
|
"js/conf/Keybinds.js",
|
||||||
|
|
||||||
|
"js/uw-bg.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": [
|
||||||
|
"tabs", "storage", "activeTab", "<all_urls>", "webNavigation"
|
||||||
|
],
|
||||||
|
|
||||||
|
"browser_action": {
|
||||||
|
"default_icon": "res/icons/uw-32.png",
|
||||||
|
"default_popup": "res/popup/popup.html",
|
||||||
|
"default_title": "Ultrawidify"
|
||||||
|
},
|
||||||
|
|
||||||
|
"web_accessible_resources": [
|
||||||
|
"js/*",
|
||||||
|
"res/fonts/*",
|
||||||
|
"res/css/*",
|
||||||
|
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
||||||
22206
package-lock.json
generated
88
package.json
@ -1,88 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ultrawidify",
|
|
||||||
"version": "6.3.998",
|
|
||||||
"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",
|
|
||||||
"build-all": "bash ./scripts/build-all.sh",
|
|
||||||
"build-chrome": "cross-env NODE_ENV=production BROWSER=chrome CHANNEL=stable webpack",
|
|
||||||
"build-chrome:dev": "cross-env NODE_ENV=development BROWSER=chrome webpack",
|
|
||||||
"build-edge": "cross-env NODE_ENV=production BROWSER=edge CHANNEL=stable webpack",
|
|
||||||
"build-nightly": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=nightly webpack",
|
|
||||||
"build-nightly-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=nightly webpack",
|
|
||||||
"build-testing": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=testing webpack",
|
|
||||||
"build-testing-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=testing webpack",
|
|
||||||
"build-zip": "node scripts/build-zip.js",
|
|
||||||
"build:dev": "webpack",
|
|
||||||
"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.18.6",
|
|
||||||
"@mdi/font": "^7.4.47",
|
|
||||||
"@mdi/js": "^7.4.47",
|
|
||||||
"@types/resize-observer-browser": "^0.1.11",
|
|
||||||
"concurrently": "^9.2.1",
|
|
||||||
"fs-extra": "^11.3.2",
|
|
||||||
"gl-matrix": "^3.4.4",
|
|
||||||
"json-cyclic": "1.0.2",
|
|
||||||
"json-difference": "^1.16.1",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"mdi-vue": "^3.0.13",
|
|
||||||
"typescript": "^5.9.3",
|
|
||||||
"vanilla-jsoneditor": "^3.10.0",
|
|
||||||
"vue": "^3.5.25",
|
|
||||||
"vue-style-loader": "^4.1.3",
|
|
||||||
"vuex": "^4.1.0",
|
|
||||||
"vuex-webextensions": "^1.3.3",
|
|
||||||
"webextension-polyfill": "^0.12.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.28.5",
|
|
||||||
"@babel/preset-env": "^7.28.5",
|
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
|
||||||
"@types/chrome": "0.1.31",
|
|
||||||
"@types/core-js": "^2.5.8",
|
|
||||||
"@types/es6-promise": "^3.3.2",
|
|
||||||
"@types/firefox": "0.0.34",
|
|
||||||
"@types/lodash": "^4.17.21",
|
|
||||||
"@types/node": "^24.10.1",
|
|
||||||
"@vue/cli": "^5.0.9",
|
|
||||||
"@vue/cli-plugin-typescript": "^5.0.9",
|
|
||||||
"@vue/compiler-sfc": "^3.5.25",
|
|
||||||
"archiver": "^7.0.1",
|
|
||||||
"babel-loader": "^10.0.0",
|
|
||||||
"babel-preset-es2020": "^1.0.2",
|
|
||||||
"copy-webpack-plugin": "^13.0.1",
|
|
||||||
"cross-env": "^10.1.0",
|
|
||||||
"css-loader": "^7.1.2",
|
|
||||||
"ejs": "^3.1.10",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"mini-css-extract-plugin": "^2.9.4",
|
|
||||||
"postcss": "^8.5.6",
|
|
||||||
"postcss-import": "^16.1.1",
|
|
||||||
"postcss-nested": "^7.0.2",
|
|
||||||
"postcss-preset-env": "^10.4.0",
|
|
||||||
"postcss-strip-inline-comments": "^0.1.5",
|
|
||||||
"raw-loader": "^4.0.2",
|
|
||||||
"resolve-url-loader": "^5.0.0",
|
|
||||||
"tailwindcss": "^4.1.17",
|
|
||||||
"ts-loader": "^9.5.4",
|
|
||||||
"tsconfig-paths": "^4.2.0",
|
|
||||||
"vue-cli-plugin-vue-next": "~0.1.4",
|
|
||||||
"vue-loader": "^17.4.2",
|
|
||||||
"vue-tsc": "^3.1.5",
|
|
||||||
"web-ext-types": "^3.2.1",
|
|
||||||
"webpack": "^5.103.0",
|
|
||||||
"webpack-cli": "^6.0.1",
|
|
||||||
"webpack-shell-plugin": "^0.5.0",
|
|
||||||
"webpack-shell-plugin-next": "^2.3.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
const path = require('path')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
'@src': path.resolve(__dirname, 'src'),
|
|
||||||
'@ui': path.resolve(__dirname, 'src/ui'),
|
|
||||||
'@components': path.resolve(__dirname, 'src/ui/components'),
|
|
||||||
'@res': path.resolve(__dirname, 'src/ui/res'),
|
|
||||||
'@': path.resolve(__dirname, 'src'),
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const aliases = require('./paths.config');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
plugins: [
|
|
||||||
require('postcss-import')({
|
|
||||||
resolve(id) {
|
|
||||||
for (const alias in aliases) {
|
|
||||||
if (id === alias || id.startsWith(alias + '/')) {
|
|
||||||
return path.resolve(
|
|
||||||
aliases[alias],
|
|
||||||
id.slice(alias.length + 1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
require('@tailwindcss/postcss'),
|
|
||||||
require('postcss-nested'),
|
|
||||||
require('autoprefixer'),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
29
res/css/font/overpass-mono.css
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('../../fonts/overpass-mono-webfont/overpass-mono-light.woff2') format('woff2');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('../../fonts/overpass-mono-webfont/overpass-mono-regular.woff2') format('woff2');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('../../fonts/overpass-mono-webfont/overpass-mono-semibold.woff2') format('woff2');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('../../fonts/overpass-mono-webfont/overpass-mono-bold.woff2') format('woff2');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
125
res/css/font/overpass.css
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('../../fonts/overpass-webfont/overpass-extrabold.woff2') format('woff2');
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('../../fonts/overpass-webfont/overpass-extrabold-italic.woff2') format('woff2');
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('../../fonts/overpass-webfont/overpass-heavy.woff2') format('woff2');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('../../fonts/overpass-webfont/overpass-heavy-italic.woff2') format('woff2');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
50
res/fonts/LICENSE.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
## 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.
|
||||||
BIN
res/fonts/overpass-mono-webfont/overpass-mono-bold.woff
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-bold.woff2
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-light.woff
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-light.woff2
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-regular.woff
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-regular.woff2
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-semibold.woff
Normal file
BIN
res/fonts/overpass-mono-webfont/overpass-mono-semibold.woff2
Normal file
51
res/fonts/overpass-mono-webfont/overpass-mono.css
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('overpass-mono-light.eot');
|
||||||
|
src: url('overpass-mono-light.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-mono-light.woff2') format('woff2'),
|
||||||
|
url('overpass-mono-light.woff') format('woff'),
|
||||||
|
url('overpass-mono-light.ttf') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('overpass-mono-regular.eot');
|
||||||
|
src: url('overpass-mono-regular.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-mono-regular.woff2') format('woff2'),
|
||||||
|
url('overpass-mono-regular.woff') format('woff'),
|
||||||
|
url('overpass-mono-regular.ttf') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('overpass-mono-semibold.eot');
|
||||||
|
src: url('overpass-mono-semibold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-mono-semibold.woff2') format('woff2'),
|
||||||
|
url('overpass-mono-semibold.woff') format('woff'),
|
||||||
|
url('overpass-mono-semibold.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass-mono';
|
||||||
|
src: url('overpass-mono-bold.eot');
|
||||||
|
src: url('overpass-mono-bold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-mono-bold.woff2') format('woff2'),
|
||||||
|
url('overpass-mono-bold.woff') format('woff'),
|
||||||
|
url('overpass-mono-bold.ttf') format('truetype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
BIN
res/fonts/overpass-webfont/overpass-bold-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-bold-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-bold.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-bold.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-extrabold-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-extrabold-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-extrabold.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-extrabold.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-extralight-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-extralight-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-extralight.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-extralight.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-heavy-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-heavy-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-heavy.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-heavy.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-light-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-light-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-light.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-light.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-regular.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-regular.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-semibold-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-semibold-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-semibold.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-semibold.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-thin-italic.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-thin-italic.woff2
Normal file
BIN
res/fonts/overpass-webfont/overpass-thin.woff
Normal file
BIN
res/fonts/overpass-webfont/overpass-thin.woff2
Normal file
189
res/fonts/overpass-webfont/overpass.css
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-thin.eot'); /* IE9 Compat Modes */
|
||||||
|
src: url('overpass-thin.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||||
|
url('overpass-thin.woff2') format('woff2'), /* Super Modern Browsers */
|
||||||
|
url('overpass-thin.woff') format('woff'), /* Pretty Modern Browsers */
|
||||||
|
url('overpass-thin.ttf') format('truetype'); /* Safari, Android, iOS */
|
||||||
|
font-weight: 200;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-thin-italic.eot');
|
||||||
|
src: url('overpass-thin-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-thin-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-thin-italic.woff') format('woff'),
|
||||||
|
url('overpass-thin-italic.ttf') format('truetype');
|
||||||
|
font-weight: 200;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-extralight.eot');
|
||||||
|
src: url('overpass-extralight.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-extralight.woff2') format('woff2'),
|
||||||
|
url('overpass-extralight.woff') format('woff'),
|
||||||
|
url('overpass-extralight.ttf') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-extralight-italic.eot');
|
||||||
|
src: url('overpass-extralight-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-extralight-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-extralight-italic.woff') format('woff'),
|
||||||
|
url('overpass-extralight-italic.ttf') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-light.eot');
|
||||||
|
src: url('overpass-light.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-light.woff2') format('woff2'),
|
||||||
|
url('overpass-light.woff') format('woff'),
|
||||||
|
url('overpass-light.ttf') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-light-italic.eot');
|
||||||
|
src: url('overpass-light-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-light-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-light-italic.woff') format('woff'),
|
||||||
|
url('overpass-light-italic.ttf') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-regular.eot');
|
||||||
|
src: url('overpass-regular.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-regular.woff2') format('woff2'),
|
||||||
|
url('overpass-regular.woff') format('woff'),
|
||||||
|
url('overpass-regular.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-italic.eot');
|
||||||
|
src: url('overpass-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-italic.woff') format('woff'),
|
||||||
|
url('overpass-italic.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-semibold.eot');
|
||||||
|
src: url('overpass-semibold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-semibold.woff2') format('woff2'),
|
||||||
|
url('overpass-semibold.woff') format('woff'),
|
||||||
|
url('overpass-semibold.ttf') format('truetype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-semibold-italic.eot');
|
||||||
|
src: url('overpass-semibold-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-semibold-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-semibold-italic.woff') format('woff'),
|
||||||
|
url('overpass-semibold-italic.ttf') format('truetype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-bold.eot');
|
||||||
|
src: url('overpass-bold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-bold.woff2') format('woff2'),
|
||||||
|
url('overpass-bold.woff') format('woff'),
|
||||||
|
url('overpass-bold.ttf') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-bold-italic.eot');
|
||||||
|
src: url('overpass-bold-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-bold-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-bold-italic.woff') format('woff'),
|
||||||
|
url('overpass-bold-italic.ttf') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-extrabold.eot');
|
||||||
|
src: url('overpass-extrabold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-extrabold.woff2') format('woff2'),
|
||||||
|
url('overpass-extrabold.woff') format('woff'),
|
||||||
|
url('overpass-extrabold.ttf') format('truetype');
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-extrabold-italic.eot');
|
||||||
|
src: url('overpass-extrabold-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-extrabold-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-extrabold-italic.woff') format('woff'),
|
||||||
|
url('overpass-extrabold-italic.ttf') format('truetype');
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-heavy.eot');
|
||||||
|
src: url('overpass-heavy.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-heavy.woff2') format('woff2'),
|
||||||
|
url('overpass-heavy.woff') format('woff'),
|
||||||
|
url('overpass-heavy.ttf') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'overpass';
|
||||||
|
src: url('overpass-heavy-italic.eot');
|
||||||
|
src: url('overpass-heavy-italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('overpass-heavy-italic.woff2') format('woff2'),
|
||||||
|
url('overpass-heavy-italic.woff') format('woff'),
|
||||||
|
url('overpass-heavy-italic.ttf') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
BIN
res/img/settings/about-bg.png
Normal file
|
After Width: | Height: | Size: 783 KiB |