Merge tag '4.5.0' into stable
This commit is contained in:
commit
2f802f4e68
14
CHANGELOG.md
14
CHANGELOG.md
@ -13,12 +13,22 @@ QoL improvements for me:
|
|||||||
|
|
||||||
* logging: allow to enable logging at will and export said logs to a file
|
* logging: allow to enable logging at will and export said logs to a file
|
||||||
|
|
||||||
|
### v4.5.0
|
||||||
|
|
||||||
|
* 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 (Current)
|
### v4.4.10 (Current)
|
||||||
|
|
||||||
* Video alignment should now work on Twitch [#109](https://github.com/tamius-han/ultrawidify/issues/109)
|
* 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
|
* 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 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
|
* 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
|
### v4.4.9
|
||||||
|
|
||||||
|
9032
package-lock.json
generated
9032
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
42
package.json
42
package.json
@ -1,39 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "ultrawidify",
|
"name": "ultrawidify",
|
||||||
"version": "4.4.9",
|
"version": "4.5.0",
|
||||||
"description": "Aspect ratio fixer for youtube and other sites, with automatic aspect ratio detection. Supports ultrawide and other ratios.",
|
"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>",
|
"author": "Tamius Han <tamius.han@gmail.com>",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run dev",
|
|
||||||
"pre-build": "rm -rf ./dist-ff; rm -rf ./dist-chrome; rm -rf ./node_modules; npm ci",
|
|
||||||
"build": "npm run pre-build; cross-env NODE_ENV=production BROWSER=firefox CHANNEL=stable webpack --hide-modules",
|
"build": "npm run pre-build; cross-env NODE_ENV=production BROWSER=firefox CHANNEL=stable webpack --hide-modules",
|
||||||
"build-chrome": "cross-env NODE_ENV=production BROWSER=chrome CHANNEL=stable webpack --hide-modules",
|
|
||||||
"build-edge": "cross-env NODE_ENV=production BROWSER=edge CHANNEL=stable webpack --hide-modules",
|
|
||||||
"build:dev": "webpack --hide-modules",
|
|
||||||
"build-testing": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=testing webpack --hide-modules",
|
|
||||||
"build-nightly": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=nightly webpack --hide-modules",
|
|
||||||
"build-testing-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=testing webpack --hide-modules",
|
|
||||||
"build-nightly-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=nightly webpack --hide-modules",
|
|
||||||
"build-chrome:dev": "cross-env NODE_ENV=development BROWSER=chrome webpack --hide-modules",
|
|
||||||
"build-all": "mkdir -p ./build/old; npm run pre-build; rm ./dist-zip/uw-amo-source.zip; mv -f ./dist-zip/*.zip ./build/old; npm run build; node scripts/build-zip.js ff; npm run build-chrome; node scripts/build-zip.js chrome; ./scripts/prepare-amo-source.sh",
|
"build-all": "mkdir -p ./build/old; npm run pre-build; rm ./dist-zip/uw-amo-source.zip; mv -f ./dist-zip/*.zip ./build/old; npm run build; node scripts/build-zip.js ff; npm run build-chrome; node scripts/build-zip.js chrome; ./scripts/prepare-amo-source.sh",
|
||||||
|
"build-chrome": "cross-env NODE_ENV=production BROWSER=chrome CHANNEL=stable webpack --hide-modules",
|
||||||
|
"build-chrome:dev": "cross-env NODE_ENV=development BROWSER=chrome webpack --hide-modules",
|
||||||
|
"build-edge": "cross-env NODE_ENV=production BROWSER=edge CHANNEL=stable webpack --hide-modules",
|
||||||
|
"build-nightly": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=nightly webpack --hide-modules",
|
||||||
|
"build-nightly-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=nightly webpack --hide-modules",
|
||||||
|
"build-testing": "cross-env NODE_ENV=development BROWSER=firefox CHANNEL=testing webpack --hide-modules",
|
||||||
|
"build-testing-chrome": "cross-env NODE_ENV=development BROWSER=chrome CHANNEL=testing webpack --hide-modules",
|
||||||
"build-zip": "node scripts/build-zip.js",
|
"build-zip": "node scripts/build-zip.js",
|
||||||
"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\""
|
"build:dev": "webpack --hide-modules",
|
||||||
|
"dev": "cross-env NODE_ENV=development CHANNEL=dev concurrently \"cross-env BROWSER=firefox npm run build:dev -- --watch\" \"cross-env BROWSER=chrome npm run build:dev -- --watch\"",
|
||||||
|
"pre-build": "rm -rf ./dist-ff; rm -rf ./dist-chrome; rm -rf ./node_modules; npm ci",
|
||||||
|
"start": "npm run dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/core-js": "^2.5.3",
|
"@types/core-js": "^2.5.3",
|
||||||
"@types/es6-promise": "^3.3.0",
|
"@types/es6-promise": "^3.3.0",
|
||||||
|
"@vue/cli": "^4.5.9",
|
||||||
|
"bootstrap": "^4.5.3",
|
||||||
|
"bootstrap-icons": "^1.1.0",
|
||||||
|
"bootstrap-icons-vue": "^0.3.0",
|
||||||
|
"bootstrap-vue": "^2.20.1",
|
||||||
"concurrently": "^5.2.0",
|
"concurrently": "^5.2.0",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"json-cyclic": "0.0.3",
|
"json-cyclic": "0.0.3",
|
||||||
"vue": "^2.6.11",
|
"vue": "^3.0.0-beta.1",
|
||||||
"vuex": "^3.5.1",
|
"vuex": "^4.0.0-alpha.1",
|
||||||
"vuex-webextensions": "^1.3.0",
|
"vuex-webextensions": "^1.3.0"
|
||||||
"webextension-polyfill": "^0.6.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.10.5",
|
"@babel/core": "^7.10.5",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.10.4",
|
"@babel/plugin-proposal-optional-chaining": "^7.10.4",
|
||||||
"@babel/preset-env": "^7.10.4",
|
"@babel/preset-env": "^7.10.4",
|
||||||
|
"@vue/compiler-sfc": "^3.0.3",
|
||||||
"archiver": "^3.0.0",
|
"archiver": "^3.0.0",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"copy-webpack-plugin": "^4.5.3",
|
"copy-webpack-plugin": "^4.5.3",
|
||||||
@ -44,9 +49,10 @@
|
|||||||
"mini-css-extract-plugin": "^0.4.4",
|
"mini-css-extract-plugin": "^0.4.4",
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"vue-loader": "^15.9.3",
|
"vue-cli-plugin-vue-next": "~0.1.4",
|
||||||
"vue-template-compiler": "^2.6.11",
|
"vue-loader": "^16.0.0",
|
||||||
"web-ext-types": "^2.1.0",
|
"web-ext-types": "^2.1.0",
|
||||||
|
"webextension-polyfill": "^0.6.0",
|
||||||
"webpack": "^4.44.0",
|
"webpack": "^4.44.0",
|
||||||
"webpack-chrome-extension-reloader": "^0.8.3",
|
"webpack-chrome-extension-reloader": "^0.8.3",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
|
@ -151,98 +151,99 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../res/css/colors.scss';
|
@import '../../res/css/colors.scss';
|
||||||
|
|
||||||
.action {
|
.uw-ultrawidify-container-root {
|
||||||
cursor: pointer;
|
.action {
|
||||||
position: relative;
|
cursor: pointer;
|
||||||
box-sizing: border-box;
|
position: relative;
|
||||||
}
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.action .command-details {
|
.action .command-details {
|
||||||
height: 0px;
|
height: 0px;
|
||||||
max-height: 0px;
|
max-height: 0px;
|
||||||
transition: max-height 0.5s ease;
|
transition: max-height 0.5s ease;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: height 0.5s ease;
|
transition: height 0.5s ease;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action:hover .command-details {
|
.action:hover .command-details {
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 200px;
|
max-height: 200px;
|
||||||
transition: max-height 0.5s ease;
|
transition: max-height 0.5s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-details {
|
.command-details {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-name-cmd-container, .p1rem {
|
.action-name-cmd-container, .p1rem {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cd-pad {
|
.cd-pad {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-name {
|
.action-name {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: $text-normal;
|
color: $text-normal;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-name:hover, .action:hover .action-name {
|
.action-name:hover, .action:hover .action-name {
|
||||||
color: lighten($primary-color, 20%);
|
color: lighten($primary-color, 20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.red {
|
.red {
|
||||||
color: $primary-color !important;
|
color: $primary-color !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cmd-container {
|
.cmd-container {
|
||||||
width: 13.37rem;
|
width: 13.37rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cmdlist {
|
.cmdlist {
|
||||||
font-family: 'Overpass Mono';
|
font-family: 'Overpass Mono';
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: $text-dim;
|
color: $text-dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bold {
|
.bold {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scope-scope {
|
.scope-scope {
|
||||||
width: 5rem;
|
width: 5rem;
|
||||||
text-align: right !important;
|
text-align: right !important;
|
||||||
color: $secondary-color;
|
color: $secondary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scope-visible {
|
.scope-visible {
|
||||||
width: 7rem;
|
width: 7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scope-button-label {
|
.scope-button-label {
|
||||||
width: 16rem;
|
width: 16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scope-row-label {
|
.scope-row-label {
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scope-row-highlight {
|
.scope-row-highlight {
|
||||||
color: $text-normal;
|
color: $text-normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transparent {
|
.transparent {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
96
src/common/components/Icon.vue
Normal file
96
src/common/components/Icon.vue
Normal file
File diff suppressed because one or more lines are too long
@ -1,23 +1,25 @@
|
|||||||
.json-level-indent {
|
.uw-ultrawidify-container-root {
|
||||||
padding-left: 2em !important;
|
.json-level-indent {
|
||||||
font-family: 'Overpass Mono', monospace;
|
padding-left: 2em !important;
|
||||||
}
|
font-family: 'Overpass Mono', monospace;
|
||||||
.item-key {
|
}
|
||||||
color: rgb(255, 196, 148);
|
.item-key {
|
||||||
}
|
color: rgb(255, 196, 148);
|
||||||
.item-key-boolean-false {
|
}
|
||||||
color: rgb(207, 149, 101)
|
.item-key-boolean-false {
|
||||||
}
|
color: rgb(207, 149, 101)
|
||||||
|
}
|
||||||
|
|
||||||
.json-value-boolean-true {
|
.json-value-boolean-true {
|
||||||
color: rgb(150, 240, 198);
|
color: rgb(150, 240, 198);
|
||||||
}
|
}
|
||||||
.json-value-boolean-false {
|
.json-value-boolean-false {
|
||||||
color: rgb(241, 21, 21);
|
color: rgb(241, 21, 21);
|
||||||
}
|
}
|
||||||
.json-value-number {
|
.json-value-number {
|
||||||
color: rgb(121, 121, 238);
|
color: rgb(121, 121, 238);
|
||||||
}
|
}
|
||||||
.json-value-string {
|
.json-value-string {
|
||||||
color: rgb(226, 175, 7);
|
color: rgb(226, 175, 7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,33 +21,35 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss" scoped>
|
||||||
.mt2px {
|
.uw-ultrawidify-container-root {
|
||||||
margin-top: 7px;
|
.mt2px {
|
||||||
}
|
margin-top: 7px;
|
||||||
.id {
|
}
|
||||||
border: 1px solid #d00;
|
.id {
|
||||||
background-color: rgba(216, 94, 24, 0.25)
|
border: 1px solid #d00;
|
||||||
}
|
background-color: rgba(216, 94, 24, 0.25)
|
||||||
.class {
|
}
|
||||||
border: 1px solid #33d;
|
.class {
|
||||||
background-color: rgba(69, 69, 255, 0.25)
|
border: 1px solid #33d;
|
||||||
}
|
background-color: rgba(69, 69, 255, 0.25)
|
||||||
.closeButton {
|
}
|
||||||
margin-top: 2px;
|
.closeButton {
|
||||||
margin-left: 4px;
|
margin-top: 2px;
|
||||||
margin-right: 4px;
|
margin-left: 4px;
|
||||||
font-size: 1.5em;
|
margin-right: 4px;
|
||||||
color: #e00;
|
font-size: 1.5em;
|
||||||
}
|
color: #e00;
|
||||||
.closeButton:hover {
|
}
|
||||||
cursor: pointer;
|
.closeButton:hover {
|
||||||
color: #fa6;
|
cursor: pointer;
|
||||||
}
|
color: #fa6;
|
||||||
.qsb {
|
}
|
||||||
cursor:default;
|
.qsb {
|
||||||
margin-left: 3px;
|
cursor:default;
|
||||||
margin-right: 3px;
|
margin-left: 3px;
|
||||||
margin-bottom: 2px;
|
margin-right: 3px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -20,11 +20,13 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.center-text {
|
.uw-ultrawidify-container-root {
|
||||||
text-align: center;
|
.center-text {
|
||||||
}
|
text-align: center;
|
||||||
.dark {
|
}
|
||||||
opacity: 50%;
|
.dark {
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
14
src/common/data/notifications.js
Normal file
14
src/common/data/notifications.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
let Notifications = Object.freeze({
|
||||||
|
'TEST_NOTIFICATION': {
|
||||||
|
icon: 'card-text',
|
||||||
|
text: 'This is a test notification.',
|
||||||
|
timeout: -1,
|
||||||
|
},
|
||||||
|
'AARD_DRM': {
|
||||||
|
icon: 'exclamation-triangle',
|
||||||
|
text: '<b>Autodetection cannot run on this video.</b> This usually happens when sites use DRM. You will have to set aspect ratio manually.',
|
||||||
|
timeout: 5000,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Notifications;
|
@ -1,5 +1,5 @@
|
|||||||
if (process.env.CHANNEL !== 'stable') {
|
if (process.env.CHANNEL !== 'stable') {
|
||||||
console.log('Loaded ExtensionMode');
|
console.info('Loading ExtensionMode');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -12,4 +12,8 @@ var ExtensionMode = Object.freeze({
|
|||||||
Enabled: 3,
|
Enabled: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable') {
|
||||||
|
console.info('Loaded ExtensionMode');
|
||||||
|
}
|
||||||
|
|
||||||
export default ExtensionMode;
|
export default ExtensionMode;
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row flex-end w100">
|
<div class="flex flex-row flex-end w100">
|
||||||
<div v-if="!showTextMode" class="button" @click="showTextMode = true">
|
<div v-if="!showTextMode" class="button" @click="showTextMode = true">
|
||||||
Paste config ...
|
<Icon icon="clipboard-plus" style="font-size: 2em"></Icon> Paste config ...
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="button" @click="showTextMode = false">
|
<div v-else class="button" @click="showTextMode = false">
|
||||||
Back
|
Back
|
||||||
@ -164,10 +164,12 @@ import Logger from '../ext/lib/Logger';
|
|||||||
import Comms from '../ext/lib/comms/Comms';
|
import Comms from '../ext/lib/comms/Comms';
|
||||||
import IO from '../common/js/IO';
|
import IO from '../common/js/IO';
|
||||||
import JsonObject from '../common/components/JsonEditor/JsonObject';
|
import JsonObject from '../common/components/JsonEditor/JsonObject';
|
||||||
|
import Icon from '../common/components/Icon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
JsonObject,
|
JsonObject,
|
||||||
|
Icon,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -304,134 +306,134 @@ export default {
|
|||||||
@import '../res/css/font/overpass-mono.css';
|
@import '../res/css/font/overpass-mono.css';
|
||||||
@import '../res/css/common.scss';
|
@import '../res/css/common.scss';
|
||||||
|
|
||||||
|
.uw-ultrawidify-container-root {
|
||||||
|
.root-window {
|
||||||
|
position: fixed !important;
|
||||||
|
top: 5vh !important;
|
||||||
|
left: 5vw !important;
|
||||||
|
width: 90vw !important;
|
||||||
|
height: 90vh !important;
|
||||||
|
z-index: 999999 !important;
|
||||||
|
background-color: rgba( $page-background, 0.9) !important;
|
||||||
|
color: #f1f1f1 !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
|
||||||
.root-window {
|
box-sizing: border-box !important;
|
||||||
position: fixed !important;
|
}
|
||||||
top: 5vh !important;
|
|
||||||
left: 5vw !important;
|
|
||||||
width: 90vw !important;
|
|
||||||
height: 90vh !important;
|
|
||||||
z-index: 999999 !important;
|
|
||||||
background-color: rgba( $page-background, 0.9) !important;
|
|
||||||
color: #f1f1f1 !important;
|
|
||||||
font-size: 14px !important;
|
|
||||||
|
|
||||||
box-sizing: border-box !important;
|
div {
|
||||||
}
|
font-family: 'Overpass';
|
||||||
|
}
|
||||||
|
|
||||||
div {
|
h1, h2 {
|
||||||
font-family: 'Overpass';
|
font-family: 'Overpass Thin';
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2 {
|
|
||||||
font-family: 'Overpass Thin';
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
font-size: 4em;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-bottom: -0.20em;
|
font-size: 4em;
|
||||||
margin-top: 0.0em;
|
|
||||||
}
|
}
|
||||||
.header-top, .header-bottom {
|
h2 {
|
||||||
padding-left: 16px;
|
font-size: 2em;
|
||||||
padding-right: 16px;
|
|
||||||
}
|
}
|
||||||
.header-top {
|
|
||||||
background-color: $popup-header-background !important;
|
.header {
|
||||||
|
h1 {
|
||||||
|
margin-bottom: -0.20em;
|
||||||
|
margin-top: 0.0em;
|
||||||
|
}
|
||||||
|
.header-top, .header-bottom {
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
.header-top {
|
||||||
|
background-color: $popup-header-background !important;
|
||||||
|
}
|
||||||
|
.header-bottom {
|
||||||
|
font-size: 1.75em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.header-bottom {
|
.content {
|
||||||
font-size: 1.75em;
|
box-sizing: border-box;
|
||||||
|
padding: 8px 32px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.settings-panel {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-right: 8px;
|
||||||
|
flex-grow: 2 !important;
|
||||||
|
min-width: 30% !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
height: inherit !important;
|
||||||
|
}
|
||||||
|
.results-panel {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-left: 8px;
|
||||||
|
max-width: 70% !important;
|
||||||
|
flex-grow: 5 !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
height: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-hidden {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: 'Overpass Mono';
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-025em {
|
||||||
|
margin: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-t-025em {
|
||||||
|
padding-top: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
padding-left: 2em;
|
||||||
|
padding-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary {
|
||||||
|
background-color: $primary;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-big {
|
||||||
|
font-size: 1.5em;
|
||||||
|
padding: 1.75em 3.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-bar {
|
||||||
|
font-size: 1.25em;
|
||||||
|
padding: 0.25em 1.25em;
|
||||||
|
margin-left: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-header {
|
||||||
|
font-size: 2em;
|
||||||
|
padding-top: 0.1em;
|
||||||
|
padding-left: 1em;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jsonbg {
|
||||||
|
background-color: #131313;
|
||||||
|
}
|
||||||
|
.jsonbg-error {
|
||||||
|
background-color: #884420;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-config-margin {
|
||||||
|
margin-top: 3em;
|
||||||
|
margin-bottom: 3em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.content {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 8px 32px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.settings-panel {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-right: 8px;
|
|
||||||
flex-grow: 2 !important;
|
|
||||||
min-width: 30% !important;
|
|
||||||
flex-shrink: 0 !important;
|
|
||||||
height: inherit !important;
|
|
||||||
}
|
|
||||||
.results-panel {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-left: 8px;
|
|
||||||
max-width: 70% !important;
|
|
||||||
flex-grow: 5 !important;
|
|
||||||
flex-shrink: 0 !important;
|
|
||||||
height: inherit !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollable {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overflow-hidden {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
font-family: 'Overpass Mono';
|
|
||||||
}
|
|
||||||
|
|
||||||
.m-025em {
|
|
||||||
margin: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-t-025em {
|
|
||||||
padding-top: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-items: center;
|
|
||||||
padding-left: 2em;
|
|
||||||
padding-right: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-primary {
|
|
||||||
background-color: $primary;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-big {
|
|
||||||
font-size: 1.5em;
|
|
||||||
padding: 1.75em 3.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-bar {
|
|
||||||
font-size: 1.25em;
|
|
||||||
padding: 0.25em 1.25em;
|
|
||||||
margin-left: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-header {
|
|
||||||
font-size: 2em;
|
|
||||||
padding-top: 0.1em;
|
|
||||||
padding-left: 1em;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.jsonbg {
|
|
||||||
background-color: #131313;
|
|
||||||
}
|
|
||||||
.jsonbg-error {
|
|
||||||
background-color: #884420;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-config-margin {
|
|
||||||
margin-top: 3em;
|
|
||||||
margin-bottom: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
216
src/csui/NotificationUi.vue
Normal file
216
src/csui/NotificationUi.vue
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="showNotification" class="uw-ultrawidify-container flex flex-column overflow-hidden">
|
||||||
|
<div class="notification-popup flex flex-row">
|
||||||
|
<div v-if="notificationIcon" class="flex-nogrow flex-noshrink notification-icon">
|
||||||
|
<Icon
|
||||||
|
class="flex-nogrow flex-noshrink"
|
||||||
|
:icon="notificationIcon"
|
||||||
|
>
|
||||||
|
</Icon>
|
||||||
|
</div>
|
||||||
|
<div class="notification-content flex-grow flex-shrink flex flex-column flex-cross-center">
|
||||||
|
<div
|
||||||
|
class="notification-text"
|
||||||
|
v-html="notificationText"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="notificationActions"
|
||||||
|
class="action-buttons flex flex-row"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="action of notificationActions"
|
||||||
|
class="action-button"
|
||||||
|
:key="action"
|
||||||
|
@click="action.command"
|
||||||
|
>
|
||||||
|
<Icon v-if="action.icon" :icon="action.icon"></Icon>{{action.label}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="hideActions"
|
||||||
|
class="hide-actions"
|
||||||
|
>
|
||||||
|
Never show again:<wbr>
|
||||||
|
<template
|
||||||
|
v-for="action of hideActions"
|
||||||
|
:key="action"
|
||||||
|
>
|
||||||
|
<i @click="closeNotification">
|
||||||
|
<a
|
||||||
|
class="hide-action-button"
|
||||||
|
@click="action.command"
|
||||||
|
>
|
||||||
|
{{action.label}}
|
||||||
|
</a>
|
||||||
|
<wbr>
|
||||||
|
</i>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="notification-icon action-button"
|
||||||
|
@click="closeNotification()"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
class="flex-nogrow flex-noshrink"
|
||||||
|
icon="x"
|
||||||
|
>
|
||||||
|
</Icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
import Icon from '../common/components/Icon';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Icon,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
notificationTimeout: null,
|
||||||
|
notificationIcon: "exclamation-triangle",
|
||||||
|
notificationText: "<b>Sample text.</b> This will be replaced with real notification later.",
|
||||||
|
notificationActions: null,
|
||||||
|
hideActions: null,
|
||||||
|
showNotification: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'notificationConfig'
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
/**
|
||||||
|
* Sets new notification config. Currently, we can only show one notification at a time.
|
||||||
|
*
|
||||||
|
* We expect a config object like this:
|
||||||
|
* {
|
||||||
|
* timeout: number — how long we'll be displaying the notification. If empty, 10s. -1: until user dismisses it
|
||||||
|
* icon: string — what icon we're gonna show. We're using bootstrap icons. Can be empty.
|
||||||
|
* text: — notification text. Supports HTML.
|
||||||
|
* notificationActions: [
|
||||||
|
* {
|
||||||
|
* command: function that gets executed upon clicking the button.
|
||||||
|
* label: label of the button
|
||||||
|
* icon: icon of the button
|
||||||
|
* }
|
||||||
|
* ],
|
||||||
|
* hideOptions: [
|
||||||
|
* // more of notificationActions except it's a special case
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
notificationConfig(newConfig) {
|
||||||
|
if (newConfig) {
|
||||||
|
this.notificationText = newConfig.text;
|
||||||
|
this.notificationActions = newConfig.notificationActions;
|
||||||
|
this.notificationIcon = newConfig.icon;
|
||||||
|
this.hideActions = newConfig.hideActions;
|
||||||
|
|
||||||
|
this.showNotification = true;
|
||||||
|
|
||||||
|
if (newConfig.timeout !== -1) {
|
||||||
|
this.notificationTimeout = setTimeout(() => this.closeNotification(), newConfig.timeout ?? 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeNotification() {
|
||||||
|
clearTimeout(this.notificationTimeout);
|
||||||
|
|
||||||
|
this.showNotification = false;
|
||||||
|
this.notificationIcon = null;
|
||||||
|
this.notificationText = null;
|
||||||
|
this.notificationActions = null;
|
||||||
|
this.hideActions = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../res/css/uwui-base.scss';
|
||||||
|
@import '../res/css/colors.scss';
|
||||||
|
@import '../res/css/font/overpass.css';
|
||||||
|
@import '../res/css/font/overpass-mono.css';
|
||||||
|
@import '../res/css/common.scss';
|
||||||
|
|
||||||
|
.uw-ultrawidify-container-root {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
display: block !important;
|
||||||
|
position: relative !important;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
|
||||||
|
font-size: 16px !important;
|
||||||
|
|
||||||
|
.notification-popup {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99999999;
|
||||||
|
top: 2em;
|
||||||
|
right: 2em;
|
||||||
|
width: 32em;
|
||||||
|
|
||||||
|
padding: 0.7em 0.5em;
|
||||||
|
|
||||||
|
font-family: 'Overpass';
|
||||||
|
|
||||||
|
background-color: rgba(108, 55, 12, 0.779);
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notifcation-content {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-text {
|
||||||
|
text-align: justify;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
padding-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-icon {
|
||||||
|
font-size: 3em;
|
||||||
|
line-height: 0.5;
|
||||||
|
}
|
||||||
|
.action-button {
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-actions {
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 0.8em;
|
||||||
|
justify-self: flex-end;
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-action-button {
|
||||||
|
color: #eee;
|
||||||
|
font-size: 0.9em;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: rgba(255,255,255,0.5);
|
||||||
|
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -23,7 +23,15 @@ var ActionList = {
|
|||||||
name: 'Manually specify ratio',
|
name: 'Manually specify ratio',
|
||||||
arg: AspectRatio.Fixed,
|
arg: AspectRatio.Fixed,
|
||||||
customArg: true,
|
customArg: true,
|
||||||
hintHTML: '',
|
customSetter: (value) => {
|
||||||
|
const [width, height] = value.split(':');
|
||||||
|
|
||||||
|
if (width && height) {
|
||||||
|
return +width / +height;
|
||||||
|
}
|
||||||
|
return +width;
|
||||||
|
},
|
||||||
|
hintHTML: '<small>Enter the aspect ratio as {width}:{height} or a single number, e.g. "21:9", "2.35:1", or "2.35" (without quotes).</small>',
|
||||||
}],
|
}],
|
||||||
scopes: {
|
scopes: {
|
||||||
global: false,
|
global: false,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
if (process.env.CHANNEL !== 'stable') {
|
if (process.env.CHANNEL !== 'stable') {
|
||||||
console.log('Loaded BrowserDetect');
|
console.info('Loaded BrowserDetect');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ const BrowserDetect = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable') {
|
if (process.env.CHANNEL !== 'stable') {
|
||||||
console.log("Loading: BrowserDetect.js\n\nprocess.env.BROWSER:", process.env.BROWSER, "Exporting BrowserDetect:", BrowserDetect);
|
console.info("BrowserDetect loaded:\n\nprocess.env.BROWSER:", process.env.BROWSER, "\nExporting BrowserDetect:", BrowserDetect);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BrowserDetect;
|
export default BrowserDetect;
|
@ -1,6 +1,6 @@
|
|||||||
if (process.env.CHANNEL !== 'stable') {
|
if (process.env.CHANNEL !== 'stable') {
|
||||||
console.log('We are not on stable channel. File init will be printed to console.');
|
console.info('We are not on stable channel. File init will be printed to console.');
|
||||||
console.log('Loaded Debug.js');
|
console.info('Loading Debug.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set prod to true when releasing
|
// Set prod to true when releasing
|
||||||
@ -54,9 +54,13 @@ function __disableAllDebug(obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Debug.debug)
|
if (Debug.debug) {
|
||||||
console.log("Guess we're debugging ultrawidify then. Debug.js must always load first, and others must follow.\nLoading: Debug.js");
|
console.info("Guess we're debugging ultrawidify then. Debug.js must always load first, and others must follow.\nLoading: Debug.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable') {
|
||||||
|
console.info('Loaded Debug.js');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default Debug;
|
export default Debug;
|
@ -390,6 +390,22 @@ const ExtensionConfPatch = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
forVersion: '4.5.0',
|
||||||
|
sites: {
|
||||||
|
"www.wakanim.tv": {
|
||||||
|
type: 'community',
|
||||||
|
DOM: {
|
||||||
|
player: {
|
||||||
|
manual: true,
|
||||||
|
querySelectors: "#jwplayer-container",
|
||||||
|
additionalCss: "",
|
||||||
|
useRelativeAncestor: false,
|
||||||
|
playerNodeCss: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1193,6 +1193,18 @@ var ExtensionConf = {
|
|||||||
videoAlignment: 1,
|
videoAlignment: 1,
|
||||||
type: 'official',
|
type: 'official',
|
||||||
},
|
},
|
||||||
|
"www.wakanim.tv": {
|
||||||
|
type: 'community',
|
||||||
|
DOM: {
|
||||||
|
player: {
|
||||||
|
manual: true,
|
||||||
|
querySelectors: "#jwplayer-container",
|
||||||
|
additionalCss: "",
|
||||||
|
useRelativeAncestor: false,
|
||||||
|
playerNodeCss: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import PlayerData from './video-data/PlayerData';
|
|||||||
import ExtensionMode from '../../common/enums/extension-mode.enum';
|
import ExtensionMode from '../../common/enums/extension-mode.enum';
|
||||||
|
|
||||||
if(process.env.CHANNEL !== 'stable'){
|
if(process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Loading ActionHandler");
|
console.info("Loading ActionHandler");
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActionHandler {
|
class ActionHandler {
|
||||||
@ -332,7 +332,7 @@ class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(process.env.CHANNEL !== 'stable'){
|
if(process.env.CHANNEL !== 'stable'){
|
||||||
console.log("ActionHandler loaded");
|
console.info("ActionHandler loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ActionHandler;
|
export default ActionHandler;
|
||||||
|
@ -3,7 +3,7 @@ import { decycle } from 'json-cyclic';
|
|||||||
import Comms from './comms/Comms';
|
import Comms from './comms/Comms';
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log('Loading Logger');
|
console.info('Loading Logger');
|
||||||
}
|
}
|
||||||
|
|
||||||
class Logger {
|
class Logger {
|
||||||
@ -486,10 +486,14 @@ class Logger {
|
|||||||
|
|
||||||
saveViaBgScript() {
|
saveViaBgScript() {
|
||||||
console.info('[info] will attempt to save. Issuing "show-logger"');
|
console.info('[info] will attempt to save. Issuing "show-logger"');
|
||||||
if (!this.conf?.fileOptions?.enabled || this.isBackgroundScript) {
|
if (this.isBackgroundScript) {
|
||||||
console.info('[info] Logging to file is either disabled or we\'re not on the content script. Not saving.');
|
console.info('[info] Background script cannot display logger UI.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if (!this.conf?.fileOptions?.enabled) {
|
||||||
|
// console.info('[info] Logging to file is disabled. Logger won\'t get shown.');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
Comms.sendMessage({cmd: 'show-logger', forwardToSameFramePort: true, port: 'content-ui-port'});
|
Comms.sendMessage({cmd: 'show-logger', forwardToSameFramePort: true, port: 'content-ui-port'});
|
||||||
|
|
||||||
@ -556,7 +560,7 @@ class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log('Logger loaded');
|
console.info('Logger loaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Logger;
|
export default Logger;
|
||||||
|
@ -9,7 +9,7 @@ import ExtensionConfPatch from '../conf/ExtConfPatches';
|
|||||||
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
import CropModePersistence from '../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
if(process.env.CHANNEL !== 'stable'){
|
if(process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Loading Settings");
|
console.info("Loading Settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
@ -589,3 +589,7 @@ class Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|
||||||
|
if(process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("Settings loaded");
|
||||||
|
}
|
||||||
|
@ -38,6 +38,9 @@ class ArDetector {
|
|||||||
this._nextTick = false;
|
this._nextTick = false;
|
||||||
|
|
||||||
this.canDoFallbackMode = false;
|
this.canDoFallbackMode = false;
|
||||||
|
|
||||||
|
this.drmNotificationShown = false;
|
||||||
|
|
||||||
this.logger.log('info', 'init', `[ArDetector::ctor] creating new ArDetector. arid: ${this.arid}`);
|
this.logger.log('info', 'init', `[ArDetector::ctor] creating new ArDetector. arid: ${this.arid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,6 +509,25 @@ class ArDetector {
|
|||||||
id = undefined;
|
id = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether video we're trying to play is protected by DRM.
|
||||||
|
*
|
||||||
|
* When trying to get an image frame of a DRM-protected video in
|
||||||
|
* firefox, the method canvas.drawImage(video) will throw an exception.
|
||||||
|
*
|
||||||
|
* This doesn't happen in Chrome. As opposed to Firefox, chrome will
|
||||||
|
* simply draw a transparent black image and not tell anyone that
|
||||||
|
* anything is amiss. However, since the image is (according to my testing
|
||||||
|
* on netflix) completely transparent, this means we can determine whether
|
||||||
|
* the video is DRM-protected by looking at the alpha byte of the image.
|
||||||
|
*
|
||||||
|
* (Videos don't tend to have an alpha channel, so they're always
|
||||||
|
* completely opaque (i.e. have value of 255))
|
||||||
|
*/
|
||||||
|
hasDRM() {
|
||||||
|
return this.blackframeContext.getImageData(0,0,1,1).data[3] === 0;
|
||||||
|
}
|
||||||
|
|
||||||
frameCheck(){
|
frameCheck(){
|
||||||
if(! this.video){
|
if(! this.video){
|
||||||
this.logger.log('error', 'debug', `%c[ArDetect::frameCheck] <@${this.arid}> Video went missing. Destroying current instance of videoData.`);
|
this.logger.log('error', 'debug', `%c[ArDetect::frameCheck] <@${this.arid}> Video went missing. Destroying current instance of videoData.`);
|
||||||
@ -525,12 +547,19 @@ class ArDetector {
|
|||||||
//
|
//
|
||||||
try {
|
try {
|
||||||
this.blackframeContext.drawImage(this.video, 0, 0, this.blackframeCanvas.width, this.blackframeCanvas.height);
|
this.blackframeContext.drawImage(this.video, 0, 0, this.blackframeCanvas.width, this.blackframeCanvas.height);
|
||||||
|
|
||||||
|
// special browsers require special tests
|
||||||
|
if (this.hasDRM()) {
|
||||||
|
throw 'Video is protected by DRM. Autodetection cannot run here.';
|
||||||
|
}
|
||||||
this.fallbackMode = false;
|
this.fallbackMode = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.log('error', 'arDetect', `%c[ArDetect::frameCheck] <@${this.arid}> %c[ArDetect::frameCheck] can't draw image on canvas. ${this.canDoFallbackMode ? 'Trying canvas.drawWindow instead' : 'Doing nothing as browser doesn\'t support fallback mode.'}`, "color:#000; backgroud:#f51;", e);
|
this.logger.log('error', 'arDetect', `%c[ArDetect::frameCheck] <@${this.arid}> %c[ArDetect::frameCheck] can't draw image on canvas. ${this.canDoFallbackMode ? 'Trying canvas.drawWindow instead' : 'Doing nothing as browser doesn\'t support fallback mode.'}`, "color:#000; backgroud:#f51;", e);
|
||||||
|
|
||||||
// nothing to see here, really, if fallback mode isn't supported by browser
|
// nothing to see here, really, if fallback mode isn't supported by browser
|
||||||
if (! this.canDoFallbackMode) {
|
if (!this.drmNotificationShown) {
|
||||||
|
this.drmNotificationShown = true;
|
||||||
|
this.conf.player.showNotification('AARD_DRM');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (! this.canvasReadyForDrawWindow()) {
|
if (! this.canvasReadyForDrawWindow()) {
|
||||||
|
@ -2,7 +2,7 @@ import Debug from '../../conf/Debug';
|
|||||||
import BrowserDetect from '../../conf/BrowserDetect';
|
import BrowserDetect from '../../conf/BrowserDetect';
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Loading Comms");
|
console.info("Loading Comms");
|
||||||
}
|
}
|
||||||
|
|
||||||
class Comms {
|
class Comms {
|
||||||
@ -37,7 +37,7 @@ class Comms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Comms loaded");
|
console.info("Comms loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Comms;
|
export default Comms;
|
||||||
|
@ -2,7 +2,7 @@ import Debug from '../../conf/Debug';
|
|||||||
import BrowserDetect from '../../conf/BrowserDetect';
|
import BrowserDetect from '../../conf/BrowserDetect';
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Loading CommsClient");
|
console.info("Loading CommsClient");
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommsClient {
|
class CommsClient {
|
||||||
@ -130,7 +130,7 @@ class CommsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log("CommsClient loaded");
|
console.info("CommsClient loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CommsClient;
|
export default CommsClient;
|
||||||
|
185
src/ext/lib/uwui/PlayerNotificationUI.js
Normal file
185
src/ext/lib/uwui/PlayerNotificationUI.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import UI from './UI';
|
||||||
|
import VuexWebExtensions from 'vuex-webextensions';
|
||||||
|
import NotificationUi from '../../../csui/NotificationUi.vue';
|
||||||
|
import Notifications from '../../../common/data/notifications';
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("Loading: PlayerNotificationUi");
|
||||||
|
}
|
||||||
|
|
||||||
|
let MuteScope = Object.freeze({
|
||||||
|
CurrentSite: 'current-site',
|
||||||
|
Global: 'global'
|
||||||
|
});
|
||||||
|
|
||||||
|
class PlayerNotificationUi extends UI {
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
playerElement,
|
||||||
|
settings
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
'notification',
|
||||||
|
PlayerNotificationUi.getStoreConfig(),
|
||||||
|
PlayerNotificationUi.getUiConfig(playerElement),
|
||||||
|
PlayerNotificationUi.getCommsConfig()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#region constructor helpers
|
||||||
|
// we will move some things out of the constructor in order to keep things clean
|
||||||
|
static getStoreConfig() {
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
VuexWebExtensions({
|
||||||
|
persistentStates: [
|
||||||
|
'notificationConfig'
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
state: {
|
||||||
|
// should be null by default!
|
||||||
|
notificationConfig: {
|
||||||
|
text: 'sample text <b>now with 100% more html formatting!</b>',
|
||||||
|
icon: 'exclamation-circle',
|
||||||
|
timeout: 5000,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
'uw-set-notification'(state, payload) {
|
||||||
|
console.log('mutation!', state, payload);
|
||||||
|
state['notificationConfig'] = payload;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
'uw-set-notification'({commit}, payload) {
|
||||||
|
console.log('action!', commit, payload);
|
||||||
|
commit('uw-set-notification', payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getUiConfig(playerElement) {
|
||||||
|
return {
|
||||||
|
parentElement: playerElement,
|
||||||
|
component: NotificationUi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getCommsConfig() {
|
||||||
|
return {
|
||||||
|
handlers: {
|
||||||
|
'show-notification': [(message) => this.showNotification(message)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region lifecycle
|
||||||
|
replace(playerElement) {
|
||||||
|
super.replace(this.getUiConfig(playerElement));
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notification on screen.
|
||||||
|
*
|
||||||
|
* @param notificationConfig notification config (or ID of notification config in /common/data/notifications.js)
|
||||||
|
*
|
||||||
|
* notificationConfig should resemble this:
|
||||||
|
* {
|
||||||
|
* timeout: number — how long we'll be displaying the notification. If empty, 10s. -1: until user dismisses it
|
||||||
|
* icon: string — what icon we're gonna show. We're using bootstrap icons. Can be empty.
|
||||||
|
* text: — notification text. Supports HTML.
|
||||||
|
* notificationActions: [
|
||||||
|
* {
|
||||||
|
* command: function that gets executed upon clicking the button.
|
||||||
|
* label: label of the button
|
||||||
|
* icon: icon of the button
|
||||||
|
* }
|
||||||
|
* ],
|
||||||
|
* hideActions: [
|
||||||
|
* // more of notificationActions but with special case
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* When notificationConfig is a string, the function will add two additional notifications on the notificationActionsPile
|
||||||
|
* * never show this notification ever again on any site
|
||||||
|
* * never show this notification again on this site
|
||||||
|
*/
|
||||||
|
showNotification(notificationConfig) {
|
||||||
|
if (typeof notificationConfig === 'string') {
|
||||||
|
try {
|
||||||
|
const config = Notifications[notificationConfig];
|
||||||
|
|
||||||
|
// this should _never_ appear on production version of the extension, but it should help with development.
|
||||||
|
if (!config) {
|
||||||
|
return this.vuexStore?.dispatch('uw-set-notification', {
|
||||||
|
icon: 'x-circle-fill',
|
||||||
|
text: `Notification for key ${notificationConfig} does not exist.`,
|
||||||
|
timeout: -1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't show notification if it's muted
|
||||||
|
if (this.isNotificationMuted(notificationConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vuexStore?.dispatch('uw-set-notification', {
|
||||||
|
...config,
|
||||||
|
hideActions: [
|
||||||
|
{
|
||||||
|
command: () => this.muteNotification(notificationConfig, MuteScope.CurrentSite),
|
||||||
|
label: 'this site'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: () => this.muteNotification(notificationConfig, MuteScope.Global),
|
||||||
|
label: 'never ever'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('theres been an error:', e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.vuexStore?.dispatch('uw-set-notification', notificationConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
muteNotification(notificationId, scope) {
|
||||||
|
// ensure objects we try to set exist
|
||||||
|
if (!this.settings.active.mutedNotifications) {
|
||||||
|
this.settings.active.mutedNotifications = {};
|
||||||
|
}
|
||||||
|
if (!this.settings.active.mutedNotifications[notificationId]) {
|
||||||
|
this.settings.active.mutedNotifications[notificationId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// actually mute notification
|
||||||
|
if (scope === MuteScope.Global) {
|
||||||
|
this.settings.active.mutedNotifications[notificationId].$global = true;
|
||||||
|
} else {
|
||||||
|
this.settings.active.mutedNotifications[notificationId][window.location.hostname] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// persist settings
|
||||||
|
this.settings.saveWithoutReload();
|
||||||
|
}
|
||||||
|
|
||||||
|
isNotificationMuted(notificationId) {
|
||||||
|
return this.settings.active.mutedNotifications?.[notificationId]?.$global
|
||||||
|
|| this.settings.active.mutedNotifications?.[notificationId]?.[window.location.hostname];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("PlayerNotificationUi loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default PlayerNotificationUi;
|
85
src/ext/lib/uwui/UI.js
Normal file
85
src/ext/lib/uwui/UI.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import { createStore } from 'vuex';
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("Loading: UI");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UI {
|
||||||
|
constructor(
|
||||||
|
interfaceId,
|
||||||
|
storeConfig,
|
||||||
|
uiConfig, // {component, parentElement?}
|
||||||
|
commsConfig,
|
||||||
|
) {
|
||||||
|
this.interfaceId = interfaceId;
|
||||||
|
this.commsConfig = commsConfig;
|
||||||
|
this.storeConfig = storeConfig,
|
||||||
|
this.uiConfig = uiConfig;
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
// initialize vuejs, but only once (check handled in initVue())
|
||||||
|
// we need to initialize this _after_ initializing comms.
|
||||||
|
|
||||||
|
this.initVue();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initVue() {
|
||||||
|
if (this.storeConfig) {
|
||||||
|
this.vuexStore = createStore(this.storeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initUi() {
|
||||||
|
const random = Math.round(Math.random() * 69420);
|
||||||
|
const uwid = `uw-${this.interfaceId}-root-${random}`
|
||||||
|
|
||||||
|
const rootDiv = document.createElement('div');
|
||||||
|
|
||||||
|
rootDiv.setAttribute('style', `pointer-events: none; position: ${this.uiConfig.style?.position ?? 'absolute'}; width: ${this.uiConfig.style?.width ?? '100%'}; height: ${this.uiConfig.style?.height ?? '100%'}; top: ${this.uiConfig.style?.height ?? '0'}; ${this.uiConfig.additionalStyle ?? ''}`);
|
||||||
|
rootDiv.setAttribute('id', uwid);
|
||||||
|
rootDiv.classList.add('uw-ultrawidify-container-root');
|
||||||
|
|
||||||
|
if (this.uiConfig?.parentElement) {
|
||||||
|
this.uiConfig.parentElement.appendChild(rootDiv);
|
||||||
|
} else {
|
||||||
|
document.body.appendChild(rootDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element = rootDiv;
|
||||||
|
|
||||||
|
const app = createApp(this.uiConfig.component);
|
||||||
|
if (this.vuexStore) {
|
||||||
|
app.use(this.vuexStore);
|
||||||
|
}
|
||||||
|
app.mount(`#${uwid}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces ui config and re-inits the UI
|
||||||
|
* @param {*} newUiConfig
|
||||||
|
*/
|
||||||
|
replace(newUiConfig) {
|
||||||
|
this.element?.remove();
|
||||||
|
this.uiConfig = newUiConfig;
|
||||||
|
this.initUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
// this.comms?.destroy();
|
||||||
|
this.element?.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("UI.js loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default UI;
|
@ -5,7 +5,7 @@ import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
|||||||
import CropModePersistence from '../../../common/enums/crop-mode-persistence.enum';
|
import CropModePersistence from '../../../common/enums/crop-mode-persistence.enum';
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Loading PageInfo");
|
console.info("Loading PageInfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
class PageInfo {
|
class PageInfo {
|
||||||
@ -58,22 +58,22 @@ class PageInfo {
|
|||||||
this.currentZoomScale = 1;
|
this.currentZoomScale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
injectCss(cssString) {
|
async injectCss(cssString) {
|
||||||
this.comms.sendMessage({
|
await this.comms.sendMessage({
|
||||||
cmd: 'inject-css',
|
cmd: 'inject-css',
|
||||||
cssString: cssString
|
cssString: cssString
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ejectCss(cssString) {
|
async ejectCss(cssString) {
|
||||||
this.comms.sendMessage({
|
await this.comms.sendMessage({
|
||||||
cmd: 'eject-css',
|
cmd: 'eject-css',
|
||||||
cssString: cssString
|
cssString: cssString
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceCss(oldCssString, newCssString) {
|
async replaceCss(oldCssString, newCssString) {
|
||||||
this.comms.sendMessage({
|
await this.comms.sendMessage({
|
||||||
cmd: 'replace-css',
|
cmd: 'replace-css',
|
||||||
newCssString,
|
newCssString,
|
||||||
oldCssString
|
oldCssString
|
||||||
@ -623,4 +623,8 @@ class PageInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("PageInfo loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
export default PageInfo;
|
export default PageInfo;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import Debug from '../../conf/Debug';
|
import Debug from '../../conf/Debug';
|
||||||
import ExtensionMode from '../../../common/enums/extension-mode.enum'
|
import ExtensionMode from '../../../common/enums/extension-mode.enum'
|
||||||
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
||||||
|
import PlayerNotificationUi from '../uwui/PlayerNotificationUI';
|
||||||
|
|
||||||
if(Debug.debug)
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.log("Loading: PlayerData.js");
|
console.info("Loading: PlayerData.js");
|
||||||
|
}
|
||||||
|
|
||||||
/* sprejme <video> tag (element) in seznam imen, ki se lahko pojavijo v razredih oz. id staršev.
|
/* sprejme <video> tag (element) in seznam imen, ki se lahko pojavijo v razredih oz. id staršev.
|
||||||
// vrne dimenzije predvajalnika (širina, višina)
|
// vrne dimenzije predvajalnika (širina, višina)
|
||||||
@ -42,6 +44,7 @@ class PlayerData {
|
|||||||
this.extensionMode = videoData.extensionMode;
|
this.extensionMode = videoData.extensionMode;
|
||||||
this.invalid = false;
|
this.invalid = false;
|
||||||
this.element = this.getPlayer();
|
this.element = this.getPlayer();
|
||||||
|
this.notificationService = new PlayerNotificationUi(this.element, this.settings);
|
||||||
this.dimensions = undefined;
|
this.dimensions = undefined;
|
||||||
this.overlayNode = undefined;
|
this.overlayNode = undefined;
|
||||||
|
|
||||||
@ -62,6 +65,7 @@ class PlayerData {
|
|||||||
this.checkPlayerSizeChange();
|
this.checkPlayerSizeChange();
|
||||||
}
|
}
|
||||||
this.startChangeDetection();
|
this.startChangeDetection();
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[Ultrawidify::PlayerData::ctor] There was an error setting up player data. You should be never seeing this message. Error:', e);
|
console.error('[Ultrawidify::PlayerData::ctor] There was an error setting up player data. You should be never seeing this message. Error:', e);
|
||||||
this.invalid = true;
|
this.invalid = true;
|
||||||
@ -72,7 +76,6 @@ class PlayerData {
|
|||||||
return new Promise( (resolve, reject) => setTimeout(() => resolve(), timeout));
|
return new Promise( (resolve, reject) => setTimeout(() => resolve(), timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static isFullScreen(){
|
static isFullScreen(){
|
||||||
return ( window.innerHeight == window.screen.height && window.innerWidth == window.screen.width);
|
return ( window.innerHeight == window.screen.height && window.innerWidth == window.screen.width);
|
||||||
}
|
}
|
||||||
@ -97,6 +100,7 @@ class PlayerData {
|
|||||||
destroy() {
|
destroy() {
|
||||||
this.stopChangeDetection();
|
this.stopChangeDetection();
|
||||||
this.destroyOverlay();
|
this.destroyOverlay();
|
||||||
|
this.notificationService?.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
startChangeDetection(){
|
startChangeDetection(){
|
||||||
@ -222,6 +226,10 @@ class PlayerData {
|
|||||||
// is defined. Since resizer needs a PlayerData object to exist, videoData.resizer will
|
// is defined. Since resizer needs a PlayerData object to exist, videoData.resizer will
|
||||||
// be undefined the first time this function will run.
|
// be undefined the first time this function will run.
|
||||||
this.videoData.resizer?.restore();
|
this.videoData.resizer?.restore();
|
||||||
|
|
||||||
|
// NOTE: it's possible that notificationService hasn't been initialized yet at this point.
|
||||||
|
// no biggie if it wasn't, we just won't replace the notification UI
|
||||||
|
this.notificationService?.replace(this.element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,6 +472,14 @@ class PlayerData {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showNotification(notificationId) {
|
||||||
|
this.notificationService?.showNotification(notificationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
console.info("PlayerData loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PlayerData;
|
export default PlayerData;
|
||||||
|
@ -6,6 +6,7 @@ import AspectRatio from '../../../common/enums/aspect-ratio.enum';
|
|||||||
|
|
||||||
class VideoData {
|
class VideoData {
|
||||||
|
|
||||||
|
|
||||||
constructor(video, settings, pageInfo){
|
constructor(video, settings, pageInfo){
|
||||||
this.vdid = (Math.random()*100).toFixed();
|
this.vdid = (Math.random()*100).toFixed();
|
||||||
this.logger = pageInfo.logger;
|
this.logger = pageInfo.logger;
|
||||||
@ -27,16 +28,7 @@ class VideoData {
|
|||||||
height: this.video.offsetHeight,
|
height: this.video.offsetHeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is in case extension loads before the video
|
this.setupStageOne();
|
||||||
video.addEventListener('loadeddata', () => {
|
|
||||||
this.logger.log('info', 'init', '[VideoData::ctor->video.onloadeddata] Video fired event "loaded data!"');
|
|
||||||
this.onVideoLoaded();
|
|
||||||
});
|
|
||||||
|
|
||||||
// this one is in case extension loads after the video is loaded
|
|
||||||
video.addEventListener('timeupdate', () => {
|
|
||||||
this.onVideoLoaded();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onVideoLoaded() {
|
async onVideoLoaded() {
|
||||||
@ -60,6 +52,41 @@ class VideoData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async injectBaseCss() {
|
||||||
|
try {
|
||||||
|
await this.pageInfo.injectCss(`
|
||||||
|
.uw-ultrawidify-base-wide-screen {
|
||||||
|
margin: 0px 0px 0px 0px !important; width: initial !important; align-self: start !important; justify-self: start !important;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to inject base css!', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetBaseClass() {
|
||||||
|
this.video.classList.remove('uw-ultrawidify-base-wide-screen');
|
||||||
|
}
|
||||||
|
|
||||||
|
async setupStageOne() {
|
||||||
|
this.logger.log('info', 'init', '%c[VideoData::setupStageOne] ——————————— Starting setup stage one! ———————————', 'color: #0f9');
|
||||||
|
// ensure base css is loaded before doing anything
|
||||||
|
this.injectBaseCss();
|
||||||
|
|
||||||
|
// this is in case extension loads before the video
|
||||||
|
this.video.addEventListener('loadeddata', () => {
|
||||||
|
this.logger.log('info', 'init', '[VideoData::ctor->video.onloadeddata] Video fired event "loaded data!"');
|
||||||
|
this.onVideoLoaded();
|
||||||
|
});
|
||||||
|
|
||||||
|
// this one is in case extension loads after the video is loaded
|
||||||
|
this.video.addEventListener('timeupdate', () => {
|
||||||
|
this.onVideoLoaded();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger.log('info', 'init', '%c[VideoData::setupStageOne] ——————————— Setup stage one complete! ———————————', 'color: #0f9');
|
||||||
|
}
|
||||||
|
|
||||||
async setupStageTwo() {
|
async setupStageTwo() {
|
||||||
// POZOR: VRSTNI RED JE POMEMBEN (arDetect mora bit zadnji)
|
// POZOR: VRSTNI RED JE POMEMBEN (arDetect mora bit zadnji)
|
||||||
// NOTE: ORDERING OF OBJ INITIALIZATIONS IS IMPORTANT (arDetect needs to go last)
|
// NOTE: ORDERING OF OBJ INITIALIZATIONS IS IMPORTANT (arDetect needs to go last)
|
||||||
@ -98,8 +125,13 @@ class VideoData {
|
|||||||
this.logger.log('info', ['debug', 'init'], '[VideoData::ctor] Created videoData with vdid', this.vdid, '\nextension mode:', this.extensionMode)
|
this.logger.log('info', ['debug', 'init'], '[VideoData::ctor] Created videoData with vdid', this.vdid, '\nextension mode:', this.extensionMode)
|
||||||
|
|
||||||
this.pageInfo.initMouseActionHandler(this);
|
this.pageInfo.initMouseActionHandler(this);
|
||||||
|
|
||||||
|
// NOTE — since base class for our <video> element depends on player aspect ratio,
|
||||||
|
// we handle it in PlayerData class.
|
||||||
|
this.video.classList.add('uw-ultrawidify-base-wide-screen');
|
||||||
this.video.classList.add(this.userCssClassName); // this also needs to be applied BEFORE we initialize resizer!
|
this.video.classList.add(this.userCssClassName); // this also needs to be applied BEFORE we initialize resizer!
|
||||||
|
|
||||||
|
|
||||||
// start fallback video/player size detection
|
// start fallback video/player size detection
|
||||||
this.fallbackChangeDetection();
|
this.fallbackChangeDetection();
|
||||||
|
|
||||||
@ -123,6 +155,7 @@ class VideoData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
restoreCrop() {
|
restoreCrop() {
|
||||||
this.logger.log('info', 'debug', '[VideoData::restoreCrop] Attempting to reset aspect ratio.')
|
this.logger.log('info', 'debug', '[VideoData::restoreCrop] Attempting to reset aspect ratio.')
|
||||||
// if we have default crop set for this page, apply this.
|
// if we have default crop set for this page, apply this.
|
||||||
@ -175,7 +208,8 @@ class VideoData {
|
|||||||
// we still only need to make sure we're only adding our class to classlist if it has been
|
// we still only need to make sure we're only adding our class to classlist if it has been
|
||||||
// removed. classList.add() will _still_ trigger mutation (even if classlist wouldn't change).
|
// removed. classList.add() will _still_ trigger mutation (even if classlist wouldn't change).
|
||||||
// This is a problem because INFINITE RECURSION TIME, and we _really_ don't want that.
|
// This is a problem because INFINITE RECURSION TIME, and we _really_ don't want that.
|
||||||
context.video.classList.add(this.userCssClassName);
|
context.video.classList.add(this.userCssClassName);
|
||||||
|
context.video.classList.add('uw-ultrawidify-base-wide-screen');
|
||||||
}
|
}
|
||||||
// always trigger refresh on class changes, since change of classname might trigger change
|
// always trigger refresh on class changes, since change of classname might trigger change
|
||||||
// of the player size as well.
|
// of the player size as well.
|
||||||
@ -298,6 +332,7 @@ class VideoData {
|
|||||||
|
|
||||||
if (this.video) {
|
if (this.video) {
|
||||||
this.video.classList.remove(this.userCssClassName);
|
this.video.classList.remove(this.userCssClassName);
|
||||||
|
this.video.classList.remove('uw-ultrawidify-base-wide-screen');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pause();
|
this.pause();
|
||||||
|
@ -670,10 +670,6 @@ class Resizer {
|
|||||||
|
|
||||||
const styleArray = this.buildStyleArray('', extraStyleString)
|
const styleArray = this.buildStyleArray('', extraStyleString)
|
||||||
|
|
||||||
// sometimes, site designers will center <video> by setting margin: to something. We do not like that, as
|
|
||||||
// it prevents extension from working properly.
|
|
||||||
styleArray.push('margin: 0px 0px 0px 0px !important; width: initial !important; height: initial !important');
|
|
||||||
|
|
||||||
// add remaining elements
|
// add remaining elements
|
||||||
if (stretchFactors) {
|
if (stretchFactors) {
|
||||||
styleArray.push(`transform: translate(${translate.x}px, ${translate.y}px) scale(${stretchFactors.xFactor}, ${stretchFactors.yFactor}) !important;`);
|
styleArray.push(`transform: translate(${translate.x}px, ${translate.y}px) scale(${stretchFactors.xFactor}, ${stretchFactors.yFactor}) !important;`);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// vue dependency imports
|
// vue dependency imports
|
||||||
import Vue from 'vue';
|
import { createApp } from 'vue';
|
||||||
import Vuex from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import VuexWebExtensions from 'vuex-webextensions';
|
import VuexWebExtensions from 'vuex-webextensions';
|
||||||
import LoggerUi from '../csui/LoggerUi';
|
import LoggerUi from '../csui/LoggerUi';
|
||||||
|
|
||||||
@ -123,17 +123,16 @@ class UwUi {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
this.vuexStore = createStore({
|
||||||
Vue.prototype.$browser = global.browser;
|
plugins: [
|
||||||
Vue.use(Vuex);
|
VuexWebExtensions({
|
||||||
this.vuexStore = new Vuex.Store({
|
persistentStates: [
|
||||||
plugins: [VuexWebExtensions({
|
'uwLog',
|
||||||
persistentStates: [
|
'showLogger',
|
||||||
'uwLog',
|
'loggingEnded',
|
||||||
'showLogger',
|
],
|
||||||
'loggingEnded',
|
}),
|
||||||
],
|
],
|
||||||
})],
|
|
||||||
state: {
|
state: {
|
||||||
uwLog: '',
|
uwLog: '',
|
||||||
showLogger: false,
|
showLogger: false,
|
||||||
@ -168,9 +167,6 @@ class UwUi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
|
||||||
console.error("Ultrawidify failed to initialize vue. Error:", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we don't init twice
|
// make sure we don't init twice
|
||||||
this.vueInitiated = true;
|
this.vueInitiated = true;
|
||||||
@ -184,22 +180,27 @@ class UwUi {
|
|||||||
const uwid = `uw-ui-root-${random}`;
|
const uwid = `uw-ui-root-${random}`;
|
||||||
|
|
||||||
const rootDiv = document.createElement('div');
|
const rootDiv = document.createElement('div');
|
||||||
rootDiv.setAttribute("style", "position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999999; background-color: #ff0000;");
|
rootDiv.setAttribute("style", "position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999999; pointer-events: none");
|
||||||
rootDiv.setAttribute("id", uwid);
|
rootDiv.setAttribute("id", uwid);
|
||||||
|
rootDiv.classList.add('uw-ultrawidify-container-root');
|
||||||
|
|
||||||
document.body.appendChild(rootDiv);
|
document.body.appendChild(rootDiv);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new Vue({
|
createApp(LoggerUi)
|
||||||
el: `#${uwid}`,
|
.use(this.vuexStore)
|
||||||
components: {
|
.mount(`#${uwid}`);
|
||||||
LoggerUi: LoggerUi
|
|
||||||
},
|
// new Vue({
|
||||||
store: this.vuexStore,
|
// el: `#${uwid}`,
|
||||||
render(h) {
|
// components: {
|
||||||
return h('logger-ui');
|
// LoggerUi: LoggerUi
|
||||||
}
|
// },
|
||||||
});
|
// store: this.vuexStore,
|
||||||
|
// render(h) {
|
||||||
|
// return h('logger-ui');
|
||||||
|
// }
|
||||||
|
// });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error while initiating vue:", e)
|
console.error("Error while initiating vue:", e)
|
||||||
}
|
}
|
||||||
@ -208,12 +209,14 @@ class UwUi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async showLogger() {
|
async showLogger() {
|
||||||
|
console.log("show logger?")
|
||||||
if (!this.loggerUiInitiated) {
|
if (!this.loggerUiInitiated) {
|
||||||
await this.initLoggerUi();
|
await this.initLoggerUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log("will show logger")
|
||||||
this.vuexStore.dispatch('uw-show-logger');
|
this.vuexStore.dispatch('uw-show-logger');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to dispatch vuex store', e)
|
console.error('Failed to dispatch vuex store', e)
|
||||||
|
@ -9,17 +9,17 @@ import PageInfo from './lib/video-data/PageInfo';
|
|||||||
import Logger from './lib/Logger';
|
import Logger from './lib/Logger';
|
||||||
|
|
||||||
|
|
||||||
if(Debug.debug){
|
if(process.env.CHANNEL !== 'stable'){
|
||||||
console.log("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀᴡɪᴅɪꜰʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n");
|
console.warn("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀᴡɪᴅɪꜰʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n");
|
||||||
try {
|
try {
|
||||||
if(window.self !== window.top){
|
if(window.self !== window.top){
|
||||||
console.log("%cWe aren't in an iframe.", "color: #afc, background: #174");
|
console.info("%cWe aren't in an iframe.", "color: #afc, background: #174");
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
console.log("%cWe are in an iframe!", "color: #fea, background: #d31", window.self, window.top);
|
console.info("%cWe are in an iframe!", "color: #fea, background: #d31", window.self, window.top);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("%cWe are in an iframe!", "color: #fea, background: #d31");
|
console.info("%cWe are in an iframe!", "color: #fea, background: #d31");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Ultrawidify",
|
"name": "Ultrawidify",
|
||||||
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
||||||
"version": "4.4.10",
|
"version": "4.5.0",
|
||||||
"applications": {
|
"applications": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
|
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
|
||||||
@ -19,11 +19,13 @@
|
|||||||
|
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
"matches": ["*://*/*"],
|
"matches": ["*://*/*"],
|
||||||
"js": [
|
"js": [
|
||||||
"ext/uw.js"
|
"common/lib/browser-polyfill.js",
|
||||||
|
"ext/uw.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"ext/uw-ui.css"
|
"ext/uw-ui.css",
|
||||||
|
"ext/uw.css"
|
||||||
],
|
],
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
}],
|
}],
|
||||||
@ -47,7 +49,8 @@
|
|||||||
"ext/*",
|
"ext/*",
|
||||||
"res/fonts/*",
|
"res/fonts/*",
|
||||||
"res/css/*",
|
"res/css/*",
|
||||||
"res/img/settings/about-bg.png"
|
"res/img/settings/about-bg.png",
|
||||||
|
"res/icons/*"
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"storage",
|
"storage",
|
||||||
|
@ -213,6 +213,7 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (BrowserDetect.firefox) {
|
if (BrowserDetect.firefox) {
|
||||||
|
// reminder — webextension-polyfill doesn't seem to work in vue!
|
||||||
await browser.permissions.request({permissions: ['downloads']});
|
await browser.permissions.request({permissions: ['downloads']});
|
||||||
browser.downloads.download({saveAs: true, filename: 'ultrawidify-settings.json', url: fileUrl});
|
browser.downloads.download({saveAs: true, filename: 'ultrawidify-settings.json', url: fileUrl});
|
||||||
} else if (BrowserDetect.chrome) {
|
} else if (BrowserDetect.chrome) {
|
||||||
|
@ -38,12 +38,14 @@ import Settings from '../ext/lib/Settings';
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
addonVersion: Settings.getVersion(),
|
addonVersion: '[extension version not loaded. This is a bug.]',
|
||||||
mailtoLink: 'mailto:tamius.han@gmail.com',
|
mailtoLink: 'mailto:tamius.han@gmail.com',
|
||||||
redditLink: '',
|
redditLink: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.addonVersion = Settings.getExtensionVersion();
|
||||||
|
|
||||||
const messageTemplate = encodeURIComponent(
|
const messageTemplate = encodeURIComponent(
|
||||||
`Describe your issue in more detail. In case of misaligned videos, please provide screenshots. When reporting\
|
`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\
|
issues with autodetection not detecting aspect ratio correctly, please provide a link with timestamp to the\
|
||||||
|
@ -49,8 +49,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CUSTOM ARGUMENT INPUT -->
|
<!-- CUSTOM ARGUMENT INPUT -->
|
||||||
<div v-if="selectedArgument && selectedArgument.customArg"
|
<div v-if="selectedArgument && selectedArgument.customArg">
|
||||||
class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<div class="flex label-secondary form-label">
|
<div class="flex label-secondary form-label">
|
||||||
<span class="w100">
|
<span class="w100">
|
||||||
{{selectedArgument.name}}:
|
{{selectedArgument.name}}:
|
||||||
@ -59,9 +59,15 @@
|
|||||||
<div class="flex flex-grow flex-input">
|
<div class="flex flex-grow flex-input">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
class="w100"
|
class="w100"
|
||||||
v-model="customArgumentValue"
|
:value="customArgumentValue"
|
||||||
|
@input="setCustomValue($event.target.value, selectedArgument.customSetter)"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div v-if="selectedArgument.hintHTML" v-html="selectedArgument.hintHTML">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -122,6 +128,13 @@ export default {
|
|||||||
this.selectedArgument = ActionList[this.selectedAction].args.find(x => x.arg == arg);
|
this.selectedArgument = ActionList[this.selectedAction].args.find(x => x.arg == arg);
|
||||||
this.customArgumentValue = undefined;
|
this.customArgumentValue = undefined;
|
||||||
},
|
},
|
||||||
|
setCustomValue(value, customSetter) {
|
||||||
|
if (!customSetter) {
|
||||||
|
this.customArgumentValue = value;
|
||||||
|
} else {
|
||||||
|
this.customArgumentValue = customSetter(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
emitCommand() {
|
emitCommand() {
|
||||||
this.$emit(
|
this.$emit(
|
||||||
'set-command',
|
'set-command',
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<!-- Load some resources only in development environment -->
|
<!-- Load some resources only in development environment -->
|
||||||
<% } %>
|
<% } %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="uw-ultrawidify-container-root">
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script src="options.js"></script>
|
<script src="options.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
import Vue from 'vue'
|
import { createApp } from 'vue';
|
||||||
import App from './App'
|
import App from './App';
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
createApp(App).mount('#app');
|
||||||
new Vue({
|
|
||||||
el: '#app',
|
|
||||||
render: h => h(App)
|
|
||||||
})
|
|
||||||
|
@ -1,17 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!--
|
||||||
|
NOTE — the code that makes ultrawidify popup work in firefox regardless of whether the
|
||||||
|
extension is being displayed in a normal or a small/overflow popup breaks the popup
|
||||||
|
behaviour on Chrome (where the popup would never reach the full width of 800px)
|
||||||
|
|
||||||
|
Since I'm tired and the hour is getting late, we'll just add an extra CSS class for
|
||||||
|
non-firefox builds of this extension and be done with it. No need to complicate things
|
||||||
|
further than that.
|
||||||
|
-->
|
||||||
<div v-if="settingsInitialized"
|
<div v-if="settingsInitialized"
|
||||||
class="popup flex flex-column no-overflow"
|
class="popup flex flex-column no-overflow"
|
||||||
|
:class="{'popup-chrome': ! BrowserDetect.firefox}"
|
||||||
>
|
>
|
||||||
<div class="header flex-row flex-nogrow flex-noshrink relative">
|
<div class="flex-row flex-nogrow flex-noshrink relative"
|
||||||
|
:class="{'header': !narrowPopup, 'header-small': narrowPopup}"
|
||||||
|
>
|
||||||
<span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small>
|
<span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small>
|
||||||
<div class="absolute channel-info" v-if="BrowserDetect.processEnvChannel !== 'stable'">
|
<div class="absolute channel-info" v-if="BrowserDetect.processEnvChannel !== 'stable'">
|
||||||
Build channel: {{BrowserDetect.processEnvChannel}}
|
Build channel: {{BrowserDetect.processEnvChannel}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="narrowPopup"
|
||||||
|
class="w100 show-more flex flex-row flex-center flex-cross-center menu-button"
|
||||||
|
@click="toggleSideMenu()"
|
||||||
|
>
|
||||||
|
<Icon v-if="!sideMenuVisible" icon="list" />
|
||||||
|
<Icon v-else icon="x" />
|
||||||
|
<div>Menu</div>
|
||||||
|
</div>
|
||||||
<div class="flex flex-row body no-overflow flex-grow">
|
<div class="flex flex-row body no-overflow flex-grow">
|
||||||
<!-- TABS/SIDEBAR -->
|
<!-- TABS/SIDEBAR -->
|
||||||
<div id="tablist" class="flex flex-column flex-nogrow flex-noshrink h100">
|
<div id="tablist"
|
||||||
|
v-show="!narrowPopup || sideMenuVisible"
|
||||||
|
class="flex flex-column flex-nogrow flex-noshrink h100"
|
||||||
|
:class="{'w100': narrowPopup}"
|
||||||
|
>
|
||||||
<div class="menu-item"
|
<div class="menu-item"
|
||||||
:class="{'selected-tab': selectedTab === 'global'}"
|
:class="{'selected-tab': selectedTab === 'global'}"
|
||||||
@click="selectTab('global')"
|
@click="selectTab('global')"
|
||||||
@ -29,7 +53,7 @@
|
|||||||
<div class="">
|
<div class="">
|
||||||
Site settings
|
Site settings
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedTab === 'site' && this.activeSites.length > 1"
|
<div v-if="selectedTab === 'site' && activeSites.length > 1"
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<small>Select site to control:</small>
|
<small>Select site to control:</small>
|
||||||
@ -55,7 +79,7 @@
|
|||||||
<div class="">
|
<div class="">
|
||||||
Video settings <span v-if="canShowVideoTab.canShow && canShowVideoTab.warning" class="warning-color">⚠</span>
|
Video settings <span v-if="canShowVideoTab.canShow && canShowVideoTab.warning" class="warning-color">⚠</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedTab === 'video' && this.activeFrames.length > 0"
|
<div v-if="selectedTab === 'video' && activeFrames.length > 0"
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<small>Select embedded frame to control:</small>
|
<small>Select embedded frame to control:</small>
|
||||||
@ -82,7 +106,7 @@
|
|||||||
<div class="">
|
<div class="">
|
||||||
Advanced settings
|
Advanced settings
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedTab === 'site-details' && this.activeSites.length > 1"
|
<div v-if="selectedTab === 'site-details' && activeSites.length > 1"
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<small>Select site to control:</small>
|
<small>Select site to control:</small>
|
||||||
@ -136,8 +160,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PANELS/CONTENT -->
|
<!-- PANELS/CONTENT -->
|
||||||
<div id="tab-content" class="flex-grow h100 overflow-y-auto">
|
<div id="tab-content"
|
||||||
<VideoPanel v-if="settings && settings.active && selectedTab === 'video'"
|
v-show="!(narrowPopup && sideMenuVisible)"
|
||||||
|
class="flex-grow h100 overflow-y-auto"
|
||||||
|
:class="{'narrow-content': narrowPopup}"
|
||||||
|
>
|
||||||
|
<VideoPanel v-if="settings?.active && selectedTab === 'video'"
|
||||||
class=""
|
class=""
|
||||||
:someSitesDisabledWarning="canShowVideoTab.warning"
|
:someSitesDisabledWarning="canShowVideoTab.warning"
|
||||||
:settings="settings"
|
:settings="settings"
|
||||||
@ -145,7 +173,7 @@
|
|||||||
:zoom="currentZoom"
|
:zoom="currentZoom"
|
||||||
@zoom-change="updateZoom($event)"
|
@zoom-change="updateZoom($event)"
|
||||||
/>
|
/>
|
||||||
<DefaultSettingsPanel v-if="settings && settings.active && (selectedTab === 'site' || selectedTab === 'global')"
|
<DefaultSettingsPanel v-if="settings?.active && (selectedTab === 'global' || selectedTab === 'site')"
|
||||||
class=""
|
class=""
|
||||||
:settings="settings"
|
:settings="settings"
|
||||||
:scope="selectedTab"
|
:scope="selectedTab"
|
||||||
@ -167,6 +195,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Icon from '../common/components/Icon.vue'
|
||||||
import WhatsNewPanel from './panels/WhatsNewPanel.vue';
|
import WhatsNewPanel from './panels/WhatsNewPanel.vue';
|
||||||
import SiteDetailsPanel from './panels/SiteDetailsPanel.vue';
|
import SiteDetailsPanel from './panels/SiteDetailsPanel.vue';
|
||||||
import Donate from '../common/misc/Donate.vue';
|
import Donate from '../common/misc/Donate.vue';
|
||||||
@ -206,6 +235,8 @@ export default {
|
|||||||
canShowVideoTab: {canShow: true, warning: true},
|
canShowVideoTab: {canShow: true, warning: true},
|
||||||
showWhatsNew: false,
|
showWhatsNew: false,
|
||||||
BrowserDetect: BrowserDetect,
|
BrowserDetect: BrowserDetect,
|
||||||
|
narrowPopup: null,
|
||||||
|
sideMenuVisible: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
@ -245,6 +276,20 @@ export default {
|
|||||||
await this.sleep(5000);
|
await this.sleep(5000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async updated() {
|
||||||
|
const body = document.getElementsByTagName('body')[0];
|
||||||
|
|
||||||
|
// ensure that narrowPopup only gets set the first time the popup renders
|
||||||
|
// if popup was rendered before, we don't do anything because otherwise
|
||||||
|
// we'll be causing an unwanted re-render
|
||||||
|
//
|
||||||
|
// another thing worth noting — the popup gets first initialized with
|
||||||
|
// offsetWidth set to 0. This means proper popup will be displayed as a
|
||||||
|
// mini popup if we don't check for that.
|
||||||
|
if (this.narrowPopup === null && body.offsetWidth > 0) {
|
||||||
|
this.narrowPopup = body.offsetWidth < 600;
|
||||||
|
}
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
VideoPanel,
|
VideoPanel,
|
||||||
DefaultSettingsPanel,
|
DefaultSettingsPanel,
|
||||||
@ -255,6 +300,7 @@ export default {
|
|||||||
Donate,
|
Donate,
|
||||||
SiteDetailsPanel,
|
SiteDetailsPanel,
|
||||||
WhatsNewPanel,
|
WhatsNewPanel,
|
||||||
|
Icon,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async sleep(t) {
|
async sleep(t) {
|
||||||
@ -282,6 +328,7 @@ export default {
|
|||||||
this.settings.active.whatsNewChecked = true;
|
this.settings.active.whatsNewChecked = true;
|
||||||
this.settings.save();
|
this.settings.save();
|
||||||
}
|
}
|
||||||
|
this.toggleSideMenu(false);
|
||||||
},
|
},
|
||||||
selectFrame(frame) {
|
selectFrame(frame) {
|
||||||
this.selectedFrame = frame;
|
this.selectedFrame = frame;
|
||||||
@ -325,6 +372,7 @@ export default {
|
|||||||
if (!this.site || this.site.host !== message.site.host) {
|
if (!this.site || this.site.host !== message.site.host) {
|
||||||
this.port.postMessage({cmd: 'get-current-zoom'});
|
this.port.postMessage({cmd: 'get-current-zoom'});
|
||||||
}
|
}
|
||||||
|
console.log("processing received message:", message)
|
||||||
this.site = message.site;
|
this.site = message.site;
|
||||||
|
|
||||||
// update activeSites
|
// update activeSites
|
||||||
@ -475,6 +523,10 @@ export default {
|
|||||||
},
|
},
|
||||||
selectSite(host) {
|
selectSite(host) {
|
||||||
this.selectedSite = host;
|
this.selectedSite = host;
|
||||||
|
},
|
||||||
|
toggleSideMenu(visible) {
|
||||||
|
console.warn('toggling side menu visible to:', visible ?? !this.sideMenuVisible, "arg:", visible )
|
||||||
|
this.sideMenuVisible = visible ?? !this.sideMenuVisible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -486,13 +538,22 @@ export default {
|
|||||||
<style src="../res/css/common.scss"></style>
|
<style src="../res/css/common.scss"></style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
html, body {
|
html {
|
||||||
width: 800px !important;
|
// width: 800px !important;
|
||||||
max-width: 800px !important;
|
// max-width: 800px !important;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zero-width {
|
||||||
|
width: 0px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .header-small, .narrow-content {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
#tablist {
|
#tablist {
|
||||||
min-width: 275px;
|
min-width: 275px;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
@ -509,6 +570,17 @@ html, body {
|
|||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
font-size: 2.7em;
|
font-size: 2.7em;
|
||||||
}
|
}
|
||||||
|
.header-small {
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #7f1416;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0px;
|
||||||
|
margin-top: 0px;
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
font-size: 1.27em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.menu-item-inline-desc{
|
.menu-item-inline-desc{
|
||||||
@ -575,6 +647,7 @@ html, body {
|
|||||||
background-color: initial;
|
background-color: initial;
|
||||||
border-left: #f0c089 3px solid !important;
|
border-left: #f0c089 3px solid !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabitem-selected::before {
|
.tabitem-selected::before {
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
@ -588,12 +661,37 @@ html, body {
|
|||||||
padding-left: 0.33em;
|
padding-left: 0.33em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-button {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
border-bottom: #f18810 1px solid !important;
|
||||||
|
font-size: 1.5rem !important;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;;
|
||||||
|
}
|
||||||
|
|
||||||
.popup {
|
.popup {
|
||||||
// max-width: 780px;
|
|
||||||
// width: 800px;
|
|
||||||
height: 600px;
|
height: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This was written at the top, but it's worth repeating.
|
||||||
|
|
||||||
|
NOTE — the code that makes ultrawidify popup work in firefox regardless of whether the
|
||||||
|
extension is being displayed in a normal or a small/overflow popup breaks the popup
|
||||||
|
behaviour on Chrome (where the popup would never reach the full width of 800px)
|
||||||
|
|
||||||
|
Since I'm tired and the hour is getting late, we'll just add an extra CSS class for
|
||||||
|
non-firefox builds of this extension and be done with it. No need to complicate things
|
||||||
|
further than that.
|
||||||
|
|
||||||
|
It also seems that Chrome doesn't like if we set the width of the popup all the way to
|
||||||
|
800px (probably something something scrollbar), so let's just take away a few px.
|
||||||
|
*/
|
||||||
|
.popup-chrome {
|
||||||
|
width: 780px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.relative {
|
.relative {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@ -606,4 +704,9 @@ html, body {
|
|||||||
bottom: 0.85rem;
|
bottom: 0.85rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-more {
|
||||||
|
padding-top: 12px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -47,7 +47,8 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
addonVersion: browser.runtime.getManifest().version || chrome.runtime.getManifest().version,
|
// reminder — webextension-polyfill doesn't seem to work in vue!
|
||||||
|
addonVersion: BrowserDetect.firefox ? browser.runtime.getManifest().version : chrome.runtime.getManifest().version,
|
||||||
loggingEnabled: false,
|
loggingEnabled: false,
|
||||||
loggerSettings: '',
|
loggerSettings: '',
|
||||||
loggerSettingsError: false,
|
loggerSettingsError: false,
|
||||||
|
@ -147,7 +147,6 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
ShortcutButton,
|
ShortcutButton,
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
settings: {
|
settings: {
|
||||||
deep: true,
|
deep: true,
|
||||||
@ -172,7 +171,6 @@ export default {
|
|||||||
let site;
|
let site;
|
||||||
if (this.scope === 'global') {
|
if (this.scope === 'global') {
|
||||||
site = '@global'
|
site = '@global'
|
||||||
this.site = site;
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.site) {
|
if (!this.site) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -2,19 +2,27 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>What's new</h2>
|
<h2>What's new</h2>
|
||||||
<p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
|
<p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
|
||||||
<p class="label">4.4.10</p>
|
<p class="label">4.5.0</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
Video alignment should now work on Twitch (<a href="https://github.com/tamius-han/ultrawidify/issues/109">#109</a>)
|
Under the hood: migrated from vue2 to vue3, because optional chaining in templates is too OP.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Videos should now align properly on Hulu while cropped (<a href="https://github.com/tamius-han/ultrawidify/issues/111">#111 & via email</a>)
|
(On options page, section 'Action & shortcuts') Manual aspect ratio now supports entering custom ratios using '21/9' and '2.39:1' formats (as opposed to single number, e.g. '2.39') — <a href="https://github.com/tamius-han/ultrawidify/issues/121">#121</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
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 <a href="(https://github.com/tamius-han/ultrawidify/issues/112">#112</a>?)
|
Added config for wakanim.tv (special thanks to <a href="https://github.com/saschanaz">@saschanaz</a> for doing the legwork — <a href="https://github.com/tamius-han/ultrawidify/issues/113">#113</a>)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Fixed a problem where embedded videos would be misaligned after switching from full screen
|
(In Firefox) When extension was placed in overflow menu, the popup was cut off. That should be fixed now. (<a href="https://github.com/tamius-han/ultrawidify/issues/119">#119</a>)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The extension will now show a notification when autodetection can't run due to DRM.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Videos on facebook and reddit no longer get shifted up and to the left for me (cropping most of the video off-screen), but I haven't been
|
||||||
|
deliberately trying to fix that issue. If you experience that issue, please consider contacting me (via github or email) with a link to a
|
||||||
|
problematic video.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<!-- Load some resources only in development environment -->
|
<!-- Load some resources only in development environment -->
|
||||||
<% } %>
|
<% } %>
|
||||||
</head>
|
</head>
|
||||||
<body style="width: 800px; height: 600px; overflow: hidden !important">
|
<body style="width: 100%; height: 100%; overflow-x: hidden;" class="uw-ultrawidify-container-root">
|
||||||
<div id="app">
|
<div id="app">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,4 @@
|
|||||||
import Vue from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App'
|
import App from './App';
|
||||||
|
|
||||||
// global.browser = require('webextension-polyfill')
|
createApp(App).mount('#app');
|
||||||
// Vue.prototype.$browser = global.browser
|
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
|
||||||
new Vue({
|
|
||||||
el: '#app',
|
|
||||||
render: h => h(App)
|
|
||||||
})
|
|
||||||
|
@ -17,7 +17,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* STANDARD WIDTHS AND HEIGHTS */
|
/* STANDARD WIDTHS AND HEIGHTS */
|
||||||
|
.uw-ultrawidify-container-root {
|
||||||
.w100 {
|
.w100 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@ -99,294 +99,293 @@ body {
|
|||||||
.description {
|
.description {
|
||||||
color: $text-dim;
|
color: $text-dim;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
padding-top: 1.5rem;
|
padding-top: 1.5rem;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-variant: small-caps;
|
font-variant: small-caps;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-secondary {
|
.label-secondary {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-box {
|
.button-box {
|
||||||
padding-top: 0.69rem;
|
padding-top: 0.69rem;
|
||||||
padding-bottom: 0.69rem;
|
padding-bottom: 0.69rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.indent {
|
.indent {
|
||||||
padding-left: 4.2rem;
|
padding-left: 4.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row-padding {
|
.row-padding {
|
||||||
padding-top: 0.69rem;
|
padding-top: 0.69rem;
|
||||||
padding-bottom: 0.69rem;
|
padding-bottom: 0.69rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
a, a:visited {
|
a, a:visited {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
color: lighten($primary-color, 10%);
|
color: lighten($primary-color, 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* INPUT FORMATTING */
|
/* INPUT FORMATTING */
|
||||||
input[type="number"], input[type="text"], input {
|
input[type="number"], input[type="text"], input {
|
||||||
outline: none;
|
outline: none;
|
||||||
background-color: $input-background;
|
background-color: $input-background;
|
||||||
color: $text-normal;
|
color: $text-normal;
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
padding-top: 0.2rem;
|
padding-top: 0.2rem;
|
||||||
padding-bottom: 0.1rem;
|
padding-bottom: 0.1rem;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
border: 1px solid $input-border;
|
border: 1px solid $input-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:disabled {
|
input:disabled {
|
||||||
background: #444444;
|
background: #444444;
|
||||||
color: darken($text-normal, 50%);
|
color: darken($text-normal, 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ELEMENT POSITIONING */
|
/* ELEMENT POSITIONING */
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row {
|
.button-row {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-left {
|
.float-left {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
.float-right {
|
.float-right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline-block {
|
.inline-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide {
|
.hide {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TEXT FORMATTING (no colors) */
|
/* TEXT FORMATTING (no colors) */
|
||||||
|
|
||||||
small {
|
small {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium-small {
|
.medium-small {
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smallcaps{
|
.smallcaps{
|
||||||
font-variant: small-caps;
|
font-variant: small-caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center{
|
.center{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.invalid-input {
|
.invalid-input {
|
||||||
border: 1px solid #720 !important;
|
border: 1px solid #720 !important;
|
||||||
background-color: #410 !important;
|
background-color: #410 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
/*display: inline-block;*/
|
/*display: inline-block;*/
|
||||||
// padding-top: 8px;
|
// padding-top: 8px;
|
||||||
// padding-bottom: 3px;
|
// padding-bottom: 3px;
|
||||||
//padding-left: 5px;
|
//padding-left: 5px;
|
||||||
//padding-right: 5px;
|
//padding-right: 5px;
|
||||||
border: 1px solid rgb(39, 39, 39);
|
border: 1px solid rgb(39, 39, 39);
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
color: $text-dim;
|
color: $text-dim;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
cursor: pointer;
|
||||||
|
user-select: none;;
|
||||||
|
}
|
||||||
.selected, .setting-selected {
|
|
||||||
color: $selected-color !important;
|
|
||||||
background-color: $background-selected !important;
|
.selected, .setting-selected {
|
||||||
}
|
color: $selected-color !important;
|
||||||
|
background-color: $background-selected !important;
|
||||||
.selected-tab {
|
}
|
||||||
color: $selected-color;
|
|
||||||
}
|
.selected-tab {
|
||||||
|
color: $selected-color;
|
||||||
.setting-selected {
|
}
|
||||||
border: 1px solid shade($selected-color, 25%);
|
|
||||||
}
|
.setting-selected {
|
||||||
|
border: 1px solid shade($selected-color, 25%);
|
||||||
.button:hover {
|
}
|
||||||
color: lighten($selected-color, 10%);
|
|
||||||
background-color: lighten($background-selected, 10%);
|
.button:hover {
|
||||||
}
|
color: lighten($selected-color, 10%);
|
||||||
|
background-color: lighten($background-selected, 10%);
|
||||||
.button {
|
}
|
||||||
cursor: pointer !important;
|
|
||||||
}
|
.disabled {
|
||||||
|
pointer-events: none;
|
||||||
.disabled {
|
/* color: #666; */
|
||||||
pointer-events: none;
|
filter: contrast(50%) brightness(40%) grayscale(100%);
|
||||||
/* color: #666; */
|
}
|
||||||
filter: contrast(50%) brightness(40%) grayscale(100%);
|
|
||||||
}
|
.disabled-button {
|
||||||
|
color: #666 !important;
|
||||||
.disabled-button {
|
cursor: not-allowed !important;
|
||||||
color: #666 !important;
|
}
|
||||||
cursor: not-allowed !important;
|
|
||||||
}
|
.disabled-button:hover {
|
||||||
|
color: #777 !important;
|
||||||
.disabled-button:hover {
|
background-color: #222 !important;
|
||||||
color: #777 !important;
|
}
|
||||||
background-color: #222 !important;
|
|
||||||
}
|
/* BROWSER-SPECIFIC DISABLE */
|
||||||
|
.disabled-edge {
|
||||||
/* BROWSER-SPECIFIC DISABLE */
|
pointer-events: none !important;
|
||||||
.disabled-edge {
|
filter: contrast(50%) brightness(40%) grayscale(100%) !important;
|
||||||
pointer-events: none !important;
|
content: "NOT SUPPORTED IN THIS BROWSER";
|
||||||
filter: contrast(50%) brightness(40%) grayscale(100%) !important;
|
}
|
||||||
content: "NOT SUPPORTED IN THIS BROWSER";
|
.disabled-edge::after {
|
||||||
}
|
background-color: #333272;
|
||||||
.disabled-edge::after {
|
color: #d8d9e6;
|
||||||
background-color: #333272;
|
display: inline-block;
|
||||||
color: #d8d9e6;
|
font-size: .75em;
|
||||||
display: inline-block;
|
font-variant: small-caps;
|
||||||
font-size: .75em;
|
padding-left: 5px;
|
||||||
font-variant: small-caps;
|
padding-right: 5px;
|
||||||
padding-left: 5px;
|
margin-left: 10px;
|
||||||
padding-right: 5px;
|
}
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
/** misc **/
|
||||||
|
|
||||||
/** misc **/
|
.warning-color {
|
||||||
|
color: #d6ba4a;
|
||||||
.warning-color {
|
}
|
||||||
color: #d6ba4a;
|
|
||||||
}
|
.warning, .warning-lite {
|
||||||
|
color: #d6ba4a;
|
||||||
.warning, .warning-lite {
|
padding-left: 35px;
|
||||||
color: #d6ba4a;
|
float: right;
|
||||||
padding-left: 35px;
|
}
|
||||||
float: right;
|
|
||||||
}
|
.warning::before, .warning-lite::before {
|
||||||
|
content: "⚠ ";
|
||||||
.warning::before, .warning-lite::before {
|
display: inline-block;
|
||||||
content: "⚠ ";
|
}
|
||||||
display: inline-block;
|
.warning::before {
|
||||||
}
|
font-weight: bold;
|
||||||
.warning::before {
|
font-size: 2.5em;
|
||||||
font-weight: bold;
|
margin-left: -35px;
|
||||||
font-size: 2.5em;
|
padding-right: 10px;
|
||||||
margin-left: -35px;
|
}
|
||||||
padding-right: 10px;
|
|
||||||
}
|
.info {
|
||||||
|
color: $info-color;
|
||||||
.info {
|
padding-left: 35px;
|
||||||
color: $info-color;
|
float: right;
|
||||||
padding-left: 35px;
|
}
|
||||||
float: right;
|
|
||||||
}
|
.info::before {
|
||||||
|
content: "ⓘ";
|
||||||
.info::before {
|
display: inline-block;
|
||||||
content: "ⓘ";
|
font-weight: bold;
|
||||||
display: inline-block;
|
margin-left: -35px;
|
||||||
font-weight: bold;
|
padding-right: 10px;
|
||||||
margin-left: -35px;
|
}
|
||||||
padding-right: 10px;
|
|
||||||
}
|
.new {
|
||||||
|
color: #fff;
|
||||||
.new {
|
}
|
||||||
color: #fff;
|
|
||||||
}
|
.new::after {
|
||||||
|
content: "ⓘ";
|
||||||
.new::after {
|
color: $info-color !important;
|
||||||
content: "ⓘ";
|
display: inline-block;
|
||||||
color: $info-color !important;
|
font-weight: bold;
|
||||||
display: inline-block;
|
padding-right: 10px;
|
||||||
font-weight: bold;
|
}
|
||||||
padding-right: 10px;
|
|
||||||
}
|
.experimental::after {
|
||||||
|
// content: "Experimental";
|
||||||
.experimental::after {
|
content: "Ⓔ";
|
||||||
// content: "Experimental";
|
color: #ffde12;
|
||||||
content: "Ⓔ";
|
// background-color: #1f1f1f;
|
||||||
color: #ffde12;
|
display: inline-block;
|
||||||
// background-color: #1f1f1f;
|
font-size: .75em;
|
||||||
display: inline-block;
|
font-variant: small-caps;
|
||||||
font-size: .75em;
|
padding-left: 5px;
|
||||||
font-variant: small-caps;
|
padding-right: 5px;
|
||||||
padding-left: 5px;
|
margin-left: 10px;
|
||||||
padding-right: 5px;
|
margin-top: -4px;
|
||||||
margin-left: 10px;
|
}
|
||||||
margin-top: -4px;
|
.experimental:hover::after {
|
||||||
}
|
content: "Ⓔ Experimental";
|
||||||
.experimental:hover::after {
|
// content: "";
|
||||||
content: "Ⓔ Experimental";
|
color: #ffde12;
|
||||||
// content: "";
|
// background-color: #1f1f1f;
|
||||||
color: #ffde12;
|
display: inline-block;
|
||||||
// background-color: #1f1f1f;
|
font-size: .75em;
|
||||||
display: inline-block;
|
font-variant: small-caps;
|
||||||
font-size: .75em;
|
padding-left: 5px;
|
||||||
font-variant: small-caps;
|
padding-right: 5px;
|
||||||
padding-left: 5px;
|
margin-left: 10px;
|
||||||
padding-right: 5px;
|
margin-top: -4px;
|
||||||
margin-left: 10px;
|
}
|
||||||
margin-top: -4px;
|
|
||||||
}
|
.sticky-bottom {
|
||||||
|
width: 100%;
|
||||||
.sticky-bottom {
|
position: sticky;
|
||||||
width: 100%;
|
// position: fixed;
|
||||||
position: sticky;
|
bottom: 0px;
|
||||||
// position: fixed;
|
background-color: rgba($background-primary, 0.7);
|
||||||
bottom: 0px;
|
}
|
||||||
background-color: rgba($background-primary, 0.7);
|
|
||||||
}
|
.rtl {
|
||||||
|
direction: rtl;
|
||||||
.rtl {
|
}
|
||||||
direction: rtl;
|
|
||||||
}
|
.ltr {
|
||||||
|
direction: ltr;
|
||||||
.ltr {
|
}
|
||||||
direction: ltr;
|
.monospace {
|
||||||
}
|
font-family: 'Overpass Mono';
|
||||||
.monospace {
|
}
|
||||||
font-family: 'Overpass Mono';
|
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,53 @@
|
|||||||
.flex {
|
.uw-ultrawidify-container-root {
|
||||||
display: flex;
|
.flex {
|
||||||
}
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-row {
|
.flex-row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-column {
|
.flex-column {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-auto {
|
.flex-auto {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.flex-nogrow {
|
.flex-nogrow {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
}
|
}
|
||||||
.flex-shrink {
|
.flex-shrink {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
.flex-noshrink {
|
.flex-noshrink {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.flex-wrap {
|
.flex-wrap {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-center {
|
.flex-center {
|
||||||
align-content: center;
|
align-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-end {
|
.flex-end {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-cross-center {
|
.flex-cross-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-self-center {
|
.flex-self-center {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.uw-ultrawidify-container-root {
|
||||||
|
/* todo: any form CSS must be nested under this element */
|
||||||
|
}
|
6
src/res/css/uwui-base.scss
Normal file
6
src/res/css/uwui-base.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.uw-ultrawidify-container-root {
|
||||||
|
all: initial;
|
||||||
|
* {
|
||||||
|
all: unset;
|
||||||
|
}
|
||||||
|
}
|
BIN
src/res/icons/ms-promo-tile.png
Normal file
BIN
src/res/icons/ms-promo-tile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
BIN
src/res/icons/uw-microsoft-store-icon.png
Normal file
BIN
src/res/icons/uw-microsoft-store-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
@ -23,10 +23,18 @@ const config = {
|
|||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.vue'],
|
// maybe we'll move to TS some day, but today is not the day
|
||||||
|
extensions: [
|
||||||
|
// '.ts', '.tsx',
|
||||||
|
'.js', '.vue'
|
||||||
|
],
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
// {
|
||||||
|
// test: /\.tsx?$/,
|
||||||
|
// loader: 'ts-loader',
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
loaders: 'vue-loader',
|
loaders: 'vue-loader',
|
||||||
@ -77,6 +85,16 @@ const config = {
|
|||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
{ from: 'res', to: 'res', ignore: ['css', 'css/**']},
|
{ from: 'res', to: 'res', ignore: ['css', 'css/**']},
|
||||||
{ from: 'ext', to: 'ext', ignore: ['conf/*', 'lib/**']},
|
{ from: 'ext', to: 'ext', ignore: ['conf/*', 'lib/**']},
|
||||||
|
|
||||||
|
// we need to get webextension-polyfill and put it in common/lib
|
||||||
|
{ from: '../node_modules/webextension-polyfill/dist/browser-polyfill.js', to: 'common/lib/browser-polyfill.js'},
|
||||||
|
|
||||||
|
// This is a hack to get bootstrap icons svg file in /res/icons
|
||||||
|
{ from: '../node_modules/bootstrap-icons/bootstrap-icons.svg', to: 'res/icons/bootstrap-icons.svg'},
|
||||||
|
|
||||||
|
// This is extension icon, as used on extension lists and/or extension's action button
|
||||||
|
// This folder does not contain any GUI icons — these are in /res/icons.
|
||||||
|
// (TODO: check if this copy is even necessary — /icons has same content as /res/icons)
|
||||||
{ from: 'icons', to: 'icons', ignore: ['icon.xcf'] },
|
{ from: 'icons', to: 'icons', ignore: ['icon.xcf'] },
|
||||||
{ from: 'popup/popup.html', to: 'popup/popup.html', transform: transformHtml },
|
{ from: 'popup/popup.html', to: 'popup/popup.html', transform: transformHtml },
|
||||||
{ from: 'options/options.html', to: 'options/options.html', transform: transformHtml },
|
{ from: 'options/options.html', to: 'options/options.html', transform: transformHtml },
|
||||||
|
Loading…
Reference in New Issue
Block a user