Compare commits
18 Commits
c5515934d9
...
e56d32180c
| Author | SHA1 | Date | |
|---|---|---|---|
| e56d32180c | |||
| 6c92837317 | |||
| d4015a86ef | |||
| 4b4be96e26 | |||
| 823e1d983c | |||
| 47fba5b81a | |||
| ee23ebb705 | |||
| d6d3a95daf | |||
| e839e632fc | |||
| cb6f0a9a32 | |||
| 12644bfbea | |||
| 5ca9325e16 | |||
| b8fdf0911a | |||
| a7302fee4b | |||
| 41bf4d2764 | |||
| 0970140a3a | |||
| b8eb8ec052 | |||
| 46b7d6a25a |
39
CHANGELOG.md
39
CHANGELOG.md
@ -11,12 +11,43 @@
|
||||
## v7.0 (planned major)
|
||||
* WebGL autodetection
|
||||
|
||||
## v6.0 (next major)
|
||||
## v6.0 (current major)
|
||||
|
||||
* in-player GUI
|
||||
* Fix UI logger
|
||||
### v6.0.1
|
||||
|
||||
## v5.x (current major)
|
||||
* 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
|
||||
|
||||
|
||||
25
package-lock.json
generated
25
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ultrawidify",
|
||||
"version": "6.0.0",
|
||||
"version": "6.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -3796,6 +3796,16 @@
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
|
||||
@ -6811,6 +6821,13 @@
|
||||
"integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==",
|
||||
"dev": true
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"filename-reserved-regex": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
|
||||
@ -7485,6 +7502,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"gl-matrix": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz",
|
||||
"integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA=="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
@ -16019,6 +16041,7 @@
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"bindings": "^1.5.0",
|
||||
"nan": "^2.12.1"
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ultrawidify",
|
||||
"version": "6.0.0",
|
||||
"version": "6.0.1",
|
||||
"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": {
|
||||
@ -31,6 +31,7 @@
|
||||
"@types/resize-observer-browser": "^0.1.6",
|
||||
"concurrently": "^5.3.0",
|
||||
"fs-extra": "^7.0.1",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"json-cyclic": "0.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"mdi-vue": "^3.0.11",
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#
|
||||
# Script assumes we're in basedir of the repository and that extension has been built and zipped to /dist-zip
|
||||
# using the crx name we want (same name as zip, except different extension)
|
||||
#
|
||||
#
|
||||
# also this doesn't check for errors ever so
|
||||
#
|
||||
|
||||
@ -42,4 +42,4 @@ sig_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$sig" | awk '{print $5}')))
|
||||
echo "Wrote $crx"
|
||||
|
||||
echo "exiting dist-zip"
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
@ -24,7 +24,7 @@ const buildZip = (src, dist, zipFilename) => {
|
||||
|
||||
const archive = archiver('zip', { zlib: { level: 9 }});
|
||||
const stream = fs.createWriteStream(path.join(dist, zipFilename));
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
archive
|
||||
.directory(src, false)
|
||||
@ -46,14 +46,14 @@ const main = () => {
|
||||
browserPostfix = browser;
|
||||
}
|
||||
const destDir = path.join(__dirname, `../dist-${browserPostfix}`);
|
||||
const zipDir = path.join(__dirname, '../dist-zip');
|
||||
const zipDir = path.join(__dirname, '../dist-zip');
|
||||
const {name, version} = extractExtensionData(browserPostfix);
|
||||
|
||||
// collapse spaces and dashes into single dash
|
||||
const baseFilename = `${name.replace(/[ -]+/g, '-')}-${version}`;
|
||||
|
||||
let realZipDir;
|
||||
|
||||
|
||||
if (!!testingOrNightly) {
|
||||
realZipDir = path.join(zipDir, version);
|
||||
} else {
|
||||
@ -61,7 +61,7 @@ const main = () => {
|
||||
}
|
||||
|
||||
const zipFilename = `${baseFilename}-${browser}.zip`;
|
||||
|
||||
|
||||
try {
|
||||
makeDirIfNotExists(realZipDir, {recursive: true});
|
||||
} catch (e) {
|
||||
@ -70,7 +70,7 @@ const main = () => {
|
||||
}
|
||||
buildZip(destDir, realZipDir, zipFilename)
|
||||
.then(() => console.info('OK'))
|
||||
.catch(console.err);
|
||||
.catch(console.err);
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
@ -185,6 +185,12 @@ interface SettingsInterface {
|
||||
}
|
||||
},
|
||||
|
||||
ui: {
|
||||
inPlayer: {
|
||||
enabled: boolean
|
||||
}
|
||||
}
|
||||
|
||||
restrictions?: RestrictionsSettings;
|
||||
|
||||
crop: {
|
||||
@ -310,52 +316,6 @@ interface SettingsInterface {
|
||||
sites: {
|
||||
[x: string]: SiteSettingsInterface,
|
||||
}
|
||||
// sites: {
|
||||
// [x: string]: {
|
||||
// defaultCrop?: any, // v6 new
|
||||
// defaultStretch?: any, // v6 new
|
||||
// enabled: ExtensionEnvironmentSettingsInterface, // v6 new
|
||||
// enabledAard: ExtensionEnvironmentSettingsInterface,// v6 new
|
||||
|
||||
// // everything 'superseded by' needs to be implemented
|
||||
// // as well as ported from the old settings
|
||||
// mode?: ExtensionMode, // v6 — superseded by looking at enableIn
|
||||
// autoar?: ExtensionMode, // v6 — superseded by looking at enableIn
|
||||
// autoarFallback?: ExtensionMode, // v6 — deprecated, no replacement
|
||||
// stretch?: StretchType, // v6 — superseded by defaultStretch
|
||||
// videoAlignment?: VideoAlignmentType,
|
||||
// keyboardShortcutsEnabled?: ExtensionMode,
|
||||
// type?: string,
|
||||
// override?: boolean,
|
||||
// arPersistence?: boolean,
|
||||
// actions?: any;
|
||||
|
||||
// cropModePersistence?: CropModePersistence;
|
||||
|
||||
// DOM?: {
|
||||
// player?: {
|
||||
// manual?: boolean,
|
||||
// querySelectors?: string,
|
||||
// additionalCss?: string,
|
||||
// useRelativeAncestor?: boolean,
|
||||
// videoAncestor?: any,
|
||||
// playerNodeCss?: string,
|
||||
// periodicallyRefreshPlayerElement?: boolean
|
||||
// },
|
||||
// video?: {
|
||||
// manual?: boolean,
|
||||
// querySelectors?: string,
|
||||
// additionalCss?: string,
|
||||
// useRelativeAncestor?: boolean,
|
||||
// playerNodeCss?: string
|
||||
// }
|
||||
// },
|
||||
// css?: string;
|
||||
// usePlayerArInFullscreen?: boolean;
|
||||
|
||||
// restrictions?: RestrictionsSettings;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
export interface SiteSettingsInterface {
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
</ul>
|
||||
<p>
|
||||
<small>
|
||||
[1] If using anything other than Firefox, Chrome, or Edge, please check if issue also happens in Chrome or Edge. Bugs affecting Opera will only get fixed if they also affect Chrome, because <a href="https://stuff.tamius.net/sacred-texts/2024/06/08/why-im-boycotting-opera/">I'm salty</a>.<br/>
|
||||
[1] If using anything other than Firefox, Chrome, or Edge, please check if issue also happens in Chrome or Edge. Bugs affecting Opera will only get fixed if they also affect Chrome, because <a target="_blank" href="https://stuff.tamius.net/sacred-texts/2024/06/08/why-im-boycotting-opera/">I'm salty</a>.<br/>
|
||||
[2] It is recommended that users of Microsoft Edge install Ultrawidify from the Microsoft Edge Addons source
|
||||
</small>
|
||||
</p>
|
||||
@ -41,7 +41,7 @@
|
||||
If you think I deserve money for the work I did up to this point, you can bankroll my caffeine addiction.
|
||||
</p>
|
||||
<p class="text-center">
|
||||
<a class="donate" href="https://www.paypal.com/paypalme/tamius">Donate on Paypal</a>
|
||||
<a class="donate" href="https://www.paypal.com/paypalme/tamius" target="_blank">Donate on Paypal</a>
|
||||
</p>
|
||||
<h2>Fun stuff</h2>
|
||||
<p>
|
||||
|
||||
@ -3,7 +3,10 @@
|
||||
<div class="flex flex-row gap-2 bg-black">
|
||||
<div class="w-[1/2]" style="width: 50%">
|
||||
<h1>What's new</h1>
|
||||
<p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
|
||||
<p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md" target="_blank">is available here</a>.</p>
|
||||
|
||||
<h2>6.0.1</h2>
|
||||
<p>Fixed external links.</p>
|
||||
|
||||
<h2>6.0.0</h2>
|
||||
<p>
|
||||
@ -32,12 +35,12 @@
|
||||
<li>
|
||||
The in-player UI should now display a warning whenever Ultrawidify detects automatic aspect ratio detection isn't happening because the site uses DRM.
|
||||
</li>
|
||||
<li>
|
||||
<!-- <li>
|
||||
Better zooming. The slider is back, baby.
|
||||
</li>
|
||||
<li>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
Panning option that's a bit more intuitive.
|
||||
</li>
|
||||
</li> -->
|
||||
</ul>
|
||||
<h3>Unbaked features</h3>
|
||||
<ul>
|
||||
@ -72,7 +75,7 @@
|
||||
If you think I deserve money for the work I did up to this point, you can bankroll my caffeine addiction.
|
||||
</p>
|
||||
<p class="text-center">
|
||||
<a class="donate" href="https://www.paypal.com/paypalme/tamius">Donate on Paypal</a>
|
||||
<a class="donate" href="https://www.paypal.com/paypalme/tamius" target="_blank">Donate on Paypal</a>
|
||||
</p>
|
||||
<h2>Fun stuff</h2>
|
||||
<p>
|
||||
|
||||
@ -132,11 +132,11 @@
|
||||
<div class="select">
|
||||
<select
|
||||
v-model="siteDefaultCrop"
|
||||
@click="setOption('defaults.crop', $event)"
|
||||
@change="setOption('defaults.crop', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="!isDefaultConfiguration"
|
||||
:value="undefined"
|
||||
:value="JSON.stringify({useDefault: true})"
|
||||
>
|
||||
Use default ({{getCommandValue(settings?.active.commands.crop, siteSettings.data.defaults.crop)}})
|
||||
</option>
|
||||
@ -158,11 +158,11 @@
|
||||
<div class="select">
|
||||
<select
|
||||
v-model="siteDefaultStretch"
|
||||
@click="setOption('defaults.stretch', $event)"
|
||||
@change="setOption('defaults.stretch', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="!isDefaultConfiguration"
|
||||
:value="undefined"
|
||||
:value="JSON.stringify({useDefault: true})"
|
||||
>
|
||||
Use default ({{getCommandValue(settings?.active.commands.stretch, siteSettings.data.defaults.stretch)}})
|
||||
</option>
|
||||
@ -183,11 +183,11 @@
|
||||
<div class="select">
|
||||
<select
|
||||
v-model="siteDefaultAlignment"
|
||||
@click="setOption('defaults.alignment', $event)"
|
||||
@change="setOption('defaults.alignment', $event)"
|
||||
>
|
||||
<option
|
||||
v-if="!isDefaultConfiguration"
|
||||
:value="undefined"
|
||||
:value="JSON.stringify({useDefault: true})"
|
||||
>
|
||||
Use default ({{getAlignmentLabel(siteSettings.data.defaults.alignment)}})
|
||||
</option>
|
||||
@ -268,13 +268,14 @@ export default {
|
||||
}
|
||||
},
|
||||
siteDefaultCrop() {
|
||||
return this.siteSettings.raw?.defaults?.crop ? JSON.stringify(this.siteSettings.raw?.defaults?.crop) : undefined;
|
||||
// console.log('Getting default site crop:', this.siteSettings.raw?.defaults?.crop ? 'yay' : '{useDefault}', this.siteSettings.raw?.defaults?.crop)
|
||||
return this.siteSettings.raw?.defaults?.crop ? JSON.stringify(this.siteSettings.raw?.defaults?.crop) : JSON.stringify({useDefault: true});
|
||||
},
|
||||
siteDefaultStretch() {
|
||||
return this.siteSettings.raw?.defaults?.stretch ? JSON.stringify(this.siteSettings.raw?.defaults?.stretch) : undefined;
|
||||
return this.siteSettings.raw?.defaults?.stretch ? JSON.stringify(this.siteSettings.raw?.defaults?.stretch) : JSON.stringify({useDefault: true});
|
||||
},
|
||||
siteDefaultAlignment() {
|
||||
return this.siteSettings.raw?.defaults?.alignment ? JSON.stringify(this.siteSettings.raw?.defaults?.alignment) : undefined;
|
||||
return this.siteSettings.raw?.defaults?.alignment ? JSON.stringify(this.siteSettings.raw?.defaults?.alignment) : JSON.stringify({useDefault: true});
|
||||
},
|
||||
siteDefaultCropPersistence() {
|
||||
return this.siteSettings.raw?.persistCSA ?? undefined;
|
||||
@ -386,17 +387,24 @@ export default {
|
||||
getOption(option) {
|
||||
|
||||
},
|
||||
setOption(option, $event) {
|
||||
async setOption(option, $event) {
|
||||
const value = $event.target.value;
|
||||
let commandArguments;
|
||||
|
||||
// if argument is json, parse json. Otherwise, pass the value as-is
|
||||
try {
|
||||
commandArguments = $event.target.value !== undefined ? JSON.parse($event.target.value) : undefined;
|
||||
commandArguments = value !== undefined ? JSON.parse(value) : undefined;
|
||||
} catch(e) {
|
||||
commandArguments = $event.target.value;
|
||||
commandArguments = value;
|
||||
}
|
||||
|
||||
this.siteSettings.set(option, commandArguments);
|
||||
if (commandArguments.useDefault) {
|
||||
commandArguments = undefined;
|
||||
}
|
||||
|
||||
// console.log('setting option', option, 'to cmd:', commandArguments, 'event data in:', value);
|
||||
await this.siteSettings.set(option, commandArguments);
|
||||
this.$nextTick( () => this.$forceUpdate() );
|
||||
},
|
||||
setExtensionMode(component, event) {
|
||||
const option = event.target.value;
|
||||
|
||||
@ -120,7 +120,7 @@
|
||||
<div class="select">
|
||||
<select
|
||||
:value="siteDefaultCrop"
|
||||
@click="setDefaultCrop($event, 'site')"
|
||||
@change="setDefaultCrop($event, 'site')"
|
||||
>
|
||||
<option
|
||||
v-for="(command, index) of settings?.active.commands.crop"
|
||||
|
||||
@ -134,7 +134,7 @@
|
||||
<div class="select">
|
||||
<select
|
||||
v-model="siteDefaultStretchMode"
|
||||
@click="setDefaultStretchingMode($event, 'site')"
|
||||
@change="setDefaultStretchingMode($event, 'site')"
|
||||
>
|
||||
<option
|
||||
v-for="(command, index) of settings?.active.commands.stretch"
|
||||
|
||||
@ -40,6 +40,7 @@ import Comms from '../../ext/lib/comms/Comms';
|
||||
import ShortcutButton from '../../common/components/ShortcutButton';
|
||||
import BrowserDetect from '../../ext/conf/BrowserDetect';
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ShortcutButton,
|
||||
@ -53,11 +54,13 @@ export default {
|
||||
loggerSettingsError: false,
|
||||
lastLoadedLoggerSettings: undefined,
|
||||
mailtoLink: '',
|
||||
redditLink: '',
|
||||
showEasterEgg: false,
|
||||
gmailLink: '',
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
const b64="dGFtaXVzLmhhbkBnbWFpbC5jb20";
|
||||
this.gmailLink = atob(b64);
|
||||
const messageTemplate = encodeURIComponent(
|
||||
`Describe your issue in more detail. In case of misaligned videos, please provide screenshots. When reporting\
|
||||
issues with autodetection not detecting aspect ratio correctly, please provide a link with timestamp to the\
|
||||
|
||||
@ -11,129 +11,14 @@ import AspectRatioType from '../../common/enums/AspectRatioType.enum';
|
||||
|
||||
const ExtensionConfPatch = [
|
||||
{
|
||||
forVersion: '5.0.5',
|
||||
sites: {
|
||||
"app.plex.tv": {
|
||||
mode: 3,
|
||||
autoar: 3,
|
||||
type: "community",
|
||||
stretch: -1,
|
||||
videoAlignment: -1,
|
||||
keyboardShortcutsEnabled: 0,
|
||||
DOM: {
|
||||
player: {
|
||||
manual: false,
|
||||
querySelectors: "",
|
||||
additionalCss: "",
|
||||
useRelativeAncestor: false,
|
||||
playerNodeCss: ""
|
||||
}
|
||||
},
|
||||
css: "body {\n background-color: #000;\n}\n\n.application {\n background-color: #000;\n}"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.0.6',
|
||||
sites: {
|
||||
"metaivi.com": {
|
||||
mode: 0,
|
||||
autoar: 0,
|
||||
type: "community",
|
||||
stretch: -1,
|
||||
videoAlignment: -1,
|
||||
DOM: {
|
||||
video: {
|
||||
manual: false,
|
||||
querySelectors: "",
|
||||
additionalCss: "position: absolute !important;"
|
||||
},
|
||||
player: {
|
||||
manual: false,
|
||||
querySelectors: "",
|
||||
additionalCss: "",
|
||||
useRelativeAncestor: false,
|
||||
playerNodeCss: ""
|
||||
}
|
||||
},
|
||||
"css": ""
|
||||
},
|
||||
"piped.kavin.rocks": {
|
||||
mode: 0,
|
||||
autoar: 0,
|
||||
type: 'community',
|
||||
autoarFallback: 0,
|
||||
stretch: 0,
|
||||
videoAlignment: -1,
|
||||
keyboardShortcutsEnabled: 0,
|
||||
DOM: {
|
||||
player: {
|
||||
manual: false,
|
||||
querySelectors: "",
|
||||
additionalCss: "",
|
||||
useRelativeAncestor: false,
|
||||
playerNodeCss: ""
|
||||
}
|
||||
},
|
||||
css: ".shaka-video-container {\n flex-direction: column !important;\n}"
|
||||
},
|
||||
},
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
// 5.0.5 initially incorrectly had app.plex.tv marked as 'user-added'
|
||||
// when 'user-added' is generally reserved for marking sites with user-
|
||||
// changed configuration. Site patches submitted by community should have
|
||||
// 'community' type. extConfPatch for 5.0.5 was also retroactively corrected.
|
||||
userOptions.sites['app.plex.tv'].type = 'community';
|
||||
userOptions.sites['piped.kavin.rocks'] = {
|
||||
mode: 0,
|
||||
autoar: 0,
|
||||
type: 'community',
|
||||
autoarFallback: 0,
|
||||
stretch: 0,
|
||||
videoAlignment: -1,
|
||||
keyboardShortcutsEnabled: 0,
|
||||
DOM: {
|
||||
player: {
|
||||
manual: false,
|
||||
querySelectors: "",
|
||||
additionalCss: "",
|
||||
useRelativeAncestor: false,
|
||||
playerNodeCss: ""
|
||||
}
|
||||
},
|
||||
css: ".shaka-video-container {\n flex-direction: column !important;\n}"
|
||||
};
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.0.7',
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
// 5.0.5 initially incorrectly had app.plex.tv marked as 'user-added'
|
||||
// when 'user-added' is generally reserved for marking sites with user-
|
||||
// changed configuration. Site patches submitted by community should have
|
||||
// 'community' type. extConfPatch for 5.0.5 was also retroactively corrected.
|
||||
userOptions.sites['www.youtube.com'].DOM.player = {
|
||||
manual: true,
|
||||
querySelectors: "#movie_player, #player, #c4-player",
|
||||
additionalCss: "",
|
||||
useRelativeAncestor: false,
|
||||
playerNodeCss: "",
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.0.8',
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
userOptions.sites['www.netflix.com'].DOM.player = {
|
||||
manual: false
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.99.0-1',
|
||||
forVersion: '6.0.1-1',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
// add new commands
|
||||
userOptions.commands = defaultOptions.commands;
|
||||
}
|
||||
}, {
|
||||
// NOTE - when releasing shit, ensure ALL alpha migrations are combined together in one function
|
||||
forVersion: '5.99.0-2',
|
||||
forVersion: '6.0.1-2',
|
||||
updateFn: (userOptions, defaultOptions) => {
|
||||
userOptions.commands = defaultOptions.commands;
|
||||
|
||||
@ -204,7 +89,7 @@ const ExtensionConfPatch = [
|
||||
}
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.99.0-3',
|
||||
forVersion: '6.0.1-3',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
delete (userOptions as any).sites['@global'].persistOption;
|
||||
delete (userOptions as any).sites['@empty'].persistOption;
|
||||
@ -213,7 +98,7 @@ const ExtensionConfPatch = [
|
||||
userOptions.sites['@empty'].persistCSA = CropModePersistence.Disabled;
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.99.0-4',
|
||||
forVersion: '6.0.1-4',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
|
||||
// deprecated much?
|
||||
@ -254,7 +139,7 @@ const ExtensionConfPatch = [
|
||||
})
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.99.5',
|
||||
forVersion: '6.0.1-5',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
if (!userOptions.sites['@global'].defaults.alignment || !userOptions.sites['@global'].defaults.alignment.x || !userOptions.sites['@global'].defaults.alignment.y) {
|
||||
userOptions.sites['@global'].defaults.alignment = {
|
||||
@ -265,7 +150,7 @@ const ExtensionConfPatch = [
|
||||
userOptions.sites['@empty'].defaults.alignment = {x: VideoAlignmentType.Default, y: VideoAlignmentType.Default};
|
||||
}
|
||||
}, {
|
||||
forVersion: '5.99.6',
|
||||
forVersion: '6.0.1-6',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
for (const site in userOptions.sites) {
|
||||
userOptions.sites[site].defaultType = userOptions.sites[site].type as any;
|
||||
@ -273,6 +158,20 @@ const ExtensionConfPatch = [
|
||||
userOptions.sites['@global'].defaultType = 'unknown';
|
||||
userOptions.sites['@empty'].defaultType = 'modified';
|
||||
}
|
||||
}, {
|
||||
forVersion: '6.0.1-7',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
// remove custom CSS, as it is no longer needed
|
||||
for (const site in userOptions.sites) {
|
||||
for (const domOption in userOptions.sites[site].DOMConfig)
|
||||
userOptions.sites[site].DOMConfig[domOption].customCss;
|
||||
}
|
||||
userOptions.ui = {
|
||||
inPlayer: {
|
||||
enabled: false, // keep disabled for existing users
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@ -141,6 +141,13 @@ const ExtensionConf: SettingsInterface = {
|
||||
testRowOffset: 0.02 // we test this % of height from detected edge
|
||||
}
|
||||
},
|
||||
|
||||
ui: {
|
||||
inPlayer: {
|
||||
enabled: true, // enable by default on new installs
|
||||
}
|
||||
},
|
||||
|
||||
crop: {
|
||||
default: {
|
||||
type: AspectRatioType.Automatic,
|
||||
@ -1445,7 +1452,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
persistCSA: CropModePersistence.Disabled,
|
||||
|
||||
defaults: {
|
||||
crop: {type: AspectRatioType.Reset}, // does NOT override Aard
|
||||
crop: {type: AspectRatioType.Automatic},
|
||||
stretch: StretchType.NoStretch,
|
||||
alignment: {x: VideoAlignmentType.Center, y: VideoAlignmentType.Center},
|
||||
}
|
||||
@ -1561,7 +1568,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
querySelectors: ".btm-media-client-element"
|
||||
}
|
||||
},
|
||||
customCss: ".hudson-container { height: 100%; }"
|
||||
// customCss: ".hudson-container { height: 100%; }"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1584,32 +1591,6 @@ const ExtensionConf: SettingsInterface = {
|
||||
type: 'official',
|
||||
defaultType: 'official',
|
||||
},
|
||||
// "streamable.com": {
|
||||
// enable: {
|
||||
// fullscreen: ExtensionMode.Default,
|
||||
// theater: ExtensionMode.Default,
|
||||
// normal: ExtensionMode.Default,
|
||||
// },
|
||||
// enableAard: {
|
||||
// fullscreen: ExtensionMode.Default,
|
||||
// theater: ExtensionMode.Default,
|
||||
// normal: ExtensionMode.Default,
|
||||
// },
|
||||
// enableKeyboard: {
|
||||
// fullscreen: ExtensionMode.Default,
|
||||
// theater: ExtensionMode.Default,
|
||||
// normal: ExtensionMode.Default
|
||||
// },
|
||||
// type: 'official',
|
||||
// type: 'defaultType',
|
||||
// activeDOMConfig: 'official',
|
||||
// DOMConfig: {
|
||||
// 'official': {
|
||||
// type: 'official',
|
||||
// customCss: ".player {text-align: left}"
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
"vimeo.com": {
|
||||
enable: {
|
||||
fullscreen: ExtensionMode.Default,
|
||||
@ -1632,7 +1613,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
DOMConfig: {
|
||||
'official': {
|
||||
type: 'official',
|
||||
customCss: ".player_outro_area {\n width: 100% !important;\n display: flex !important;\n justify-content: center !important;\n}\n\n.player_container, .player {\n width: 100% !important; \n}",
|
||||
// customCss: ".player_outro_area {\n width: 100% !important;\n display: flex !important;\n justify-content: center !important;\n}\n\n.player_container, .player {\n width: 100% !important; \n}",
|
||||
elements: {
|
||||
player: {
|
||||
manual: true,
|
||||
@ -1664,7 +1645,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
DOMConfig: {
|
||||
'official': {
|
||||
type: 'official',
|
||||
customCss: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
|
||||
// customCss: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
|
||||
elements: {
|
||||
player: {
|
||||
manual: false,
|
||||
@ -1696,7 +1677,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
DOMConfig: {
|
||||
'official': {
|
||||
type: 'official',
|
||||
customCss: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
|
||||
// customCss: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
|
||||
elements: {
|
||||
player: {
|
||||
manual: false,
|
||||
@ -1816,7 +1797,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
DOMConfig: {
|
||||
'community': {
|
||||
type: 'community',
|
||||
customCss: "body {\n background-color: #000;\n}\n\n.application {\n background-color: #000;\n}"
|
||||
// customCss: "body {\n background-color: #000;\n}\n\n.application {\n background-color: #000;\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1872,7 +1853,7 @@ const ExtensionConf: SettingsInterface = {
|
||||
DOMConfig: {
|
||||
'community': {
|
||||
type: 'community',
|
||||
customCss: ".shaka-video-container {\n flex-direction: column !important;\n}"
|
||||
// customCss: ".shaka-video-container {\n flex-direction: column !important;\n}"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
326
src/ext/lib/aard/gl/GlCanvas.ts
Normal file
326
src/ext/lib/aard/gl/GlCanvas.ts
Normal file
@ -0,0 +1,326 @@
|
||||
import { mat4 } from 'gl-matrix';
|
||||
import { GlCanvasBuffers, initBuffers } from './gl-init';
|
||||
|
||||
export interface GlCanvasOptions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
// Vertex shader program
|
||||
const vsSource = `
|
||||
attribute vec4 aVertexPosition;
|
||||
attribute vec3 aVertexNormal;
|
||||
attribute vec2 aTextureCoord;
|
||||
|
||||
uniform mat4 uNormalMatrix;
|
||||
uniform mat4 uModelViewMatrix;
|
||||
uniform mat4 uProjectionMatrix;
|
||||
|
||||
varying highp vec2 vTextureCoord;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = uProjectionMatrix * aVertexPosition;
|
||||
vTextureCoord = aTextureCoord;
|
||||
}
|
||||
`;
|
||||
// Fragment shader program
|
||||
const fsSource = `
|
||||
varying highp vec2 vTextureCoord;
|
||||
uniform sampler2D uSampler;
|
||||
|
||||
void main(void) {
|
||||
highp vec4 texelColor = texture2D(uSampler, vTextureCoord);
|
||||
|
||||
gl_FragColor = vec4(texelColor.rgb, texelColor.a);
|
||||
}
|
||||
`;
|
||||
|
||||
interface GlCanvasProgramInfo {
|
||||
program: WebGLProgram;
|
||||
attribLocations: {
|
||||
vertexPosition: number;
|
||||
vertexNormal: number;
|
||||
textureCoord: number;
|
||||
};
|
||||
uniformLocations: {
|
||||
projectionMatrix: WebGLUniformLocation;
|
||||
modelViewMatrix: WebGLUniformLocation;
|
||||
normalMatrix: WebGLUniformLocation;
|
||||
uSampler: WebGLUniformLocation;
|
||||
};
|
||||
}
|
||||
|
||||
export class GlCanvas {
|
||||
|
||||
private _canvas: HTMLCanvasElement;
|
||||
private set canvas(x: HTMLCanvasElement) {
|
||||
this._canvas = x;
|
||||
};
|
||||
public get canvas(): HTMLCanvasElement {
|
||||
return this._canvas;
|
||||
};
|
||||
|
||||
private _context: WebGLRenderingContext;
|
||||
private set gl(x: WebGLRenderingContext) {
|
||||
this._context = x;
|
||||
};
|
||||
private get gl(): WebGLRenderingContext {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
private frameBufferSize: number;
|
||||
private _frameBuffer: Uint8Array;
|
||||
private set frameBuffer(x: Uint8Array) {
|
||||
this._frameBuffer = x;
|
||||
}
|
||||
public get frameBuffer(): Uint8Array {
|
||||
return this._frameBuffer;
|
||||
}
|
||||
|
||||
private buffers: GlCanvasBuffers;
|
||||
private texture: WebGLTexture;
|
||||
private programInfo: GlCanvasProgramInfo;
|
||||
private projectionMatrix: mat4;
|
||||
|
||||
|
||||
constructor(options: GlCanvasOptions) {
|
||||
this.canvas = document.createElement('canvas');
|
||||
this.gl = this.canvas.getContext('webgl');
|
||||
|
||||
if (!this.gl) {
|
||||
throw new Error('WebGL not supported');
|
||||
}
|
||||
|
||||
this.canvas.width = options.width;
|
||||
this.canvas.height = options.height;
|
||||
|
||||
this.frameBufferSize = options.width * options.height * 4;
|
||||
|
||||
this.initWebgl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws video frame to the GL canvas
|
||||
* @param video video to extract a frame from
|
||||
*/
|
||||
drawVideoFrame(video: HTMLVideoElement): void {
|
||||
this.updateTexture(video);
|
||||
this.drawScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads pixels from the canvas
|
||||
* @returns
|
||||
*/
|
||||
getImageData(): Uint8Array {
|
||||
this.gl.readPixels(0, 0, this.canvas.width, this.canvas.height, this.gl.RGBA, this.gl.UNSIGNED_BYTE, this.frameBuffer);
|
||||
return this.frameBuffer;
|
||||
}
|
||||
|
||||
private initWebgl() {
|
||||
// Initialize the GL context
|
||||
this.gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
||||
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
||||
|
||||
// Create shader program
|
||||
const shaderProgram = this.initShaderProgram();
|
||||
|
||||
// Setup params for shader program
|
||||
this.programInfo = {
|
||||
program: shaderProgram,
|
||||
attribLocations: {
|
||||
vertexPosition: this.gl.getAttribLocation(shaderProgram, "aVertexPosition"),
|
||||
vertexNormal: this.gl.getAttribLocation(shaderProgram, "aVertexNormal"),
|
||||
textureCoord: this.gl.getAttribLocation(shaderProgram, "aTextureCoord"),
|
||||
},
|
||||
uniformLocations: {
|
||||
projectionMatrix: this.gl.getUniformLocation(
|
||||
shaderProgram,
|
||||
"uProjectionMatrix"
|
||||
),
|
||||
modelViewMatrix: this.gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
|
||||
normalMatrix: this.gl.getUniformLocation(shaderProgram, "uNormalMatrix"),
|
||||
uSampler: this.gl.getUniformLocation(shaderProgram, "uSampler"),
|
||||
},
|
||||
};
|
||||
|
||||
// Here's where we call the routine that builds all the
|
||||
// objects we'll be drawing.
|
||||
this.buffers = initBuffers(this.gl);
|
||||
this.initTexture();
|
||||
|
||||
// Flip image pixels into the bottom-to-top order that WebGL expects.
|
||||
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);
|
||||
|
||||
|
||||
// Since our matrix is never going to change, we can define projection outside of drawScene function:
|
||||
this.projectionMatrix = mat4.create();
|
||||
mat4.ortho(this.projectionMatrix, -1, 1, -1, 1, -10, 10);
|
||||
|
||||
// we will be reusing our frame buffer for all draws and reads
|
||||
// this improves performance and lessens production of garbage,
|
||||
// translating into fewer garbage collections (probably), resulting
|
||||
// in fewer hitches and other performance issues (probably)
|
||||
this.frameBuffer = new Uint8Array(this.frameBufferSize);
|
||||
}
|
||||
|
||||
private loadShader(type, source) {
|
||||
const shader = this.gl.createShader(type);
|
||||
this.gl.shaderSource(shader, source);
|
||||
this.gl.compileShader(shader);
|
||||
|
||||
// TODO: warn if shader failed to compile
|
||||
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
||||
this.gl.deleteShader(shader);
|
||||
return null;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
private initShaderProgram() {
|
||||
const vertexShader = this.loadShader(this.gl.VERTEX_SHADER, vsSource);
|
||||
const fragmentShader = this.loadShader(this.gl.FRAGMENT_SHADER, fsSource);
|
||||
|
||||
// Create the shader program
|
||||
const shaderProgram = this.gl.createProgram();
|
||||
this.gl.attachShader(shaderProgram, vertexShader);
|
||||
this.gl.attachShader(shaderProgram, fragmentShader);
|
||||
this.gl.linkProgram(shaderProgram);
|
||||
|
||||
// TODO: maybe give a warning if program failed to initialize
|
||||
if (!this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return shaderProgram;
|
||||
}
|
||||
|
||||
private initTexture(): void {
|
||||
this.texture = this.gl.createTexture();
|
||||
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
|
||||
|
||||
// Because video has to be download over the internet
|
||||
// they might take a moment until it's ready so
|
||||
// put a single pixel in the texture so we can
|
||||
// use it immediately.
|
||||
const level = 0;
|
||||
const internalFormat = this.gl.RGBA;
|
||||
const width = 1;
|
||||
const height = 1;
|
||||
const border = 0;
|
||||
const srcFormat = this.gl.RGBA;
|
||||
const srcType = this.gl.UNSIGNED_BYTE;
|
||||
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
|
||||
this.gl.texImage2D(
|
||||
this.gl.TEXTURE_2D,
|
||||
level,
|
||||
internalFormat,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
srcFormat,
|
||||
srcType,
|
||||
pixel
|
||||
);
|
||||
|
||||
// Turn off mips and set wrapping to clamp to edge so it
|
||||
// will work regardless of the dimensions of the video.
|
||||
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
||||
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
||||
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
||||
}
|
||||
|
||||
private updateTexture(video: HTMLVideoElement) {
|
||||
const level = 0;
|
||||
const internalFormat = this.gl.RGBA;
|
||||
const srcFormat = this.gl.RGBA;
|
||||
const srcType = this.gl.UNSIGNED_BYTE;
|
||||
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
|
||||
this.gl.texImage2D(
|
||||
this.gl.TEXTURE_2D,
|
||||
level,
|
||||
internalFormat,
|
||||
srcFormat,
|
||||
srcType,
|
||||
video
|
||||
);
|
||||
}
|
||||
|
||||
private setTextureAttribute() {
|
||||
const num = 2; // every coordinate composed of 2 values
|
||||
const type = this.gl.FLOAT; // the data in the buffer is 32-bit float
|
||||
const normalize = false; // don't normalize
|
||||
const stride = 0; // how many bytes to get from one set to the next
|
||||
const offset = 0; // how many bytes inside the buffer to start from
|
||||
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.textureCoord);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.programInfo.attribLocations.textureCoord,
|
||||
num,
|
||||
type,
|
||||
normalize,
|
||||
stride,
|
||||
offset
|
||||
);
|
||||
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.textureCoord);
|
||||
}
|
||||
|
||||
private setPositionAttribute() {
|
||||
const numComponents = 3;
|
||||
const type = this.gl.FLOAT; // the data in the buffer is 32bit floats
|
||||
const normalize = false; // don't normalize
|
||||
const stride = 0; // how many bytes to get from one set of values to the next
|
||||
// 0 = use type and numComponents above
|
||||
const offset = 0; // how many bytes inside the buffer to start from
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.position);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.programInfo.attribLocations.vertexPosition,
|
||||
numComponents,
|
||||
type,
|
||||
normalize,
|
||||
stride,
|
||||
offset
|
||||
);
|
||||
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.vertexPosition);
|
||||
}
|
||||
|
||||
private drawScene(): void {
|
||||
/**
|
||||
* Since we are drawing our frames in a way such that the entire canvas is
|
||||
* always covered by rendered video, and given our video is the only object
|
||||
* being rendered to the canvas, we can avoid some things, such as:
|
||||
* * clearing the canvas
|
||||
* * any sort of depth tests
|
||||
*/
|
||||
|
||||
// Tell WebGL how to pull out the positions from the position
|
||||
// buffer into the vertexPosition attribute.
|
||||
this.setPositionAttribute();
|
||||
this.setTextureAttribute();
|
||||
|
||||
// Tell WebGL which indices to use to index the vertices, and to use
|
||||
// our program when drawing video frame to the canvas
|
||||
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.buffers.indices);
|
||||
this.gl.useProgram(this.programInfo.program);
|
||||
|
||||
// Set the shader uniforms
|
||||
this.gl.uniformMatrix4fv(
|
||||
this.programInfo.uniformLocations.projectionMatrix,
|
||||
false,
|
||||
this.projectionMatrix
|
||||
);
|
||||
|
||||
// Tell WebGL we want to affect texture unit 0, bind texture to texture unit 0,
|
||||
// and tell the shader that we bound the texture to texture unit 0.
|
||||
this.gl.activeTexture(this.gl.TEXTURE0);
|
||||
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
|
||||
this.gl.uniform1i(this.programInfo.uniformLocations.uSampler, 0);
|
||||
|
||||
// draw geometry
|
||||
const vertexCount = 6;
|
||||
const type = this.gl.UNSIGNED_SHORT;
|
||||
const offset = 0;
|
||||
this.gl.drawElements(this.gl.TRIANGLES, vertexCount, type, offset);
|
||||
}
|
||||
}
|
||||
84
src/ext/lib/aard/gl/gl-init.ts
Normal file
84
src/ext/lib/aard/gl/gl-init.ts
Normal file
@ -0,0 +1,84 @@
|
||||
export interface GlCanvasBuffers {
|
||||
position: WebGLBuffer,
|
||||
normal: WebGLBuffer,
|
||||
textureCoord: WebGLBuffer,
|
||||
indices: WebGLBuffer,
|
||||
};
|
||||
|
||||
export function initBuffers(gl: WebGLRenderingContext): GlCanvasBuffers {
|
||||
const positionBuffer = initPositionBuffer(gl);
|
||||
const textureCoordBuffer = initTextureBuffer(gl);
|
||||
const indexBuffer = initIndexBuffer(gl);
|
||||
const normalBuffer = initNormalBuffer(gl);
|
||||
|
||||
return {
|
||||
position: positionBuffer,
|
||||
normal: normalBuffer,
|
||||
textureCoord: textureCoordBuffer,
|
||||
indices: indexBuffer,
|
||||
};
|
||||
}
|
||||
|
||||
function initPositionBuffer(gl: WebGLRenderingContext) {
|
||||
const positionBuffer = gl.createBuffer();
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
const positions = [
|
||||
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,
|
||||
];
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
|
||||
|
||||
return positionBuffer;
|
||||
}
|
||||
|
||||
function initIndexBuffer(gl: WebGLRenderingContext) {
|
||||
const indexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
|
||||
const indices = [
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
];
|
||||
|
||||
gl.bufferData(
|
||||
gl.ELEMENT_ARRAY_BUFFER,
|
||||
new Uint16Array(indices),
|
||||
gl.STATIC_DRAW
|
||||
);
|
||||
|
||||
return indexBuffer;
|
||||
}
|
||||
|
||||
function initTextureBuffer(gl: WebGLRenderingContext) {
|
||||
const textureCoordBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
|
||||
|
||||
const textureCoordinates = [
|
||||
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
|
||||
];
|
||||
|
||||
gl.bufferData(
|
||||
gl.ARRAY_BUFFER,
|
||||
new Float32Array(textureCoordinates),
|
||||
gl.STATIC_DRAW
|
||||
);
|
||||
|
||||
return textureCoordBuffer;
|
||||
}
|
||||
|
||||
function initNormalBuffer(gl: WebGLRenderingContext) {
|
||||
const normalBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
|
||||
|
||||
const vertexNormals = [
|
||||
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
|
||||
];
|
||||
|
||||
gl.bufferData(
|
||||
gl.ARRAY_BUFFER,
|
||||
new Float32Array(vertexNormals),
|
||||
gl.STATIC_DRAW
|
||||
);
|
||||
|
||||
return normalBuffer;
|
||||
}
|
||||
@ -18,15 +18,19 @@ export enum AngleVersion {
|
||||
* @returns
|
||||
*/
|
||||
function detectDX(shaderSource: string) {
|
||||
const glsl = shaderSource.match(/#version (\d+)( es)?$/m);
|
||||
try {
|
||||
const glsl = shaderSource.match(/#version (\d+)( es)?$/m);
|
||||
|
||||
const glslVer = +glsl[1];
|
||||
const glslVer = +glsl[1];
|
||||
|
||||
if (glslVer >= 300) {
|
||||
return AngleVersion.D3D11;
|
||||
}
|
||||
if (glslVer >= 100) {
|
||||
return AngleVersion.D3D9;
|
||||
if (glslVer >= 300) {
|
||||
return AngleVersion.D3D11;
|
||||
}
|
||||
if (glslVer >= 100) {
|
||||
return AngleVersion.D3D9;
|
||||
}
|
||||
} catch (e) {
|
||||
return AngleVersion.NotAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,16 +72,19 @@ function detectGl(shaderSource: string) {
|
||||
* @returns
|
||||
*/
|
||||
function detectBackend(str) {
|
||||
try {
|
||||
if (str.match(/metal::float4/)) {
|
||||
return AngleVersion.Metal;
|
||||
}
|
||||
|
||||
if (str.match(/metal::float4/)) {
|
||||
return AngleVersion.Metal;
|
||||
if (str.match(/VS_OUTPUT main\(/)) {
|
||||
return detectDX(str);
|
||||
}
|
||||
|
||||
return detectGl(str);
|
||||
} catch (e) {
|
||||
return AngleVersion.NotAvailable;
|
||||
}
|
||||
|
||||
if (str.match(/VS_OUTPUT main\(/)) {
|
||||
return detectDX(str);
|
||||
}
|
||||
|
||||
return detectGl(str);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -324,7 +324,7 @@ export class SiteSettings {
|
||||
let iterated = '';
|
||||
|
||||
for (i = 0; i < pathParts.length - 1; i++) {
|
||||
iterated = `${iterated}.${pathParts[i]}`
|
||||
iterated = `${iterated}.${pathParts[i]}`;
|
||||
|
||||
if (!iterator[pathParts[i]]) { // some optional paths may still be undefined, even after cloning empty object
|
||||
iterator[pathParts[i]] = {};
|
||||
@ -341,6 +341,7 @@ export class SiteSettings {
|
||||
await this.settings.save();
|
||||
} else {
|
||||
await this.settings.saveWithoutReload();
|
||||
this.compileSettingsObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +152,15 @@ class PlayerData {
|
||||
this.initEventBus();
|
||||
|
||||
// this.notificationService = new PlayerNotificationUi(this.element, this.settings, this.eventBus);
|
||||
this.ui = new UI('ultrawidifyUi', {parentElement: this.element, eventBus: this.eventBus});
|
||||
if (this.videoData.settings.active.ui?.inPlayer?.enabled) {
|
||||
this.ui = new UI(
|
||||
'ultrawidifyUi',
|
||||
{
|
||||
parentElement: this.element,
|
||||
eventBus: this.eventBus
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.dimensions = undefined;
|
||||
this.overlayNode = undefined;
|
||||
@ -215,7 +223,6 @@ class PlayerData {
|
||||
destroy() {
|
||||
document.removeEventListener('fullscreenchange', this.dimensionChangeListener);
|
||||
this.stopChangeDetection();
|
||||
this.destroyOverlay();
|
||||
this.notificationService?.destroy();
|
||||
}
|
||||
//#endregion
|
||||
@ -326,11 +333,14 @@ class PlayerData {
|
||||
const canEnable = this.siteSettings.isEnabledForEnvironment(this.isFullscreen, this.isTheaterMode) === ExtensionMode.Enabled;
|
||||
|
||||
if (this.runLevel === RunLevel.Off && canEnable) {
|
||||
console.log('runLevel: off -> [anything]');
|
||||
this.eventBus.send('restore-ar', null);
|
||||
// must be called after
|
||||
this.handleDimensionChanges(currentPlayerDimensions, this.dimensions);
|
||||
} else if (!canEnable && this.runLevel !== RunLevel.Off) {
|
||||
// must be called before
|
||||
console.log('runLevel: [anything] -> off');
|
||||
|
||||
this.handleDimensionChanges(currentPlayerDimensions, this.dimensions);
|
||||
this.setRunLevel(RunLevel.Off);
|
||||
}
|
||||
@ -338,8 +348,8 @@ class PlayerData {
|
||||
|
||||
|
||||
private handleDimensionChanges(newDimensions: PlayerDimensions, oldDimensions: PlayerDimensions) {
|
||||
console.log('handling dimension changes');
|
||||
if (!this.enabled) {
|
||||
console.log('handling dimension changes\n\nold dimensions:', oldDimensions, '\nnew dimensions:', newDimensions, '\n\nis enabled:', this.enabled, this.runLevel, RunLevel);
|
||||
if (this.runLevel === RunLevel.Off ) {
|
||||
this.logger.log('info', 'debug', "[PlayerDetect] player size changed, but PlayerDetect is in disabled state. The player element is probably too small.");
|
||||
return;
|
||||
}
|
||||
@ -354,8 +364,10 @@ class PlayerData {
|
||||
|| newDimensions?.height != oldDimensions?.height
|
||||
|| newDimensions?.fullscreen != oldDimensions?.fullscreen
|
||||
){
|
||||
console.log('dimensions changed + we are enabled. Sending restore-ar ...');
|
||||
// If player size changes, we restore aspect ratio
|
||||
this.eventBus.send('restore-ar', null);
|
||||
this.eventBus.send('delayed-restore-ar', {delay: 500});
|
||||
// this.videoData.resizer?.restore();
|
||||
}
|
||||
}
|
||||
@ -424,59 +436,6 @@ class PlayerData {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
//#region interface
|
||||
makeOverlay() {
|
||||
if (!this.overlayNode) {
|
||||
this.destroyOverlay();
|
||||
}
|
||||
|
||||
let overlay = document.createElement('div');
|
||||
overlay.style.width = '100%';
|
||||
overlay.style.height = '100%';
|
||||
overlay.style.position = 'absolute';
|
||||
overlay.style.top = '0';
|
||||
overlay.style.left = '0';
|
||||
overlay.style.zIndex = '1000000000';
|
||||
overlay.style.pointerEvents = 'none';
|
||||
|
||||
this.overlayNode = overlay;
|
||||
this.element.appendChild(overlay);
|
||||
}
|
||||
|
||||
destroyOverlay() {
|
||||
if(this.playerIdElement) {
|
||||
this.playerIdElement.remove();
|
||||
this.playerIdElement = undefined;
|
||||
}
|
||||
if (this.overlayNode) {
|
||||
this.overlayNode.remove();
|
||||
this.overlayNode = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
markPlayer(name, color) {
|
||||
if (!this.overlayNode) {
|
||||
this.makeOverlay();
|
||||
}
|
||||
if (this.playerIdElement) {
|
||||
this.playerIdElement.remove();
|
||||
}
|
||||
this.playerIdElement = document.createElement('div');
|
||||
this.playerIdElement.innerHTML = `<div style="background-color: ${color}; color: #fff; position: absolute; top: 0; left: 0">${name}</div>`;
|
||||
|
||||
this.overlayNode.appendChild(this.playerIdElement);
|
||||
}
|
||||
|
||||
unmarkPlayer() {
|
||||
this.logger.log('info', 'debug', "[PlayerData::unmarkPlayer] unmarking player!", {playerIdElement: this.playerIdElement});
|
||||
if (this.playerIdElement) {
|
||||
this.playerIdElement.innerHTML = '';
|
||||
this.playerIdElement.remove();
|
||||
}
|
||||
this.playerIdElement = undefined;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region helper functions
|
||||
collectionHas(collection, element) {
|
||||
|
||||
@ -739,19 +739,6 @@ class VideoData {
|
||||
this.resizer.restore();
|
||||
}
|
||||
|
||||
markPlayer(name, color) {
|
||||
if (this.invalid) {
|
||||
return;
|
||||
}
|
||||
if (this.player) {
|
||||
this.player.markPlayer(name, color)
|
||||
}
|
||||
}
|
||||
|
||||
unmarkPlayer() {
|
||||
this.player.unmarkPlayer();
|
||||
}
|
||||
|
||||
isPlaying() {
|
||||
return this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import { _cp } from '../../../common/js/utils';
|
||||
import Settings from '../Settings';
|
||||
import { Ar } from '../../../common/interfaces/ArInterface';
|
||||
import { RunLevel } from '../../enum/run-level.enum';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
if(Debug.debug) {
|
||||
console.log("Loading: Resizer.js");
|
||||
@ -133,6 +134,18 @@ class Resizer {
|
||||
}],
|
||||
'restore-ar': [{
|
||||
function: () => this.restore()
|
||||
}],
|
||||
'delayed-restore-ar': [{
|
||||
function: () => {
|
||||
_.debounce(
|
||||
this.restore,
|
||||
500,
|
||||
{
|
||||
leading: true,
|
||||
trailing: true
|
||||
}
|
||||
)
|
||||
}
|
||||
}]
|
||||
}
|
||||
//#endregion
|
||||
@ -738,7 +751,7 @@ class Resizer {
|
||||
const alignXOffset = (realVideoWidth * stretchFactors.xFactor - this.videoData.player.dimensions.width) * 0.5;
|
||||
const alignYOffset = (realVideoHeight * stretchFactors.yFactor - this.videoData.player.dimensions.height) * 0.5;
|
||||
|
||||
if (this.pan.relativeOffsetX || this.pan.relativeOffsetY) {
|
||||
if (this.pan?.relativeOffsetX || this.pan?.relativeOffsetY) {
|
||||
// don't offset when video is smaller than player
|
||||
if(alignXOffset >= 0 || alignYOffset >= 0) {
|
||||
translate.x += alignXOffset * this.pan.relativeOffsetX * this.zoom.scale;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "Ultrawidify",
|
||||
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
||||
"version": "6.0.0",
|
||||
"version": "6.0.1",
|
||||
"icons": {
|
||||
"32":"res/icons/uw-32.png",
|
||||
"64":"res/icons/uw-64.png"
|
||||
@ -50,13 +50,11 @@
|
||||
],
|
||||
"permissions": [
|
||||
"storage",
|
||||
"activeTab",
|
||||
"scripting"
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://*/*"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"downloads"
|
||||
]
|
||||
}
|
||||
|
||||
60
src/manifest.v2.json
Normal file
60
src/manifest.v2.json
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Ultrawidify",
|
||||
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
||||
"version": "5.99.5",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"32":"res/icons/uw-32.png",
|
||||
"64":"res/icons/uw-64.png"
|
||||
},
|
||||
"browser_action": {
|
||||
"default_title": "Ultrawidify",
|
||||
"default_popup": "popup/popup.html"
|
||||
},
|
||||
|
||||
"content_scripts": [{
|
||||
"matches": ["*://*/*"],
|
||||
"js": [
|
||||
"common/lib/browser-polyfill.js",
|
||||
"ext/uw.js"
|
||||
],
|
||||
"all_frames": true
|
||||
}],
|
||||
|
||||
"background": {
|
||||
"persistent": true,
|
||||
"scripts": [
|
||||
"ext/uw-bg.js"
|
||||
]
|
||||
},
|
||||
|
||||
"options_ui": {
|
||||
"page": "options/options.html",
|
||||
"browser_style": false,
|
||||
"open_in_tab": true
|
||||
},
|
||||
|
||||
"web_accessible_resources": [
|
||||
"./*",
|
||||
"ext/*",
|
||||
"res/fonts/*",
|
||||
"res/css/*",
|
||||
"res/img/settings/about-bg.png",
|
||||
"res/icons/*",
|
||||
"res/img/*",
|
||||
"csui/*"
|
||||
],
|
||||
"permissions": [
|
||||
"storage",
|
||||
"activeTab",
|
||||
"<all_urls>"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"downloads"
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user