Started using vue for settings and popup, start of rewrite for settings page

This commit is contained in:
Tamius Han 2018-12-30 23:16:09 +01:00
parent 7593e95726
commit e2df78aa78
140 changed files with 8610 additions and 857 deletions

26
.babelrc Normal file
View File

@ -0,0 +1,26 @@
{
"plugins": [
],
"presets": [
["@babel/preset-env", {
"useBuiltIns": false,
"targets": {
"esmodules": true,
},
}]
]
}
// {
// "plugins": [
// "@babel/plugin-proposal-optional-chaining"
// ],
// "presets": [
// ["@babel/preset-env", {
// "useBuiltIns": "usage",
// "targets": {
// // https://jamie.build/last-2-versions
// "browsers": ["> 0.25%", "not ie 11", "not op_mini all"]
// }
// }]
// ]
// }

7
.gitignore vendored
View File

@ -1,4 +1,7 @@
ultrawidify.zip
ultrawidify-git.zip
old/
build/
/node_modules
/*.log
/dist
/dist-zip

View File

@ -1,16 +1,29 @@
# Changelog
## v4.x
### v4.0.0 (upcoming)
* Using vue for popup and settings page
* Editable shortcuts
* Per-site controls
* Basic mode added
* Per-site controls in popup (to control embedded videos)
* Rewrote keyboard shortcuts and changed how they're handled. Massively.
## v3.x
### v3.3.0
This will probably get promoted to 4.0, continuing the trend of version something.3 not happening. Eulul
~~This will probably get promoted to 4.0, continuing the trend of version something.3 not happening. Eulul~~
* Basic mode added
* Per-site controls in popup (to control embedded videos)
* Rewrote keyboard shortcuts and changed how they're handled. Massively.
* ~~Basic mode added~~
* ~~Per-site controls in popup (to control embedded videos)~~
* ~~Rewrote keyboard shortcuts and changed how they're handled. Massively.~~
### v3.2.2
Never happened, got bumped to 4.0.0.
### v3.2.2 (current)
* Pan event listener now gets properly unbound
* Fixed 'reset zoom' button in popup

View File

@ -1,48 +0,0 @@
var _bd_usebrowser = "firefox";
var _bd_isFirefox = true;
var _bd_isChrome = false;
var _bd_isEdge = false; // we'll see if FF
try{
// todo: find something that works in firefox but not in edge (or vice-versa)
// note that this function returns a promise! and is broken for some reason
var browserinfo = browser.runtime.getBrowserInfo();
// we don't need to actually check because only firefox supports that.
// if we're not on firefox, the above call will probably throw an exception anyway.
// if browsers other than firefox start supporting that, well ... we'll also need to actually await for promise
// that getBrowserInfo() returns to resolve.
// if (Browser.name.toLowerCase().indexOf(firefox) !== -1 || Browser.vendor.toLowerCase().indexOf(mozilla) !== -1) {
_bd_isFirefox = true;
_bd_isEdge = false;
// }
}
catch (e) {
if(Debug.debug) {
console.info("[BrowserDetect] browser.runtime.getBrowserInfo() probably failed. This means we're probably not using firefox.", e)
}
};
if(typeof browser === "undefined"){ // This is a good sign we're in chrome or chromium-based browsers
if(chrome){
browser = chrome;
_bd_usebrowser = "chrome";
_bd_isChrome = true;
_bd_isEdge = false;
_bd_isFirefox = false;
}
}
var BrowserDetect = {
usebrowser: _bd_usebrowser,
firefox: _bd_isFirefox,
chrome: _bd_isChrome,
edge: _bd_isEdge
}
if(Debug.debug){
console.log("BrowserDetect loaded! Here's BrowserDetect object:", BrowserDetect)
}

View File

@ -1,54 +0,0 @@
class BaseElement {
constructor(id, label, onClick, additionalClasses, existingElement) {
if (existingElement) {
this.element = existingElement;
} else {
this.element = document.createElement('div');
this.element.setAttribute('id', id);
}
if (additionalClasses) {
this.element.classList.add(...additionalClasses);
}
if (onClick) {
this.element.addEventListener('click', onClick);
}
if (label && !existingElement) {
this.element.innerHTML = label;
}
}
static fromExisting(element, onClick){
return new BaseElement(undefined, undefined, onClick, undefined, element);
}
disable() {
this.element.classList.add('disabled');
}
enable() {
this.element.classList.remove('disabled');
}
hide() {
this.element.classList.add('hidden');
}
show() {
this.element.classList.remove('hidden');
}
select() {
this.element.classList.add('selected');
}
unselect() {
this.element.classList.remove('selected');
}
appendTo(element) {
if (element.element) {
element.element.appendChild(this.element);
} else {
element.appendChild(this.element);
}
}
removeChildren() {
while (this.element.lastChild) {
this.element.removeChild(this.element.lastChild);
}
}
}

View File

@ -1,11 +0,0 @@
class Button extends BaseElement {
constructor(id, label, onClick, additionalClasses) {
super(
id,
label,
onClick,
additionalClasses
);
this.element.classList.add('button');
}
}

View File

@ -1,10 +0,0 @@
class ShortcutButton extends Button {
constructor(id, label, shortcutLabel, onClick, additionalClasses) {
super(
id,
shortcutLabel ? `${label}<br/><span class="smallcaps small darker">(${shortcutLabel})</span>` : `${label}<br/><span class="smallcaps small darker">&nbsp;</span>`,
onClick,
additionalClasses
);
}
}

View File

@ -1,73 +0,0 @@
class MenuItem extends BaseElement {
constructor(id, label, sublabel, onClick, additionalClasses) {
super(
id,
`${label}<span class="menu-item-inline-desc"><br/>${sublabel}</span>`,
onClick,
additionalClasses
);
this.element.classList.add('menu-item');
this.subitemListElement = document.createElement('div');
this.element.appendChild(this.subitemListElement);
this.subitemList = [];
}
insertSubitem(subitem) {
this.subitemList.push(subitem);
this.subitemListElement.appendChild(subitem.element);
}
removeSubitems() {
while (this.subitemListElement.lastChild) {
this.subitemListElement.removeChild(this.subitemListElement.lastChild);
}
this.subitemList = [];
}
selectSubitem(subitemName) {
for(let item of this.subitemList) {
if (item.name === subitemName) {
item.select();
} else {
item.unselect();
}
}
}
existsSubitem(subitemName) {
for(let item of this.subitemList) {
if (item.name === subitemName) {
return true;
}
}
return false;
}
selectFirstSubitem() {
for(let item of this.subitemList) {
item.unselect();
}
this.subitemList[0].select();
return this.subitemList[0].name;
}
showSubitems() {
this.subitemListElement.classList.remove('hidden');
}
hideSubitems() {
this.subitemListElement.classList.add('hidden');
}
select() {
super.select();
this.showSubitems();
}
unselect() {
super.unselect();
this.hideSubitems();
}
}

View File

@ -1,24 +0,0 @@
class TabItem extends BaseElement {
constructor (id, name, label, isIframe, onClick, badge, additionalClasses) {
if (badge) {
label = `<div style='display: inline-block; color:#fff; background-color:${badge.color}; padding:3px 6px 1px 6px; margin-right: 5px; font-size: 0.66em; min-width: 16px; text-align: center'>${badge.name}</div> ${label}`;
}
super(id, label, onClick, additionalClasses);
this.element.classList.add('tabitem');
if (isIframe) {
this.element.classList.add('tabitem-iframe');
}
this.name = name;
}
select() {
super.select();
this.element.classList.add('tabitem-selected');
}
unselect() {
super.unselect();
this.element.classList.remove('tabitem-selected');
}
}

View File

@ -1,46 +0,0 @@
class ActionItem extends BaseElement {
constructor(id, action, onClick) {
super(id, undefined, onClick, undefined, document.createElement('tr'));
this.element.classList.add("action-list-item");
let cmd = "";
for (var c in action.cmd) {
cmd += `${c > 0 ? '; ' : ''}${action.cmd[0].action} ${action.cmd[0].arg}`
}
this.element.innerHTML = `
<td class="cmd monospace">${cmd}</td>
<td class="label">${action.label ? action.label : ""}</td>
<td class="shortcut center-text">${action.parsedShortcut ? action.parsedShortcut : ""}</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox ${
action.shortcut && action.shortcut.length && (action.shortcut[0].onMouseMove || action.shortcut[0].onClick || action.shortcut[0].onScroll) ?
"checkbox-checked" : ""
}"></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox ${action.popup_global ? "checkbox-checked" : ""}"></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox ${action.popup_site ? "checkbox-checked" : ""}"></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox ${action.popup ? "checkbox-checked" : ""}"></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox ${action.ui ? "checkbox-checked" : ""}"></span>
</div>
</td>
<td>${action.ui_path ? action.ui_path : ""}</td>
`;
}
}

View File

@ -1,35 +0,0 @@
class ActionItemCategoryHeaderProcessor extends BaseElement {
static addCategoryName(table, categoryName) {
var row = document.createElement('tr');
row.innerHTML = `<td class="action-item-category-label">${categoryName}</td>`;
table.appendChild(row);
}
static addTableHeader(table) {
var topRow = document.createElement('tr');
var bottomRow = document.createElement('tr');
topRow.innerHTML = `
<th class="cmd" rowspan="2">Command</th>
<th class="" rowspan="2">Displayed name</th>
<th class="" rowspan="2">Shortcut</th>
<th class="" rowspan="2">Mouse action?</th>
<th colspan="3">Show in popup</th>
<th colspan="2">[reserved for future use]</th>
`;
bottomRow.innerHTML = `
<th class="action-item-table-header-small">Global</th>
<th class="action-item-table-header-small">Site</th>
<th class="action-item-table-header-small">Video</th>
<th class="action-item-table-header-small">Show</th>
<th class="action-item-table-header-small">Menu path</th>
`;
topRow.classList.add("action-item-table-header");
bottomRow.classList.add(["action-item-table-header", "action-item-table-header-small"])
table.appendChild(topRow);
table.appendChild(bottomRow);
}
}

View File

@ -1,101 +0,0 @@
{
"manifest_version": 2,
"name": "Ultrawidify",
"version": "3.3.0-a3",
"applications": {
"gecko": {
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
}
},
"icons": {
"32":"res/icons/uw-32.png",
"64":"res/icons/uw-64.png"
},
"description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.",
"content_scripts": [{
"matches": ["*://*/*"],
"js": [
"js/conf/Debug.js",
"js/lib/enums.js",
"js/lib/BrowserDetect.js",
"js/conf/ExtensionConf.js",
"js/lib/ObjectCopy.js",
"js/lib/Settings.js",
"js/lib/Comms.js",
"js/lib/EdgeDetect.js",
"js/lib/GuardLine.js",
"js/modules/PageInfo.js",
"js/modules/DebugCanvas.js",
"js/modules/ArDetect.js",
"js/modules/Zoom.js",
"js/modules/Scaler.js",
"js/modules/Stretcher.js",
"js/modules/Resizer.js",
"js/lib/PlayerData.js",
"js/lib/VideoData.js",
"js/modules/ActionHandler.js",
"js/uw.js" ],
"all_frames": true
}],
"background": {
"scripts": [
"js/conf/Debug.js",
"js/lib/BrowserDetect.js",
"js/conf/ExtensionConf.js",
"js/lib/Comms.js",
"js/lib/ObjectCopy.js",
"js/lib/Settings.js",
"js/modules/ActionHandler.js",
"js/uw-bg.js"
]
},
"permissions": [
"tabs", "storage", "activeTab", "<all_urls>", "webNavigation"
],
"browser_action": {
"default_icon": "res/icons/uw-32.png",
"default_popup": "res/popup/popup.html",
"default_title": "Ultrawidify"
},
"options_ui": {
"page": "res/settings/settings.html",
"browser_style": false,
"open_in_tab": true
},
"web_accessible_resources": [
"js/*",
"res/fonts/*",
"res/css/*",
"res/img/ytplayer-icons/zoom.png",
"res/img/ytplayer-icons/unzoom.png",
"res/img/ytplayer-icons/fitw.png",
"res/img/ytplayer-icons/fith.png",
"res/img/ytplayer-icons/reset.png",
"res/img/ytplayer-icons/settings.png",
"res/img/settings/about-bg.png"
]
}

43
package.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "ultravidify-vue",
"version": "1.0.0",
"description": "Ultrawidify but with vue settings and popup",
"author": "Tamius Han <tamius.han@gmail.com>",
"scripts": {
"build": "cross-env NODE_ENV=production webpack --hide-modules",
"build:dev": "cross-env NODE_ENV=development webpack --hide-modules",
"build-zip": "node scripts/build-zip.js",
"watch": "npm run build -- --watch",
"watch:dev": "cross-env HMR=true npm run build:dev -- --watch"
},
"dependencies": {
"@types/core-js": "^2.5.0",
"@types/es6-promise": "^3.3.0",
"vue": "^2.5.17",
"vuex": "^3.0.1",
"vuex-webextensions": "^1.2.6",
"webextension-polyfill": "^0.3.1"
},
"devDependencies": {
"@babel/core": "^7.1.2",
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"archiver": "^3.0.0",
"babel-loader": "^8.0.2",
"copy-webpack-plugin": "^4.5.3",
"cross-env": "^5.2.0",
"css-loader": "^0.28.11",
"ejs": "^2.6.1",
"file-loader": "^1.1.11",
"mini-css-extract-plugin": "^0.4.4",
"node-sass": "^4.9.3",
"sass-loader": "^7.1.0",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.5.17",
"web-ext-types": "^2.1.0",
"webpack": "^4.20.2",
"webpack-chrome-extension-reloader": "^0.8.3",
"webpack-cli": "^3.1.2",
"webpack-shell-plugin": "^0.5.0"
}
}

53
scripts/build-zip.js Normal file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const DEST_DIR = path.join(__dirname, '../dist');
const DEST_ZIP_DIR = path.join(__dirname, '../dist-zip');
const extractExtensionData = () => {
const extPackageJson = require('../package.json');
return {
name: extPackageJson.name,
version: extPackageJson.version
}
};
const makeDestZipDirIfNotExists = () => {
if(!fs.existsSync(DEST_ZIP_DIR)) {
fs.mkdirSync(DEST_ZIP_DIR);
}
}
const buildZip = (src, dist, zipFilename) => {
console.info(`Building ${zipFilename}...`);
const archive = archiver('zip', { zlib: { level: 9 }});
const stream = fs.createWriteStream(path.join(dist, zipFilename));
return new Promise((resolve, reject) => {
archive
.directory(src, false)
.on('error', err => reject(err))
.pipe(stream);
stream.on('close', () => resolve());
archive.finalize();
});
};
const main = () => {
const {name, version} = extractExtensionData();
const zipFilename = `${name}-v${version}.zip`;
makeDestZipDirIfNotExists();
buildZip(DEST_DIR, DEST_ZIP_DIR, zipFilename)
.then(() => console.info('OK'))
.catch(console.err);
};
main();

55
scripts/remove-evals.js Normal file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env node
const path = require('path');
const fs = require('fs');
const BUNDLE_DIR = path.join(__dirname, '../dist');
const bundles = [
'background.js',
'popup/popup.js',
'options/options.js',
];
const evalRegexForProduction = /;([a-z])=function\(\){return this}\(\);try{\1=\1\|\|Function\("return this"\)\(\)\|\|\(0,eval\)\("this"\)}catch\(t\){"object"==typeof window&&\(\1=window\)}/g;
const evalRegexForDevelopment = /;\\r\\n\\r\\n\/\/ This works in non-strict mode(?:.){1,304}/g;
const removeEvals = (file) => {
console.info(`Removing eval() from ${file}`);
return new Promise((resolve, reject) => {
fs.readFile(file, 'utf8', (err, data) => {
if(err) {
reject(err);
return;
}
const regex = process.env.NODE_ENV === 'production' ? evalRegexForProduction : evalRegexForDevelopment;
if(!regex.test(data)) {
reject(`No CSP specific code found in ${file}.`);
return;
}
data = data.replace(regex, '=window;');
fs.writeFile(file, data, (err) => {
if(err) {
reject(err);
return;
}
resolve();
});
});
});
};
const main = () => {
bundles.forEach(bundle => {
removeEvals(path.join(BUNDLE_DIR, bundle))
.then(() => console.info(`Bundle ${bundle}: OK`))
.catch(console.error);
});
};
main();

View File

@ -0,0 +1,202 @@
<template>
<div class="action flex flex-column">
<div class="flex flex-row action-name-cmd-container">
<div class="">
</div>
<div class="flex action-name">
<span class="icon" @click="deleteAction()">🗙</span>
<span class="icon" @click="editAction()">🖉</span> {{action.name}}
</div>
</div>
<div class="flex flex-row">
<div class="flex flex-column cmd-container">
<div class="flex bold">
Command:
</div>
<div class="flex cmdlist">
{{parseCommand(action.cmd)}}
</div>
</div>
<!-- SCOPES -->
<div class="flex flex-column scopes-container">
<div class="flex bold">Popup scopes:</div>
<!-- global scope -->
<div v-if="action.scopes.global"
class="flex flex-row scope-row"
>
<div class="flex scope-scope">
Global:
</div>
<div class="flex scope-row-label scope-visible">
Visible?&nbsp;<span class="scope-row-highlight">{{action.scopes.global.show ? 'Yes' : 'No'}}</span>
</div>
<div v-if="action.scopes.global.show"
class="flex scope-row-label scope-button-label"
>
Button label?&nbsp;
<span class="scope-row-highlight">
{{action.scopes.global.label ? action.scopes.global.label : (action.label ? action.label : '')}}
</span>
</div>
<div class="flex scope-row-label">
Keyboard shortcut:&nbsp;
<span class="scope-row-highlight">
{{action.scopes.global.shortcut ? parseActionShortcut(action.scopes.global.shortcut[0]) : 'None'}}
</span>
</div>
</div>
<!-- site scope -->
<div v-if="action.scopes.site"
class="flex flex-row scope-row"
>
<div class="flex scope-scope">
Site:
</div>
<div class="flex scope-row-label scope-visible">
Visible?&nbsp;<span class="scope-row-highlight">{{action.scopes.site.show ? 'Yes' : 'No'}}</span>
</div>
<div v-if="action.scopes.site.show"
class="flex scope-row-label scope-button-label"
>
Button label?&nbsp;
<span class="scope-row-highlight">
{{action.scopes.site.label ? action.scopes.site.label : (action.label ? action.label : '')}}
</span>
</div>
<div class="flex scope-row-label">
Keyboard shortcut:&nbsp;
<span class="scope-row-highlight">
{{action.scopes.site.shortcut ? parseActionShortcut(action.scopes.site.shortcut[0]) : 'None'}}
</span>
</div>
</div>
<!-- page scope -->
<div v-if="action.scopes.page"
class="flex flex-row scope-row"
>
<div class="flex scope-scope">
Page:
</div>
<div class="flex scope-row-label scope-visible">
Visible?&nbsp;<span class="scope-row-highlight">{{action.scopes.page.show ? 'Yes' : 'No'}}</span>
</div>
<div v-if="action.scopes.page.show"
class="flex scope-row-label scope-button-label"
>
Button label?&nbsp;
<span class="scope-row-highlight">
{{action.scopes.page.label ? action.scopes.page.label : (action.label ? action.label : '')}}
</span>
</div>
<div class="flex scope-row-label">
Keyboard shortcut:&nbsp;
<span class="scope-row-highlight">
{{action.scopes.page.shortcut ? parseActionShortcut(action.scopes.page.shortcut[0]) : 'None'}}
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import StretchMode from '../enums/stretch-mode';
import KeyboardShortcutParser from '../js/KeyboardShortcutParser';
export default {
data () {
return {
StretchMode: StretchMode
}
},
created () {
},
props: {
action: Object,
index: Number,
},
methods: {
parseActionShortcut(shortcut) {
return KeyboardShortcutParser.parseShortcut(shortcut);
},
parseCommand(cmd) {
let cmdstring = '';
for (const c of cmd) {
cmdstring += `${c.action} ${c.arg}${c.persistent ? ' persistent' : ''}; `;
}
return cmdstring;
},
editAction() {
this.$emit('edit');
},
removeAction() {
this.$emit('remove');
}
}
}
</script>
<style lang="scss" scoped>
@import '../../res/css/colors.scss';
.action {
cursor: pointer;
}
.action-name-cmd-container {
padding: 1rem;
}
.action-name {
font-size: 1.5rem;
font-weight: 300;
color: $primary-color;
}
.cmd-container {
width: 13.37rem;
}
.cmdlist {
font-family: 'Overpass Mono';
font-size: 0.9rem;
color: $text-dim;
}
.bold {
font-weight: 600;
}
.scope-scope {
width: 5rem;
text-align: right !important;
color: $secondary-color;
}
.scope-visible {
width: 7rem;
}
.scope-button-label {
width: 16rem;
}
.scope-row-label {
color: $text-dark;
}
.scope-row-highlight {
color: $text-normal;
}
</style>

View File

@ -0,0 +1,76 @@
<template>
<tr>
<td class="cmd monospace">{{parseCommand(action.cmd)}}</td>
<td class="">{{action.label ? action.label : ""}}</td>
<td class="shortcut center-text">{{parseActionShortcut(action)}}</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox"
:class="{'checkbox-checked': (action.shortcut && action.shortcut.length &&
(action.shortcut[0].onMouseMove || action.shortcut[0].onClick ||
action.shortcut[0].onScroll))}"
></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox"
:class="{'checkbox-checked': action.popup_global}"
>
</span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox"
:class="{'checkbox-checked': action.popup_site}"
></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox"
:class="{'checkbox-checked': action.popup}"
></span>
</div>
</td>
<td class="center-text">
<div class="checkbox-container">
<span class="checkbox"
:class="{'checkbox-checked': action.ui}"
></span>
</div>
</td>
<td>{{action.ui_path ? action.ui_path : ""}}</td>
</tr>
</template>
<script>
import StretchMode from '../enums/stretch-mode';
import KeyboardShortcutParser from '../js/KeyboardShortcutParser'
export default {
data () {
return {
StretchMode: StretchMode
}
},
created () {
},
props: {
action: Object
},
methods: {
parseActionShortcut(action) {
return KeyboardShortcutParser.parseShortcut(action.shortcut[0]);
},
parseCommand(cmd) {
let cmdstring = '';
for(const c of cmd) {
cmdstring += `${c.action} ${c.arg}${c.persistent ? ' persistent' : ''}; `;
}
return cmdstring;
}
}
}
</script>

View File

@ -0,0 +1,17 @@
<template>
<div class="button center-text flex"
:class="{'selected': selected, 'w24': fixedWidth, 'flex-auto': !fixedWidth }"
>
{{label}}
</div>
</template>
<script>
export default {
props: {
fixedWidth: Boolean,
selected: Boolean,
label: String,
}
}
</script>

View File

@ -0,0 +1,8 @@
var StretchMode = Object.freeze({
NO_STRETCH: 0,
BASIC: 1,
HYBRID: 2,
CONDITIONAL: 3
});
export default StretchMode;

View File

@ -0,0 +1,26 @@
class KeyboardShortcutParser {
static parseShortcut(keypress) {
var shortcutCombo = '';
if (keypress.ctrlKey) {
shortcutCombo += 'Ctrl + ';
}
if (keypress.shiftKey) {
shortcutCombo += 'Shift + ';
}
if (keypress.metaKey) {
shortcutCombo += 'Meta + ';
}
if (keypress.altKey) {
shortcutCombo += 'Alt + ';
}
if (keypress.key) {
shortcutCombo += keypress.key.toUpperCase();
} else {
shortcutCombo += '<mouse action>'
}
return shortcutCombo;
}
}
export default KeyboardShortcutParser;

View File

@ -0,0 +1,75 @@
var ActionList = {
'set-ar': {
name: 'Set aspect ratio',
args: [{
name: 'Automatic',
arg: 'auto',
},{
name: 'Fit width',
arg: 'fitw'
},{
name: 'Fit height',
arg: 'fith',
},{
name: 'Reset',
arg: 'reset',
},{
name: 'Ratio',
customArg: true,
hintHTML: '',
}],
scopes: {
global: false,
site: false,
page: true,
}
},
'stretch': {
name: 'Set stretch',
args: [{
name: 'Normal',
arg: 0
},{
name: 'Basic',
arg: 1,
},{
name: 'Hybrid',
arg: 2,
},{
name: 'Thin borders',
arg: 3,
},{
name: 'Default',
arg: -1,
scopes: {
site: true
}
}],
scopes: {
global: true,
site: true,
page: true,
}
},
'align': {
name: 'Set video alignment',
args: [{
name: 'Left',
arg: 'left',
},{
name: 'Center',
arg: 'center',
},{
name: 'Right',
arg: 'right'
},{
name: 'Default',
arg: 'default',
scopes: {
site: true,
}
}]
}
};
export default ActionList;

View File

@ -0,0 +1,71 @@
import Debug from '../conf/Debug';
var _bd_usebrowser = "firefox";
var _bd_isFirefox = true;
var _bd_isChrome = false;
var _bd_isEdge = false; // we'll see if FF
// try{
// // todo: find something that works in firefox but not in edge (or vice-versa)
// // note that this function returns a promise! and is broken for some reason
// var browserinfo = browser.runtime.getBrowserInfo();
// // we don't need to actually check because only firefox supports that.
// // if we're not on firefox, the above call will probably throw an exception anyway.
// // if browsers other than firefox start supporting that, well ... we'll also need to actually await for promise
// // that getBrowserInfo() returns to resolve.
// // if (Browser.name.toLowerCase().indexOf(firefox) !== -1 || Browser.vendor.toLowerCase().indexOf(mozilla) !== -1) {
// _bd_isFirefox = true;
// _bd_isEdge = false;
// // }
// }
// catch (e) {
// if(Debug.debug) {
// console.info("[BrowserDetect] browser.runtime.getBrowserInfo() probably failed. This means we're probably not using firefox.", e)
// }
// };
try {
if(browser === undefined){ // This is a good sign we're in chrome or chromium-based browsers
if(chrome){
browser = chrome;
_bd_usebrowser = "chrome";
_bd_isChrome = true;
_bd_isEdge = false;
_bd_isFirefox = false;
}
}
} catch (e) {
console.log("e=",e);
if(chrome){
// browser = chrome;
_bd_usebrowser = "chrome";
_bd_isChrome = true;
_bd_isEdge = false;
_bd_isFirefox = false;
} else {
console.log("No chrome either.");
}
}
console.log("extension didn't crash after browser === undefined failed");
var BrowserDetect = {
usebrowser: _bd_usebrowser,
firefox: _bd_isFirefox,
chrome: _bd_isChrome,
edge: _bd_isEdge
}
if(Debug.debug){
console.log("BrowserDetect loaded! Here's BrowserDetect object:", BrowserDetect)
}
if (BrowserDetect.firefox) {
// browser = window.browser;
}
export default BrowserDetect;

View File

@ -1,8 +1,8 @@
// Set prod to true when releasing
//_prod = true;
_prod = false;
const _prod = false;
Debug = {
var Debug = {
init: true,
debug: true,
keyboard: true,
@ -48,5 +48,11 @@ function __disableAllDebug(obj) {
}
}
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");
export default Debug;

View File

@ -1,3 +1,6 @@
import Debug from './Debug';
import currentBrowser from './BrowserDetect';
if(Debug.debug)
console.log("Loading: ExtensionConf.js");
@ -132,57 +135,6 @@ var ExtensionConf = {
},
keyboard: {
},
// List of all possible actions, for use in settings
// TODO: move to separate file as this shouldn't be user-settable
actionsList: [{
action: 'set-ar',
args: [{
name: 'Automatic',
arg: 'auto',
},{
name: 'Fit width',
arg: 'fitw'
},{
name: 'Fit height',
arg: 'fith',
},{
name: 'Reset',
arg: 'reset',
},{
name: 'Ratio',
customArg: true,
customLabel: true,
}]
},{
action: 'stretch',
args: [{
name: 'Normal',
arg: 0
},{
name: 'Basic',
arg: 1,
},{
name: 'Hybrid',
arg: 2,
},{
name: 'Thin borders',
arg: 3,
}],
sitewide: true, // if true, you can see this in site settings
global: true, // if true, it can appear in extension settings
},{
action: 'align',
args: [{
name: 'Left',
arg: 'left',
},{
name: 'Center',
arg: 'center',
},{
name: 'Right',
arg: 'right'
}]
}],
// -----------------------------------------
// ::: ACTIONS :::
// -----------------------------------------
@ -190,12 +142,24 @@ var ExtensionConf = {
//
// Polje 'shortcut' je tabela, če se slučajno lotimo kdaj delati choordov.
actions: [{
name: 'Trigger automatic detection', // name displayed in settings
label: 'Automatic', // name displayed in ui (can be overriden in scope/playerUi)
cmd: [{
action: 'set-ar',
arg: 'auto',
persistent: false, // optional, false by default. If true, change doesn't take effect immediately.
// Instead, this action saves stuff to settings
}],
scopes: {
global: { // if 'global' is undefined, 'show' is presumed to be 'false'
show: false,
},
site: {
show: false,
},
page: {
show: true,
label: 'Automatic', // example override, takes precedence over default label
shortcut: [{
key: 'a',
ctrlKey: false,
@ -205,17 +169,22 @@ var ExtensionConf = {
onKeyUp: true,
onKeyDown: false,
}],
popup: true,
popup_site: false, // optional, false by default
popup_global: false,// optional, false by default
ui: true,
ui_path: 'crop',
label: 'Automatic'
}
},
playerUi: {
show: true,
path: 'crop',
},
},{
name: 'Reset to default',
label: 'Reset',
cmd: [{
action: 'set-ar',
arg: 'reset',
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 'r',
ctrlKey: false,
@ -225,15 +194,22 @@ var ExtensionConf = {
onKeyUp: true,
onKeyDown: false,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: 'Reset',
}
},
playerUi: {
show: true,
path: 'crop'
},
},{
name: 'Fit to width',
label: 'Fit width',
cmd: [{
action: 'set-ar',
arg: 'fitw',
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 'w',
ctrlKey: false,
@ -243,15 +219,22 @@ var ExtensionConf = {
onKeyUp: true,
onKeyDown: false,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: 'Fit width',
}
},
playerUi: {
show: true,
path: 'crop'
}
},{
name: 'Fit to height',
label: 'Fit height',
cmd: [{
action: 'set-ar',
arg: 'fith',
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 'e',
ctrlKey: false,
@ -260,16 +243,23 @@ var ExtensionConf = {
shiftKey: false,
onKeyUp: true,
onKeyDown: false,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: 'Fit height',
}]
}
},
playerUi: {
show: true,
path: 'crop'
}
},{
name: 'Set aspect ratio to 16:9',
label: '16:9',
cmd: [{
action: 'set-ar',
arg: 1.78,
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 's',
ctrlKey: false,
@ -279,15 +269,22 @@ var ExtensionConf = {
onKeyUp: false,
onKeyDown: true,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: '16:9',
}
},
playerUi: {
show: true,
path: 'crop'
}
},{
name: 'Set aspect ratio to 21:9 (2.39:1)',
label: '21:9',
cmd: [{
action: 'set-ar',
arg: 2.39,
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 'd',
ctrlKey: false,
@ -296,34 +293,23 @@ var ExtensionConf = {
shiftKey: false,
onKeyUp: false,
onKeyDown: true,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: '21:9'
},{
cmd: [{
action: 'set-ar',
arg: 2.35,
}],
shortcut: [{
key: 'q',
ctrlKey: false,
metaKey: false,
altKey: false,
shiftKey: false,
onKeyUp: false,
onKeyDown: true,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: '2.35',
}]
}
},
playerUi: {
show: true,
path: 'crop'
}
},{
name: 'Set aspect ratio to 18:9',
label: '18:9',
cmd: [{
action: 'set-ar',
arg: 2.0,
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 'x',
ctrlKey: false,
@ -332,16 +318,23 @@ var ExtensionConf = {
shiftKey: false,
onKeyUp: true,
onKeyDown: false,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: '18:9'
}]
}
},
playerUi: {
show: true,
path: 'crop',
}
},{
name: 'Zoom in',
label: 'Zoom',
cmd: [{
action: 'set-zoom',
arg: 0.1
}],
scopes: {
page: {
show: false,
shortcut: [{
key: 'z',
ctrlKey: false,
@ -351,15 +344,21 @@ var ExtensionConf = {
onKeyUp: true,
onKeyDown: false,
}],
popup: false,
ui: false,
ui_path: 'crop',
label: 'Zoom',
}
},
playerUi: {
show: false,
}
},{
name: 'Zoom out',
label: 'Unzoom',
cmd: [{
action: 'set-zoom',
arg: -0.1
}],
scopes: {
page: {
show: false,
shortcut: [{
key: 'u',
ctrlKey: false,
@ -369,14 +368,21 @@ var ExtensionConf = {
onKeyUp: true,
onKeyDown: false,
}],
popup: false,
ui: false,
label: 'Unzoom',
}
},
playerUi: {
show: false
}
},{
name: 'Toggle panning mode',
label: 'Toggle pan',
cmd: [{
action: 'toggle-pan',
arg: 'toggle'
}],
scopes: {
page: {
show: true,
shortcut: [{
key: 'p',
ctrlKey: false,
@ -385,16 +391,22 @@ var ExtensionConf = {
shiftKey: false,
onKeyUp: true,
onKeyDown: false,
}],
popup: true,
ui: true,
ui_path: 'crop',
label: 'Toggle panning mode',
}]
}
},
playerUi: {
show: true,
path: 'zoom'
}
},{
name: 'Hold to pan',
cmd: [{
action: 'pan',
arg: 'toggle',
}],
scopes: {
page: {
show: false,
shortcut: [{
ctrlKey: false,
metaKey: false,
@ -404,268 +416,327 @@ var ExtensionConf = {
onKeyUp: false,
onMouseMove: true,
}],
popup: false,
ui: false,
ui_path: 'crop',
label: 'Pan (hold)'
}
}
},
//
// S T R E T C H I N G
//
{
name: 'Set stretch to "none"',
label: 'Don\'t stretch',
cmd: [{
action: 'set-stretch',
arg: 0,
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
label: 'Normal',
scopes: {
global: {
show: true,
label: 'Normal'
},
site: {
show: true,
label: 'Normal'
},
page: {
show: true,
label: 'Normal'
}
},
playerUi: {
show: true,
path: 'stretch'
}
},{
name: 'Set stretch to "basic"',
label: 'Basic stretch',
cmd: [{
action: 'set-stretch',
arg: 1,
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
ui_path: 'stretch',
scopes: {
global: {
show: true,
label: 'Basic'
},
site: {
show: true,
label: 'Basic'
},
page: {
show: true,
label: 'Basic'
}
},
playerUi: {
show: true,
path: 'stretch'
}
},{
name: 'Set stretch to "hybrid"',
label: 'Hybrid stretch',
cmd: [{
action: 'set-stretch',
arg: 2,
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
ui_path: 'stretch',
scopes: {
global: {
show: true,
label: 'Hybrid'
},
site: {
show: true,
label: 'Hybrid'
},
page: {
show: true,
label: 'Hybrid'
}
},
playerUi: {
show: true,
path: 'stretch'
}
},{
name: 'Stretch only to hide thin borders',
label: 'Thin borders only',
cmd: [{
action: 'set-stretch',
arg: 3,
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
ui_path: 'stretch',
scopes: {
global: {
show: true,
label: 'Thin borders'
},
site: {
show: true,
label: 'Thin borders'
},
page: {
show: true,
label: 'Thin borders'
}
},
playerUi: {
show: true,
path: 'stretch'
}
},{
name: 'Set stretch to default value',
label: 'Default',
cmd: [{
action: 'set-stretch',
arg: -1,
}],
popup: false,
popup_site: true,
popup_global: false,
ui: false,
label: 'Default'
scopes: {
site: {
show: true,
}
}
},
//
// A L I G N M E N T
//
{
name: 'Align video to the left',
label: 'Left',
cmd: [{
action: 'set-alignment',
arg: 'left'
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
ui_path: 'align',
label: 'Left',
scopes: {
global: {
show: true,
},
site: {
show: true,
},
page: {
show: true,
}
},
playerUi: {
show: true,
path: 'align'
}
},{
name: 'Align video to center',
label: 'Center',
cmd: [{
action: 'set-alignment',
arg: 'center'
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
ui_path: 'align',
label: 'Center',
scopes: {
global: {
show: true,
},
site: {
show: true,
},
page: {
show: true,
}
},
playerUi: {
show: true,
path: 'align'
}
},{
name: 'Align video to the right',
label: 'Right',
cmd: [{
action: 'set-alignment',
arg: 'right'
}],
popup: true,
popup_site: true,
popup_global: true,
ui: true,
ui_path: 'align',
label: 'Right',
scopes: {
global: {
show: true,
},
site: {
show: true,
},
page: {
show: true,
}
},
playerUi: {
show: true,
path: 'align'
}
},{
name: 'Use default alignment',
label: 'Default',
cmd: [{
action: 'set-alignment',
arg: 'default'
}],
popup: false,
popup_site: true,
popup_global: false,
ui: false,
label: 'Default',
scopes: {
site: {
show: true,
}
}
},
//
// E N A B L E E X T E N S I O N / A U T O A R
// (for sites/extension tab in the popup)
//
{ // extension options:
// global
{
name: 'Enable extension',
label: 'Enable',
cmd: [{
action: 'set-extension-mode',
arg: 'blacklist',
persistent: true,
}],
popup: false,
popup_global: true,
popup_site: false,
ui: true,
ui_path: 'settings/global',
label: 'Enable'
scopes: {
global: {
show: true,
},
site: {
show: true,
}
}
},{
name: 'Enable extension on whitelisted sites only',
label: 'On whitelist only',
cmd: [{
action: 'set-extension-mode',
arg: 'whitelist',
persistent: true,
}],
popup: false,
popup_global: true,
popup_site: false,
ui: true,
ui_path: 'settings/global',
label: 'On whitelisted only'
},{
cmd: [{
action: 'set-extension-mode',
arg: 'disabled',
persistent: true,
}],
popup: false,
popup_global: true,
popup_site: false,
ui: true,
ui_path: 'settings/global',
label: 'Disabled'
},{
// site-only
cmd: [{
action: 'set-extension-mode',
arg: 'whitelist',
persistent: true,
}],
popup: false,
popup_global: false,
popup_site: true,
ui: true,
ui_path: 'settings/site',
label: 'Enable'
scopes: {
global: {
show: true
}
}
},{
name: 'Extension mode: use default settings',
label: 'Default',
cmd: [{
action: 'set-extension-mode',
arg: 'default',
persistent: true,
}],
popup: false,
popup_global: false,
popup_site: true,
ui: true,
ui_path: 'settings/site',
label: 'Use default option'
scopes: {
site: {
show: true
}
}
},{
name: 'Disable extension',
label: 'Disable',
cmd: [{
action: 'set-extension-mode',
arg: 'disabled',
persistent: true,
}],
popup: false,
popup_global: false,
popup_site: true,
ui: true,
ui_path: 'settings/site',
label: 'Disable'
},{ // extension options:
// global
scopes: {
global: {
show: true,
},
site: {
show: true,
}
}
},{
name: 'Enable automatic aspect ratio detection',
label: 'Enabled',
cmd: [{
action: 'set-autoar-mode',
arg: 'blacklist',
persistent: true,
}],
popup: false,
popup_global: true,
popup_site: false,
ui: true,
ui_path: 'settings/global',
label: 'Enable'
scopes: {
global: {
show: true
},
site: {
show: true
}
}
},{
name: 'Enable automatic aspect ratio detection on whitelisted sites only',
label: 'On whitelist only',
cmd: [{
action: 'set-autoar-mode',
arg: 'whitelist',
persistent: true,
}],
popup: false,
popup_global: true,
popup_site: false,
ui: true,
ui_path: 'settings/global',
label: 'On whitelisted only'
scopes: {
global: {
show: true,
}
}
},{
cmd: [{
action: 'set-autoar-mode',
arg: 'disabled',
persistent: true,
}],
popup: false,
popup_global: true,
popup_site: false,
ui: true,
ui_path: 'settings/global',
label: 'Disabled'
},{
// site-only
cmd: [{
action: 'set-autoar-mode',
arg: 'whitelist',
persistent: true,
}],
popup: false,
popup_global: false,
popup_site: true,
ui: true,
ui_path: 'settings/global',
label: 'Enable'
},{
name: 'Use default settings for automatic aspect ratio detection',
label: 'Default',
cmd: [{
action: 'set-autoar-mode',
arg: 'default',
persistent: true,
}],
popup: false,
popup_global: false,
popup_site: true,
ui: true,
ui_path: 'settings/global',
label: 'Use default option'
scopes: {
site: {
show: true,
}
}
},{
name: 'Disable automatic aspect ratio detection',
label: 'Disable',
cmd: [{
action: 'set-autoar-mode',
arg: 'disabled',
persistent: true,
}],
popup: false,
popup_global: false,
popup_site: true,
ui: true,
ui_path: 'settings/site',
label: 'Disable'
scopes: {
global: {
show: true,
},
site: {
show: true,
}
}
},],
// -----------------------------------------
// ::: SITE CONFIGURATION :::
@ -709,10 +780,12 @@ var ExtensionConf = {
},
"www.netflix.com" : {
status: "enabled",
arStatus: BrowserDetect.firefox ? "default" : "disabled",
arStatus: currentBrowser.firefox ? "default" : "disabled",
statusEmbedded: "enabled",
override: false,
type: 'official'
},
}
}
export default ExtensionConf;

View File

@ -4,11 +4,11 @@ if(Debug.debug){
class CommsClient {
constructor(name, settings) {
if (BrowserDetect.firefox) {
if (window.currentBrowser.firefox) {
this.port = browser.runtime.connect({name: name});
} else if (BrowserDetect.chrome) {
} else if (window.currentBrowser.chrome) {
this.port = chrome.runtime.connect({name: name});
} else if (BrowserDetect.edge) {
} else if (window.currentBrowser.edge) {
this.port = browser.runtime.connect({name: name})
}
@ -24,7 +24,7 @@ class CommsClient {
destroy() {
this.pageInfo = null;
this.settings = null;
if (!BrowserDetect.edge) { // edge is a very special browser made by outright morons.
if (!window.currentBrowser.edge) { // edge is a very special browser made by outright morons.
this.port.onMessage.removeListener(this._listener);
}
}
@ -39,7 +39,7 @@ class CommsClient {
var ths = this;
this._listener = m => ths.processReceivedMessage(m);
if (!BrowserDetect.edge) {
if (!window.currentBrowser.edge) {
this.port.onMessage.removeListener(this._listener);
}
this.port.onMessage.addListener(this._listener);
@ -98,12 +98,12 @@ class CommsClient {
}
async sendMessage_nonpersistent(message){
if(BrowserDetect.firefox){
if(window.currentBrowser.firefox){
return browser.runtime.sendMessage(message)
} else {
return new Promise((resolve, reject) => {
try{
if(BrowserDetect.edge){
if(window.currentBrowser.edge){
browser.runtime.sendMessage(message, function(response){
var r = response;
resolve(r);
@ -171,7 +171,7 @@ class CommsServer {
var ths = this;
if (BrowserDetect.firefox) {
if (window.currentBrowser.firefox) {
browser.runtime.onConnect.addListener(p => ths.onConnect(p));
browser.runtime.onMessage.addListener(m => ths.processReceivedMessage_nonpersistent_ff(m));
} else {
@ -209,7 +209,7 @@ class CommsServer {
}
async _getActiveTab() {
if (BrowserDetect.firefox) {
if (window.currentBrowser.firefox) {
return await browser.tabs.query({currentWindow: true, active: true});
} else {
return await new Promise( (resolve, reject) => {
@ -440,12 +440,12 @@ class CommsServer {
class Comms {
static async sendMessage(message){
if(BrowserDetect.firefox){
if(window.currentBrowser.firefox){
return browser.runtime.sendMessage(message)
} else {
return new Promise((resolve, reject) => {
try{
if(BrowserDetect.edge){
if(window.currentBrowser.edge){
browser.runtime.sendMessage(message, function(response){
var r = response;
resolve(r);

View File

@ -51,3 +51,5 @@ class ObjectCopy {
// ignoreKeys: if key is an object, we don't recursively call this function on that key
}
}
export default ObjectCopy;

View File

@ -1,3 +1,8 @@
import Debug from '../conf/Debug';
import currentBrowser from '../conf/BrowserDetect';
import ExtensionConf from '../conf/ExtensionConf';
class Settings {
constructor(activeSettings, updateCallback) {
@ -7,9 +12,17 @@ class Settings {
this.version = undefined;
this.updateCallback = updateCallback;
console.log("chrome object:", chrome)
console.log("browser.storage", browser.storage)
console.log("browser object:", browser)
console.log("window.browser", window.browser)
console.log("ExtensionConf", ExtensionConf)
const ths = this;
if(BrowserDetect.firefox) {
if(currentBrowser.firefox) {
browser.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) {
console.log("[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
@ -23,13 +36,13 @@ class Settings {
if(this.updateCallback) {
try {
updateCallback();
updateCallback(ths);
} catch (e) {
console.log("[Settings] CALLING UPDATE CALLBACK FAILED.")
}
}
});
} else if (BrowserDetect.chrome) {
} else if (currentBrowser.chrome) {
chrome.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) {
console.log("[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
@ -43,7 +56,7 @@ class Settings {
if(this.updateCallback) {
try {
updateCallback();
updateCallback(ths);
} catch (e) {
console.log("[Settings] CALLING UPDATE CALLBACK FAILED.")
}
@ -61,6 +74,7 @@ class Settings {
if (Debug.flushStoredSettings) {
console.log("%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd");
Debug.flushStoredSettings = false; // don't do it again this session
this.setDefaultSettings();
this.active = this.getDefaultSettings();
return this.active;
}
@ -77,11 +91,11 @@ class Settings {
this.active = settings;
// check if extension has been updated. If not, return settings as they were retreived
if (BrowserDetect.firefox) {
if (currentBrowser.firefox) {
this.version = browser.runtime.getManifest().version;
} else if (BrowserDetect.chrome) {
} else if (currentBrowser.chrome) {
this.version = chrome.runtime.getManifest().version;
} else if (BrowserDetect.edge) {
} else if (currentBrowser.edge) {
this.version = browser.runtime.getManifest().version;
}
@ -110,19 +124,19 @@ class Settings {
}
async get() {
if (BrowserDetect.firefox) {
if (currentBrowser.firefox) {
const ret = await browser.storage.local.get('uwSettings');
try {
return JSON.parse(ret.uwSettings);
} catch(e) {
return undefined;
}
} else if (BrowserDetect.chrome) {
} else if (currentBrowser.chrome) {
const ret = new Promise( (resolve, reject) => {
chrome.storage.sync.get('uwSettings', (res) => resolve(res));
});
return ret['uwSettings'];
} else if (BrowserDetect.edge) {
} else if (currentBrowser.edge) {
const ret = new Promise( (resolve, reject) => {
browser.storage.sync.get('uwSettings', (res) => resolve(res));
});
@ -135,10 +149,10 @@ class Settings {
console.log("[Settings::set] setting new settings:", extensionConf)
}
if (BrowserDetect.firefox || BrowserDetect.edge) {
if (currentBrowser.firefox || currentBrowser.edge) {
extensionConf.version = this.version;
return this.useSync ? browser.storage.sync.set( {'uwSettings': JSON.stringify(extensionConf)}): browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
} else if (BrowserDetect.chrome) {
} else if (currentBrowser.chrome) {
return chrome.storage.sync.set( {'uwSettings': JSON.stringify(extensionConf)});
}
}
@ -365,3 +379,5 @@ class Settings {
return this.active.miscSettings.videoFloat;
}
}
export default Settings;

View File

@ -30,9 +30,9 @@ class UWServer {
this.comms = new CommsServer(this);
var ths = this;
if(BrowserDetect.firefox) {
if(window.currentBrowser.firefox) {
browser.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)});
} else if (BrowserDetect.chrome) {
} else if (window.currentBrowser.chrome) {
chrome.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)});
}
@ -92,9 +92,9 @@ class UWServer {
this.currentTabId = activeInfo.tabId; // just for readability
var tab;
if (BrowserDetect.firefox) {
if (window.currentBrowser.firefox) {
var tab = await browser.tabs.get(this.currentTabId);
} else if (BrowserDetect.chrome) {
} else if (window.currentBrowser.chrome) {
var tab = await this._promisifyTabsGet(chrome, this.currentTabId);
}
@ -118,9 +118,9 @@ class UWServer {
// does "garbage collection" on frames
let frames;
if (BrowserDetect.firefox) {
if (window.currentBrowser.firefox) {
frames = await browser.webNavigation.getAllFrames({tabId: this.currentTabId});
} else if (BrowserDetect.chrome) {
} else if (window.currentBrowser.chrome) {
frames = await new Promise( (resolve, reject) => {
chrome.webNavigation.getAllFrames({tabId: this.currentTabId}, (data) => resolve(data) );
});

View File

@ -90,5 +90,5 @@ class UW {
}
}
var uw = new UW();
uw.init();
var main = new UW();
main.init();

BIN
src/icons/icon.xcf Normal file

Binary file not shown.

BIN
src/icons/icon_128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
src/icons/icon_48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

97
src/manifest.json Normal file
View File

@ -0,0 +1,97 @@
{
"manifest_version": 2,
"name": "Ultrawidify",
"description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.",
"version": "4.0.0-a1",
"applications": {
"gecko": {
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
}
},
"icons": {
"32":"res/icons/uw-32.png",
"64":"res/icons/uw-64.png"
},
"browser_action": {
"default_title": "Ultrawidify",
"default_popup": "popup/popup.html"
},
"content_scripts": [{
"matches": ["*://*/*"],
"js": [
"js/conf/Debug.js",
"js/lib/enums.js",
"js/lib/BrowserDetect.js",
"js/conf/ExtensionConf.js",
"js/lib/ObjectCopy.js",
"js/lib/Settings.js",
"js/lib/Comms.js",
"js/lib/EdgeDetect.js",
"js/lib/GuardLine.js",
"js/modules/PageInfo.js",
"js/modules/DebugCanvas.js",
"js/modules/ArDetect.js",
"js/modules/Zoom.js",
"js/modules/Scaler.js",
"js/modules/Stretcher.js",
"js/modules/Resizer.js",
"js/lib/PlayerData.js",
"js/lib/VideoData.js",
"js/modules/ActionHandler.js",
"js/uw.js"
],
"all_frames": true
}],
"background": {
"scripts": [
"ext/conf/Debug.js",
"ext/conf/BrowserDetect.js",
"ext/conf/ExtensionConf.js",
"ext/lib/Comms.js",
"ext/lib/ObjectCopy.js",
"ext/lib/Settings.js",
"ext/modules/ActionHandler.js",
"ext/uw-bg.js"
]
},
"options_ui": {
"page": "options/options.html",
"browser_style": false,
"open_in_tab": true
},
"web_accessible_resources": [
"./*",
"ext/*",
"res/fonts/*",
"res/css/*",
"res/img/ytplayer-icons/zoom.png",
"res/img/ytplayer-icons/unzoom.png",
"res/img/ytplayer-icons/fitw.png",
"res/img/ytplayer-icons/fith.png",
"res/img/ytplayer-icons/reset.png",
"res/img/ytplayer-icons/settings.png",
"res/img/settings/about-bg.png"
],
"permissions": [
"tabs", "storage", "activeTab", "<all_urls>", "webNavigation"
]
}

176
src/options/App.vue Normal file
View File

@ -0,0 +1,176 @@
<template>
<div>
<!-- POPUPS -->
<div v-if="anyOpenedPopups"
class="popup-container"
>
<AddEditActionPopup v-if="editActionPopupVisible"
:settings="settings"
:actionIndex="editActionIndex"
@close="closePopups()"
>
</AddEditActionPopup>
</div>
<!-- ACTUAL PAGE -->
<div class="flex flex-row"
:class="{'blur': anyOpenedPopups}"
>
<div class="header flex flex-column">
<div class="flex extension-name text-sink-anchor">
<div class="text-sink title-sink-pad w100 text-center">
Ultrawidify Vue
</div>
</div>
<div class="flex flex-column menu">
<div class="menu-item"
:class="{'selected-tab': selectedTab === 'general'}"
@click="setSelectedTab('general')"
>
General settings
</div>
<div class="menu-item"
:class="{'selected-tab': selectedTab === 'autoar'}"
@click="setSelectedTab('autoar')"
>
Autodetection
</div>
<div class="menu-item"
:class="{'selected-tab': selectedTab === 'controls'}"
@click="setSelectedTab('controls')"
>
Controls
</div>
<div class="menu-item"
:class="{'selected-tab': selectedTab === 'about'}"
@click="setSelectedTab('about')"
>
About
</div>
<div class="menu-item"
:class="{'selected-tab': selectedTab === 'donate'}"
@click="setSelectedTab('donate')"
>
Donate
</div>
</div>
</div>
<div class="flex content-area flex-column">
<div class="flex content-title text-sink-anchor">
<div class="text-sink title-sink-pad">
{{selectedTabTitle}}
</div>
</div>
<div class="content-content">
<GeneralSettings v-if="settingsInitialized && selectedTab === 'general'"
:settings="settings"
>
</GeneralSettings>
<AutodetectionSettings v-if="settingsInitialized && selectedTab === 'autoar'"
:settings="settings"
>
</AutodetectionSettings>
<ControlsSettings v-if="selectedTab === 'controls'"
:settings="settings"
@edit-event="showEditActionPopup($event)"
>
</ControlsSettings>
<!-- Vice City/beggathon reference: https://youtu.be/Mn3YEJTSYs8?t=770 -->
</div>
</div>
</div>
</div>
</template>
<script>
import Debug from '../ext/conf/Debug.js';
import BrowserDetect from '../ext/conf/BrowserDetect.js';
import ExtensionConf from '../ext/conf/ExtensionConf.js';
import ObjectCopy from '../ext/lib/ObjectCopy.js';
import Settings from '../ext/lib/Settings.js';
import GeneralSettings from './general-settings';
import ControlsSettings from './controls-settings/controls-settings';
import AddEditActionPopup from './controls-settings/add-edit-action-popup';
export default {
name: "Ultrawidify",
data () {
return {
selectedTab: "general",
selectedTabTitle: "General settings",
settings: {},
settingsInitialized: false,
editActionPopupVisible: false,
editActionIndex: -1,
anyOpenedPopups: false,
}
},
created () {
this.settings = new Settings(undefined, this.updateSettings);
this.settings.init();
},
components: {
GeneralSettings,
ControlsSettings,
AddEditActionPopup,
},
methods: {
setSelectedTab(newTab) {
this.selectedTab = newTab;
if (newTab === 'general') {
this.selectedTabTitle = 'General settings';
} else if (newTab === 'autoar') {
this.selectedTabTitle = 'Advanced autodetection settings';
} else if (newTab === 'controls') {
this.selectedTabTitle = 'Controls';
} else if (newTab === 'about') {
this.selectedTabTitle = 'About';
} else if (newTab === 'donate') {
this.selectedTabTitle = 'Beggathon';
}
},
updateSettings(newSettings) {
this.settings = newSettings;
this.settingsInitialized = true;
},
showEditActionPopup(event) {
console.log("SHOW EDIT ACTION/APP:", event)
this.editActionPopupVisible = true;
this.anyOpenedPopups = true;
},
closePopups(){
this.anyOpenedPopups = false;
this.editActionPopupVisible = false;
}
}
};
</script>
<style src="../res/css/font/overpass.css"></style>
<style src="../res/css/font/overpass-mono.css"></style>
<style src="../res/css/flex.css"></style>
<style src="../res/css/common.scss"></style>
<style src="./options.scss"></style>
<style lang="scss" scoped>
.popup-container {
position: fixed;
width: 100%;
height: 100%;
z-index: 1000;
}
.blur {
filter: blur(2px);
}
</style>

20
src/options/about.vue Normal file
View File

@ -0,0 +1,20 @@
<template>
<div>
<h2>Ultrawidify - an aspect ratio fixer for youtube <small>(and netflix)</small></h2>
<p>Created by Tamius Han (me). If something is broken, you can shout at me on <a href="https://github.com/xternal7/ultrawidify">github</a> (shout nicely, though. Open an issue or bug report or something).
If you're curious to see the source code, <a href="https://github.com/xternal7/ultrawidify">github's here</a>.
If you're looking at this page because you're bored and want to be bored some more, <a href="http://tamius.net">my website's here</a>.</p>
<p>If you want to buy me a beer, <a href="https://paypal.me/tamius">my paypal's here</p>.
<h2>Plans for the future</h2>
<p>Improving automatic detection, trying to re-implement in-player user interface, fixing bugs.</p>
<h2>Acknowledgements</h2>
<p>This extension uses font <a href="http://overpassfont.org/">Overpass</a> and everything<a href="https://github.com/Kocal/vue-web-extension">this Vue template brings along.</p>
<p>Special thanks to me for making this extension. You're welcome.</p>
</div>
</template>
<script>
export default {
}
</script>

View File

@ -0,0 +1,204 @@
<template>
<div class="full-screen"
@click="$emit('close')"
>
<div class="dialog-box flex flex-column" @click="$event.stopPropagation()">
<div class="window-title">
{{actionIndex < 0 ? 'Add new action' : 'Edit action'}}
</div>
<CommandChain class="w100"
:command="action.command"
@new-command="addNewCommand()"
>
</CommandChain>
<CommandAddEdit class="w100"
v-if="addEditCommand"
:command="currentCmd"
>
</CommandAddEdit>
<div class="flex flex-column">
<div class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Action name:
</span>
</div>
<div class="flex flex-input flex-grow">
<input type="text"
class="w100"
:value="actionIndex < 0 ? action.name : settings.active.actions[actionIndex].name"
@input="updateActionName($event.target.value)"
>
</div>
</div>
<div class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Default label:
</span>
</div>
<div class="flex flex-input flex-grow">
<input type="text"
class="w100"
:value="actionIndex < 0 ? action.label : settings.active.actions[actionIndex].label"
@input="updateActionLabel($event.target.value)"
>
</div>
</div>
</div>
<div class="flex flex-row">
<b>Scopes:</b>
</div>
<div class="flex flex-row">
Global:
</div>
<div class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Show in popup
</span>
</div>
<div class="flex flex-input">
<input type="checkbox"
:value="actionIndex < 0 ? true : settings.active.actions[actionIndex].scopes.global && settings.active.actions[actionIndex].scopes.global.show"
@input="updateScopes('global', 'show', $event.target.value)"
>
</div>
</div>
<div class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Label <span class="hint"><small>(leave empty for default)</small></span>:
</span>
</div>
<div class="flex flex-input flex-grow">
<input type="text"
class="w100"
@input="updateScopes('global', 'label', $event.target.value)"
>
</div>
</div>
<div class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Shortcut:
</span>
</div>
<div class="flex flex-input flex-grow">
TODO: insert shortcut changing component
</div>
</div>
</div>
</div>
</template>
<script>
import StretchMode from '../../common/enums/stretch-mode';
import KeyboardShortcutParser from '../../common/js/KeyboardShortcutParser';
import CommandChain from './command-builder/command-chain';
import CommandAddEdit from './command-builder/command-add-edit';
export default {
components: {
CommandChain: CommandChain,
CommandAddEdit: CommandAddEdit,
},
data () {
return {
StretchMode: StretchMode,
action: {
name: 'New action',
label: 'New action',
cmd: [],
},
addEditCommand: false,
currentCmd: {},
}
},
created () {
},
props: {
settings: Object,
actionIndex: Number,
},
methods: {
parseActionShortcut(action) {
return KeyboardShortcutParser.parseShortcut(action.shortcut[0]);
},
parseCommand(cmd) {
let cmdstring = '';
for(const c of cmd) {
cmdstring += `${c.action} ${c.arg}${c.persistent ? ' persistent' : ''}; `;
}
return cmdstring;
},
updateActionName(newName) {
this.action.name = newName;
},
updateActionLabel(newLabel) {
this.action.label = newLabel;
},
updateScopes(scope, prop, value) {
},
addNewCommand() {
this.currentCmd = {};
this.addEditCommand = true;
}
}
}
</script>
<style lang="scss" scoped>
.full-screen {
background-color: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-items: center;
width: 100%;
height: 100%;
position: absolute;
}
.dialog-box {
background-color: rgba(0,0,0,0.9);
// width: 100%;
// height: 100%;
max-width: 130rem;
max-height: 42rem;
padding-top: 2rem;
padding-left: 3rem;
padding-right: 3rem;
}
.window-title {
font-size: 2.4rem;
font-variant: small-caps;
margin-bottom: 1.69rem;
}
.form-label {
width: 16rem;
text-align: right;
vertical-align: baseline;
}
.hint {
opacity: 50% !important;
font-weight: 300;
}
.w100 {
width: 100%;
}
</style>

View File

@ -0,0 +1,127 @@
<template>
<div class="">
<div class="window-content">
<!-- ACTION SELECT -->
<div class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Select action:
</span>
</div>
<div class="flex flex-grow flex-input">
<select class=""
@change="setAction($event.target.value)"
>
<option v-for="(action, key) in ActionList"
:value="key"
>
{{action.name}}
</option>
</select>
</div>
</div>
<!-- ARGUMENT SELECT -->
<div v-if="selectedAction && ActionList[selectedAction]"
class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
Select action parameter:
</span>
</div>
<div class="flex flex-grow flex-input">
<select @change="setArgument($event.target.value)">
<option v-for="arg of ActionList[selectedAction].args"
:value="arg"
>
{{arg.name}}
</option>
</select>
</div>
</div>
<!-- CUSTOM ARGUMENT INPUT -->
<div v-if="selectedArgument && selectedArgument.customArg"
class="flex flex-row">
<div class="flex label-secondary form-label">
<span class="w100">
{{selectedArgument.name}}:
</span>
</div>
<div class="flex flex-grow flex-input">
<input type="text"
class="w100"
v-model="customArgumentValue"
>
</div>
</div>
</div>
<div class="window-footer">
<div class="button"
@click="$emit('close-popup')"
>
Cancel
</div>
<div class="button"
@click="emitCommand()"
>
Save
</div>
</div>
</div>
</template>
<script>
import ActionList from '../../../ext/conf/ActionList';
import StretchMode from '../../../common/enums/stretch-mode';
export default {
data () {
return {
StretchMode: StretchMode,
ActionList: ActionList,
selectedAction: this.action ? action.action : undefined,
selectedArgument: this.action ? {
name: ActionList[action.action].args.find(x => x.arg === action.arg) || ActionList[action.action].args.find(x => x.customArg),
arg: action.arg
} : undefined,
customArgumentValue: this.action ? action.arg : undefined
}
},
created () {
console.log("this.actionList", ActionList, this.ActionList)
for(const a in ActionList) {
console.log(a);
}
},
props: {
action: Object,
scope: String,
},
methods: {
setAction(cmd) {
console.log("SETTING ACTION", cmd);
this.selectedAction = cmd;
this.selectedArgument = undefined;
this.customArgumentValue = undefined;
},
setArgument(arg) {
console.log("SETTING ARGUMENT", cmd);
this.selectedArgument = arg;
this.customArgumentValue = undefined;
},
emitCommand() {
this.$emit(
'set-command',
this.selectedAction,
this.customArgumentValue ? this.customArgumentValue : this.selectedArgument.arg
);
}
}
}
</script>

View File

@ -0,0 +1,82 @@
<template>
<div class="block-main">
<div v-if="!first"
class="prev"
@click="emit('move-left')"
>
&lt;
</div>
<div class="button-main">
<div class="button-action-display">
{{ActionList[action.action].name}}: {{
ActionList[action.action].args.find(x => x.arg === action.arg) || action.arg
}}
</div>
<div class="actions flex flex-row">
<div class="flex flex-grow"
@click="$emit('delete')"
>
🗙
</div>
<div class="flex flex-grow"
@click="$emit('edit')"
>
🖉
</div>
</div>
</div>
<div v-if="!last"
class="next"
@click="$emit('move-right')"
>
&gt;
</div>
</div>
</template>
<script>
import ActionList from '../../../ext/conf/ActionList';
export default {
data () {
return {
ActionList: ActionList,
}
},
created () {
},
props: {
action: Object,
first: Boolean,
last: Boolean
},
methods: {
parseActionShortcut(action) {
return KeyboardShortcutParser.parseShortcut(action.shortcut[0]);
},
setAction(cmd) {
console.log("SETTING ACTION", cmd);
this.selectedAction = cmd;
this.selectedArgument = undefined;
this.customArgumentValue = undefined;
},
setArgument(arg) {
console.log("SETTING ARGUMENT", cmd);
this.selectedArgument = arg;
this.customArgumentValue = undefined;
},
emitCommand() {
this.$emit(
'set-command',
this.selectedAction,
this.customArgumentValue ? this.customArgumentValue : this.selectedArgument.arg
);
}
}
}
</script>

View File

@ -0,0 +1,41 @@
<template>
<div class="">
<div class="flex flex-row">
<CommandBlock v-for="(cmd, index) of command"
:command="cmd"
first
last
@edit="$emit('edit', index)"
@delete="$emit('delete', index)"
@move-left="$emit('move-left', index)"
@move-right="$emit('move-left', (index + 1))"
>
</CommandBlock>
<div class="new-command"
@click="$emit('new-command')"
>
+
</div>
</div>
</div>
</template>
<script>
import CommandBlock from './command-block';
import CommandAddEdit from './command-add-edit';
export default {
created () {
},
components: {
CommandBlock,
CommandAddEdit,
},
props: [
'command'
],
methods: {
}
}
</script>

View File

@ -0,0 +1,127 @@
<template>
<div>
<p>Here, you can change keyboard shortcuts or even create your own.</p>
<div class="flex flex-column">
<div class="action-item-category-header">
Crop actions
</div>
<template v-for="(action, index) of settings.active.actions">
<ActionAlt v-if="action.cmd.length === 1 && action.cmd[0].action === 'set-ar'"
:action="action"
@edit="changeShortcut(index)"
>
</ActionAlt>
</template>
<div class="action-item-category-header">
Stretch actions
</div>
<template v-for="(action, index) of settings.active.actions">
<ActionAlt v-if="action.cmd.length === 1 && action.cmd[0].action === 'set-stretch'"
:action="action"
@edit="changeShortcut(index)"
>
</ActionAlt>
</template>
<div class="action-item-category-header">
Alignment actions
</div>
<template v-for="(action, index) of settings.active.actions">
<ActionAlt v-if="action.cmd.length === 1 && action.cmd[0].action === 'set-alignment'"
:action="action"
@edit="changeShortcut(index)"
>
</ActionAlt>
</template>
<div class="action-item-category-header">
Zoom / panning actions
</div>
<template v-for="(action, index) of settings.active.actions">
<ActionAlt v-if="action.cmd.length === 1 && (
action.cmd[0].action === 'set-zoom' ||
action.cmd[0].action === 'set-pan' ||
action.cmd[0].action === 'pan' ||
action.cmd[0].action === 'set-pan'
)"
:action="action"
@edit="changeShortcut(index)"
>
</ActionAlt>
</template>
<div class="action-item-category-header">
Other actions
</div>
<template v-for="(action, index) of settings.active.actions">
<ActionAlt v-if="action.cmd.length > 1 || (
action.cmd[0].action !== 'set-zoom' &&
action.cmd[0].action !== 'set-pan' &&
action.cmd[0].action !== 'pan' &&
action.cmd[0].action !== 'set-pan' &&
action.cmd[0].action !== 'set-alignment' &&
action.cmd[0].action !== 'set-stretch' &&
action.cmd[0].action !== 'set-ar'
)"
:action="action"
@edit="changeShortcut(index)"
>
</ActionAlt>
</template>
</div>
</div>
</template>
<script>
import Button from '../../common/components/button';
import StretchMode from '../../common/enums/stretch-mode';
import ActionAlt from '../../common/components/action-alt';
export default {
components: {
Button,
ActionAlt,
},
data () {
return {
StretchMode: StretchMode,
tableVisibility: {
crop: true,
}
}
},
created () {
},
props: {
settings: Object
},
watch: {
settings: (newVal, oldVal) => {
console.log("this.settings", this.settings, newVal, oldVal)
this.settings = newVal;
}
},
methods: {
changeShortcut(index) {
this.$emit('edit-event', index);
}
}
}
</script>
<style lang="scss" scoped>
@import '../../res/css/colors.scss';
.action-item-category-header {
margin-top: 3rem;
color: $primary-color;
font-size: 2.4rem;
font-variant: small-caps;
font-weight: 600;
}
</style>

View File

@ -0,0 +1,167 @@
<template>
<div>
<div class="label">
Enable this extension:
</div>
<div class="flex flex-row button-box">
<Button label="Always"
:selected="settings.active.extensionMode === 'blacklist'"
@click.native="setDefaultExtensionMode('blacklist')"
>
</Button>
<Button label="On whitelisted sites"
:selected="settings.active.extensionMode === 'whitelist'"
@click.native="setDefaultExtensionMode('whitelist')"
>
</Button>
<Button label="Never"
:selected="settings.active.extensionMode === 'disabled'"
@click.native="setDefaultExtensionMode('disabled')"
>
</Button>
</div>
<div class="description">
<b>Always</b> enables this extension on every site you visit that you didn't blacklist.<br/>
<b>On whitelisted sites</b> enables this extension only on sites you explicitly whitelisted.<br/>
<b>Never</b> disables extension on all sites, even on those you whitelisted.
</div>
<div class="label">
Enable autodetection:
</div>
<div class="flex flex-row button-box">
<Button label="Always"
:selected="settings.active.arDetect.mode === 'blacklist'"
@click.native="setDefaultAutodetectionMode('blacklist')">
</Button>
<Button label="On whitelisted sites"
:selected="settings.active.arDetect.mode === 'whitelist'"
@click.native="setDefaultAutodetectionMode('whitelist')">
</Button>
<Button label="Never"
:selected="settings.active.arDetect.mode === 'disabled'"
@click.native="setDefaultAutodetectionMode('never')">
</Button>
</div>
<div class="description">
<b>Always</b> enables autodetection on every site this extension is enabled for, unless blacklisted.<br/>
<b>On whitelisted sites</b> enables autodetection only for sites that you explicitly enabled.<br/>
<b>Never</b> disables autodetection on all sites, even on those you whitelisted.<br/>
<!-- <br/> -->
<!-- For more settings related to autodetection, please check the 'Autodetection' tab. -->
</div>
<div class="label">
Default video alignment:
</div>
<div class="flex flex-row button-box">
<Button label="Left"
:selected="settings.active.miscSettings.videoFloat === 'left'"
@click.native="setDefaultVideoFloat('left')">
</Button>
<Button label="Center"
:selected="settings.active.miscSettings.videoFloat === 'center'"
@click.native="setDefaultVideoFloat('center')">
</Button>
<Button label="Right"
:selected="settings.active.miscSettings.videoFloat === 'right'"
@click.native="setDefaultVideoFloat('right')">
</Button>
</div>
<div class="label">
Default stretch mode:
</div>
<div class="flex flex-row button-box">
<Button label="Don't stretch"
:selected="settings.active.stretch.initialMode === StretchMode.NO_STRETCH"
@click.native="setDefaultStretchingMode(StretchMode.NO_STRETCH)">
</Button>
<Button label="Basic stretch"
:selected="settings.active.stretch.initialMode === StretchMode.BASIC"
@click.native="setDefaultStretchingMode(StretchMode.BASIC)">
</Button>
<Button label="Hybrid stretch"
:selected="settings.active.stretch.initialMode === StretchMode.HYBRID"
@click.native="setDefaultStretchingMode(StretchMode.HYBRID)">
</Button>
<Button label="Thin borders only"
:selected="settings.active.stretch.initialMode === StretchMode.CONDITIONAL"
@click.native="setDefaultStretchingMode(StretchMode.CONDITIONAL)"
>
</Button>
</div>
<div class="description">
<b>None:</b> do not stretch the video at all. This is the default option, for men of culture.<br/>
<b>Basic:</b> stretches video to fit the player or screen unconditionally. If video has letterbox encoded, this option <i>will not</i> try to remove letterbox before stretching. You probably shouldn't be using this option.<br/>
<b>Hybrid:</b> stretches the video to fit the player, but only if cropping didn't completely remove the black bars.<br/>
<b>Thin borders:</b> stretches only if the width of black borders after cropping is thin.
<br/>
Treshold for thin borders can be defined below.
</div>
<div class="indent">
<div class="flex flex-row row-padding">
<div class="flex label-secondary">
Thin border treshold:
</div>
<div class="flex flex-input">
<input type="number"
step="any"
:value="settings.active.stretch.conditionalDifferencePercent"
@input="updateStretchTreshold($event.target.value)"
>
</div>
</div>
</div>
</div>
</template>
<script>
import Button from '../common/components/button';
import StretchMode from '../common/enums/stretch-mode';
export default {
components: {
Button,
},
data () {
return {
StretchMode: StretchMode,
stretchThreshold: 0,
}
},
created () {
},
props: {
settings: Object
},
methods: {
setDefaultAutodetectionMode(mode) {
this.settings.active.arDetect.mode = mode;
this.settings.save();
},
setDefaultExtensionMode(mode) {
this.settings.active.extensionMode = mode;
this.settings.save();
},
setDefaultVideoFloat(mode) {
this.settings.active.videoFloat = mode;
this.settings.save();
},
setDefaultStretchingMode(mode) {
this.settings.active.stretch.initialMode = mode;
this.settings.save();
},
updateStretchTreshold(newTreshold) {
if (!newTreshold || isNaN(newTreshold)) {
return;
}
this.settings.active.stretch.conditionalDifferencePercent = newTreshold;
this.settings.save();
}
}
}
</script>

15
src/options/options.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ultravidify-vue - Options</title>
<link rel="stylesheet" href="options.css">
<% if (NODE_ENV === 'development') { %>
<!-- Load some resources only in development environment -->
<% } %>
</head>
<body>
<div id="app"></div>
<script src="options.js"></script>
</body>
</html>

13
src/options/options.js Normal file
View File

@ -0,0 +1,13 @@
// console.log("global browser", browser, global.browser)
// global.browser = require('webextension-polyfill')
import Vue from 'vue'
import App from './App'
/* eslint-disable no-new */
new Vue({
el: '#app',
render: h => h(App)
})

256
src/options/options.scss Normal file
View File

@ -0,0 +1,256 @@
@import "../res/css/font/overpass.css";
@import "../res/css/font/overpass-mono.css";
@import "../res/css/colors.scss";
@import "../res/css/common.scss";
body {
background-image: url('/res/img/settings/bg_random2.png');
background-size: 25em;
text-align: center;
z-index: -1000;
}
/*
+
+ BASIC LAYOUT
+
*/
.header {
width: 42rem;
height: 100vh;
position: fixed;
}
.content-area {
width: 100%;
padding-left: 42rem;
text-align: center;
}
.text-sink-anchor {
position: relative;
}
.text-sink {
position: absolute;
bottom: 0px;
}
.title-sink-pad {
padding-bottom: 1.69rem;
}
/*
+
+ SIDE MENU
+
*/
.extension-name {
font-size: 4.20rem;
height: 7.7rem;
text-align: center;
}
.menu {
font-size: 1.9rem;
font-variant: small-caps;
}
/*
+
+ TAB PANEL
+
*/
.content-title {
font-size: 3.3rem;
height: 7.7rem;
}
.content-content {
width: 100%;
max-width: 96rem;
display: inline-block;
margin: 0 auto;
text-align: left;
}
.block {
display: inline-block;
margin-left: 1em;
margin-right: 1em;
}
.tabline {
background-color: #000;
width: 100%;
margin-bottom: 1.5em;
padding-top: 0.3em;
padding-bottom: 0.4em;
z-index: -200;
}
.dup_keybinds{
background-color: #720 !important;
}
input[type=text]{
font-size: 1em;
padding-left: 0.6em;
margin-left: 1em;
width: 2em;
background-color: #000;
border: 1px #442 solid;
}
.uw_shortcuts_line{
padding-top: 0.25em;
padding-left: 5em;
}
.uw_shortcuts_label{
display: inline-block;
color: #fff;
width: 17.5em;
}
.uw_options_line{
margin-top: 0.75em;
font-size: 1.1em;
width: 80%;
margin-left: 5%;
}
.uw_options_option{
margin-left: 5%;
}
.uw_suboption{
margin-left: 5em;
margin-top: 0.75em;
font-size: 0.85em;
}
.uw_options_desc, .uw_suboption_desc{
margin-top: 0.33em;
font-size: 0.69em;
color: #aaa;
}
.uw_suboption_desc{
margin-left: 5em;
}
.buttonbar{
/* width: 100%; */
padding-left: 20em;
margin-bottom: 2em;
}
.button {
display: inline-block;
margin-left: 1em;
margin-right: 1em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0.4em;
width: 4em;
text-align: center;
background-color: rgba(0,0,0,0.66);
color: #ffc;
height: 1.7em;
}
.monospace {
font-family: 'Overpass Mono', monospace
}
.center-text {
text-align: center;
}
/** site options css **/
.site_name {
padding-left: 1em;
padding-bottom: 0.3em;
color: #fff;
font-size: 1.1em;
height: 13em !important;
}
.site_details {
font-size: 0.8em;
}
.site_title_ebox {
width: 10em !important;
font-size: 1.5em !important;
background-color: rgba(0,0,0,0) !important;
margin-left: 0px !important;
border: 0px !important;
color: #ffc !important;
}
.details_ebox {
width: 12em !important;
background-color: rgba(0,0,0,0) !important;
border: 0px !important;
color: #ffc !important;
margin-left: 0em !important;
}
.details_ebox:disabled {
color: #aaa !important;
}
.checkbox-center {
text-align: center;
}
.checkbox-container {
display: inline-block;
position: relative;
padding-left: 35px;
margin-bottom: 12px;
/* cursor: pointer; */
font-size: 22px;
/* -webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; */
}
.checkbox {
position: absolute;
top: 0;
left: 0;
height: 25px;
width: 25px;
}
.checkbox-checked {
position: absolute;
left: 9px;
top: 5px;
width: 5px;
height: 10px;
border: solid rgb(245, 145, 63);
border-width: 0 3px 3px 0;
transform: rotate(45deg);
}
/* ACTION TABLE STYLES */
.action-item-category-label {
color: rgb(245, 145, 63);
font-size: 2em;
font-weight: 200;
margin-bottom: 0px;
padding-bottom: 0px;
padding-top: 1em;
}
.action-item-table-header {
color: rgb(245, 145, 63);
}
.action-item-table-header-small {
color: rgb(245, 145, 63);
font-size: 0.85em !important;
font-weight: 300 !important;
}
.action-list-item:hover {
background-color: rgba(254, 146, 63, 0.15);
}

19
src/popup/App.vue Normal file
View File

@ -0,0 +1,19 @@
<template>
<div>
<p>Hello world!</p>
</div>
</template>
<script>
export default {
data () {
return {}
}
}
</script>
<style lang="scss" scoped>
p {
font-size: 20px;
}
</style>

17
src/popup/popup.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="popup.css">
<% if (NODE_ENV === 'development') { %>
<!-- Load some resources only in development environment -->
<% } %>
</head>
<body>
<div id="app">
</div>
<script src="popup.js"></script>
</body>
</html>

15
src/popup/popup.js Normal file
View File

@ -0,0 +1,15 @@
import Vue from 'vue'
import App from './App'
import store from '../store'
// global.browser = require('webextension-polyfill')
// Vue.prototype.$browser = global.browser
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
render: h => h(App)
})

8
src/res/css/colors.scss Normal file
View File

@ -0,0 +1,8 @@
$text-normal: #ddd;
$text-dim: #999;
$text-dark: #666;
$primary-color: #fb772a;
$secondary-color: #e70c0c;
$background-primary: #101010;
$background-selected: #944918;

View File

@ -1,22 +1,30 @@
html, body {
color: #f8f8f8;
background-color: #1f1f1f;
font-family: "overpass";
font-size: 1em;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
@import "colors.scss";
@import "/res/css/font/overpass.css";
@import "/res/css/font/overpass-mono.css";
body {
background-color: $background-primary;
color: $text-normal;
font-family: 'Overpass', sans-serif;
font-size: 1.2em;
width: 100%;
min-height: 100%;
height: 100vh;
border: 0px;
margin: 0px;
padding: 0px;
}
/* STANDARD WIDTHS AND HEIGHTS */
.w100 {
width: 100%;
}
.h100 {
height: 100%;
}
.w24 {
width: 100px;
}
@ -30,6 +38,63 @@ html, body {
padding-right: 1em;
}
/* .SELECTED CLASSES */
.selected-tab {
background-color: initial;
border-left: $primary-color 5px solid;
}
.selected-tab-secondary {
background-color: initial;
border-left: $secondary-color 3px solid !important;
}
/* BASIC STYLING */
.description {
color: $text-dim;
font-size: 1rem;
}
.label {
padding-top: 1.5rem;
font-size: 1.5rem;
font-variant: small-caps;
font-weight: 600;
}
.label-secondary {
font-weight: 600;
}
.button-box {
padding-top: 0.69rem;
padding-bottom: 0.69rem;
}
.indent {
padding-left: 4.2rem;
}
.row-padding {
padding-top: 0.69rem;
padding-bottom: 0.69rem;
}
/* INPUT FORMATTING */
input[type="number"] {
// border: 1px solid #322;
background-color: transparent;
padding: 0.1rem;
padding-top: 0.1rem;
padding-bottom: 0.1rem;
margin-left: 1rem;
}
/* ELEMENT POSITIONING */
.row {
@ -100,34 +165,10 @@ small {
/* COLORS */
a {
color: #af7f37;
}
a:hover {
color: #c0924e;
}
.color_warn {
color: #d6ba4a;
}
strike {
opacity: 0.5;
}
.darker {
color: #666;
}
.label{
font-size: 1.1em;
font-weight: 600;
color: #ffe;
}
.selected{
color: #ffddaa;
background-color: #433221;
color: #ffddaa !important;
background-color: #433221 !important;
}
.disabled {
@ -166,20 +207,13 @@ strike {
/* BUTTONS AND INPUTS */
input {
border: 1px solid #322;
padding: 0.5em;
padding-top: 0.5em;
padding-bottom: 0.5em;
}
.invalid-input {
border: 1px solid #720 !important;
background-color: #410 !important;
}
.button {
display: inline-block;
/* display: inline-block; */
padding-top: 8px;
padding-bottom: 3px;
padding-left: 20px;

View File

@ -13,3 +13,7 @@
.flex-auto {
flex: 1 1 auto;
}
.flex-grow {
flex-grow: 1;
}

0
src/res/css/form.scss Normal file
View File

Some files were not shown because too many files have changed in this diff Show More