Merge branch 'master' into stable

This commit is contained in:
Tamius Han 2019-09-22 02:40:14 +02:00
commit 5171c3129b
42 changed files with 10307 additions and 7068 deletions

29
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"cSpell.words": [
"ardetector",
"autodetection",
"blackbar",
"blackframe",
"canvas",
"equalish",
"insta",
"recursing",
"reddit",
"resizer",
"textbox",
"videodata",
"youtube"
],
"cSpell.ignoreWords": [
"autoar",
"cheight",
"cwidth",
"fcstart",
"fctime",
"ncol",
"nrow",
"tickrate",
"undisable",
"vdid"
]
}

View File

@ -5,6 +5,22 @@
### Plans for the future ### Plans for the future
* Settings page looks ugly af right now. Maybe fix it some time later * Settings page looks ugly af right now. Maybe fix it some time later
* rework keyboard shortcuts so things like russian layouts don't mess thigns up
* other bug fixes
QoL improvements for me:
* logging: allow to enable logging at will and export said logs to a file
### v4.3.0 (current)
* Fixed some issues with incorrect alignment after window resize
* Fixed all sorts of issues for videos hosted on v.reddit for new (and old) reddit
* Fixed the issue where setting extension to 'whitelist only' would disable 'site settings' in popup.
* Added user-friendly way to export/import settings (export requires 'download' permissions)
* Reworked logging
* Started using mutation observers to watch for changes in player size as well. Since mutation observers aren't entirely reliable, old way of doing things is still somewhat present as a backup way, but runs less frequently.
* Implemented/improved/fixed settings patching
### v4.2.4 / 4.2.4.x ### v4.2.4 / 4.2.4.x
@ -14,7 +30,6 @@
* **[4.2.4.2]** Additional bugfixes. Updated/fixed default settings. * **[4.2.4.2]** Additional bugfixes. Updated/fixed default settings.
### v4.2.3 / 4.2.3.x ### v4.2.3 / 4.2.3.x
* Fixed twitchy behaviour on Twitch, Facebook and Twatter. Here's a [blog post](https://stuff.tamius.net/sacred-texts/2019/08/24/ultrawidify-the-twitchy-twitch-problem/) that covers the issue in more detail. * Fixed twitchy behaviour on Twitch, Facebook and Twatter. Here's a [blog post](https://stuff.tamius.net/sacred-texts/2019/08/24/ultrawidify-the-twitchy-twitch-problem/) that covers the issue in more detail.
* Cropping now uses user styles (as opposed to modifying element's style attribute) * Cropping now uses user styles (as opposed to modifying element's style attribute)
* Fixed the issue where one-pixel letterbox would result in constant aspect ratio corrections. * Fixed the issue where one-pixel letterbox would result in constant aspect ratio corrections.
@ -22,8 +37,8 @@
* **[4.2.3.1]** fixed some bugs in popup. * **[4.2.3.1]** fixed some bugs in popup.
### v4.2.2 ### v4.2.2
* Fixed alignment issues for reddit on videos from v.reddit
* Some people reported issues with inconsistent video alignment on youtube. While I've not been able to make that bug happen to me, (which means I haven't been able to fix it either), reports describe behaviour similar to what was going on with Iridium. Examining the Iridium issue revealed an issue that could be potentially blamed for this behaviour. That issue was fixed. Since I've never been able to make this problem happen to me, I'm not being able to verify whether that issue is gone. If you're still experiencing issues with inconsistent video alignment, please contact me via github, reddit or email. See 'Report a problem' tab for more details. * Fixed player detection on reddit (for videos from v.reddit)
### v4.2.1 ### v4.2.1
* Fixed bug where custom CSS didn't get applied to pages * Fixed bug where custom CSS didn't get applied to pages

View File

@ -2,17 +2,13 @@
## Build platform ## Build platform
The extension is built on a PC running Manjaro Linux. Yarn is the package manager of choice. The extension is built on a PC running Manjaro Linux. npm and node are installed from repositories/aur.
Yarn version: 1.16.0
Node version: v11.15.0
## Installing dependencies ## Installing dependencies
`yarn install --frozen-lockfile` Run `npm ci`
According to Yarn documentation, that should install the exact version of dependencies that the extension is using.
## Reproducing build ## Reproducing build

8470
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "ultravidify", "name": "ultravidify",
"version": "4.2.4", "version": "4.3.0",
"description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.", "description": "Aspect ratio fixer for youtube that works around some people's disability to properly encode 21:9 (and sometimes, 16:9) videos.",
"author": "Tamius Han <tamius.han@gmail.com>", "author": "Tamius Han <tamius.han@gmail.com>",
"scripts": { "scripts": {
@ -11,6 +11,7 @@
"build:dev": "cross-env NODE_ENV=development BROWSER=firefox webpack --hide-modules", "build:dev": "cross-env NODE_ENV=development BROWSER=firefox webpack --hide-modules",
"build-chrome:dev": "cross-env NODE_ENV=development BROWSER=chrome webpack --hide-modules", "build-chrome:dev": "cross-env NODE_ENV=development BROWSER=chrome webpack --hide-modules",
"build-edge:dev": "cross-env NODE_ENV=development BROWSER=edge webpack --hide-modules", "build-edge:dev": "cross-env NODE_ENV=development BROWSER=edge webpack --hide-modules",
"build-all": "rm ./dist-zip/uw-amo-source.zip; mv ./dist-zip/*.zip ./dist-zip/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-zip": "node scripts/build-zip.js", "build-zip": "node scripts/build-zip.js",
"watch": "npm run build -- --watch", "watch": "npm run build -- --watch",
"watch-chrome": "npm run build-chrome -- --watch", "watch-chrome": "npm run build-chrome -- --watch",

View File

@ -7,8 +7,9 @@ const archiver = require('archiver');
const DEST_DIR = path.join(__dirname, '../dist'); const DEST_DIR = path.join(__dirname, '../dist');
const DEST_ZIP_DIR = path.join(__dirname, '../dist-zip'); const DEST_ZIP_DIR = path.join(__dirname, '../dist-zip');
const extractExtensionData = () => { const extractExtensionData = () => {
const extPackageJson = require('../package.json'); const extPackageJson = require('../src/manifest.json');
return { return {
name: extPackageJson.name, name: extPackageJson.name,
@ -40,8 +41,10 @@ const buildZip = (src, dist, zipFilename) => {
}; };
const main = () => { const main = () => {
const browser = process.argv[2];
const {name, version} = extractExtensionData(); const {name, version} = extractExtensionData();
const zipFilename = `${name}-v${version}.zip`; const zipFilename = `${name}-${version}-${browser}.zip`;
makeDestZipDirIfNotExists(); makeDestZipDirIfNotExists();

5
scripts/prepare-amo-source.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
# makes a zip file with human-readable source code that we need to upload to AMO
# since webpack minifies stuff
zip -r dist-zip/uw-amo-source.zip README-AMO.md .babelrc package.json package-lock.json webpack.config.js src/

View File

@ -0,0 +1,53 @@
<template>
<div class="qsb flex flex-row flex-cross-center flex-center flex-nogrow"
:class="{
'id': selector.startsWith('#'),
'class': selector.startsWith('.'),
}">
<div class="flex mt2px">{{selector}}</div> <span class="flex closeButton" @click="remove">×</span>
</div>
</template>
<script>
export default {
props: {
selector: String,
},
methods: {
remove() {
this.$emit('remove');
}
}
}
</script>
<style>
.mt2px {
margin-top: 7px;
}
.id {
border: 1px solid #d00;
background-color: rgba(216, 94, 24, 0.25)
}
.class {
border: 1px solid #33d;
background-color: rgba(69, 69, 255, 0.25)
}
.closeButton {
margin-top: 2px;
margin-left: 4px;
margin-right: 4px;
font-size: 1.5em;
color: #e00;
}
.closeButton:hover {
cursor: pointer;
color: #fa6;
}
.qsb {
cursor:default;
margin-left: 3px;
margin-right: 3px;
margin-bottom: 2px;
}
</style>

View File

@ -11,7 +11,6 @@ var Debug = {
// debugArDetect: true, // debugArDetect: true,
// scaler: true, // scaler: true,
// debugStorage: true, // debugStorage: true,
// comms: false,
// comms: true, // comms: true,
// showArDetectCanvas: true, // showArDetectCanvas: true,
// flushStoredSettings: true, // flushStoredSettings: true,

View File

@ -1,8 +1,9 @@
// How to use: // How to use:
// version: {ExtensionConf object, but only properties that get overwritten} // version: {ExtensionConf object, but only properties that get overwritten}
const ExtensionConfPatch = { const ExtensionConfPatch = [
'4.2.0': { {
forVersion: '4.2.0',
sites: { sites: {
"old.reddit.com" : { "old.reddit.com" : {
type: 'testing', type: 'testing',
@ -38,7 +39,70 @@ const ExtensionConfPatch = {
} }
}, },
} }
}, }, {
} forVersion: '4.2.3.1',
sites: {
"old.reddit.com" : {
type: 'testing',
DOM: {
player: {
manual: true,
useRelativeAncestor: false,
querySelectors: '.media-preview-content, .reddit-video-player-root'
}
},
css: '',
},
"www.reddit.com" : {
type: 'testing',
DOM: {
player: {
manual: true,
useRelativeAncestor: false,
querySelectors: '.media-preview-content, .reddit-video-player-root'
}
},
css: '',
},
"www.youtube.com" : {
DOM: {
player: {
manual: true,
querySelectors: "#movie_player, #player",
additionalCss: "",
useRelativeAncestor: false,
playerNodeCss: "",
}
}
},
}
}, {
forVersion: '4.3.0',
sites: {
"old.reddit.com" : {
type: 'testing',
DOM: {
player: {
manual: false,
useRelativeAncestor: false,
querySelectors: '.reddit-video-player-root, .media-preview-content'
}
},
css: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
},
"www.reddit.com" : {
type: 'testing',
DOM: {
player: {
manual: false,
useRelativeAncestor: false,
querySelectors: '.reddit-video-player-root, .media-preview-content'
}
},
css: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
},
}
}
];
export default ExtensionConfPatch; export default ExtensionConfPatch;

View File

@ -915,6 +915,7 @@ whatsNewChecked: true,
stretch: Stretch.Default, stretch: Stretch.Default,
videoAlignment: VideoAlignment.Default, videoAlignment: VideoAlignment.Default,
keyboardShortcutsEnabled: ExtensionMode.Default, keyboardShortcutsEnabled: ExtensionMode.Default,
arPersistence: true, // persist aspect ratio between different videos
autoarPreventConditions: { // prevents autoar on following conditions autoarPreventConditions: { // prevents autoar on following conditions
videoStyleString: { // if video style string thing does anything of what follows videoStyleString: { // if video style string thing does anything of what follows
containsProperty: { // if video style string has any of these properties (listed as keys) containsProperty: { // if video style string has any of these properties (listed as keys)
@ -973,12 +974,12 @@ whatsNewChecked: true,
keyboardShortcutsEnabled: ExtensionMode.Default, keyboardShortcutsEnabled: ExtensionMode.Default,
DOM: { DOM: {
player: { player: {
manual: true, manual: false,
useRelativeAncestor: false, useRelativeAncestor: false,
querySelectors: '.reddit-video-player-root, .media-preview-content' querySelectors: '.reddit-video-player-root, .media-preview-content'
} }
}, },
css: '', css: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
}, },
"www.reddit.com" : { "www.reddit.com" : {
mode: ExtensionMode.Enabled, mode: ExtensionMode.Enabled,
@ -990,12 +991,12 @@ whatsNewChecked: true,
keyboardShortcutsEnabled: ExtensionMode.Default, keyboardShortcutsEnabled: ExtensionMode.Default,
DOM: { DOM: {
player: { player: {
manual: true, manual: false,
useRelativeAncestor: false, useRelativeAncestor: false,
querySelectors: '.reddit-video-player-root, .media-preview-content' querySelectors: '.reddit-video-player-root, .media-preview-content'
} }
}, },
css: '', css: 'video {\n width: 100% !important;\n height: 100% !important;\n}',
}, },
"imgur.com": { "imgur.com": {
mode: -1, mode: -1,

View File

@ -5,6 +5,7 @@ import ExtensionMode from '../../common/enums/extension-mode.enum';
class ActionHandler { class ActionHandler {
constructor(pageInfo) { constructor(pageInfo) {
this.logger = pageInfo.logger;
this.pageInfo = pageInfo; this.pageInfo = pageInfo;
this.settings = pageInfo.settings; this.settings = pageInfo.settings;
@ -13,9 +14,7 @@ class ActionHandler {
} }
init() { init() {
if (Debug.debug) { this.logger.log('info', 'debug', "[ActionHandler::init] starting init");
console.log("[ActionHandler::init] starting init");
}
this.keyUpActions = []; this.keyUpActions = [];
this.keyDownActions = []; this.keyDownActions = [];
@ -105,15 +104,13 @@ class ActionHandler {
document.addEventListener('keyup', (event) => ths.handleKeyup(event) ); document.addEventListener('keyup', (event) => ths.handleKeyup(event) );
this.pageInfo.setActionHandler(this); this.pageInfo.setActionHandler(this);
if (Debug.debug) {
console.log("[ActionHandler::init] initialization complete"); this.logger.log('info', 'debug', "[ActionHandler::init] initialization complete");
}
} }
registerHandleMouse(videoData) { registerHandleMouse(videoData) {
if (Debug.debug && Debug.mousemove) { this.logger.log('info', ['actionHandler', 'mousemove'], "[ActionHandler::registerHandleMouse] registering handle mouse for videodata:", videoData)
console.log("[ActionHandler::registerHandleMouse] registering handle mouse for videodata:", videoData)
}
var ths = this; var ths = this;
if (videoData.player && videoData.player.element) { if (videoData.player && videoData.player.element) {
videoData.player.element.addEventListener('mousemove', (event) => ths.handleMouseMove(event, videoData)); videoData.player.element.addEventListener('mousemove', (event) => ths.handleMouseMove(event, videoData));
@ -139,10 +136,10 @@ class ActionHandler {
preventAction() { preventAction() {
var activeElement = document.activeElement; var activeElement = document.activeElement;
if(Debug.debug && Debug.keyboard) { if(this.logger.canLog('keyboard')) {
Debug.debug = false; // temp disable to avoid recursing; this.logger.pause(); // temp disable to avoid recursing;
console.log("[ActionHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" + this.logger.log('info', 'keyboard', "[ActionHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" +
"is full screen? (yes->allow):", PlayerData.isFullScreen(), "is full screen? (yes->allow):", PlayerData.isFullScreen(),
"\nis tag one of defined inputs? (yes->prevent):", this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1, "\nis tag one of defined inputs? (yes->prevent):", this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1,
"\nis role = textbox? (yes -> prevent):", activeElement.getAttribute("role") === "textbox", "\nis role = textbox? (yes -> prevent):", activeElement.getAttribute("role") === "textbox",
@ -157,7 +154,7 @@ class ActionHandler {
"insta-fail inputs:", this.inputs "insta-fail inputs:", this.inputs
); );
Debug.debug = true; // undisable this.logger.resume(); // undisable
} }
// lately youtube has allowed you to read and write comments while watching video in // lately youtube has allowed you to read and write comments while watching video in
@ -193,15 +190,11 @@ class ActionHandler {
} }
execAction(actions, event, videoData) { execAction(actions, event, videoData) {
if(Debug.debug && Debug.keyboard ){ this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] Trying to find and execute action for event. Actions/event: ", "color: #ff0", actions, event);
console.log("%c[ActionHandler::execAction] Trying to find and execute action for event. Actions/event: ", "color: #ff0", actions, event);
}
for (var action of actions) { for (var action of actions) {
if (this.isActionMatch(action.shortcut, event)) { if (this.isActionMatch(action.shortcut, event)) {
if(Debug.debug && Debug.keyboard ){ this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action);
console.log("%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action);
}
for (var cmd of action.cmd) { for (var cmd of action.cmd) {
if (action.scope === 'page') { if (action.scope === 'page') {
@ -249,14 +242,10 @@ class ActionHandler {
handleKeyup(event) { handleKeyup(event) {
if(Debug.debug && Debug.keyboard ){ this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keyup: ", event.keyup, "event:", event);
console.log("%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keyup: ", event.keyup, "event:", event);
}
if (this.preventAction()) { if (this.preventAction()) {
if (Debug.debug && Debug.keyboard) { this.logger.log('info', 'keyboard', "[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing.");
console.log("[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing.");
}
return; return;
} }
@ -264,14 +253,10 @@ class ActionHandler {
} }
handleKeydown(event) { handleKeydown(event) {
if(Debug.debug && Debug.keyboard ){ this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeydown] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event)
console.log("%c[ActionHandler::handleKeydown] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event);
}
if (this.preventAction()) { if (this.preventAction()) {
if (Debug.debug && Debug.keyboard) { this.logger.log('info', 'keyboard', "[ActionHandler::handleKeydown] we are in a text box or something. Doing nothing.");
console.log("[ActionHandler::handleKeydown] we are in a text box or something. Doing nothing.");
}
return; return;
} }
@ -279,9 +264,7 @@ class ActionHandler {
} }
handleMouseMove(event, videoData) { handleMouseMove(event, videoData) {
if (Debug.debug && Debug.mousemove) { this.logger.log('info', 'keyboard', "[ActionHandler::handleMouseMove] mouse move is being handled.\nevent:", event, "\nvideo data:", videoData);
console.log("[ActionHandler::handleMouseMove] mouse move is being handled.\nevent:", event, "\nvideo data:", videoData);
}
videoData.panHandler(event); videoData.panHandler(event);
this.execAction(this.mouseMoveActions, event, videoData) this.execAction(this.mouseMoveActions, event, videoData)
} }

211
src/ext/lib/Logger.js Normal file
View File

@ -0,0 +1,211 @@
import Debug from '../conf/Debug';
import currentBrowser from '../conf/BrowserDetect';
class Logger {
constructor(conf) {
this.initLogger();
if (conf) {
this.conf = conf;
}
this.history = [];
this.startTime = performance.now();
this.temp_disable = false;
}
initLogger() {
const ths = this;
const br = currentBrowser.firefox ? browser : chrome;
br.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) {
console.log("[Logger::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
if (changes['uwLogger'] && changes['uwLogger'].newValue) {
console.log("[Logger::<storage/on change>] new settings object:", JSON.parse(changes.uwLogger.newValue));
}
}
if(changes['uwLogger'] && changes['uwLogger'].newValue) {
ths.conf = JSON.parse(changes.uwLogger.newValue);
}
});
}
async init() {
if (!this.conf) {
this.conf = await this.getSaved();
}
}
clear() {
this.log = [];
this.startTime = performance.now();
}
setConf(conf) {
this.conf = conf; // effective immediately
// also persist settings:
if (currentBrowser.firefox || currentBrowser.edge) {
return browser.storage.local.set( {'uwLogger': JSON.stringify(this.conf)});
} else if (currentBrowser.chrome) {
return chrome.storage.local.set( {'uwLogger': JSON.stringify(this.logger)});
}
}
async getSaved() {
let ret;
if (currentBrowser.firefox) {
ret = await browser.storage.local.get('uwLogger');
} else if (currentBrowser.chrome) {
ret = await new Promise( (resolve, reject) => {
chrome.storage.local.get('uwLogger', (res) => resolve(res));
});
} else if (currentBrowser.edge) {
ret = await new Promise( (resolve, reject) => {
browser.storage.local.get('uwLogger', (res) => resolve(res));
});
}
if (Debug.debug && Debug.debugStorage) {
try {
console.log("[Logger::getSaved] Got settings:", JSON.parse(ret.uwLogger));
} catch (e) {
console.log("[Logger::getSaved] No settings.")
}
}
try {
return JSON.parse(ret.uwLogger);
} catch(e) {
return {logToFile: false, logToConsole: false, consoleOptions: {}, fileOptions: {}};
}
}
// allow syncing of start times between bg and page scripts.
// may result in negative times in the log file, but that doesn't
// really matter
getStartTime() {
return this.startTime;
}
setStartTime(startTime) {
if (startTime) {
this.startTime = startTime;
} else {
this.startTime = performance.now();
}
}
getLogFileString() {
let logfileStr = '';
let logTs = ''; // number of seconds since extension started on a given page¸
for (let i = 0; i < this.history.length; i++) {
logTs = ((this.history[i].ts - Math.floor(this.performance.now)) / 3).toFixed(3);
logfileStr = `${logfileStr}[@${logTs}] -- ${this.history[i].message}\n`
}
return logfileStr;
}
pause() {
this.temp_disable = true;
}
resume() {
this.temp_disable = false;
}
canLog(component) {
return this.canLogFile(component) || this.canLogConsole(component);
}
canLogFile(component) {
if (!this.conf.fileOptions.enabled || this.temp_disable) {
return false;
}
if (component.length ) {
for (const c in component) {
if (this.conf.fileOptions[component]) {
return this.conf.fileOptions[component];
}
}
}
return this.conf.fileOptions[component];
}
canLogConsole(component) {
if (!this.conf.consoleOptions.enabled || this.temp_disable) {
return false;
}
if (Array.isArray(component) && component.length) {
for (const c in component) {
if (this.conf.consoleOptions[component]) {
return this.conf.consoleOptions[component];
}
}
}
return this.conf.consoleOptions[component];
}
// level is unused as of now, but this may change in the future
// levels: 'info', 'warn', 'error'
log(level, component, ...message) {
if (!this.conf) {
return;
}
if (this.conf.logToFile) {
if (this.canLogFile(component)) {
let ts = performance.now();
if (ts <= this.history[this.history.length - 1]) {
ts = this.history[this.history.length - 1] + 0.00001;
}
this.history.push({
ts: ts,
message: JSON.stringify(message),
})
}
}
if (this.conf.logToConsole) {
if (this.canLogConsole(component)) {
console.log(...message);
}
}
}
// leaves a noticeable mark in the file log at the time it got triggered, as well as
// at the intervals of 1s and .5s before the trigger moment
cahen() {
if (this.conf.logToFile) {
let ts = performance.now();
let secondMark = ts - 1000;
let halfSecondMark = ts - 500;
let i = this.history.length();
// correct ts _after_ secondMark and halfSecondMark were determined
if (ts <= this.history[this.history.length - 1]) {
ts = this.history[this.history.length - 1] + 0.00001;
}
this.history.push({
ts: ts,
message: "-------------------------------------- CAHEN --------------------------------------"
});
// find the spot for the half second mark. In this case, we don't really particularly care whether timestamps
// are duped due to cahen warnings
while (this.history[i--].ts > halfSecondMark) {}
this.history.push({
ts: halfSecondMark,
message: "-------------------------------------- 0.5s to CAHEN --------------------------------------"
});
// repeat for one second warning
while (this.history[i--].ts > secondMark) {}
this.history.push({
ts: secondMark,
message: "-------------------------------------- 1s to CAHEN --------------------------------------"
});
}
}
}
export default Logger;

View File

@ -0,0 +1,189 @@
class PlayerPickerHelper {
constructor (settings, callbacks) {
this.settings = settings;
this.videos = document.selectElementsByTagName('video');
this.selectedParentIndex = this.findPlayerForVideos(settings, this.videos)[0];
this.savedCss = [];
this.markVideos();
this.markIndexForAll(index);
this.markInitialQuerySelectors();
}
/*
*
* Internal functions
*
*/
saveBorder(element) {
if (this.savedCss.findIndex(x => x.element === element) !== -1) {
this.savedCss.push({element: element, border: element.style.border});
}
}
restoreBorders() {
for (const e of this.savedCss) {
e.element.style.border = e.border;
}
}
findPlayerForVideos(settings, videos) {
const playerIndexes = [];
for (const v of videos) {
playerIndexes.push(this.findPlayerForVideo(settings, v));
}
return playerIndexes;
}
findPlayerForVideo(settings, video) {
const host = window.location.host;
let element = video.parentNode;
if (this.settings.active.sites[host]
&& this.settings.active.sites[host].DOM
&& this.settings.active.sites[host].DOM.player
&& this.settings.active.sites[host].DOM.player.manual) {
if (this.settings.active.sites[host].DOM.player.useRelativeAncestor
&& this.settings.active.sites[host].DOM.player.videoAncestor) {
return this.settings.active.sites[host].DOM.player.videoAncestor;
} else if (this.settings.active.sites[host].DOM.player.querySelectors) {
const allSelectors = document.querySelectorAll(this.settings.active.sites[host].DOM.player.querySelectors);
let elementIndex = 1;
while (element && !this.collectionHas(allSelectors, element)) {
element = element.parentNode;
elementIndex++;
}
return elementIndex;
}
}
let elementIndex = 0;
var trustCandidateAfterGrows = 2; // if candidate_width or candidate_height increases in either dimensions this many
// times, we say we found our player. (This number ignores weird elements)
// in case our <video> is bigger than player in one dimension but smaller in the other
// if site is coded properly, player can't be wider than that
var candidate_width = Math.max(element.offsetWidth, window.innerWidth);
var candidate_height = Math.max(element.offsetHeight, window.innerHeight);
var playerCandidateNode = element;
// if we haven't found element using fancy methods, we resort to the good old fashioned way
var grows = trustCandidateAfterGrows;
while(element != undefined){
// odstranimo čudne elemente, ti bi pokvarili zadeve
// remove weird elements, those would break our stuff
if ( element.offsetWidth == 0 || element.offsetHeight == 0){
element = element.parentNode;
elementIndex++;
continue;
}
if ( element.offsetHeight <= candidate_height &&
element.offsetWidth <= candidate_width ){
// if we're in fullscreen, we only consider elements that are exactly as big as the monitor.
if( ! isFullScreen ||
(element.offsetWidth == window.innerWidth && element.offsetHeight == window.innerHeight) ){
playerCandidateNode = element;
candidate_width = element.offsetWidth;
candidate_height = element.offsetHeight;
grows = trustCandidateAfterGrows;
this.logger.log('info', 'debug', "Found new candidate for player. Dimensions: w:", candidate_width, "h:",candidate_height, "node:", playerCandidateNode);
}
}
else if(grows --<= 0){
this.logger.log('info', 'playerDetect', "Current element grew in comparrison to the child. We probably found the player. breaking loop, returning current result");
break;
}
element = element.parentNode;
elementIndex++;
}
return elementIndex;
}
markVideos() {
for (const v of this.videos) {
this.markVideo(v);
}
}
markVideo(video) {
this.saveBorder(video);
video.style.border = "1px solid #00f";
}
markIndexForAll(index){
for (const v of this.videos) {
this.markIndex(index, v);
}
}
markIndex(index, video) {
el = video.parentNode;
while (index --> 1) {
el = el.parentNode;
}
this.saveBorder(el);
el.style.border = "1px solid #88f";
}
markInitialQuerySelectors() {
try {
if (this.settings.active.sites[host].DOM.player.querySelectors.trim()) {
this.markQuerySelectorMatches(this.settings.active.sites[host].DOM.player.querySelectors);
}
} catch (e) {
// nothing to see here. something in that if spaghett is undefined, which causes
// everything to fail. Since this means we've got zero query string matches to mark,
// we just ignore the failure
}
}
markQuerySelectorMatches(qsString) {
const allSelectors = document.querySelectorAll(qsString);
for (e of allSelectors) {
this.saveBorder(e);
e.style.border = "1px dashed fd2";
}
}
markQsPlayerDetection(qsString, index, video) {
let element = video.parentNode;
let elementIndex = 1;
const allSelectors = document.querySelectorAll(qsString);
while (element && !this.collectionHas(allSelectors, element)) {
element = element.parentNode;
elementIndex++;
}
this.saveBorder(element)
if (elementIndex > index) {
element.style.border = "2px solid #f00"
} else if (elementIndex === index) {
element.style.border = "2px solid #027a5c"
}
}
/*
*
*
* Function that actually interface with playerpicker and do stuff
*
*
*/
setQuerySelectors(querySelectorString) {
}
}
export default PlayerPickerHelper

View File

@ -11,7 +11,12 @@ import ExtensionConfPatch from '../conf/ExtConfPatches';
class Settings { class Settings {
constructor(activeSettings, updateCallback) { constructor(options) {
// Options: activeSettings, updateCallback, logger
this.logger = options.logger;
const activeSettings = options.activeSettings;
const updateCallback = options.updateCallback;
this.active = activeSettings ? activeSettings : undefined; this.active = activeSettings ? activeSettings : undefined;
this.default = ExtensionConf; this.default = ExtensionConf;
this.default['version'] = this.getExtensionVersion(); this.default['version'] = this.getExtensionVersion();
@ -23,11 +28,9 @@ class Settings {
if(currentBrowser.firefox) { if(currentBrowser.firefox) {
browser.storage.onChanged.addListener( (changes, area) => { browser.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) { this.logger.log('info', 'settings', "[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
console.log("[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area); if (changes['uwSettings'] && changes['uwSettings'].newValue) {
if (changes['uwSettings'] && changes['uwSettings'].newValue) { this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
console.log("[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
}
} }
if(changes['uwSettings'] && changes['uwSettings'].newValue) { if(changes['uwSettings'] && changes['uwSettings'].newValue) {
ths.setActive(JSON.parse(changes.uwSettings.newValue)); ths.setActive(JSON.parse(changes.uwSettings.newValue));
@ -37,17 +40,15 @@ class Settings {
try { try {
updateCallback(ths); updateCallback(ths);
} catch (e) { } catch (e) {
console.log("[Settings] CALLING UPDATE CALLBACK FAILED.") this.logger.log('error', 'settings', "[Settings] CALLING UPDATE CALLBACK FAILED.")
} }
} }
}); });
} else if (currentBrowser.chrome) { } else if (currentBrowser.chrome) {
chrome.storage.onChanged.addListener( (changes, area) => { chrome.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) { this.logger.log('info', 'settings', "[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
console.log("[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area); if (changes['uwSettings'] && changes['uwSettings'].newValue) {
if (changes['uwSettings'] && changes['uwSettings'].newValue) { this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
console.log("[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
}
} }
if(changes['uwSettings'] && changes['uwSettings'].newValue) { if(changes['uwSettings'] && changes['uwSettings'].newValue) {
ths.setActive(JSON.parse(changes.uwSettings.newValue)); ths.setActive(JSON.parse(changes.uwSettings.newValue));
@ -57,7 +58,7 @@ class Settings {
try { try {
updateCallback(ths); updateCallback(ths);
} catch (e) { } catch (e) {
console.log("[Settings] CALLING UPDATE CALLBACK FAILED.") this.logger.log('error', 'settings',"[Settings] CALLING UPDATE CALLBACK FAILED.")
} }
} }
}); });
@ -74,86 +75,177 @@ class Settings {
} }
} }
compareExtensionVersions(a, b) {
let aa = a.split('.');
let bb = b.split('.');
if (+aa[0] !== +bb[0]) {
// difference on first digit
return +aa[0] - +bb[0];
} if (+aa[1] !== +bb[1]) {
// first digit same, difference on second digit
return +aa[1] - +bb[1];
} if (+aa[2] !== +bb[2]) {
return +aa[2] - +bb[2];
// first two digits the same, let's check the third digit
} else {
// fourth digit is optional. When not specified, 0 is implied
// btw, ++(aa[3] || 0) - ++(bb[3] || 0) doesn't work
// Since some things are easier if we actually have a value for
// the fourth digit, we turn a possible undefined into a zero
aa[3] = aa[3] === undefined ? 0 : aa[3];
bb[3] = bb[3] === undefined ? 0 : bb[3];
// also, the fourth digit can start with a letter.
// versions that start with a letter are ranked lower than
// versions x.x.x.0
if (isNaN(+aa[3]) ^ isNaN(+bb[3])) {
return isNaN(+aa[3]) ? -1 : 1;
}
// at this point, either both version numbers are a NaN or
// both versions are a number.
if (!isNaN(+aa[3])) {
return +aa[3] - +bb[3];
}
// letters have their own hierarchy:
// dev < a < b < rc
let av = this.getPrereleaseVersionHierarchy(aa[3]);
let bv = this.getPrereleaseVersionHierarchy(bb[3]);
if (av !== bv) {
return av - bv;
} else {
return +(aa[3].replace(/\D/g,'')) - +(bb[3].replace(/\D/g, ''));
}
}
}
getPrereleaseVersionHierarchy(version) {
if (version.startsWith('dev')) {
return 0;
}
if (version.startsWith('a')) {
return 1;
}
if (version.startsWith('b')) {
return 2;
}
return 3;
}
sortConfPatches(patchesIn) {
return patchesIn.sort( (a, b) => this.compareExtensionVersions(a.forVersion, b.forVersion));
}
findFirstNecessaryPatch(version, extconfPatches) {
const sorted = this.sortConfPatches(extconfPatches);
return sorted.findIndex(x => this.compareExtensionVersions(x.forVersion, version) > 0);
}
applySettingsPatches(oldVersion, patches) {
let index = this.findFirstNecessaryPatch(oldVersion, patches);
if (index === -1) {
this.logger.log('info','settings','[Settings::applySettingsPatches] There are no pending conf patches.');
return;
}
// apply all remaining patches
this.logger.log('info', 'settings', `[Settings::applySettingsPatches] There are ${patches.length - index} settings patches to apply`);
while (index < patches.length) {
delete patches[index].forVersion;
ObjectCopy.overwrite(this.active, patches[index]);
index++;
}
}
async init() { async init() {
const settings = await this.get(); const settings = await this.get();
this.version = this.getExtensionVersion();
// |—> on first setup, settings is undefined & settings.version is haram // |—> on first setup, settings is undefined & settings.version is haram
// | since new installs ship with updates by default, no patching is // | since new installs ship with updates by default, no patching is
// | needed. In this case, we assume we're on the current version // | needed. In this case, we assume we're on the current version
const oldVersion = (settings && settings.version) || this.getExtensionVersion(); const oldVersion = (settings && settings.version) || this.version;
const currentVersion = this.getExtensionVersion();
if(Debug.debug) { if(Debug.debug) {
console.log("[Settings::init] Configuration fetched from storage:", settings, this.logger.log('info', 'settings', "[Settings::init] Configuration fetched from storage:", settings,
"\nlast saved with:", settings.version, "\nlast saved with:", settings.version,
"\ncurrent version:", currentVersion "\ncurrent version:", this.version
); );
if (Debug.flushStoredSettings) { // if (Debug.flushStoredSettings) {
console.log("%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd"); // this.logger.log('info', 'settings', "%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd");
Debug.flushStoredSettings = false; // don't do it again this session // Debug.flushStoredSettings = false; // don't do it again this session
this.active = this.getDefaultSettings(); // this.active = this.getDefaultSettings();
this.active.version = currentVersion; // this.active.version = this.version;
this.set(this.active); // this.set(this.active);
return this.active; // return this.active;
} // }
} }
// if there's no settings saved, return default settings. // if there's no settings saved, return default settings.
if(! settings || (Object.keys(settings).length === 0 && settings.constructor === Object)) { if(! settings || (Object.keys(settings).length === 0 && settings.constructor === Object)) {
this.logger.log('info', 'settings', '[Settings::init] settings don\'t exist. Using defaults.\n#keys:', Object.keys(settings).length, '\nsettings:', settings);
this.active = this.getDefaultSettings(); this.active = this.getDefaultSettings();
this.active.version = currentVersion; this.active.version = this.version;
this.set(this.active); await this.save();
return this.active; return this.active;
} }
// if last saved settings was for version prior to 4.x, we reset settings to default
// it's not like people will notice cos that version didn't preserve settings at all
if (settings.version && !settings.version.startsWith('4')) {
this.active = this.getDefaultSettings();
this.active.version = currentVersion;
this.set(this.active);
return this.active;
}
// in every case, we'll update the version number:
settings.version = currentVersion;
// if there's settings, set saved object as active settings // if there's settings, set saved object as active settings
this.active = settings; this.active = settings;
// check if extension has been updated. If not, return settings as they were retreived // if last saved settings was for version prior to 4.x, we reset settings to default
// it's not like people will notice cos that version didn't preserve settings at all
if (this.active.version && !settings.version.startsWith('4')) {
if (oldVersion == currentVersion) { this.active = this.getDefaultSettings();
if(Debug.debug) { this.active.version = this.version;
console.log("[Settings::init] extension was saved with current version of ultrawidify. Returning object as-is."); await this.save();
}
return this.active; return this.active;
} }
// if version number is undefined, we make it defined
// this should only happen on first extension initialization
if (!this.active.version) {
this.active.version = this.version;
await this.save();
return this.active;
}
// check if extension has been updated. If not, return settings as they were retrieved
if (this.active.version === this.version) {
this.logger.log('info', 'settings', "[Settings::init] extension was saved with current version of ultrawidify. Returning object as-is.");
return this.active;
}
// This means extension update happened.
// btw fun fact — we can do version rollbacks, which might come in handy while testing
this.active.version = this.version;
// if extension has been updated, update existing settings with any options added in the // if extension has been updated, update existing settings with any options added in the
// new version. In addition to that, we remove old keys that are no longer used. // new version. In addition to that, we remove old keys that are no longer used.
const patched = ObjectCopy.addNew(settings, this.default); const patched = ObjectCopy.addNew(settings, this.default);
if(Debug.debug) { this.logger.log('info', 'settings',"[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default);
console.log("[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default,);
}
if(patched){ if (patched) {
this.active = patched; this.active = patched;
} else {
this.active = JSON.parse(JSON.stringify(this.default));
} }
// in case settings in previous version contained a fucky wucky, we overwrite existing settings with a patch // in case settings in previous version contained a fucky wucky, we overwrite existing settings with a patch
ObjectCopy.overwrite(this.active, ExtensionConfPatch['4.2.0']); this.applySettingsPatches(oldVersion, ExtensionConfPatch);
// set 'whatsNewChecked' flag to false when updating // set 'whatsNewChecked' flag to false when updating, always
this.active.whatsNewChecked = false; this.active.whatsNewChecked = false;
// update settings version to current // update settings version to current
this.active.version = currentVersion; this.active.version = this.version;
this.set(this.active); await this.save();
return this.active; return this.active;
} }
@ -172,13 +264,7 @@ class Settings {
}); });
} }
if (Debug.debug && Debug.debugStorage) { this.logger.log('info', 'settings', 'Got settings:', ret && ret.uwSettings && JSON.parse(ret.uwSettings));
try {
console.log("[Settings::get] Got settings:", JSON.parse(ret.uwSettings));
} catch (e) {
console.log("[Settings::get] No settings.")
}
}
try { try {
return JSON.parse(ret.uwSettings); return JSON.parse(ret.uwSettings);
@ -188,13 +274,12 @@ class Settings {
} }
async set(extensionConf) { async set(extensionConf) {
if (Debug.debug && Debug.debugStorage) { extensionConf.version = this.version;
console.log("[Settings::set] setting new settings:", extensionConf)
} this.logger.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
if (currentBrowser.firefox || currentBrowser.edge) { if (currentBrowser.firefox || currentBrowser.edge) {
extensionConf.version = this.version; return browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
return this.useSync ? browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}): browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
} else if (currentBrowser.chrome) { } else if (currentBrowser.chrome) {
return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}); return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
} }
@ -213,7 +298,7 @@ class Settings {
console.log("[Settings::save] Saving active settings:", this.active); console.log("[Settings::save] Saving active settings:", this.active);
} }
this.set(this.active); await this.set(this.active);
} }
async rollback() { async rollback() {
@ -224,12 +309,6 @@ class Settings {
return JSON.parse(JSON.stringify(this.default)); return JSON.parse(JSON.stringify(this.default));
} }
setDefaultSettings() {
this.default.version = this.getExtensionVersion();
this.set(this.default);
}
// ----------------------------------------- // -----------------------------------------
// Nastavitve za posamezno stran // Nastavitve za posamezno stran
// Config for a given page: // Config for a given page:
@ -266,10 +345,7 @@ class Settings {
site = window.location.hostname; site = window.location.hostname;
if (!site) { if (!site) {
if (Debug.debug) { this.logger.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
console.log("[Settings::canStartExtension] window.location.hostname is null or undefined:", window.location.hostname)
console.log("active settings:", this.active)
}
return ExtensionMode.Disabled; return ExtensionMode.Disabled;
} }
} }
@ -291,9 +367,8 @@ class Settings {
} }
} catch(e){ } catch(e){
if(Debug.debug){ this.logger.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\n\nerror:", e, "\n\nSettings object:", this)
console.log("[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\n\nerror:", e, "\n\nSettings object:", this)
}
return ExtensionMode.Disabled; return ExtensionMode.Disabled;
} }
} }
@ -304,8 +379,7 @@ class Settings {
site = window.location.hostname; site = window.location.hostname;
if (!site) { if (!site) {
console.log("[Settings::canStartExtension] window.location.hostname is null or undefined:", window.location.hostname) this.logger.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
console.log("active settings:", this.active)
return false; return false;
} }
} }
@ -331,10 +405,8 @@ class Settings {
} else { } else {
return false; return false;
} }
} catch(e){ } catch(e) {
if(Debug.debug){ this.logger.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\nSettings object:", this);
console.log("[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\nSettings object:", this)
}
return false; return false;
} }
} }
@ -356,9 +428,7 @@ class Settings {
return this.active.sites[site].keyboardShortcutsEnabled === ExtensionMode.Enabled; return this.active.sites[site].keyboardShortcutsEnabled === ExtensionMode.Enabled;
} }
} catch (e) { } catch (e) {
if (Debug.debug) { this.logger.log('info', 'settings',"[Settings.js::keyboardDisabled] something went wrong:", e);
console.error("[Settings.js::keyboardDisabled] something went wrong:", e);
}
return false; return false;
} }
} }
@ -389,12 +459,12 @@ class Settings {
const csar = this.canStartAutoAr(site); const csar = this.canStartAutoAr(site);
Debug.debug = true; Debug.debug = true;
console.log("[Settings::canStartAutoAr] ----------------\nCAN WE START AUTOAR ON SITE", site, this.logger.log('info', 'settings', "[Settings::canStartAutoAr] ----------------\nCAN WE START AUTOAR ON SITE", site,
"?\n\nsettings.active.sites[site]=", this.active.sites[site], "settings.active.sites[@global]=", this.active.sites['@global'], "?\n\nsettings.active.sites[site]=", this.active.sites[site], "settings.active.sites[@global]=", this.active.sites['@global'],
"\nAutoar mode (global)?", this.active.sites['@global'].autoar, "\nAutoar mode (global)?", this.active.sites['@global'].autoar,
`\nAutoar mode (${site})`, this.active.sites[site] ? this.active.sites[site].autoar : '<not defined>', `\nAutoar mode (${site})`, this.active.sites[site] ? this.active.sites[site].autoar : '<not defined>',
"\nCan autoar be started?", csar "\nCan autoar be started?", csar
); );
} }
// if site is not defined, we use default mode: // if site is not defined, we use default mode:
@ -405,10 +475,10 @@ class Settings {
if (this.active.sites['@global'].autoar === ExtensionMode.Enabled) { if (this.active.sites['@global'].autoar === ExtensionMode.Enabled) {
return this.active.sites[site].autoar !== ExtensionMode.Disabled; return this.active.sites[site].autoar !== ExtensionMode.Disabled;
} else if (this.active.sites['@global'].autoar === ExtensionMode.Whitelist) { } else if (this.active.sites['@global'].autoar === ExtensionMode.Whitelist) {
console.log("canStartAutoAr — can(not) start csar because extension is in whitelist mode, and this site is (not) equal to", ExtensionMode.Enabled) this.logger.log('info', 'settings', "canStartAutoAr — can(not) start csar because extension is in whitelist mode, and this site is (not) equal to", ExtensionMode.Enabled)
return this.active.sites[site].autoar === ExtensionMode.Enabled; return this.active.sites[site].autoar === ExtensionMode.Enabled;
} else { } else {
console.log("canStartAutoAr — cannot start csar because extension is globally disabled") this.logger.log('info', 'settings', "canStartAutoAr — cannot start csar because extension is globally disabled")
return false; return false;
} }
} }

View File

@ -12,6 +12,7 @@ import AspectRatio from '../../../common/enums/aspect-ratio.enum';
class ArDetector { class ArDetector {
constructor(videoData){ constructor(videoData){
this.logger = videoData.logger;
this.conf = videoData; this.conf = videoData;
this.video = videoData.video; this.video = videoData.video;
this.settings = videoData.settings; this.settings = videoData.settings;
@ -36,9 +37,7 @@ class ArDetector {
this._nextTick = false; this._nextTick = false;
this.canDoFallbackMode = false; this.canDoFallbackMode = false;
if (Debug.init) { this.logger.log('info', 'init', `[ArDetector::ctor] creating new ArDetector. arid: ${this.arid}`);
console.log("[ArDetector::ctor] creating new ArDetector. arid:", this.arid);
}
} }
setManualTick(manualTick) { setManualTick(manualTick) {
@ -50,9 +49,7 @@ class ArDetector {
} }
init(){ init(){
if (Debug.debug || Debug.init) { this.logger.log('info', 'init', `[ArDetect::init] <@${this.arid}> Initializing autodetection.`);
console.log("[ArDetect::init] Initializing autodetection. arid:", this.arid);
}
try { try {
if (this.settings.canStartAutoAr()) { if (this.settings.canStartAutoAr()) {
@ -61,36 +58,27 @@ class ArDetector {
throw "Settings prevent autoar from starting" throw "Settings prevent autoar from starting"
} }
} catch (e) { } catch (e) {
if (Debug.debug) { this.logger.log('error', 'init', `%c[ArDetect::init] <@${this.arid}> Initialization failed.`, _ard_console_stop, e);
console.log("%c[ArDetect::init] INITIALIZATION FAILED!\n", _ard_console_stop, e);
}
} }
} }
destroy(){ destroy(){
if(Debug.debug || Debug.init) { this.logger.log('info', 'init', `%c[ArDetect::destroy] <@${this.arid}> Destroying aard.`, _ard_console_stop, e);
console.log(`[ArDetect::destroy] <arid:${this.arid}>`)
}
// this.debugCanvas.destroy(); // this.debugCanvas.destroy();
this.stop(); this.stop();
} }
setup(cwidth, cheight){ setup(cwidth, cheight){
if(Debug.debug || Debug.init) { this.logger.log('info', 'init', `[ArDetect::setup] <@${this.arid}> Starting autodetection setup.`);
console.log("[ArDetect::setup] Starting autodetection setup. arid:", this.arid);
}
// //
// [-1] check for zero-width and zero-height videos. If we detect this, we kick the proverbial // [-1] check for zero-width and zero-height videos. If we detect this, we kick the proverbial
// can some distance down the road. This problem will prolly fix itself soon. We'll also // can some distance down the road. This problem will prolly fix itself soon. We'll also
// not do any other setup until this issue is fixed // not do any other setup until this issue is fixed
// //
if(this.video.videoWidth === 0 || this.video.videoHeight === 0 ){ if(this.video.videoWidth === 0 || this.video.videoHeight === 0 ){
if(Debug.debug){ this.logger.log('warn', 'debug', `[ArDetect::setup] <@${this.arid}> This video has zero width or zero height. Dimensions: ${this.video.videoWidth} × ${this.video.videoHeight}`);
console.log("[ArDetector::setup] video has no width or height!", this.video.videoWidth,"×", this.video.videoHeight)
}
this.scheduleInitRestart(); this.scheduleInitRestart();
return; return;
} }
@ -170,9 +158,7 @@ class ArDetector {
// //
if (this.fallbackMode) { if (this.fallbackMode) {
if(Debug.debug) { this.logger.log('warn', 'debug', `[ArDetect::setup] <@${this.arid}> WARNING: CANVAS RESET DETECTED/we're in fallback mode - recalculating guardLine`, "background: #000; color: #ff2");
console.log("%c[ArDetect::setup] WARNING: CANVAS RESET DETECTED - recalculating guardLine", "background: #000; color: #ff2" )
}
// blackbar, imagebar // blackbar, imagebar
this.guardLine.reset(); this.guardLine.reset();
} }
@ -214,9 +200,8 @@ class ArDetector {
} }
start() { start() {
if (Debug.debug) { this.logger.log('info', 'debug', `"%c[ArDetect::start] <@${this.arid}> Starting automatic aspect ratio detection`, _ard_console_start);
console.log("%c[ArDetect::setup] Starting automatic aspect ratio detection.", _ard_console_start);
}
if (this.conf.resizer.lastAr.type === AspectRatio.Automatic) { if (this.conf.resizer.lastAr.type === AspectRatio.Automatic) {
// ensure first autodetection will run in any case // ensure first autodetection will run in any case
this.conf.resizer.setLastAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()}); this.conf.resizer.setLastAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()});
@ -231,6 +216,7 @@ class ArDetector {
// as false. Still, we'll explicitly fix this here. // as false. Still, we'll explicitly fix this here.
this._paused = false; this._paused = false;
this._halted = false; this._halted = false;
this._paused = false;
} }
unpause() { unpause() {
@ -250,9 +236,7 @@ class ArDetector {
} }
stop(){ stop(){
if(Debug.debug){ this.logger.log('info', 'debug', `"%c[ArDetect::stop] <@${this.arid}> Stopping automatic aspect ratio detection`, _ard_console_stop);
console.log("%c[ArDetect::_ard_stop] Stopping automatic aspect ratio detection", _ard_console_stop);
}
this._halted = true; this._halted = true;
// this.conf.resizer.setArLastAr(); // this.conf.resizer.setArLastAr();
} }
@ -272,21 +256,15 @@ class ArDetector {
let exitedRetries = 10; let exitedRetries = 10;
while (!this._exited && exitedRetries --> 0) { while (!this._exited && exitedRetries --> 0) {
if (Debug.debug) { this.logger.log('warn', 'debug', `[ArDetect::main] <@${this.arid}> We are trying to start another instance of autodetection on current video, but the previous instance hasn't exited yet. Waiting for old instance to exit ...`);
console.log("[ArDetector::main] We are trying to start another instance of autodetection on current video, but the previous instance hasn't exited yet. Waiting for old instance to exit ...")
}
await this.sleep(this.settings.active.arDetect.timers.tickrate); await this.sleep(this.settings.active.arDetect.timers.tickrate);
} }
if (!this._exited) { if (!this._exited) {
if (Debug.debug) { this.logger.log('error', 'debug', `[ArDetect::main] <@${this.arid}> Previous instance didn't exit in time. Not starting a new one.`);
console.log("[ArDetector::main] Previous instance didn't exit in time. Not starting a new one.")
}
return; return;
} }
if (Debug.debug) { this.logger.log('info', 'debug', `%c[ArDetect::main] <@${this.arid}> Previous instance didn't exit in time. Not starting a new one.`);
console.log("%c[ArDetect::main] Main autodetection loop started.", _ard_console_start);
}
// we need to unhalt: // we need to unhalt:
this._halted = false; this._halted = false;
@ -313,9 +291,7 @@ class ArDetector {
try { try {
this.frameCheck(); this.frameCheck();
} catch (e) { } catch (e) {
if (Debug.debug) { this.logger.log('error', 'debug', `%c[ArDetect::main] <@${this.arid}> Frame check failed:`, "color: #000, background: #f00", e);
console.log("%c[ArDetector::main] Frame check failed:", "color: #000, background: #f00", e);
}
} }
if (Debug.performanceMetrics) { if (Debug.performanceMetrics) {
@ -329,9 +305,7 @@ class ArDetector {
await this.sleep(this.settings.active.arDetect.timers.tickrate); await this.sleep(this.settings.active.arDetect.timers.tickrate);
} }
if (Debug.debug) { this.logger.log('info', 'debug', `%c[ArDetect::main] <@${this.arid}> Main autodetection loop exited. Halted? ${this._halted}`, _ard_console_stop);
console.log(`%c[ArDetect::main] Main autodetection loop exited. Halted? ${this._halted}`, _ard_console_stop);
}
this._exited = true; this._exited = true;
} }
@ -376,8 +350,10 @@ class ArDetector {
this.setupTimer = setTimeout(function(){ this.setupTimer = setTimeout(function(){
ths.setupTimer = null; ths.setupTimer = null;
try{ try{
ths.main(); ths.main();
}catch(e){console.log("[ArDetector::scheduleInitRestart] Failed to start init(). Error:",e)} } catch(e) {
this.logger('error', 'debug', `[ArDetector::scheduleInitRestart] <@${this.arid}> Failed to start main(). Error:`,e);
}
ths = null; ths = null;
}, },
timeout timeout
@ -402,37 +378,14 @@ class ArDetector {
} }
canvasReadyForDrawWindow(){ canvasReadyForDrawWindow(){
if(Debug.debug) this.logger.log('info', 'debug', `%c[ArDetect::canvasReadyForDrawWindow] <@${this.arid}> canvas is ${this.canvas.height === window.innerHeight ? '' : 'NOT '}ready for drawWindow(). Canvas height: ${this.canvas.height}px; window inner height: ${window.innerHeight}px.`)
console.log("%c[ArDetect::_ard_canvasReadyForDrawWindow] (?)", "color: #44f", this.canvas.height == window.innerHeight, "(ard_height:", this.canvas.height, "| window height:", window.innerHeight, ")");
return this.canvas.height == window.innerHeight return this.canvas.height == window.innerHeight
} }
getTimeout(baseTimeout, startTime){ getTimeout(baseTimeout, startTime){
var execTime = (performance.now() - startTime); var execTime = (performance.now() - startTime);
if( execTime > this.settings.active.arDetect.autoDisable.maxExecutionTime ){
// this.detectionTimeoutEventCount++;
if(Debug.debug){
console.log("[ArDetect::getTimeout] Exec time exceeded maximum allowed execution time. This has now happened " + this.detectionTimeoutEventCount + " times in a row.");
}
// if( this.detectionTimeoutEventCount >= this.settings.active.arDetect.autoDisable.consecutiveTimeoutCount ){
// if (Debug.debug){
// console.log("[ArDetect::getTimeout] Maximum execution time was exceeded too many times. Automatic aspect ratio detection has been disabled.");
// }
// Comms.sendToBackgroundScript({cmd: 'disable-autoar', reason: 'Automatic aspect ratio detection was taking too much time and has been automatically disabled in order to avoid lag.'});
// _ard_stop();
// return 999999;
// }
} else {
this.detectionTimeoutEventCount = 0;
}
// return baseTimeout > this.settings.active.arDetect.minimumTimeout ? baseTimeout : this.settings.active.arDetect.minimumTimeout;
return baseTimeout; return baseTimeout;
} }
//#endregion //#endregion
@ -491,9 +444,7 @@ class ArDetector {
var trueHeight = this.canvas.height * zoomFactor - letterbox; var trueHeight = this.canvas.height * zoomFactor - letterbox;
if(edges.top > 1 && edges.top <= this.settings.active.arDetect.fallbackMode.noTriggerZonePx ){ if(edges.top > 1 && edges.top <= this.settings.active.arDetect.fallbackMode.noTriggerZonePx ){
if(Debug.debug && Debug.debugArDetect) { this.logger.log('info', 'arDetect', `%c[ArDetect::calculateArFromEdges] <@${this.arid}> Edge is in the no-trigger zone. Aspect ratio change is not triggered.`)
console.log("Edge is in the no-trigger zone. Aspect ratio change is not triggered.")
}
return; return;
} }
@ -508,7 +459,6 @@ class ArDetector {
} }
processAr(trueAr){ processAr(trueAr){
let actualHeight = 0; // purely for fallback mode
this.detectedAr = trueAr; this.detectedAr = trueAr;
// poglejmo, če se je razmerje stranic spremenilo // poglejmo, če se je razmerje stranic spremenilo
@ -529,33 +479,22 @@ class ArDetector {
// ali je sprememba v mejah dovoljenega? Če da -> fertik // ali je sprememba v mejah dovoljenega? Če da -> fertik
// is ar variance within acceptable levels? If yes -> we done // is ar variance within acceptable levels? If yes -> we done
if(Debug.debug && Debug.debugArDetect) this.logger.log('info', 'arDetect', `%c[ArDetect::processAr] <@${this.arid}> New aspect ratio varies from the old one by this much:\n`,"color: #aaf","old Ar", lastAr.ar, "current ar", trueAr, "arDiff (absolute):",arDiff,"ar diff (relative to new ar)", arDiff_percent);
console.log("%c[ArDetect::processAr] new aspect ratio varies from the old one by this much:\n","color: #aaf","old Ar", lastAr.ar, "current ar", trueAr, "arDiff (absolute):",arDiff,"ar diff (relative to new ar)", arDiff_percent);
if (arDiff < trueAr * this.settings.active.arDetect.allowedArVariance){ if (arDiff < trueAr * this.settings.active.arDetect.allowedArVariance){
if(Debug.debug && Debug.debugArDetect) this.logger.log('info', 'arDetect', `%c[ArDetect::processAr] <@${this.arid}> Aspect ratio change denied — diff %: ${arDiff_percent}`, "background: #740; color: #fa2");
console.log("%c[ArDetect::processAr] aspect ratio change denied — diff %:", "background: #740; color: #fa2", arDiff_percent)
return; return;
} }
else if(Debug.debug && Debug.debugArDetect){ this.logger.log('info', 'arDetect', `%c[ArDetect::processAr] <@${this.arid}> aspect ratio change accepted — diff %: ${arDiff_percent}`, "background: #153; color: #4f9");
console.log("%c[ArDetect::processAr] aspect ratio change accepted — diff %:", "background: #153; color: #4f9", arDiff_percent)
}
}
if(Debug.debug) {
console.log("%c[ArDetect::processAr] Triggering aspect ratio change. New aspect ratio: ", _ard_console_change, trueAr);
} }
this.logger.log('info', 'debug', `%c[ArDetect::processAr] <@${this.arid}> Triggering aspect ratio change. New aspect ratio: ${trueAr}`, _ard_console_change);
this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: trueAr}, {type: AspectRatio.Automatic, ratio: trueAr}); this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: trueAr}, {type: AspectRatio.Automatic, ratio: trueAr});
} }
frameCheck(){ frameCheck(){
if(! this.video){ if(! this.video){
if(Debug.debug || Debug.warnings_critical) { this.logger.log('error', 'debug', `%c[ArDetect::frameCheck] <@${this.arid}> Video went missing. Destroying current instance of videoData.`);
console.log("[ArDetect::frameCheck] Video went missing. Destroying current instance of videoData.")
}
this.conf.destroy(); this.conf.destroy();
return; return;
} }
@ -574,9 +513,8 @@ class ArDetector {
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);
this.fallbackMode = false; this.fallbackMode = false;
} catch (e) { } catch (e) {
if(Debug.debug && Debug.debugArDetect) { 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);
console.log(`%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.canDoFallbackMode) {
return; return;
@ -607,28 +545,20 @@ class ArDetector {
try { try {
this.context.drawWindow(window, this.canvasDrawWindowHOffset, 0, this.canvas.width, this.canvas.height, "rgba(0,0,128,1)"); this.context.drawWindow(window, this.canvasDrawWindowHOffset, 0, this.canvas.width, this.canvas.height, "rgba(0,0,128,1)");
} catch (e) { } catch (e) {
console.log(`%c[ArDetect::frameCheck] can't draw image on canvas with fallback mode either. This error is prolly only temporary.`, "color:#000; backgroud:#f51;", e); this.logger.log('error', 'arDetect', `%c[ArDetect::frameCheck] can't draw image on canvas with fallback mode either. This error is prolly only temporary.`, "color:#000; backgroud:#f51;", e);
return; // it's prolly just a fluke, so we do nothing special here return; // it's prolly just a fluke, so we do nothing special here
} }
// draw blackframe sample from our main sample: // draw blackframe sample from our main sample:
this.blackframeContext.drawImage(this.canvas, this.blackframeCanvas.width, this.blackframeCanvas.height) this.blackframeContext.drawImage(this.canvas, this.blackframeCanvas.width, this.blackframeCanvas.height)
if (Debug.debug) { this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] canvas.drawImage seems to have worked`, "color:#000; backgroud:#2f5;");
console.log("%c[ArDetect::frameCheck] canvas.drawImage seems to have worked", "color:#000; backgroud:#2f5;");
}
} }
const bfanalysis = this.blackframeTest(); const bfanalysis = this.blackframeTest();
if (bfanalysis.isBlack) { if (bfanalysis.isBlack) {
// we don't do any corrections on frames confirmed black // we don't do any corrections on frames confirmed black
if (Debug.debug && Debug.arDetect) { this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Black frame analysis suggests this frame is black or too dark. Doing nothing.`, "color: #fa3", bfanalysis);
console.log("%c[ArDetect::frameCheck] Black frame analysis suggests this frame is black or too dark. Doing nothing,", "color: #fa3", bfanalysis);
}
return; return;
} else {
// if (Debug.debug && Debug.arDetect) {
// console.log("%c[ArDetect::frameCheck] Black frame analysis suggests this frame is not completely black. Doing further analysis,", "color: #3fa", bfanalysis);
// }
} }
@ -649,10 +579,8 @@ class ArDetector {
this.guardLine.reset(); this.guardLine.reset();
this.noLetterboxCanvasReset = true; this.noLetterboxCanvasReset = true;
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Letterbox not detected in fast test. Letterbox is either gone or we manually corrected aspect ratio. Nothing will be done.`, "color: #fa3");
if (Debug.debug && Debug.arDetect) {
console.log("%c[ArDetect::frameCheck] Letterbox not detected in fast test. Letterbox is either gone or we manually corrected aspect ratio. Nothing will be done.", "color: #fa3");
}
return; return;
} }
@ -669,10 +597,7 @@ class ArDetector {
// če ni padla nobena izmed funkcij, potem se razmerje stranic ni spremenilo // če ni padla nobena izmed funkcij, potem se razmerje stranic ni spremenilo
// if both succeed, then aspect ratio hasn't changed. // if both succeed, then aspect ratio hasn't changed.
if (!guardLineOut.imageFail && !guardLineOut.blackbarFail) { if (!guardLineOut.imageFail && !guardLineOut.blackbarFail) {
if(Debug.debug && Debug.debugArDetect){ this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] guardLine tests were successful. (no imagefail and no blackbarfail)\n`, "color: #afa", guardLineOut);
console.log(`%c[ArDetect::frameCheck] guardLine tests were successful. (no imagefail and no blackbarfail)\n`, "color: #afa", guardLineOut);
}
return; return;
} }
@ -709,25 +634,20 @@ class ArDetector {
if(guardLineOut.blackbarFail || guardLineOut.imageFail){ if(guardLineOut.blackbarFail || guardLineOut.imageFail){
if(this.edgeDetector.findBars(imageData, null, EdgeDetectPrimaryDirection.HORIZONTAL).status === 'ar_known'){ if(this.edgeDetector.findBars(imageData, null, EdgeDetectPrimaryDirection.HORIZONTAL).status === 'ar_known'){
if(Debug.debug && guardLineOut.blackbarFail){
console.log("[ArDetect::frameCheck] Detected blackbar violation and pillarbox. Resetting to default aspect ratio.");
}
if(guardLineOut.blackbarFail){ if(guardLineOut.blackbarFail){
this.logger.log('info', 'arDetect', `[ArDetect::frameCheck] Detected blackbar violation and pillarbox. Resetting to default aspect ratio.`);
this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()}); this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()});
this.guardLine.reset(); this.guardLine.reset();
} }
triggerTimeout = this.getTimeout(baseTimeout, startTime); triggerTimeout = this.getTimeout(baseTimeout, startTime);
this.scheduleFrameCheck(triggerTimeout); this.scheduleFrameCheck(triggerTimeout);
return; return;
} }
} }
} catch(e) { } catch(e) {
if(Debug.debug) { this.logger.log('info', 'arDetect', `[ArDetect::frameCheck] something went wrong while checking for pillarbox. Error:\n`, e);
console.log("[ArDetect.js::frameCheck] something went wrong when checking for pillarbox. Error:\n", e)
}
} }
// pa poglejmo, kje se končajo črne letvice na vrhu in na dnu videa. // pa poglejmo, kje se končajo črne letvice na vrhu in na dnu videa.
@ -738,43 +658,19 @@ class ArDetector {
var edgePost = this.edgeDetector.findBars(imageData, sampleCols, EdgeDetectPrimaryDirection.VERTICAL, EdgeDetectQuality.IMPROVED, guardLineOut, bfanalysis); var edgePost = this.edgeDetector.findBars(imageData, sampleCols, EdgeDetectPrimaryDirection.VERTICAL, EdgeDetectQuality.IMPROVED, guardLineOut, bfanalysis);
if(Debug.debug && Debug.debugArDetect){ this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] edgeDetector returned this\n`, "color: #aaf", edgePost);
console.log(`%c[ArDetect::frameCheck] edgeDetector returned this\n`, "color: #aaf", edgePost);
}
// console.log("SAMPLES:", blackbarSamples, "candidates:", edgeCandidates, "post:", edgePost,"\n\nblack level:", this.blackLevel, "tresh:", this.blackLevel + this.settings.active.arDetect.blackbar.threshold);
if (edgePost.status !== EdgeStatus.AR_KNOWN){ if (edgePost.status !== EdgeStatus.AR_KNOWN){
// rob ni bil zaznan, zato ne naredimo ničesar. // rob ni bil zaznan, zato ne naredimo ničesar.
// no edge was detected. Let's leave things as they were // no edge was detected. Let's leave things as they were
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Edge wasn't detected with findBars`, "color: #fa3", edgePost, "EdgeStatus.AR_KNOWN:", EdgeStatus.AR_KNOWN);
if (Debug.debug && Debug.arDetect) {
console.log("%c[ArDetect::frameCheck] Edge wasn't detected with findBars", "color: #fa3", edgePost, "EdgeStatus.AR_KNOWN:", EdgeStatus.AR_KNOWN);
}
return; return;
} }
var newAr = this.calculateArFromEdges(edgePost); var newAr = this.calculateArFromEdges(edgePost);
// if (this.fallbackMode
// && (!guardLineOut.blackbarFail && guardLineOut.imageFail)
// && newAr < this.conf.resizer.getLastAr().ar
// ) {
// // V primeru nesmiselnih rezultatov tudi ne naredimo ničesar.
// // v fallback mode se lahko naredi, da je novo razmerje stranice ožje kot staro, kljub temu da je šel
// // blackbar test skozi. Spremembe v tem primeru ne dovolimo.
// //
// // (Pravilen fix? Popraviti je treba računanje robov. V fallback mode je treba upoštevati, da obrobe,
// // ki smo jih obrezali, izginejo is canvasa)
// //
// // NOTE: pravilen fix je bil implementiran
// return;
// }
if(Debug.debug && Debug.debugArDetect){ this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Triggering aspect ration change! new ar: ${newAr}`, "color: #aaf");
console.log(`%c[ArDetect::frameCheck] Triggering aspect ration change! new ar: ${newAr}`, "color: #aaf");
}
// we also know edges for guardline, so set them. // we also know edges for guardline, so set them.
// we need to be mindful of fallbackMode though // we need to be mindful of fallbackMode though
// if edges are okay and not invalid, we also // if edges are okay and not invalid, we also
@ -800,7 +696,12 @@ class ArDetector {
} catch (e) { } catch (e) {
// edges weren't gucci, so we'll just reset // edges weren't gucci, so we'll just reset
// the aspect ratio to defaults // the aspect ratio to defaults
this.guardline.reset(); try {
this.guardline.reset();
} catch (e) {
// guardline wasn't gucci either, but we'll just ignore
// that and reset the aspect ratio anyway
}
this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()}); this.conf.resizer.setAr({type: AspectRatio.Automatic, ratio: this.getDefaultAr()});
} }
} }
@ -815,10 +716,7 @@ class ArDetector {
blackframeTest() { blackframeTest() {
if (this.blackLevel === undefined) { if (this.blackLevel === undefined) {
if (Debug.debug && Debug.debugArDetect) { this.logger.log('info', 'arDetect_verbose', "[ArDetect::blackframeTest] black level undefined, resetting");
console.log("[ArDetect::frameCheck] black level undefined, resetting");
}
this.resetBlackLevel(); this.resetBlackLevel();
} }

View File

@ -92,7 +92,6 @@ class GuardLine {
// should succeed by default. Also need to check bottom, for cases where only one edge is known // should succeed by default. Also need to check bottom, for cases where only one edge is known
if(! fallbackMode && (! this.blackbar.top || ! this.blackbar.bottom)) { if(! fallbackMode && (! this.blackbar.top || ! this.blackbar.bottom)) {
// console.log("NO EDGE WAS DETECTED. THIS TEST IS POINTLESS. btw guardline")
return { success: true }; return { success: true };
} }

View File

@ -12,6 +12,7 @@ class EdgeDetect{
constructor(ardConf){ constructor(ardConf){
this.conf = ardConf; this.conf = ardConf;
this.logger = ardConf.logger;
this.settings = ardConf.settings; this.settings = ardConf.settings;
this.sampleWidthBase = this.settings.active.arDetect.edgeDetection.sampleWidth << 2; // corrected so we can work on imageData this.sampleWidthBase = this.settings.active.arDetect.edgeDetection.sampleWidth << 2; // corrected so we can work on imageData
@ -43,9 +44,7 @@ class EdgeDetect{
bars = this.edgePostprocess(edgeCandidates, this.conf.canvas.height); bars = this.edgePostprocess(edgeCandidates, this.conf.canvas.height);
// } // }
} catch (e) { } catch (e) {
if (Debug.debug) { this.logger.log('error', 'arDetect', '%c[EdgeDetect::findBars] find bars failed.', 'background: #f00, color: #000', e);
console.log("%c[EdgeDetect::findBars] find bars failed.", "background: #f00, color: #000", e);
}
return {status: EdgeStatus.AR_UNKNOWN} return {status: EdgeStatus.AR_UNKNOWN}
} }
} else { } else {
@ -58,89 +57,80 @@ class EdgeDetect{
findCandidates(image, sampleCols, guardLineOut){ findCandidates(image, sampleCols, guardLineOut){
try { try {
let upper_top, upper_bottom, lower_top, lower_bottom; let upper_top, upper_bottom, lower_top, lower_bottom;
// const cols_a = sampleCols.slice(0); // const cols_a = sampleCols.slice(0);
const cols_a = new Array(sampleCols.length); const cols_a = new Array(sampleCols.length);
const res_top = []; const res_top = [];
for (let i = 0; i < cols_a.length; i++) { for (let i = 0; i < cols_a.length; i++) {
cols_a[i] = { cols_a[i] = {
id: i, id: i,
value: sampleCols[i], value: sampleCols[i],
}; };
} }
const cols_b = cols_a.slice(0); const cols_b = cols_a.slice(0);
const res_bottom = []; const res_bottom = [];
// console.log("[EdgeDetect::findCandidates] cols a, b (initial):", cols_a, cols_b); this.colsThreshold = sampleCols.length * this.settings.active.arDetect.edgeDetection.minColsForSearch;
if (this.colsThreshold == 0)
this.colsThreshold = 1;
this.colsThreshold = sampleCols.length * this.settings.active.arDetect.edgeDetection.minColsForSearch;
if (this.colsThreshold == 0) this.blackbarThreshold = this.conf.blackLevel + this.settings.active.arDetect.blackbar.threshold;
this.colsThreshold = 1; this.imageThreshold = this.blackbarThreshold + this.settings.active.arDetect.blackbar.imageThreshold;
this.blackbarThreshold = this.conf.blackLevel + this.settings.active.arDetect.blackbar.threshold; // if guardline didn't fail and imageDetect did, we don't have to check the upper few pixels
this.imageThreshold = this.blackbarThreshold + this.settings.active.arDetect.blackbar.imageThreshold; // but only if upper and lower edge are defined. If they're not, we need to check full height
if(guardLineOut){
// if guardline didn't fail and imageDetect did, we don't have to check the upper few pixels if(guardLineOut.imageFail && !guardLineOut.blackbarFail && this.conf.guardLine.blackbar.top) {
// but only if upper and lower edge are defined. If they're not, we need to check full height upper_top = this.conf.guardLine.blackbar.top;
if(guardLineOut){ upper_bottom = this.conf.canvas.height >> 1;
if(guardLineOut.imageFail && !guardLineOut.blackbarFail && this.conf.guardLine.blackbar.top) { lower_top = upper_bottom;
upper_top = this.conf.guardLine.blackbar.top; lower_bottom = this.conf.guardLine.blackbar.bottom;
upper_bottom = this.conf.canvas.height >> 1; } else if (! guardLineOut.imageFail && !guardLineOut.blackbarFail && this.conf.guardLine.blackbar.top) {
lower_top = upper_bottom; // ta primer se lahko zgodi tudi zaradi kakšnega logotipa. Ker nočemo, da nam en jeben
lower_bottom = this.conf.guardLine.blackbar.bottom; // logotip vsili reset razmerja stranic, se naredimo hrvata in vzamemo nekaj varnostnega
} else if (! guardLineOut.imageFail && !guardLineOut.blackbarFail && this.conf.guardLine.blackbar.top) { // pasu preko točke, ki jo označuje guardLine.blackbar. Recimo 1/8 višine platna na vsaki strani.
// ta primer se lahko zgodi tudi zaradi kakšnega logotipa. Ker nočemo, da nam en jeben // a logo could falsely trigger this case, so we need to add some extra margins past
// logotip vsili reset razmerja stranic, se naredimo hrvata in vzamemo nekaj varnostnega // the point marked by guardLine.blackbar. Let's say 1/8 of canvas height on either side.
// pasu preko točke, ki jo označuje guardLine.blackbar. Recimo 1/8 višine platna na vsaki strani. upper_top = 0;
// a logo could falsely trigger this case, so we need to add some extra margins past upper_bottom = this.conf.guardLine.blackbar.top + (this.conf.canvas.height >> 3);
// the point marked by guardLine.blackbar. Let's say 1/8 of canvas height on either side. lower_top = this.conf.guardLine.blackbar.bottom - (this.conf.canvas.height >> 3);
upper_top = 0; lower_bottom = this.conf.canvas.height - 1;
upper_bottom = this.conf.guardLine.blackbar.top + (this.conf.canvas.height >> 3); } else {
lower_top = this.conf.guardLine.blackbar.bottom - (this.conf.canvas.height >> 3); upper_top = 0;
lower_bottom = this.conf.canvas.height - 1; upper_bottom = (this.conf.canvas.height >> 1) /*- parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/
} else { lower_top = (this.conf.canvas.height >> 1) /*+ parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/
lower_bottom = this.conf.canvas.height - 1;
}
} else{
upper_top = 0; upper_top = 0;
upper_bottom = (this.conf.canvas.height >> 1) /*- parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ upper_bottom = (this.conf.canvas.height >> 1) /*- parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/
lower_top = (this.conf.canvas.height >> 1) /*+ parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/ lower_top = (this.conf.canvas.height >> 1) /*+ parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/
lower_bottom = this.conf.canvas.height - 1; lower_bottom = this.conf.canvas.height - 1;
} }
} else{
upper_top = 0;
upper_bottom = (this.conf.canvas.height >> 1) /*- parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/
lower_top = (this.conf.canvas.height >> 1) /*+ parseInt(this.conf.canvas.height * this.settings.active.arDetect.edgeDetection.middleIgnoredArea);*/
lower_bottom = this.conf.canvas.height - 1;
}
if(Debug.debug && Debug.debugArDetect){ this.logger.log('info', 'arDetect', '[EdgeDetect::findCandidates] searching for candidates on ranges', upper_top, '<->', upper_bottom, ';', lower_top, '<->', lower_bottom);
console.log("[EdgeDetect::findCandidates] searching for candidates on ranges", upper_top, "<->", upper_bottom, ";", lower_top, "<->", lower_bottom);
} var upper_top_corrected = upper_top * this.conf.canvasImageDataRowLength;
var upper_bottom_corrected = upper_bottom * this.conf.canvasImageDataRowLength;
var lower_top_corrected = lower_top * this.conf.canvasImageDataRowLength;
var lower_bottom_corrected = lower_bottom * this.conf.canvasImageDataRowLength;
// if(Debug.debugCanvas.enabled){
// this._columnTest_dbgc(image, upper_top_corrected, upper_bottom_corrected, cols_a, res_top, false);
// this._columnTest_dbgc(image, lower_top_corrected, lower_bottom_corrected, cols_b, res_bottom, true);
// } else {
this._columnTest3_cross(image, upper_top_corrected, upper_bottom_corrected, cols_a, res_top, false);
this._columnTest3_cross(image, lower_top_corrected, lower_bottom_corrected, cols_b, res_bottom, true);
// }
this.logger.log('info', 'arDetect', '[EdgeDetect::findCandidates] candidates found -->', {res_top: res_top, res_bottom: res_bottom});
var upper_top_corrected = upper_top * this.conf.canvasImageDataRowLength; return {res_top: res_top, res_bottom: res_bottom};
var upper_bottom_corrected = upper_bottom * this.conf.canvasImageDataRowLength;
var lower_top_corrected = lower_top * this.conf.canvasImageDataRowLength;
var lower_bottom_corrected = lower_bottom * this.conf.canvasImageDataRowLength;
// if(Debug.debugCanvas.enabled){
// this._columnTest_dbgc(image, upper_top_corrected, upper_bottom_corrected, cols_a, res_top, false);
// this._columnTest_dbgc(image, lower_top_corrected, lower_bottom_corrected, cols_b, res_bottom, true);
// } else {
this._columnTest3_cross(image, upper_top_corrected, upper_bottom_corrected, cols_a, res_top, false);
this._columnTest3_cross(image, lower_top_corrected, lower_bottom_corrected, cols_b, res_bottom, true);
// }
if (Debug.debug && Debug.debugArDetect){
console.log("[EdgeDetect::findCandidates] candidates found -->", {res_top: res_top, res_bottom: res_bottom});
}
return {res_top: res_top, res_bottom: res_bottom};
} catch (e) { } catch (e) {
console.log("[EdgeDetect::findCandidates] there was an error", e); this.logger.log('error', 'debug', '[EdgeDetect::findCandidates] there was an error while finding candidates:', e);
} }
} }
@ -333,7 +323,7 @@ class EdgeDetect{
} }
} }
} catch (e) { } catch (e) {
console.log("\n\nuwu fucky wucky:", e, "\n\n") this.logger.log('error', 'debug', '[EdgeDetect::edgeDetect] There was an error:', e);
} }
return { return {

View File

@ -2,7 +2,8 @@ import Debug from '../../conf/Debug';
import BrowserDetect from '../../conf/BrowserDetect'; import BrowserDetect from '../../conf/BrowserDetect';
class CommsClient { class CommsClient {
constructor(name, settings) { constructor(name, settings, logger) {
this.logger = logger;
if (BrowserDetect.firefox) { if (BrowserDetect.firefox) {
this.port = browser.runtime.connect({name: name}); this.port = browser.runtime.connect({name: name});
} else if (BrowserDetect.chrome) { } else if (BrowserDetect.chrome) {
@ -32,9 +33,7 @@ class CommsClient {
this.pageInfo = pageInfo; this.pageInfo = pageInfo;
if(Debug.debug) { this.logger.log('info', 'debug', `[CommsClient::setPageInfo] <${this.commsId}>`, "SETTING PAGEINFO —", this.pageInfo, this)
console.log(`[CommsClient::setPageInfo] <${this.commsId}>`, "SETTING PAGEINFO —", this.pageInfo, this)
}
var ths = this; var ths = this;
this._listener = m => ths.processReceivedMessage(m); this._listener = m => ths.processReceivedMessage(m);
@ -46,17 +45,13 @@ class CommsClient {
} }
processReceivedMessage(message){ processReceivedMessage(message){
if(Debug.debug && Debug.comms){ this.logger.log('info', 'comms', `[CommsClient.js::processMessage] <${this.commsId}> Received message from background script!`, message);
console.log(`[CommsClient.js::processMessage] <${this.commsId}> Received message from background script!`, message);
}
if (!this.pageInfo || !this.settings.active) { if (!this.pageInfo || !this.settings.active) {
if(Debug.debug && Debug.comms){ this.logger.log('info', 'comms', `[CommsClient.js::processMessage] <${this.commsId}> this.pageInfo (or settings) not defined. Extension is probably disabled for this site.\npageInfo:`, this.pageInfo,
console.log(`[CommsClient.js::processMessage] <${this.commsId}> this.pageInfo (or settings) not defined. Extension is probably disabled for this site.\npageInfo:`, this.pageInfo, "\nsettings.active:", this.settings.active,
"\nsettings.active:", this.settings.active, "\nnobj:", this
"\nnobj:", this );
);
}
return; return;
} }
@ -67,7 +62,7 @@ class CommsClient {
if (message.cmd === "set-ar") { if (message.cmd === "set-ar") {
this.pageInfo.setAr({type: message.arg, ratio: message.customArg}, message.playing); this.pageInfo.setAr({type: message.arg, ratio: message.customArg}, message.playing);
} else if (message.cmd === 'set-alignment') { } else if (message.cmd === 'set-alignment') {
this.pageInfo.setvideoAlignment(message.arg, message.playing); this.pageInfo.setVideoAlignment(message.arg, message.playing);
this.pageInfo.restoreAr(); this.pageInfo.restoreAr();
} else if (message.cmd === "set-stretch") { } else if (message.cmd === "set-stretch") {
this.pageInfo.setStretchMode(message.arg, message.playing); this.pageInfo.setStretchMode(message.arg, message.playing);
@ -135,13 +130,11 @@ class CommsClient {
} }
async requestSettings(){ async requestSettings(){
if(Debug.debug){ this.logger.log('info', 'comms', "%c[CommsClient::requestSettings] sending request for congif!", "background: #11D; color: #aad");
console.log("%c[CommsClient::requestSettings] sending request for congif!", "background: #11D; color: #aad");
}
var response = await this.sendMessage_nonpersistent({cmd: 'get-config'}); var response = await this.sendMessage_nonpersistent({cmd: 'get-config'});
if(Debug.debug){
console.log("%c[CommsClient::requestSettings] received settings response!", "background: #11D; color: #aad", response); this.logger.log('info', 'comms', "%c[CommsClient::requestSettings] received settings response!", "background: #11D; color: #aad", response);
}
if(! response || response.extensionConf){ if(! response || response.extensionConf){
return Promise.resolve(false); return Promise.resolve(false);
@ -156,9 +149,7 @@ class CommsClient {
} }
registerVideo(){ registerVideo(){
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', `[CommsClient::registerVideo] <${this.commsId}>`, "Registering video for current page.");
console.log(`[CommsClient::registerVideo] <${this.commsId}>`, "Registering video for current page.");
}
if (this.pageInfo) { if (this.pageInfo) {
if (this.pageInfo.hasVideo()) { if (this.pageInfo.hasVideo()) {
this.port.postMessage({cmd: "has-video"}); this.port.postMessage({cmd: "has-video"});
@ -173,9 +164,7 @@ class CommsClient {
} }
unregisterVideo(){ unregisterVideo(){
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', `[CommsClient::unregisterVideo] <${this.commsId}>`, "Unregistering video for current page.");
console.log(`[CommsClient::unregisterVideo] <${this.commsId}>`, "Unregistering video for current page.");
}
this.port.postMessage({cmd: "noVideo"}); // ayymd this.port.postMessage({cmd: "noVideo"}); // ayymd
} }

View File

@ -4,13 +4,12 @@ import BrowserDetect from '../../conf/BrowserDetect';
class CommsServer { class CommsServer {
constructor(server) { constructor(server) {
this.server = server; this.server = server;
this.logger = server.logger;
this.settings = server.settings; this.settings = server.settings;
this.ports = []; this.ports = [];
var ths = this; var ths = this;
// console.log("[CommsServer::ctor] INIT! are we in ff?", BrowserDetect.firefox, "BrowserDetect says ...", BrowserDetect)
if (BrowserDetect.firefox) { if (BrowserDetect.firefox) {
browser.runtime.onConnect.addListener(p => ths.onConnect(p)); browser.runtime.onConnect.addListener(p => ths.onConnect(p));
browser.runtime.onMessage.addListener((m, sender) => ths.processReceivedMessage_nonpersistent(m, sender)); browser.runtime.onMessage.addListener((m, sender) => ths.processReceivedMessage_nonpersistent(m, sender));
@ -20,20 +19,8 @@ class CommsServer {
} }
} }
async toObject(obj) {
// console.log("(not actually) CLONING OBJECT", obj);
// try {
// const r = JSON.parse(JSON.stringify(obj));
// return r;
// } catch (e) {
// console.log("ERROR WHILE CLONING", obj);
return obj;
// }
}
async getCurrentTabHostname() { async getCurrentTabHostname() {
const activeTab = await this._getActiveTab(); const activeTab = await this._getActiveTab();
const url = activeTab[0].url; const url = activeTab[0].url;
var hostname; var hostname;
@ -52,7 +39,6 @@ class CommsServer {
} }
sendToAll(message){ sendToAll(message){
message = JSON.parse(JSON.stringify(message)); // vue quirk. We should really use vue store instead
for(var p of this.ports){ for(var p of this.ports){
for(var frame in p){ for(var frame in p){
p[frame].postMessage(message); p[frame].postMessage(message);
@ -74,10 +60,7 @@ class CommsServer {
} }
async sendToFrame(message, tab, frame) { async sendToFrame(message, tab, frame) {
// message = JSON.parse(JSON.stringify(message)); // vue quirk. We should really use vue store instead this.logger.log('info', 'CommsServer', `%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
if(Debug.debug && Debug.comms){
console.log(`%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
}
if (isNaN(tab)) { if (isNaN(tab)) {
if (tab === '__playing') { if (tab === '__playing') {
@ -91,33 +74,23 @@ class CommsServer {
[tab, frame] = tab.split('-') [tab, frame] = tab.split('-')
} }
if(Debug.debug && Debug.comms){ this.logger.log('info', 'CommsServer', `%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
console.log(`%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
}
try { try {
this.ports[tab][frame].postMessage(message); this.ports[tab][frame].postMessage(message);
} catch (e) { } catch (e) {
if(Debug.debug && Debug.comms){ this.logger.log('error', 'CommsServer', `%c[CommsServer::sendToFrame] Sending message failed. Reason:`, "background: #dda; color: #11D", e);
console.log(`%c[CommsServer::sendToFrame] Sending message failed. Reason:`, "background: #dda; color: #11D", e);
}
} }
} }
async sendToActive(message) { async sendToActive(message) {
message = JSON.parse(JSON.stringify(message)); // vue quirk. We should really use vue store instead this.logger.log('info', 'CommsServer', "%c[CommsServer::sendToActive] trying to send a message to active tab. Message:", "background: #dda; color: #11D", message);
if(Debug.debug && Debug.comms){
console.log("%c[CommsServer::sendToActive] trying to send a message to active tab. Message:", "background: #dda; color: #11D", message);
}
var tabs = await this._getActiveTab(); var tabs = await this._getActiveTab();
if(Debug.debug && Debug.comms){ this.logger.log('info', 'CommsServer', "[CommsServer::_sendToActive] currently active tab(s)?", tabs);
console.log("[CommsServer::_sendToActive] currently active tab(s)?", tabs); for (var key in this.ports[tabs[0].id]) {
for (var key in this.ports[tabs[0].id]) { this.logger.log('info', 'CommsServer', "key?", key, this.ports[tabs[0].id]);
console.log("key?", key, this.ports[tabs[0].id]);
}
} }
for (var key in this.ports[tabs[0].id]) { for (var key in this.ports[tabs[0].id]) {
@ -151,27 +124,19 @@ class CommsServer {
} }
async processReceivedMessage(message, port){ async processReceivedMessage(message, port){
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "[CommsServer.js::processReceivedMessage] Received message from popup/content script!", message, "port", port, "\nsettings and server:", this.settings,this.server);
console.log("[CommsServer.js::processReceivedMessage] Received message from popup/content script!", message, "port", port, "\nsettings and server:", this.settings,this.server);
}
if (message.forwardToContentScript) { if (message.forwardToContentScript) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "[CommsServer.js::processReceivedMessage] Message has 'forward to content script' flag set. Forwarding message as is. Message:", message);
console.log("[CommsServer.js::processReceivedMessage] Message has 'forward to content script' flag set. Forwarding message as is. Message:", message);
}
this.sendToFrame(message, message.targetTab, message.targetFrame); this.sendToFrame(message, message.targetTab, message.targetFrame);
} }
if (message.forwardToAll) { if (message.forwardToAll) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "[CommsServer.js::processReceivedMessage] Message has 'forward to all' flag set. Forwarding message as is. Message:", message);
console.log("[CommsServer.js::processReceivedMessage] Message has 'forward to all' flag set. Forwarding message as is. Message:", message);
}
this.sendToAll(message); this.sendToAll(message);
} }
if (message.forwardToActive) { if (message.forwardToActive) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "[CommsServer.js::processReceivedMessage] Message has 'forward to active' flag set. Forwarding message as is. Message:", message);
console.log("[CommsServer.js::processReceivedMessage] Message has 'forward to active' flag set. Forwarding message as is. Message:", message);
}
this.sendToActive(message) this.sendToActive(message)
} }
@ -198,9 +163,7 @@ class CommsServer {
} }
if (message.cmd === 'get-config') { if (message.cmd === 'get-config') {
if(Debug.debug) { this.logger.log('info', 'CommsServer', "CommsServer: received get-config. Active settings?", this.settings.active, "\n(settings:", this.settings, ")");
console.log("CommsServer: received get-config. Active settings?", this.settings.active, "\n(settings:", this.settings, ")")
}
port.postMessage( port.postMessage(
{cmd: "set-config", conf: this.settings.active, site: this.server.currentSite} {cmd: "set-config", conf: this.settings.active, site: this.server.currentSite}
); );
@ -212,9 +175,7 @@ class CommsServer {
} }
processReceivedMessage_nonpersistent(message, sender, sendResponse){ processReceivedMessage_nonpersistent(message, sender, sendResponse){
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "%c[CommsServer.js::processMessage_nonpersistent] Received message from background script!", "background-color: #11D; color: #aad", message, sender);
console.log("%c[CommsServer.js::processMessage_nonpersistent] Received message from background script!", "background-color: #11D; color: #aad", message, sender);
}
if (message.cmd === 'inject-css') { if (message.cmd === 'inject-css') {
this.server.injectCss(message.cssString, sender); this.server.injectCss(message.cssString, sender);
@ -229,10 +190,8 @@ class CommsServer {
} }
if (message.forwardToContentScript) { if (message.forwardToContentScript) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "[CommsServer.js::processMessage_nonpersistent] Message has 'forward to content script' flag set. Forwarding message as is. Message:", message);
console.log("[CommsServer.js::processMessage_nonpersistent] Message has 'forward to content script' flag set. Forwarding message as is. Message:", message); this.logger.log('info', 'CommsServer', "[CommsServer.js::processMessage_nonpersistent] (btw we probably shouldn't be seeing this. This should prolly happen in persistent connection?");
console.log("[CommsServer.js::processMessage_nonpersistent] (btw we probably shouldn't be seeing this. This should prolly happen in persistent connection?");
}
this.sendToFrame(message, message.targetFrame); this.sendToFrame(message, message.targetFrame);
} }
@ -240,9 +199,7 @@ class CommsServer {
if (message.cmd === 'get-config') { if (message.cmd === 'get-config') {
if (BrowserDetect.firefox) { if (BrowserDetect.firefox) {
var ret = {extensionConf: JSON.stringify(this.settings.active)}; var ret = {extensionConf: JSON.stringify(this.settings.active)};
if (Debug.debug && Debug.comms) { this.logger.log('info', 'CommsServer', "%c[CommsServer.js::processMessage_nonpersistent] Returning this:", "background-color: #11D; color: #aad", ret);
console.log("%c[CommsServer.js::processMessage_nonpersistent] Returning this:", "background-color: #11D; color: #aad", ret);
}
Promise.resolve(ret); Promise.resolve(ret);
} else { } else {
sendResponse({extensionConf: JSON.stringify(this.settings.active)}); sendResponse({extensionConf: JSON.stringify(this.settings.active)});
@ -252,9 +209,7 @@ class CommsServer {
this.settings.active.sites['@global'].autoar = "blacklist"; this.settings.active.sites['@global'].autoar = "blacklist";
this.settings.save(); this.settings.save();
this.sendToAll({cmd: "reload-settings", sender: "uwbg"}) this.sendToAll({cmd: "reload-settings", sender: "uwbg"})
if(Debug.debug){ this.logger.log('info', 'CommsServer', "[uw-bg] autoar set to enabled (blacklist). evidenz:", this.settings.active);
console.log("[uw-bg] autoar set to enabled (blacklist). evidenz:", this.settings.active);
}
} else if (message.cmd === "autoar-disable") { } else if (message.cmd === "autoar-disable") {
this.settings.active.sites['@global'].autoar = "disabled"; this.settings.active.sites['@global'].autoar = "disabled";
if(message.reason){ if(message.reason){
@ -264,13 +219,10 @@ class CommsServer {
} }
this.settings.save(); this.settings.save();
this.sendToAll({cmd: 'reload-settings', newConf: this.settings.active}); this.sendToAll({cmd: 'reload-settings', newConf: this.settings.active});
if(Debug.debug){ this.logger.log('info', 'CommsServer', "[uw-bg] autoar set to disabled. evidenz:", this.settings.active);
console.log("[uw-bg] autoar set to disabled. evidenz:", this.settings.active);
}
} else if (message.cmd === "autoar-set-interval") { } else if (message.cmd === "autoar-set-interval") {
if (Debug.debug) { this.logger.log('info', 'CommsServer', `[uw-bg] trying to set new interval for autoAr. New interval is, ${message.timeout} ms`);
console.log("[uw-bg] trying to set new interval for autoAr. New interval is",message.timeout,"ms");
}
// set fairly liberal limit // set fairly liberal limit
var timeout = message.timeout < 4 ? 4 : message.timeout; var timeout = message.timeout < 4 ? 4 : message.timeout;
this.settings.active.arDetect.timer_playing = timeout; this.settings.active.arDetect.timer_playing = timeout;

View File

@ -9,7 +9,8 @@ if(Debug.debug)
class PageInfo { class PageInfo {
constructor(comms, settings, extensionMode, readOnly = false){ constructor(comms, settings, logger, extensionMode, readOnly = false){
this.logger = logger;
this.hasVideos = false; this.hasVideos = false;
this.siteDisabled = false; this.siteDisabled = false;
this.videos = []; this.videos = [];
@ -20,6 +21,7 @@ class PageInfo {
this.extensionMode = extensionMode; this.extensionMode = extensionMode;
this.readOnly = readOnly; this.readOnly = readOnly;
if (comms){ if (comms){
this.comms = comms; this.comms = comms;
} }
@ -64,9 +66,7 @@ class PageInfo {
} }
destroy() { destroy() {
if(Debug.debug || Debug.init){ this.logger.log('info', ['debug', 'init'], "[PageInfo::destroy] destroying all videos!")
console.log("[PageInfo::destroy] destroying all videos!")
}
if(this.rescanTimer){ if(this.rescanTimer){
clearTimeout(this.rescanTimer); clearTimeout(this.rescanTimer);
} }
@ -75,7 +75,7 @@ class PageInfo {
this.comms.unregisterVideo(video.id) this.comms.unregisterVideo(video.id)
video.destroy(); video.destroy();
} catch (e) { } catch (e) {
console.log("unabel to destroy video!", e) this.logger.log('error', ['debug', 'init'], '[PageInfo::destroy] unable to destroy video! Error:', e);
} }
} }
@ -138,97 +138,95 @@ class PageInfo {
const oldVideoCount = this.videos.length; const oldVideoCount = this.videos.length;
try{ try{
var vids = this.getVideos(window.location.host); var vids = this.getVideos(window.location.host);
if(!vids || vids.length == 0){ if(!vids || vids.length == 0){
this.hasVideos = false;
if(rescanReason == RescanReason.PERIODIC){
this.logger.log('info', 'videoRescan', "[PageInfo::rescan] Scheduling normal rescan.")
this.scheduleRescan(RescanReason.PERIODIC);
}
return;
}
// add new videos
this.hasVideos = false; this.hasVideos = false;
var videoExists = false;
if(rescanReason == RescanReason.PERIODIC){ var video, v;
if (Debug.debug && Debug.videoRescan && Debug.periodic) {
console.log("[PageInfo::rescan] Scheduling normal rescan:")
}
this.scheduleRescan(RescanReason.PERIODIC);
}
return;
}
// add new videos for (video of vids) {
this.hasVideos = false; // če najdemo samo en video z višino in širino, to pomeni, da imamo na strani veljavne videe
var videoExists = false; // če trenutni video nima definiranih teh vrednostih, preskočimo vse nadaljnja preverjanja
var video, v; // <===[:::::::]===>
// if we find even a single video with width and height, that means the page has valid videos
// if video lacks either of the two properties, we skip all further checks cos pointless
if(video.offsetWidth && video.offsetHeight){
this.hasVideos = true;
for (video of vids) { if (this.readOnly) {
// če najdemo samo en video z višino in širino, to pomeni, da imamo na strani veljavne videe // in lite mode, we're done. This is all the info we want, but we want to actually start doing
// če trenutni video nima definiranih teh vrednostih, preskočimo vse nadaljnja preverjanja // things that interfere with the website. We still want to be runnig a rescan, tho.
// <===[:::::::]===>
// if we find even a single video with width and height, that means the page has valid videos
// if video lacks either of the two properties, we skip all further checks cos pointless
if(video.offsetWidth && video.offsetHeight){
this.hasVideos = true;
if (this.readOnly) { if(rescanReason == RescanReason.PERIODIC){
// in lite mode, we're done. This is all the info we want, but we want to actually start doing this.scheduleRescan(RescanReason.PERIODIC);
// things that interfere with the website. We still want to be runnig a rescan, tho. }
return;
if(rescanReason == RescanReason.PERIODIC){
this.scheduleRescan(RescanReason.PERIODIC);
} }
return;
}
} else {
continue;
}
videoExists = false;
for (v of this.videos) {
if (v.destroyed) {
continue; //TODO: if destroyed video is same as current video, copy aspect ratio settings to current video
}
if (v.video == video) {
videoExists = true;
break;
}
}
if (videoExists) {
continue;
} else {
if (Debug.debug && Debug.periodic && Debug.videoRescan) {
console.log("[PageInfo::rescan] found new video candidate:", video, "NOTE:: Video initialization starts here:\n--------------------------------\n")
}
v = new VideoData(video, this.settings, this);
// console.log("[PageInfo::rescan] v is:", v)
v.initArDetection();
this.videos.push(v);
if(Debug.debug && Debug.periodic && Debug.videoRescan){
console.log("[PageInfo::rescan] END VIDEO INITIALIZATION\n\n\n-------------------------------------\nvideos[] is now this:", this.videos,"\n\n\n\n\n\n\n\n")
}
}
}
this.removeDestroyed();
// če smo ostali brez videev, potem odregistriraj stran.
// če nismo ostali brez videev, potem registriraj stran.
//
// if we're left withotu videos on the current page, we unregister the page.
// if we have videos, we call register.
// if(Debug.debug) {
// console.log("[PageInfo::rescan] Comms:", this.comms, "\nvideos.length:", this.videos.length, "\nold video count:", oldVideoCount)
// }
if (this.comms) {
if (this.videos.length != oldVideoCount) { // only if number of videos changed, tho
if (this.videos.length > 0) {
this.comms.registerVideo({host: window.location.host, location: window.location});
} else { } else {
this.comms.unregisterVideo({host: window.location.host, location: window.location}); continue;
}
videoExists = false;
for (v of this.videos) {
if (v.destroyed) {
continue; //TODO: if destroyed video is same as current video, copy aspect ratio settings to current video
}
if (v.video == video) {
videoExists = true;
break;
}
}
if (videoExists) {
continue;
} else {
this.logger.log('info', 'videoRescan', "[PageInfo::rescan] found new video candidate:", video, "NOTE:: Video initialization starts here:\n--------------------------------\n")
try {
v = new VideoData(video, this.settings, this);
if (!v.invalid) {
v.initArDetection();
} else {
this.logger.log('error', 'debug', 'Video is invalid. Aard not started.', video);
}
this.videos.push(v);
} catch (e) {
this.logger.log('error', 'debug', "rescan error: failed to initialize videoData. Skipping this video.",e);
}
this.logger.log('info', 'videoRescan', "END VIDEO INITIALIZATION\n\n\n-------------------------------------\nvideos[] is now this:", this.videos,"\n\n\n\n\n\n\n\n")
}
}
this.removeDestroyed();
// če smo ostali brez videev, potem odregistriraj stran.
// če nismo ostali brez videev, potem registriraj stran.
//
// if we're left withotu videos on the current page, we unregister the page.
// if we have videos, we call register.
if (this.comms) {
if (this.videos.length != oldVideoCount) { // only if number of videos changed, tho
if (this.videos.length > 0) {
this.comms.registerVideo({host: window.location.host, location: window.location});
} else {
this.comms.unregisterVideo({host: window.location.host, location: window.location});
}
} }
} }
}
} catch(e) { } catch(e) {
// če pride do zajeba, potem lahko domnevamo da na strani ni nobenega videa. Uničimo vse objekte videoData // če pride do zajeba, potem lahko domnevamo da na strani ni nobenega videa. Uničimo vse objekte videoData
@ -238,9 +236,7 @@ class PageInfo {
// if we encounter a fuckup, we can assume that no videos were found on the page. We destroy all videoData // if we encounter a fuckup, we can assume that no videos were found on the page. We destroy all videoData
// objects to prevent multiple initalization (which happened, but I don't know why). No biggie if we destroyed // objects to prevent multiple initalization (which happened, but I don't know why). No biggie if we destroyed
// videoData objects in error — they'll be back in the next rescan // videoData objects in error — they'll be back in the next rescan
if (Debug.debug) { this.logger.log('error', 'debug', "rescan error: — destroying all videoData objects",e);
console.log("rescan error: — destroying all videoData objects",e);
}
for (const v of this.videos) { for (const v of this.videos) {
v.destroy(); v.destroy();
} }
@ -275,9 +271,7 @@ class PageInfo {
ths = null; ths = null;
}, this.settings.active.pageInfo.timeouts.rescan, RescanReason.PERIODIC) }, this.settings.active.pageInfo.timeouts.rescan, RescanReason.PERIODIC)
} catch(e) { } catch(e) {
if(Debug.debug){ this.logger.log('error', 'debug', "[PageInfo::scheduleRescan] scheduling rescan failed. Here's why:",e)
console.log("[PageInfo::scheduleRescan] scheduling rescan failed. Here's why:",e)
}
} }
} }
@ -289,23 +283,19 @@ class PageInfo {
var ths = this; var ths = this;
this.rescanTimer = setTimeout(function(){ this.urlCheckTimer = setTimeout(function(){
ths.rescanTimer = null; ths.urlCheckTimer = null;
ths.ghettoUrlCheck(); ths.ghettoUrlCheck();
ths = null; ths = null;
}, this.settings.active.pageInfo.timeouts.urlCheck) }, this.settings.active.pageInfo.timeouts.urlCheck)
} catch(e){ } catch(e){
if(Debug.debug){ this.logger.log('error', 'debug', "[PageInfo::scheduleUrlCheck] scheduling URL check failed. Here's why:",e)
console.error("[PageInfo::scheduleUrlCheck] scheduling URL check failed. Here's why:",e)
}
} }
} }
ghettoUrlCheck() { ghettoUrlCheck() {
if (this.lastUrl != window.location.href){ if (this.lastUrl != window.location.href){
if(Debug.debug && Debug.periodic){ this.logger.log('error', 'videoRescan', "[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!");
console.log("[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!");
}
this.rescan(RescanReason.URL_CHANGE); this.rescan(RescanReason.URL_CHANGE);
this.lastUrl = window.location.href; this.lastUrl = window.location.href;
@ -369,7 +359,7 @@ class PageInfo {
startArDetection(playingOnly){ startArDetection(playingOnly){
if (Debug.debug) { if (Debug.debug) {
console.log('[PageInfo::startArDetection()] starting automatic ar detection!') this.logger.log('info', 'debug', '[PageInfo::startArDetection()] starting automatic ar detection!')
} }
if (playingOnly) { if (playingOnly) {
for(var vd of this.videos){ for(var vd of this.videos){
@ -399,16 +389,12 @@ class PageInfo {
} }
setAr(ar, playingOnly){ setAr(ar, playingOnly){
if (Debug.debug) { this.logger.log('info', 'debug', '[PageInfo::setAr] aspect ratio:', ar, "playing only?", playingOnly)
console.log('[PageInfo::setAr] aspect ratio:', ar, "playing only?", playingOnly)
}
if (ar.type !== AspectRatio.Automatic) { if (ar.type !== AspectRatio.Automatic) {
this.stopArDetection(playingOnly); this.stopArDetection(playingOnly);
} else { } else {
if (Debug.debug) { this.logger.log('info', 'debug', '[PageInfo::setAr] aspect ratio is auto');
console.log('[PageInfo::setAr] aspect ratio is auto');
}
try { try {
for (var vd of this.videos) { for (var vd of this.videos) {
@ -417,7 +403,7 @@ class PageInfo {
} }
} }
} catch (e) { } catch (e) {
console.log("???", e); this.logger.log('error', 'debug', "???", e);
} }
this.initArDetection(playingOnly); this.initArDetection(playingOnly);
this.startArDetection(playingOnly); this.startArDetection(playingOnly);
@ -440,16 +426,16 @@ class PageInfo {
} }
} }
setvideoAlignment(videoAlignment, playingOnly) { setVideoAlignment(videoAlignment, playingOnly) {
if (playingOnly) { if (playingOnly) {
for(var vd of this.videos) { for(var vd of this.videos) {
if (vd.isPlaying()) { if (vd.isPlaying()) {
vd.setvideoAlignment(videoAlignment) vd.setVideoAlignment(videoAlignment)
} }
} }
} else { } else {
for(var vd of this.videos) { for(var vd of this.videos) {
vd.setvideoAlignment(videoAlignment) vd.setVideoAlignment(videoAlignment)
} }
} }
} }

View File

@ -34,24 +34,49 @@ if(Debug.debug)
class PlayerData { class PlayerData {
constructor(videoData) { constructor(videoData) {
this.videoData = videoData; try {
this.video = videoData.video; this.logger = videoData.logger;
this.settings = videoData.settings; this.videoData = videoData;
this.extensionMode = videoData.extensionMode; this.video = videoData.video;
this.element = undefined; this.settings = videoData.settings;
this.dimensions = undefined; this.extensionMode = videoData.extensionMode;
this.overlayNode = undefined; this.invalid = false;
this.element = this.getPlayer();
this.dimensions = undefined;
this.overlayNode = undefined;
if (this.extensionMode === ExtensionMode.Enabled) { // this happens when we don't find a matching player element
this.getPlayerDimensions(); if (!this.element) {
this.invalid = true;
return;
}
if (this.extensionMode === ExtensionMode.Enabled) {
this.checkPlayerSizeChange();
}
this.startChangeDetection();
} catch (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.startChangeDetection();
} }
async sleep(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);
} }
// player size observer may not be strictly necessary here
onPlayerDimensionsChanged(mutationList, observer, context) {
if (context.checkPlayerSizeChange()) {
context.videoData.resizer.restore();
}
}
start(){ start(){
this.startChangeDetection(); this.startChangeDetection();
@ -68,10 +93,47 @@ class PlayerData {
} }
startChangeDetection(){ startChangeDetection(){
this.scheduleGhettoWatcher(); if (this.invalid) {
return;
}
try {
const ths = this;
this.observer = new MutationObserver((m,o) => this.onPlayerDimensionsChanged(m,o,ths));
const observerConf = {
attributes: true,
// attributeFilter: ['style', 'class'],
attributeOldValue: true,
};
this.observer.observe(this.element, observerConf);
} catch (e) {
console.error("failed to set observer",e )
} }
// legacy mode still exists, but acts as a fallback for observers and is triggered less
// frequently in order to avoid too many pointless checks
this.legacyChangeDetection();
}
async legacyChangeDetection() {
console.log("starting legacy cd")
while (!this.halted) {
console.log("loop")
await this.sleep(1000);
try {
if (this.checkPlayerSizeChange()) {
this.videoData.resizer.restore();
}
} catch (e) {
console.error('[playerdata::legacycd] this message is pretty high on the list of messages you shouldnt see', e);
}
}
console.log("HALTED - STOPPING CHANGE DETECTION FOR", this.element)
}
stopChangeDetection(){ stopChangeDetection(){
clearTimeout(this.watchTimeout); this.observer.disconnect();
} }
makeOverlay() { makeOverlay() {
@ -117,113 +179,13 @@ class PlayerData {
} }
unmarkPlayer() { unmarkPlayer() {
if (Debug.debug) { this.logger.log('info', 'debug', "[PlayerData::unmarkPlayer] unmarking player!")
console.log("[PlayerData::unmarkPlayer] unmarking player!")
}
if (this.playerIdElement) { if (this.playerIdElement) {
this.playerIdElement.remove(); this.playerIdElement.remove();
} }
this.playerIdElement = undefined; this.playerIdElement = undefined;
} }
scheduleGhettoWatcher(timeout, force_reset) {
if(! timeout){
timeout = 100;
}
if(this.halted){
return;
}
// don't allow more than 1 instance
if(this.watchTimeout){
clearTimeout(this.watchTimeout);
}
var ths = this;
this.watchTimeout = setTimeout(function(){
ths.watchTimeout = null;
try{
ths.ghettoWatcher();
} catch(e) {
if (Debug.debug) {
console.log("[PlayerData::scheduleGhettoWatcher] Scheduling failed. Error:",e)
}
ths.scheduleGhettoWatcher(1000);
}
ths = null;
},
timeout
);
}
ghettoWatcherFull() {
if(this.checkPlayerSizeChange()){
if(Debug.debug){
console.log("[uw::ghettoOnChange] change detected");
}
this.getPlayerDimensions();
if(! this.element ){
return;
}
this.videoData.resizer.restore(); // note: this returns true if change goes through, false otherwise.
return;
}
// sem ter tja, checkPlayerSizeChange() ne zazna prehoda v celozaslonski način (in iz njega). Zato moramo
// uporabiti dodatne trike.
// sometimes, checkPlayerSizeChange might not detect a change to fullscreen. This means we need to
// trick it into doing that
if(this.dimensions.fullscreen != PlayerData.isFullScreen()) {
if(Debug.debug){
console.log("[PlayerData::ghettoWatcher] fullscreen switch detected (basic change detection failed)");
}
this.getPlayerDimensions();
if(! this.element ){
return;
}
this.videoData.resizer.restore();
}
}
ghettoWatcherBasic() {
if (this.checkFullscreenChange()) {
if (PlayerData.isFullScreen()) {
const lastAr = this.videoData.resizer.getLastAr(); // save last ar for restore later
this.videoData.resizer.restore();
if (lastAr.type === 'original' || lastAr.type === AspectRatio.Automatic) {
this.videoData.rebootArDetection();
}
} else {
const lastAr = this.videoData.resizer.getLastAr(); // save last ar for restore later
this.videoData.resizer.reset();
this.videoData.resizer.stop();
this.videoData.stopArDetection();
this.videoData.resizer.setLastAr(lastAr);
}
}
}
ghettoWatcher(){
if (this.extensionMode === ExtensionMode.Enabled) {
this.ghettoWatcherFull();
this.scheduleGhettoWatcher();
} else if (this.extensionMode === ExtensionMode.Basic) {
this.ghettoWatcherBasic();
this.scheduleGhettoWatcher();
}
}
collectionHas(collection, element) { collectionHas(collection, element) {
for (let i = 0, len = collection.length; i < len; i++) { for (let i = 0, len = collection.length; i < len; i++) {
if (collection[i] == element) { if (collection[i] == element) {
@ -233,7 +195,7 @@ class PlayerData {
return false; return false;
} }
getPlayer(isFullScreen) { getPlayer() {
const host = window.location.host; const host = window.location.host;
let element = this.video.parentNode; let element = this.video.parentNode;
const videoWidth = this.video.offsetWidth, videoHeight = this.video.offsetHeight; const videoWidth = this.video.offsetWidth, videoHeight = this.video.offsetHeight;
@ -241,197 +203,180 @@ class PlayerData {
let scorePenalty = 0; let scorePenalty = 0;
let score; let score;
if(! element ){ try {
if(Debug.debug) { if(! element ){
console.log("[PlayerDetect::_pd_getPlayer] element is not valid, doing nothing.", element) this.logger.log('info', 'debug', "[PlayerDetect::_pd_getPlayer] element is not valid, doing nothing.", element)
} if(this.element) {
if(this.element) { const ths = this;
const ths = this;
}
this.element = undefined;
this.dimensions = undefined;
return;
}
if (this.settings.active.sites[host]
&& this.settings.active.sites[host].DOM
&& this.settings.active.sites[host].DOM.player
&& this.settings.active.sites[host].DOM.player.manual) {
if (this.settings.active.sites[host].DOM.player.useRelativeAncestor
&& this.settings.active.sites[host].DOM.player.videoAncestor) {
let parentsLeft = this.settings.active.sites[host].DOM.player.videoAncestor - 1;
while (parentsLeft --> 0) {
element = element.parentNode;
} }
if (element) { this.element = undefined;
return element; this.dimensions = undefined;
} return;
} else if (this.settings.active.sites[host].DOM.player.querySelectors) { }
const allSelectors = document.querySelectorAll(this.settings.active.sites[host].DOM.player.querySelectors);
// actually we'll also score this branch in a similar way we score the regular, auto branch if (this.settings.active.sites[host]
while (element) { && this.settings.active.sites[host].DOM
&& this.settings.active.sites[host].DOM.player
&& this.settings.active.sites[host].DOM.player.manual) {
if (this.settings.active.sites[host].DOM.player.useRelativeAncestor
&& this.settings.active.sites[host].DOM.player.videoAncestor) {
// Let's see how this works let parentsLeft = this.settings.active.sites[host].DOM.player.videoAncestor - 1;
if (this.collectionHas(allSelectors, element)) { while (parentsLeft --> 0) {
score = 100; // every matching element gets a baseline 100 points element = element.parentNode;
}
// elements that match the size get a hefty bonus if (element) {
if ( (element.offsetWidth >= videoWidth && this.equalish(element.offsetHeight, videoHeight, 2)) return element;
|| (element.offsetHeight >= videoHeight && this.equalish(element.offsetWidth, videoHeight, 2))) { }
score += 75; } else if (this.settings.active.sites[host].DOM.player.querySelectors) {
const allSelectors = document.querySelectorAll(this.settings.active.sites[host].DOM.player.querySelectors);
// actually we'll also score this branch in a similar way we score the regular, auto branch
while (element) {
// Let's see how this works
if (this.collectionHas(allSelectors, element)) {
score = 100; // every matching element gets a baseline 100 points
// elements that match the size get a hefty bonus
if ( (element.offsetWidth >= videoWidth && this.equalish(element.offsetHeight, videoHeight, 2))
|| (element.offsetHeight >= videoHeight && this.equalish(element.offsetWidth, videoHeight, 2))) {
score += 75;
}
// elements farther away from the video get a penalty
score -= (scorePenalty++) * 20;
// push the element on the queue/stack:
elementQ.push({
score: score,
element: element,
});
} }
// elements farther away from the video get a penalty element = element.parentNode;
score -= (scorePenalty++) * 20;
// push the element on the queue/stack:
elementQ.push({
score: score,
element: element,
});
} }
if (elementQ.length) {
// return element with biggest score
// if video player has not been found, proceed to automatic detection
return elementQ.sort( (a,b) => b.score - a.score)[0].element;
}
}
}
// try to find element the old fashioned way
while (element){
// odstranimo čudne elemente, ti bi pokvarili zadeve
// remove weird elements, those would break our stuff
if ( element.offsetWidth == 0 || element.offsetHeight == 0){
element = element.parentNode; element = element.parentNode;
continue;
} }
if (elementQ.length) {
// return element with biggest score
// if video player has not been found, proceed to automatic detection
return elementQ.sort( (a,b) => b.score - a.score)[0].element;
}
}
}
// element je player, če je ena stranica enako velika kot video, druga pa večja ali enaka.
// za enakost dovolimo mala odstopanja
// element is player, if one of the sides is as long as the video and the other bigger (or same)
// we allow for tiny variations when checking for equality
if ( (element.offsetWidth >= videoWidth && this.equalish(element.offsetHeight, videoHeight, 2))
|| (element.offsetHeight >= videoHeight && this.equalish(element.offsetWidth, videoHeight, 2))) {
// todo — in case the match is only equalish and not exact, take difference into account when
// calculating score
score = 100;
while (element){
// odstranimo čudne elemente, ti bi pokvarili zadeve if (element.id.indexOf('player') !== -1) { // prefer elements with 'player' in id
// remove weird elements, those would break our stuff score += 75;
if ( element.offsetWidth == 0 || element.offsetHeight == 0){ }
// this has only been observed on steam
if (element.id.indexOf('movie') !== -1) {
score += 75;
}
if (element.classList.toString().indexOf('player') !== -1) { // prefer elements with 'player' in classlist, but a bit less than id
score += 50;
}
score -= scorePenalty++; // prefer elements closer to <video>
elementQ.push({
element: element,
score: score,
});
}
element = element.parentNode; element = element.parentNode;
continue;
} }
// element je player, če je ena stranica enako velika kot video, druga pa večja ali enaka.
// za enakost dovolimo mala odstopanja
// element is player, if one of the sides is as long as the video and the other bigger (or same)
// we allow for tiny variations when checking for equality
if ( (element.offsetWidth >= videoWidth && this.equalish(element.offsetHeight, videoHeight, 2))
|| (element.offsetHeight >= videoHeight && this.equalish(element.offsetWidth, videoHeight, 2))) {
// todo — in case the match is only equalish and not exact, take difference into account when
// calculating score
score = 100;
if (element.id.indexOf('player') !== -1) { // prefer elements with 'player' in id if (elementQ.length) {
score += 75; // return element with biggest score
} return elementQ.sort( (a,b) => b.score - a.score)[0].element;
if (element.classList.toString().indexOf('player') !== -1) { // prefer elements with 'player' in classlist, but a bit less than id
score += 50;
}
score -= scorePenalty++; // prefer elements closer to <video>
elementQ.push({
element: element,
score: score,
});
} }
element = element.parentNode;
}
if (elementQ.length) { // if no candidates were found, something is obviously very, _very_ wrong.
// return element with biggest score // we return nothing. Player will be marked as invalid and setup will stop.
return elementQ.sort( (a,b) => b.score - a.score)[0].element; // VideoData should check for that before starting anything.
this.logger.log('warn', 'debug', '[PlayerData::getPlayer] no matching player was found for video', this.video, 'Extension cannot work on this site.');
return;
} catch (e) {
this.logger.log('crit', 'debug', '[PlayerData::getPlayer] something went wrong while detecting player:', e, 'Shutting down extension for this page');
} }
// if no candidates were found, return parent node
return this.video.parentNode;
} }
equalish(a,b, tolerance) { equalish(a,b, tolerance) {
return a > b - tolerance && a < b + tolerance; return a > b - tolerance && a < b + tolerance;
} }
getPlayerDimensions(){
const isFullScreen = PlayerData.isFullScreen();
const element = this.getPlayer(isFullScreen);
if(! element ){
if(Debug.debug) {
console.log("[PlayerDetect::getPlayerDimensions] element is not valid, doing nothing.", element)
}
this.element = undefined;
this.dimensions = undefined;
return;
}
if (isFullScreen) {
this.dimensions = {
width: window.innerWidth,
height: window.innerHeight,
fullscreen: true
}
if (this.element != element) {
this.element = element;
this.makeOverlay()
}
} else {
this.dimensions = {
width: element.offsetWidth,
height: element.offsetHeight,
fullscreen: isFullScreen
};
if(this.element != element) {
this.element = element;
this.makeOverlay();
}
}
}
forceRefreshPlayerElement() { forceRefreshPlayerElement() {
this.getPlayerDimensions(); this.checkPlayerSizeChange();
} }
checkPlayerSizeChange(){ checkPlayerSizeChange(){
if(Debug.debug){ // this 'if' is just here for debugging — real code starts later. It's safe to collapse and
if(this.element == undefined){ // ignore the contents of this if (unless we need to change how logging works)
// return true; if (this.logger.canLog('debug')){
} if (!this.dimensions) {
// if(!this.dimensions) {
// return true;
// }
if (this.dimensions && this.dimensions.fullscreen){ } else if (this.dimensions && this.dimensions.fullscreen){
if(! PlayerData.isFullScreen()){ if(! PlayerData.isFullScreen()){
console.log("[PlayerDetect] player size changed. reason: exited fullscreen"); this.logger.log('info', 'debug', "[PlayerDetect] player size changed. reason: exited fullscreen");
} }
} }
if(! this.element && Debug.debug && Debug.playerDetect) { if(! this.element) {
console.log("[PlayerDetect] player element isnt defined"); this.logger.log('info', 'playerDetect', "[PlayerDetect] player element isn't defined");
} }
if ( this.element && if ( this.element && this.dimensions &&
( this.dimensions.width != this.element.offsetWidth || ( this.dimensions.width != this.element.offsetWidth ||
this.dimensions.height != this.element.offsetHeight ) this.dimensions.height != this.element.offsetHeight )
) { ) {
console.log("[PlayerDetect] player size changed. reason: dimension change. Old dimensions?", this.dimensions.width, this.dimensions.height, "new dimensions:", this.element.offsetWidth, this.element.offsetHeight); this.logger.log('info', 'debug', "[PlayerDetect] player size changed. reason: dimension change. Old dimensions?", this.dimensions.width, this.dimensions.height, "new dimensions:", this.element.offsetWidth, this.element.offsetHeight);
} }
} }
if(this.element == undefined){
this.element = this.getPlayer(); // if size doesn't match, update & return true
return true; if (!this.dimensions
} else if(this.dimensions.width != this.element.offsetWidth || this.dimensions.height != this.element.offsetHeight ){ || this.dimensions.width != this.element.offsetWidth
this.element = this.getPlayer(); || this.dimensions.height != this.element.offsetHeight ){
const isFullScreen = PlayerData.isFullScreen();
if (isFullScreen) {
this.dimensions = {
width: window.innerWidth,
height: window.innerHeight,
fullscreen: true
}
} else {
this.dimensions = {
width: this.element.offsetWidth,
height: this.element.offsetHeight,
fullscreen: isFullScreen
};
}
return true; return true;
} }
return false; return false;
} }
@ -450,9 +395,7 @@ class PlayerData {
return false; return false;
} }
if(Debug.debug) { this.logger.log('info', 'debug', "[PlayerData::checkFullscreenChange] this.dimensions is not defined. Assuming fs change happened and setting default values.")
console.log("[PlayerData::checkFullscreenChange] this.dimensions is not defined. Assuming fs change happened and setting default values.")
}
this.dimensions = { this.dimensions = {
fullscreen: isFs, fullscreen: isFs,

View File

@ -6,6 +6,8 @@ import ArDetector from '../ar-detect/ArDetector';
class VideoData { class VideoData {
constructor(video, settings, pageInfo){ constructor(video, settings, pageInfo){
this.vdid = (Math.random()*100).toFixed();
this.logger = pageInfo.logger;
this.arSetupComplete = false; this.arSetupComplete = false;
this.video = video; this.video = video;
this.destroyed = false; this.destroyed = false;
@ -13,85 +15,142 @@ class VideoData {
this.pageInfo = pageInfo; this.pageInfo = pageInfo;
this.extensionMode = pageInfo.extensionMode; this.extensionMode = pageInfo.extensionMode;
this.vdid = (Math.random()*100).toFixed();
this.userCssClassName = `uw-fuck-you-and-do-what-i-tell-you_${this.vdid}`; this.userCssClassName = `uw-fuck-you-and-do-what-i-tell-you_${this.vdid}`;
// We only init observers once player is confirmed valid
// We'll replace cssWatcher (in resizer) with mutationObserver
const observerConf = { const observerConf = {
attributes: true, attributes: true,
// attributeFilter: ['style', 'class'], // attributeFilter: ['style', 'class'],
attributeOldValue: true, attributeOldValue: true,
}; };
this.observer = new MutationObserver(this.onVideoDimensionsChanged);
this.observer.observe(video, observerConf);
// 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)
this.player = new PlayerData(this); this.player = new PlayerData(this);
this.resizer = new Resizer(this); if (this.player.invalid) {
this.invalid = true;
return;
}
const ths = this;
this.observer = new MutationObserver( (m, o) => this.onVideoDimensionsChanged(m, o, ths));
this.observer.observe(video, observerConf);
this.dimensions = {
width: this.video.offsetWidth,
height: this.video.offsetHeight,
};
this.resizer = new Resizer(this);
this.arDetector = new ArDetector(this); // this starts Ar detection. needs optional parameter that prevets ardetdctor from starting this.arDetector = new ArDetector(this); // this starts Ar detection. needs optional parameter that prevets ardetdctor from starting
// player dimensions need to be in: // player dimensions need to be in:
// this.player.dimensions // this.player.dimensions
// apply default align and stretch // apply default align and stretch
if (Debug.init) { this.logger.log('info', 'debug', "%c[VideoData::ctor] Initial resizer reset!", {background: '#afd', color: '#132'});
console.log("%c[VideoData::ctor] Initial resizer reset!", {background: '#afd', color: '#132'});
}
this.resizer.reset(); this.resizer.reset();
this.logger.log('info', ['debug', 'init'], '[VideoData::ctor] Created videoData with vdid', this.vdid, '\nextension mode:', this.extensionMode)
if (Debug.init) {
console.log("[VideoData::ctor] Created videoData with vdid", this.vdid,"\nextension mode:", this.extensionMode);
}
this.pageInfo.initMouseActionHandler(this); this.pageInfo.initMouseActionHandler(this);
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
this.fallbackChangeDetection();
} }
onVideoDimensionsChanged(mutationList, observer) { async fallbackChangeDetection() {
if (!mutationList || this.video === undefined) { // something's wrong while (!this.destroyed && !this.invalid) {
if (observer && this.video) { await this.sleep(500);
this.validateVideoOffsets();
}
}
async sleep(timeout) {
return new Promise( (resolve, reject) => setTimeout(() => resolve(), timeout));
}
onVideoDimensionsChanged(mutationList, observer, context) {
if (!mutationList || context.video === undefined) { // something's wrong
if (observer && context.video) {
observer.disconnect(); observer.disconnect();
} }
return; return;
} }
for (let mutation of mutationList) { for (let mutation of mutationList) {
if (mutation.type === 'attributes') { if (mutation.type === 'attributes'
if (mutation.attributeName === 'class') { && mutation.attributeName === 'class'
if (!this.video.classList.contains(this.userCssClassName)) { && !context.video.classList.contains(this.userCssClassName) ) {
// force the page to include our class in classlist, if the classlist has been removed // force the page to include our class in classlist, if the classlist has been removed
this.video.classList.add(this.userCssClassName); // while classList.add() doesn't duplicate classes (does nothing if class is already added),
// we still only need to make sure we're only adding our class to classlist if it has been
// } else if () { // removed. classList.add() will _still_ trigger mutation (even if classlist wouldn't change).
// this bug should really get // This is a problem because INFINITE RECURSION TIME, and we _really_ don't want that.
} else {
this.restoreAr(); context.video.classList.add(this.userCssClassName);
} break;
} else if (mutation.attributeName === 'style' && mutation.attributeOldValue !== this.video.getAttribute('style')) {
console.log("style changed")
// if size of the video has changed, this may mean we need to recalculate/reapply
// last calculated aspect ratio
this.player.forceRefreshPlayerElement();
this.restoreAr();
} else if (mutation.attribute = 'src' && mutation.attributeOldValue !== this.video.getAttribute('src')) {
// try fixing alignment issue on video change
try {
this.player.forceRefreshPlayerElement();
this.restoreAr();
} catch (e) {
console.error("[VideoData::onVideoDimensionsChanged] There was an error when handling src change.", e);
}
}
} }
} }
// adding player observer taught us that if element size gets triggered by a class, then
// the 'style' attributes don't necessarily trigger. This means we also need to trigger
// restoreAr here, in case video size was changed this way
context.player.forceRefreshPlayerElement();
context.restoreAr();
// sometimes something fucky wucky happens and mutations aren't detected correctly, so we
// try to get around that
setTimeout( () => {
context.validateVideoOffsets();
}, 100);
}
validateVideoOffsets() {
// validate if current video still exists. If not, we destroy current object
try {
if (! document.body.contains(this.video)) {
console.log("this video is having a bit of a hiatus:", this.video)
this.destroy();
return;
}
} catch (e) {
console.log("e", e)
}
// THIS BREAKS PANNING
const cs = window.getComputedStyle(this.video);
const pcs = window.getComputedStyle(this.player.element);
try {
const transformMatrix = cs.transform.split(')')[0].split(',');
const translateX = +transformMatrix[4];
const translateY = +transformMatrix[5];
const vh = +(cs.height.split('px')[0]);
const vw = +(cs.width.split('px')[0]);
const ph = +(pcs.height.split('px')[0]);
const pw = +(pcs.width.split('px')[0]);
// TODO: check & account for panning and alignment
if (this.isWithin(vh, (ph - (translateY / 2)), 2)
&& this.isWithin(vw, (pw - (translateX / 2)), 2)) {
} else {
this.player.forceRefreshPlayerElement();
this.restoreAr();
}
} catch(e) {
// do nothing on fail
}
}
isWithin(a, b, diff) {
return a < b + diff && a > b - diff
} }
firstTimeArdInit(){ firstTimeArdInit(){
if(this.destroyed) { if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return; return;
} }
@ -101,7 +160,7 @@ class VideoData {
} }
initArDetection() { initArDetection() {
if(this.destroyed) { if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return; return;
} }
@ -115,10 +174,8 @@ class VideoData {
} }
startArDetection() { startArDetection() {
if (Debug.debug) { this.logger.log('info', 'debug', "[VideoData::startArDetection] starting AR detection")
console.log("[VideoData::startArDetection] starting AR detection") if(this.destroyed || this.invalid) {
}
if(this.destroyed) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return; return;
} }
@ -129,7 +186,7 @@ class VideoData {
} }
rebootArDetection() { rebootArDetection() {
if(this.destroyed) { if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return; return;
} }
@ -143,37 +200,29 @@ class VideoData {
} }
destroy() { destroy() {
if(Debug.debug || Debug.init){ this.logger.log('info', ['debug', 'init'], `[VideoData::destroy] <vdid:${this.vdid}> received destroy command`);
console.log(`[VideoData::destroy] <vdid:${this.vdid}> received destroy command`);
}
this.video.classList.remove(this.userCssClassName); if (this.video) {
this.video.classList.remove(this.userCssClassName);
}
this.pause(); this.pause();
this.destroyed = true; this.destroyed = true;
if (this.arDetector){ try {
try { this.arDetector.stop();
this.arDetector.stop(); this.arDetector.destroy();
this.arDetector.destroy(); } catch (e) {}
} catch (e) {}
}
this.arDetector = undefined; this.arDetector = undefined;
if (this.resizer){ try {
try { this.resizer.destroy();
this.resizer.destroy(); } catch (e) {}
} catch (e) {}
}
this.resizer = undefined; this.resizer = undefined;
if (this.player){ try {
try { this.player.destroy();
this.player.destroy(); } catch (e) {}
} catch (e) {} try {
} this.observer.disconnect();
if (this.observer) { } catch (e) {}
try {
this.observer.disconnect();
} catch (e) {}
}
this.player = undefined; this.player = undefined;
this.video = undefined; this.video = undefined;
} }
@ -189,7 +238,7 @@ class VideoData {
} }
resume(){ resume(){
if(this.destroyed) { if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return; return;
} }
@ -200,9 +249,7 @@ class VideoData {
this.player.start(); this.player.start();
} }
} catch (e) { } catch (e) {
if(Debug.debug){ this.logger.log('error', 'debug', "[VideoData.js::resume] cannot resume for reasons. Will destroy videoData. Error here:", e);
console.log("[VideoData.js::resume] cannot resume for reasons. Will destroy videoData. Error here:", e);
}
this.destroy(); this.destroy();
} }
} }
@ -226,22 +273,37 @@ class VideoData {
} }
setLastAr(lastAr){ setLastAr(lastAr){
if (this.invalid) {
return;
}
this.resizer.setLastAr(lastAr); this.resizer.setLastAr(lastAr);
} }
setAr(ar, lastAr){ setAr(ar, lastAr){
if (this.invalid) {
return;
}
this.resizer.setAr(ar, lastAr); this.resizer.setAr(ar, lastAr);
} }
resetAr() { resetAr() {
if (this.invalid) {
return;
}
this.resizer.reset(); this.resizer.reset();
} }
resetLastAr() { resetLastAr() {
if (this.invalid) {
return;
}
this.resizer.setLastAr('original'); this.resizer.setLastAr('original');
} }
panHandler(event, forcePan) { panHandler(event, forcePan) {
if (this.invalid) {
return;
}
if(this.destroyed) { if(this.destroyed) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return; return;
@ -254,34 +316,58 @@ class VideoData {
} }
setPanMode(mode) { setPanMode(mode) {
if (this.invalid) {
return;
}
this.resizer.setPanMode(mode); this.resizer.setPanMode(mode);
} }
setvideoAlignment(videoAlignment) { setVideoAlignment(videoAlignment) {
this.resizer.setvideoAlignment(videoAlignment); if (this.invalid) {
return;
}
this.resizer.setVideoAlignment(videoAlignment);
} }
restoreAr(){ restoreAr(){
if (this.invalid) {
return;
}
this.resizer.restore(); this.resizer.restore();
} }
setStretchMode(stretchMode){ setStretchMode(stretchMode){
if (this.invalid) {
return;
}
this.resizer.setStretchMode(stretchMode); this.resizer.setStretchMode(stretchMode);
} }
setZoom(zoomLevel, no_announce){ setZoom(zoomLevel, no_announce){
if (this.invalid) {
return;
}
this.resizer.setZoom(zoomLevel, no_announce); this.resizer.setZoom(zoomLevel, no_announce);
} }
zoomStep(step){ zoomStep(step){
if (this.invalid) {
return;
}
this.resizer.zoomStep(step); this.resizer.zoomStep(step);
} }
announceZoom(scale){ announceZoom(scale){
if (this.invalid) {
return;
}
this.pageInfo.announceZoom(scale); this.pageInfo.announceZoom(scale);
} }
markPlayer(name, color) { markPlayer(name, color) {
if (this.invalid) {
return;
}
if (this.player) { if (this.player) {
this.player.markPlayer(name, color) this.player.markPlayer(name, color)
} }
@ -291,12 +377,39 @@ class VideoData {
} }
isPlaying() { isPlaying() {
// console.log("is playing? video:", this.video, "ctime:", this.video.currentTime,
// "paused/ended:", this.video.paused, this.video.ended,
// "is playing?", this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended);
return this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended; return this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended;
} }
checkVideoSizeChange(){
const videoWidth = this.video.offsetWidth;
const videoHeight = this.video.offsetHeight;
// this 'if' is just here for debugging — real code starts later. It's safe to collapse and
// ignore the contents of this if (unless we need to change how logging works)
if (this.logger.canLog('debug')){
if(! this.video) {
this.logger.log('info', 'videoDetect', "[VideoDetect] player element isn't defined");
}
if ( this.video && this.dimensions &&
( this.dimensions.width != videoWidth ||
this.dimensions.height != videoHeight )
) {
this.logger.log('info', 'debug', "[VideoDetect] player size changed. reason: dimension change. Old dimensions?", this.dimensions.width, this.dimensions.height, "new dimensions:", this.video.offsetWidth, this.video.offsetHeight);
}
}
// if size doesn't match, update & return true
if (!this.dimensions
|| this.dimensions.width != videoWidth
|| this.dimensions.height != videoHeight ){
this.dimensions = {
width: videoWidth,
height: videoHeight,
};
return true;
}
return false;
}
} }
export default VideoData; export default VideoData;

View File

@ -15,11 +15,14 @@ if(Debug.debug) {
class Resizer { class Resizer {
constructor(videoData) { constructor(videoData) {
this.resizerId = (Math.random(99)*100).toFixed(0);
this.conf = videoData; this.conf = videoData;
this.logger = videoData.logger;
this.video = videoData.video; this.video = videoData.video;
this.settings = videoData.settings; this.settings = videoData.settings;
this.extensionMode = videoData.extensionMode; this.extensionMode = videoData.extensionMode;
this.scaler = new Scaler(this.conf); this.scaler = new Scaler(this.conf);
this.stretcher = new Stretcher(this.conf); this.stretcher = new Stretcher(this.conf);
this.zoom = new Zoom(this.conf); this.zoom = new Zoom(this.conf);
@ -35,10 +38,8 @@ class Resizer {
this.videoAlignment = this.settings.getDefaultVideoAlignment(window.location.hostname); // this is initial video alignment this.videoAlignment = this.settings.getDefaultVideoAlignment(window.location.hostname); // this is initial video alignment
this.destroyed = false; this.destroyed = false;
this.resizerId = (Math.random(99)*100).toFixed(0);
if (this.settings.active.pan) { if (this.settings.active.pan) {
// console.log("can pan:", this.settings.active.miscSettings.mousePan.enabled, "(default:", this.settings.active.miscSettings.mousePan.enabled, ")")
this.canPan = this.settings.active.miscSettings.mousePan.enabled; this.canPan = this.settings.active.miscSettings.mousePan.enabled;
} else { } else {
this.canPan = false; this.canPan = false;
@ -65,9 +66,7 @@ class Resizer {
} }
destroy(){ destroy(){
if(Debug.debug || Debug.init){ this.logger.log('info', ['debug', 'init'], `[Resizer::destroy] <rid:${this.resizerId}> received destroy command.`);
console.log(`[Resizer::destroy] <rid:${this.resizerId}> received destroy command.`);
}
this.destroyed = true; this.destroyed = true;
} }
@ -82,9 +81,7 @@ class Resizer {
var ratioOut; var ratioOut;
if (!this.conf.video) { if (!this.conf.video) {
if (Debug.debug) { this.logger.log('info', 'debug', "[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
console.log("[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
}
this.conf.destroy(); this.conf.destroy();
return null; return null;
} }
@ -93,9 +90,7 @@ class Resizer {
if (! this.conf.player.dimensions) { if (! this.conf.player.dimensions) {
ratioOut = screen.width / screen.height; ratioOut = screen.width / screen.height;
} else { } else {
if (Debug.debug && Debug.resizer) { this.logger.log('info', 'debug', `[Resizer::calculateRatioForLegacyOptions] <rid:${this.resizerId}> Player dimensions:`, this.conf.player.dimensions.width ,'x', this.conf.player.dimensions.height,'aspect ratio:', this.conf.player.dimensions.width / this.conf.player.dimensions.height)
console.log(`[Resizer::calculateRatioForLegacyOptions] <rid:${this.resizerId}> Player dimensions:`, this.conf.player.dimensions.width ,'x', this.conf.player.dimensions.height,'aspect ratio:', this.conf.player.dimensions.width / this.conf.player.dimensions.height)
}
ratioOut = this.conf.player.dimensions.width / this.conf.player.dimensions.height; ratioOut = this.conf.player.dimensions.width / this.conf.player.dimensions.height;
} }
@ -114,9 +109,7 @@ class Resizer {
ar.ratio = ratioOut < fileAr ? ratioOut : fileAr; ar.ratio = ratioOut < fileAr ? ratioOut : fileAr;
} }
else if(ar.type === AspectRatio.Reset){ else if(ar.type === AspectRatio.Reset){
if(Debug.debug){ this.logger.log('info', 'debug', "[Scaler.js::modeToAr] Using original aspect ratio -", fileAr);
console.log("[Scaler.js::modeToAr] Using original aspect ratio -", fileAr);
}
ar.ratio = fileAr; ar.ratio = fileAr;
} else { } else {
return null; return null;
@ -131,9 +124,7 @@ class Resizer {
return; return;
} }
if(Debug.debug){ this.logger.log('info', 'debug', '[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', ar)
console.log('[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', ar)
}
if (ar == null) { if (ar == null) {
return; return;
@ -162,17 +153,13 @@ class Resizer {
// check if property value is on the list of allowed values // check if property value is on the list of allowed values
// if it's not, we aren't allowed to start aard // if it's not, we aren't allowed to start aard
if (bannedProperties[prop].allowedValues.indexOf(styleValue) === -1) { if (bannedProperties[prop].allowedValues.indexOf(styleValue) === -1) {
if (Debug.debug) { this.logger.log('error', 'debug', "%c[Resizer::setAr] video style contains forbidden css property/value combo: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
console.log("%c[Resizer::setAr] video style contains forbidden css property/value combo: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
}
return; return;
} }
} else { } else {
// no allowed values, no problem. We have forbidden property // no allowed values, no problem. We have forbidden property
// and this means aard can't start. // and this means aard can't start.
if (Debug.debug) { this.logger.log('info', 'debug', "%c[Resizer::setAr] video style contains forbidden css property: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
console.log("%c[Resizer::setAr] video style contains forbidden css property: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
}
return; return;
} }
} }
@ -191,9 +178,7 @@ class Resizer {
// I'm not sure whether they do. Check that. // I'm not sure whether they do. Check that.
ar = this.calculateRatioForLegacyOptions(ar); ar = this.calculateRatioForLegacyOptions(ar);
if (! ar) { if (! ar) {
if (Debug.debug && Debug.resizer) { this.logger.log('info', 'resizer', `[Resizer::setAr] <${this.resizerId}> Something wrong with ar or the player. Doing nothing.`);
console.log(`[Resizer::setAr] <${this.resizerId}> Something wrong with ar or the player. Doing nothing.`);
}
return; return;
} }
this.lastAr = {type: ar.type, ratio: ar.ratio} this.lastAr = {type: ar.type, ratio: ar.ratio}
@ -206,12 +191,11 @@ class Resizer {
} }
if (! this.video) { if (! this.video) {
// console.log("No video detected.")
this.conf.destroy(); this.conf.destroy();
} }
// // pause AR on basic stretch, unpause when using other mdoes // pause AR on basic stretch, unpause when using other modes
// fir sine reason unpause doesn't unpause. investigate that later // for sine reason unpause doesn't unpause. investigate that later
try { try {
if (this.stretcher.mode === Stretch.Basic) { if (this.stretcher.mode === Stretch.Basic) {
this.conf.arDetector.pause(); this.conf.arDetector.pause();
@ -229,16 +213,12 @@ class Resizer {
var stretchFactors = this.scaler.calculateCrop(ar); var stretchFactors = this.scaler.calculateCrop(ar);
if(! stretchFactors || stretchFactors.error){ if(! stretchFactors || stretchFactors.error){
if(Debug.debug){ this.logger.log('error', 'debug', `[Resizer::setAr] <rid:${this.resizerId}> failed to set AR due to problem with calculating crop. Error:`, (stretchFactors ? stretchFactors.error : stretchFactors));
console.log("[Resizer::setAr] <rid:"+this.resizerId+"> failed to set AR due to problem with calculating crop. Error:", (stretchFactors ? stretchFactors.error : stretchFactors));
}
if (stretchFactors.error === 'no_video'){ if (stretchFactors.error === 'no_video'){
this.conf.destroy(); this.conf.destroy();
} }
if (stretchFactors.error === 'illegal_video_dimensions') { if (stretchFactors.error === 'illegal_video_dimensions') {
if(Debug.debug){ this.logger.log('error', 'debug', `[Resizer::setAr] <rid:${this.resizerId}> Illegal video dimensions found. We will pause everything.`)
console.log("[Resizer::setAr] <rid:"+this.resizerId+"> Illegal video dimensions found. We will pause everything.");
}
} }
return; return;
} }
@ -246,25 +226,17 @@ class Resizer {
this.stretcher.applyConditionalStretch(stretchFactors, ar.ratio); this.stretcher.applyConditionalStretch(stretchFactors, ar.ratio);
} }
if (Debug.debug) { this.logger.log('info', 'debug', "[Resizer::setAr] Processed stretch factors for ", this.stretcher.mode === Stretch.NoStretch ? 'stretch-free crop.' : 'crop with conditional stretch.', 'Stretch factors are:', stretchFactors);
console.log("[Resizer::setAr] Processed stretch factors for ", this.stretcher.mode === Stretch.NoStretch ? 'stretch-free crop.' : 'crop with conditional stretch.', 'Stretch factors are:', stretchFactors);
}
} else if (this.stretcher.mode === Stretch.Hybrid) { } else if (this.stretcher.mode === Stretch.Hybrid) {
var stretchFactors = this.stretcher.calculateStretch(ar.ratio); var stretchFactors = this.stretcher.calculateStretch(ar.ratio);
if (Debug.debug) { this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for hybrid stretch/crop. Stretch factors are:', stretchFactors);
console.log('[Resizer::setAr] Processed stretch factors for hybrid stretch/crop. Stretch factors are:', stretchFactors);
}
} else if (this.stretcher.mode === Stretch.Basic) { } else if (this.stretcher.mode === Stretch.Basic) {
var stretchFactors = this.stretcher.calculateBasicStretch(); var stretchFactors = this.stretcher.calculateBasicStretch();
if (Debug.debug) { this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for basic stretch. Stretch factors are:', stretchFactors);
console.log('[Resizer::setAr] Processed stretch factors for basic stretch. Stretch factors are:', stretchFactors);
}
} else { } else {
var stretchFactors = {xFactor: 1, yFactor: 1} var stretchFactors = {xFactor: 1, yFactor: 1}
if (Debug.debug) { this.logger.log('error', 'debug', '[Resizer::setAr] Okay wtf happened? If you see this, something has gone wrong', stretchFactors,"\n------[ i n f o d u m p ]------\nstretcher:", this.stretcher);
console.log('[Resizer::setAr] Okay wtf happened? If you see this, something has gone wrong', stretchFactors,"\n------[ i n f o d u m p ]------\nstretcher:", this.stretcher);
}
} }
this.zoom.applyZoom(stretchFactors); this.zoom.applyZoom(stretchFactors);
@ -293,7 +265,6 @@ class Resizer {
} }
panHandler(event, forcePan) { panHandler(event, forcePan) {
// console.log("this.conf.canPan:", this.conf.canPan)
if (this.canPan || forcePan) { if (this.canPan || forcePan) {
if(!this.conf.player || !this.conf.player.element) { if(!this.conf.player || !this.conf.player.element) {
return; return;
@ -306,10 +277,7 @@ class Resizer {
const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth; const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth;
const relativeY = (event.pageY - player.offsetTop) / player.offsetHeight; const relativeY = (event.pageY - player.offsetTop) / player.offsetHeight;
if (Debug.debug && Debug.mousemove) { this.logger.log('info', 'mousemove', "[Resizer::panHandler] mousemove.pageX, pageY:", event.pageX, event.pageY, "\nrelativeX/Y:", relativeX, relativeY)
console.log("[Resizer::panHandler] mousemove.pageX, pageY:", event.pageX, event.pageY,
"\nrelativeX/Y:", relativeX, relativeY)
}
this.setPan(relativeX, relativeY); this.setPan(relativeX, relativeY);
} }
@ -329,21 +297,16 @@ class Resizer {
this.pan.relativeOffsetX = -(relativeMousePosX * 1.1) + 0.55; this.pan.relativeOffsetX = -(relativeMousePosX * 1.1) + 0.55;
this.pan.relativeOffsetY = -(relativeMousePosY * 1.1) + 0.55; this.pan.relativeOffsetY = -(relativeMousePosY * 1.1) + 0.55;
} }
// if(Debug.debug){
// console.log("[Resizer::setPan] relative cursor pos:", relativeMousePosX, ",",relativeMousePosY, " | new pan obj:", this.pan)
// }
this.restore(); this.restore();
} }
setvideoAlignment(videoAlignment) { setVideoAlignment(videoAlignment) {
this.videoAlignment = videoAlignment; this.videoAlignment = videoAlignment;
this.restore(); this.restore();
} }
restore() { restore() {
if(Debug.debug){ this.logger.log('info', 'debug', "[Resizer::restore] <rid:"+this.resizerId+"> attempting to restore aspect ratio. this & settings:", {'a_lastAr': this.lastAr, 'this': this, "settings": this.settings} );
console.log("[Resizer::restore] <rid:"+this.resizerId+"> attempting to restore aspect ratio. this & settings:", {'a_lastAr': this.lastAr, 'this': this, "settings": this.settings} );
}
// this is true until we verify that css has actually been applied // this is true until we verify that css has actually been applied
if(this.lastAr.type === AspectRatio.Initial){ if(this.lastAr.type === AspectRatio.Initial){
@ -351,7 +314,9 @@ class Resizer {
} }
else { else {
if (this.lastAr && this.lastAr.ratio === null) { if (this.lastAr && this.lastAr.ratio === null) {
throw "Last ar is null!" // if this is the case, we do nothing as we have the correct aspect ratio
// throw "Last ar is null!"
return;
} }
this.setAr(this.lastAr, this.lastAr) this.setAr(this.lastAr, this.lastAr)
} }
@ -405,9 +370,7 @@ class Resizer {
computeOffsets(stretchFactors){ computeOffsets(stretchFactors){
if (Debug.debug) { this.logger.log('info', 'debug', "[Resizer::computeOffsets] <rid:"+this.resizerId+"> video will be aligned to ", this.settings.active.sites['@global'].videoAlignment);
console.log("[Resizer::computeOffsets] <rid:"+this.resizerId+"> video will be aligned to ", this.settings.active.sites['@global'].videoAlignment);
}
const wdiff = this.conf.player.dimensions.width - this.conf.video.offsetWidth; const wdiff = this.conf.player.dimensions.width - this.conf.video.offsetWidth;
const hdiff = this.conf.player.dimensions.height - this.conf.video.offsetHeight; const hdiff = this.conf.player.dimensions.height - this.conf.video.offsetHeight;
@ -436,16 +399,14 @@ class Resizer {
} }
} }
if(Debug.debug) { this.logger.log('info', 'debug', "[Resizer::_res_computeOffsets] <rid:"+this.resizerId+"> calculated offsets:\n\n",
console.log("[Resizer::_res_computeOffsets] <rid:"+this.resizerId+"> calculated offsets:\n\n", '---- data in ----\n',
'---- data in ----\n', 'player dimensions:', {w: this.conf.player.dimensions.width, h: this.conf.player.dimensions.height},
'player dimensions:', {w: this.conf.player.dimensions.width, h: this.conf.player.dimensions.height}, 'video dimensions: ', {w: this.conf.video.offsetWidth, h: this.conf.video.offsetHeight},
'video dimensions: ', {w: this.conf.video.offsetWidth, h: this.conf.video.offsetHeight}, 'stretch factors: ', stretchFactors,
'stretch factors: ', stretchFactors, 'pan & zoom: ', this.pan, this.zoom,
'pan & zoom: ', this.pan, this.zoom, '\n\n---- data out ----\n',
'\n\n---- data out ----\n', 'translate:', translate);
'translate:', translate);
}
return translate; return translate;
} }
@ -507,18 +468,13 @@ class Resizer {
// apply extra CSS here. In case of duplicated properties, extraCss overrides // apply extra CSS here. In case of duplicated properties, extraCss overrides
// default styleString // default styleString
if (! this.video) { if (! this.video) {
if(Debug.debug) { this.logger.log('warn', 'debug', "[Resizer::applyCss] <rid:"+this.resizerId+"> Video went missing, doing nothing.");
console.log("[Resizer::applyCss] <rid:"+this.resizerId+"> Video went missing, doing nothing.");
}
this.conf.destroy(); this.conf.destroy();
return; return;
} }
if (Debug.debug && Debug.resizer) { this.logger.log('info', 'resizer', "[Resizer::applyCss] <rid:"+this.resizerId+"> will apply css.", {stretchFactors, translate});
console.log("[Resizer::applyCss] <rid:"+this.resizerId+"> will apply css.", {stretchFactors, translate, video: this.video});
}
// save stuff for quick tests (before we turn numbers into css values): // save stuff for quick tests (before we turn numbers into css values):
this.currentVideoSettings = { this.currentVideoSettings = {
@ -539,7 +495,15 @@ class Resizer {
// 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})`); styleArray.push(`transform: translate(${translate.x}px, ${translate.y}px) scale(${stretchFactors.xFactor}, ${stretchFactors.yFactor})`);
styleArray.push("top: 0px !important; left: 0px !important; bottom: 0px !important; right: 0px");
// important — guarantees video will be properly aligned
styleArray.push("top: 0px !important; left: 0px !important; bottom: 0px !important; right: 0px;");
// important — some websites (cough reddit redesign cough) may impose some dumb max-width and max-height
// restrictions. If site has dumb shit like 'max-width: 100%' and 'max-height: 100vh' in their CSS, that
// shit will prevent us from applying desired crop. This means we need to tell websites to fuck off with
// that crap. We know better.
styleArray.push("max-width: none !important; max-height: none !important;");
} }
const styleString = `${this.buildStyleString(styleArray)}${extraStyleString || ''}`; // string returned by buildStyleString() should end with ; anyway const styleString = `${this.buildStyleString(styleArray)}${extraStyleString || ''}`; // string returned by buildStyleString() should end with ; anyway

View File

@ -11,6 +11,7 @@ class Scaler {
// functions // functions
constructor(videoData) { constructor(videoData) {
this.conf = videoData; this.conf = videoData;
this.logger = videoData.logger;
} }
@ -25,9 +26,7 @@ class Scaler {
var ratioOut; var ratioOut;
if (!this.conf.video) { if (!this.conf.video) {
if(Debug.debug){ this.logger.log('error', 'debug', "[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
console.log("[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
}
this.conf.destroy(); this.conf.destroy();
return null; return null;
} }
@ -59,9 +58,7 @@ class Scaler {
return ratioOut; return ratioOut;
} }
else if(ar.type === AspectRatio.Reset){ else if(ar.type === AspectRatio.Reset){
if(Debug.debug){ this.logger.log('info', 'debug', "[Scaler.js::modeToAr] Using original aspect ratio -", fileAr)
console.log("[Scaler.js::modeToAr] Using original aspect ratio -", fileAr)
}
ar.ar = fileAr; ar.ar = fileAr;
return fileAr; return fileAr;
} }
@ -71,9 +68,7 @@ class Scaler {
calculateCrop(ar) { calculateCrop(ar) {
if(!this.conf.video){ if(!this.conf.video){
if (Debug.debug) { this.logger.log('info', 'debug', "[Scaler::calculateCrop] ERROR — no video detected. Conf:", this.conf, "video:", this.conf.video, "video dimensions:", this.conf.video && this.conf.video.videoWidth, '×', this.conf.video && this.conf.video.videoHeight);
console.log("[Scaler::calculateCrop] ERROR — no video detected. Conf:", this.conf, "video:", this.conf.video, "video dimensions:", this.conf.video && this.conf.video.videoWidth, '×', this.conf.video && this.conf.video.videoHeight);
}
this.conf.destroy(); this.conf.destroy();
return {error: "no_video"}; return {error: "no_video"};
@ -81,9 +76,7 @@ class Scaler {
if (this.conf.video.videoWidth == 0 || this.conf.video.videoHeight == 0) { if (this.conf.video.videoWidth == 0 || this.conf.video.videoHeight == 0) {
// that's illegal, but not illegal enough to just blast our shit to high hell // that's illegal, but not illegal enough to just blast our shit to high hell
// mr officer will let you go with a warning this time around // mr officer will let you go with a warning this time around
if (Debug.debug) { this.logger.log('error', 'debug', "[Scaler::calculateCrop] Video has illegal dimensions. Video dimensions:", this.conf.video && this.conf.video.videoWidth, '×', this.conf.video && this.conf.video.videoHeight);
console.log("[Scaler::calculateCrop] Video has illegal dimensions. Video dimensions:", this.conf.video && this.conf.video.videoWidth, '×', this.conf.video && this.conf.video.videoHeight);
}
return {error: "illegal_video_dimensions"}; return {error: "illegal_video_dimensions"};
} }
@ -94,20 +87,14 @@ class Scaler {
// handle fuckie-wuckies // handle fuckie-wuckies
if (!ar.ratio){ if (!ar.ratio){
if (Debug.debug && Debug.scaler) { this.logger.log('error', 'scaler', "[Scaler::calculateCrop] no ar?", ar.ratio, " -- we were given this mode:", ar);
console.log("[Scaler::calculateCrop] no ar?", ar.ratio, " -- we were given this mode:", ar);
}
return {error: "no_ar", ratio: ar.ratio}; return {error: "no_ar", ratio: ar.ratio};
} }
if (Debug.debug && Debug.scaler) { this.logger.log('info', 'scaler', "[Scaler::calculateCrop] trying to set ar. args are: ar->",ar.ratio,"; this.conf.player.dimensions->",this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
console.log("[Scaler::calculateCrop] trying to set ar. args are: ar->",ar.ratio,"; this.conf.player.dimensions->",this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
}
if( (! this.conf.player.dimensions) || this.conf.player.dimensions.width === 0 || this.conf.player.dimensions.height === 0 ){ if( (! this.conf.player.dimensions) || this.conf.player.dimensions.width === 0 || this.conf.player.dimensions.height === 0 ){
if (Debug.debug && Debug.scaler) { this.logger.log('error', 'scaler', "[Scaler::calculateCrop] ERROR — no (or invalid) this.conf.player.dimensions:",this.conf.player.dimensions);
console.log("[Scaler::calculateCrop] ERROR — no (or invalid) this.conf.player.dimensions:",this.conf.player.dimensions);
}
return {error: "this.conf.player.dimensions_error"}; return {error: "this.conf.player.dimensions_error"};
} }
@ -124,9 +111,7 @@ class Scaler {
} }
if (Debug.debug && Debug.scaler) { this.logger.log('info', 'scaler', "[Scaler::calculateCrop] ar is " ,ar.ratio, ", file ar is", fileAr, ", this.conf.player.dimensions are ", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
console.log("[Scaler::calculateCrop] ar is " ,ar.ratio, ", file ar is", fileAr, ", this.conf.player.dimensions are ", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
}
var videoDimensions = { var videoDimensions = {
xFactor: 1, xFactor: 1,
@ -135,16 +120,9 @@ class Scaler {
actualHeight: 0, // height of the video (excluding letterbox) when <video> tag height is equal to height actualHeight: 0, // height of the video (excluding letterbox) when <video> tag height is equal to height
} }
// if(Debug.debug){
// console.log("[Scaler::calculateCrop] Player dimensions?", this.conf.player.dimensions.width, "×", this.conf.player.dimensions.height, "| obj:", this.conf.player.dimensions);
// }
if (fileAr < ar.ratio){ if (fileAr < ar.ratio){
// imamo letterbox zgoraj in spodaj -> spremenimo velikost videa (a nikoli širše od ekrana) // imamo letterbox zgoraj in spodaj -> spremenimo velikost videa (a nikoli širše od ekrana)
// letterbox -> change video size (but never to wider than monitor width) // letterbox -> change video size (but never to wider than monitor width)
// if (Debug.debug && Debug.scaler) {
// console.log(`%c[Scaler::calculateCrop] Trying to determine scaling factors. Aspect ratios:\n file: ${fileAr.toFixed(3)}\n player: ${playerAr.toFixed(3)}\n target: ${ar.ratio.toFixed(3)}\n-----------------------`, "color: #2ba");
// }
videoDimensions.xFactor = Math.min(ar.ratio, playerAr) / fileAr; videoDimensions.xFactor = Math.min(ar.ratio, playerAr) / fileAr;
videoDimensions.yFactor = videoDimensions.xFactor; videoDimensions.yFactor = videoDimensions.xFactor;
} else { } else {
@ -152,9 +130,7 @@ class Scaler {
videoDimensions.yFactor = videoDimensions.xFactor; videoDimensions.yFactor = videoDimensions.xFactor;
} }
if (Debug.debug && Debug.scaler) { this.logger.log('info', 'scaler', "[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
console.log("[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
}
return videoDimensions; return videoDimensions;
} }

View File

@ -1,4 +1,3 @@
import Debug from '../../conf/Debug';
import Stretch from '../../../common/enums/stretch.enum'; import Stretch from '../../../common/enums/stretch.enum';
// računa vrednosti za transform-scale (x, y) // računa vrednosti za transform-scale (x, y)
@ -13,6 +12,7 @@ class Stretcher {
// functions // functions
constructor(videoData) { constructor(videoData) {
this.conf = videoData; this.conf = videoData;
this.logger = videoData.logger;
this.settings = videoData.settings; this.settings = videoData.settings;
this.mode = this.settings.getDefaultStretchMode(window.location.hostname); this.mode = this.settings.getDefaultStretchMode(window.location.hostname);
} }
@ -120,9 +120,7 @@ class Stretcher {
stretchFactors.xFactor = playerAr / videoAr; stretchFactors.xFactor = playerAr / videoAr;
stretchFactors.yFactor = actualAr / videoAr; stretchFactors.yFactor = actualAr / videoAr;
if(Debug.debug){ this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 1")
console.log("[Stretcher.js::calculateStretch] stretching strategy 1")
}
} else if ( actualAr >= videoAr) { } else if ( actualAr >= videoAr) {
// VERIFIED WORKS // VERIFIED WORKS
@ -132,18 +130,14 @@ class Stretcher {
stretchFactors.xFactor = playerAr / videoAr; stretchFactors.xFactor = playerAr / videoAr;
stretchFactors.yFactor = actualAr / videoAr; stretchFactors.yFactor = actualAr / videoAr;
if(Debug.debug){ this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 2")
console.log("[Stretcher.js::calculateStretch] stretching strategy 2")
}
} else { } else {
// NEEDS CHECKING // NEEDS CHECKING
// player > video > actual — double pillarbox // player > video > actual — double pillarbox
stretchFactors.xFactor = actualAr / playerAr; stretchFactors.xFactor = actualAr / playerAr;
stretchFactors.yFactor = 1; stretchFactors.yFactor = 1;
if(Debug.debug){ this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 3")
console.log("[Stretcher.js::calculateStretch] stretching strategy 3")
}
} }
} else { } else {
// player adds LETTERBOX // player adds LETTERBOX
@ -156,9 +150,7 @@ class Stretcher {
stretchFactors.xFactor = actualAr / playerAr; stretchFactors.xFactor = actualAr / playerAr;
stretchFactors.yFactor = videoAr / playerAr; stretchFactors.yFactor = videoAr / playerAr;
if(Debug.debug){ this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 4")
console.log("[Stretcher.js::calculateStretch] stretching strategy 4")
}
} else if ( actualAr < videoAr ) { } else if ( actualAr < videoAr ) {
// NEEDS CHECKING // NEEDS CHECKING
@ -168,9 +160,7 @@ class Stretcher {
stretchFactors.xFactor = actualAr / playerAr; stretchFactors.xFactor = actualAr / playerAr;
stretchFActors.yFactor = actualAr / playerAr; stretchFActors.yFactor = actualAr / playerAr;
if(Debug.debug){ this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 5")
console.log("[Stretcher.js::calculateStretch] stretching strategy 5")
}
} else { } else {
// VERIFIED CORRECT // VERIFIED CORRECT
@ -179,9 +169,7 @@ class Stretcher {
stretchFactors.xFactor = 1; stretchFactors.xFactor = 1;
stretchFactors.yFactor = actualAr / playerAr; stretchFactors.yFactor = actualAr / playerAr;
if(Debug.debug){ this.logger.log('info', 'stretcher', "[Stretcher.js::calculateStretch] stretching strategy 6")
console.log("[Stretcher.js::calculateStretch] stretching strategy 6")
}
} }
} }

View File

@ -6,12 +6,14 @@ import Debug from '../../conf/Debug';
class Zoom { class Zoom {
// functions // functions
constructor(videoData) { constructor(videoData) {
this.conf = videoData;
this.logger = videoData.logger;
this.scale = 1; this.scale = 1;
this.logScale = 0; this.logScale = 0;
this.scaleStep = 0.1; this.scaleStep = 0.1;
this.minScale = -1; // 50% (log2(0.5) = -1) this.minScale = -1; // 50% (log2(0.5) = -1)
this.maxScale = 3; // 800% (log2(8) = 3) this.maxScale = 3; // 800% (log2(8) = 3)
this.conf = videoData;
} }
reset(){ reset(){
@ -30,18 +32,14 @@ class Zoom {
this.scale = Math.pow(2, this.logScale); this.scale = Math.pow(2, this.logScale);
if (Debug.debug) { this.logger.log('info', 'debug', "[Zoom::zoomStep] changing zoom by", amount, ". New zoom level:", this.scale);
console.log("[Zoom::zoomStep] changing zoom by", amount, ". New zoom level:", this.scale);
}
this.conf.restoreAr(); this.conf.restoreAr();
this.conf.announceZoom(this.scale); this.conf.announceZoom(this.scale);
} }
setZoom(scale, no_announce){ setZoom(scale, no_announce){
if (Debug.debug) { this.logger.log('info', 'debug', "[Zoom::setZoom] Setting zoom to", scale, "!");
console.log("[Zoom::setZoom] Setting zoom to", scale, "!");
}
// NOTE: SCALE IS NOT LOGARITHMIC // NOTE: SCALE IS NOT LOGARITHMIC
if(scale < Math.pow(2, this.minScale)) { if(scale < Math.pow(2, this.minScale)) {
@ -62,16 +60,12 @@ class Zoom {
if (!stretchFactors) { if (!stretchFactors) {
return; return;
} }
if (Debug.debug) { this.logger.log('info', 'debug', "[Zoom::setZoom] Applying zoom. Stretch factors pre:", stretchFactors, " —> scale:", this.scale);
console.log("[Zoom::setZoom] Applying zoom. Stretch factors pre:", stretchFactors, " —> scale:", this.scale);
}
stretchFactors.xFactor *= this.scale; stretchFactors.xFactor *= this.scale;
stretchFactors.yFactor *= this.scale; stretchFactors.yFactor *= this.scale;
if (Debug.debug) { this.logger.log('info', 'debug', "[Zoom::setZoom] Applying zoom. Stretch factors post:", stretchFactors);
console.log("[Zoom::setZoom] Applying zoom. Stretch factors post:", stretchFactors);
}
} }
} }

View File

@ -2,7 +2,7 @@ import Debug from './conf/Debug.js';
import BrowserDetect from './conf/BrowserDetect'; import BrowserDetect from './conf/BrowserDetect';
import CommsServer from './lib/comms/CommsServer'; import CommsServer from './lib/comms/CommsServer';
import Settings from './lib/Settings'; import Settings from './lib/Settings';
import Logger from './lib/Logger';
var BgVars = { var BgVars = {
arIsActive: true, arIsActive: true,
@ -30,8 +30,14 @@ class UWServer {
} }
async setup() { async setup() {
this.settings = new Settings(); // logger is the first thing that goes up
this.logger = new Logger({
logToFile: false,
logToConsole: false
});
await this.logger.init();
this.settings = new Settings({logger: this.logger});
await this.settings.init(); await this.settings.init();
this.comms = new CommsServer(this); this.comms = new CommsServer(this);
@ -42,7 +48,6 @@ class UWServer {
chrome.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)}); chrome.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)});
} }
console.log("will schedule gcframe")
this.scheduleGc(); this.scheduleGc();
} }
@ -54,18 +59,13 @@ class UWServer {
async injectCss(css, sender) { async injectCss(css, sender) {
try { try {
if (Debug.debug) {
console.log("[uwbg::injectCss] Injecting CSS:", css, sender);
}
if (BrowserDetect.firefox || BrowserDetect.edge) { if (BrowserDetect.firefox || BrowserDetect.edge) {
browser.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); browser.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId});
} else if (BrowserDetect.chrome) { } else if (BrowserDetect.chrome) {
chrome.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); chrome.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId});
} }
} catch (e) { } catch (e) {
if (Debug.debug) { this.logger.log('error','debug', '[UwServer::injectCss] Error while injecting css:', {error: e, css, sender});
console.error("Error while injecting css:", {error: e, css, sender});
}
} }
} }
async removeCss(css, sender) { async removeCss(css, sender) {
@ -76,7 +76,9 @@ class UWServer {
// this doesn't work currently, but hopefully chrome will get this feature in the future // this doesn't work currently, but hopefully chrome will get this feature in the future
chrome.tabs.removeCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); chrome.tabs.removeCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId});
} }
} catch (e) { } } catch (e) {
this.logger.log('error','debug', '[UwServer::injectCss] Error while removing css:', {error: e, css, sender});
}
} }
async replaceCss(oldCss, newCss, sender) { async replaceCss(oldCss, newCss, sender) {
@ -99,7 +101,6 @@ class UWServer {
clearTimeout(ths._gctimeout); clearTimeout(ths._gctimeout);
ths.gcFrames(); ths.gcFrames();
ths._gctimeoutgcTimeout = ths.scheduleGc(5000); ths._gctimeoutgcTimeout = ths.scheduleGc(5000);
}, timeout); }, timeout);
} }
@ -124,26 +125,20 @@ class UWServer {
async onTabSwitched(activeInfo){ async onTabSwitched(activeInfo){
this.hasVideos = false; this.hasVideos = false;
if(Debug.debug)
console.log("[uw-bg::onTabSwitched] TAB CHANGED, GETTING INFO FROM MAIN TAB");
try { try {
this.currentTabId = activeInfo.tabId; // just for readability this.currentTabId = activeInfo.tabId; // just for readability
var tab; let tab;
if (BrowserDetect.firefox) { if (BrowserDetect.firefox) {
var tab = await browser.tabs.get(this.currentTabId); tab = await browser.tabs.get(this.currentTabId);
} else if (BrowserDetect.chrome) { } else if (BrowserDetect.chrome) {
var tab = await this._promisifyTabsGet(chrome, this.currentTabId); tab = await this._promisifyTabsGet(chrome, this.currentTabId);
} }
this.currentSite = this.extractHostname(tab.url); this.currentSite = this.extractHostname(tab.url);
this.logger.log('info', 'debug', '[UwServer::onTabSwitched] user switched tab. New site:', this.currentSite);
} catch(e) { } catch(e) {
console.log(e); this.logger.log('error', 'debug', '[UwServer::onTabSwitched] there was a problem getting currnet site:', e)
}
if(Debug.debug) {
console.log("TAB SWITCHED!", this.currentSite)
} }
this.selectedSubitem = { this.selectedSubitem = {
@ -176,9 +171,7 @@ class UWServer {
} }
registerVideo(sender) { registerVideo(sender) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', '[UWServer::registerVideo] Registering video.\nsender:', sender);
console.log("[UWServer::registerVideo] registering video.\nsender:", sender);
}
const tabHostname = this.extractHostname(sender.tab.url); const tabHostname = this.extractHostname(sender.tab.url);
const frameHostname = this.extractHostname(sender.url); const frameHostname = this.extractHostname(sender.url);
@ -221,15 +214,11 @@ class UWServer {
} }
} }
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', '[UWServer::registerVideo] Video registered. current videoTabs:', this.videoTabs);
console.log("[UWServer::registerVideo] video registered. current videoTabs:", this.videoTabs);
}
} }
unregisterVideo(sender) { unregisterVideo(sender) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Unregistering video.\nsender:', sender);
console.log("[UWServer::unregisterVideo] unregistering video.\nsender:", sender);
}
if (this.videoTabs[sender.tab.id]) { if (this.videoTabs[sender.tab.id]) {
if ( Object.keys(this.videoTabs[sender.tab.id].frames).length <= 1) { if ( Object.keys(this.videoTabs[sender.tab.id].frames).length <= 1) {
delete this.videoTabs[sender.tab.id] delete this.videoTabs[sender.tab.id]
@ -239,15 +228,11 @@ class UWServer {
} }
} }
} }
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Video has been unregistered. Current videoTabs:', this.videoTabs);
console.log("[UWServer::ungisterVideo] video unregistered. current videoTabs:", this.videoTabs);
}
} }
setSelectedTab(menu, subitem) { setSelectedTab(menu, subitem) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'comms', '[UwServer::setSelectedTab] saving selected tab for', menu, ':', subitem);
console.log("[uw-bg::setSelectedTab] saving selected tab for", menu, ":", subitem)
}
this.selectedSubitem[menu] = subitem; this.selectedSubitem[menu] = subitem;
} }

View File

@ -5,6 +5,7 @@ import Settings from './lib/Settings';
import ActionHandler from './lib/ActionHandler'; import ActionHandler from './lib/ActionHandler';
import CommsClient from './lib/comms/CommsClient'; import CommsClient from './lib/comms/CommsClient';
import PageInfo from './lib/video-data/PageInfo'; import PageInfo from './lib/video-data/PageInfo';
import Logger from './lib/Logger';
if(Debug.debug){ if(Debug.debug){
console.log("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀɪɪʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n"); console.log("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀɪɪʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n");
@ -30,6 +31,7 @@ class UW {
this.comms = undefined; this.comms = undefined;
this.settings = undefined; this.settings = undefined;
this.actionHandler = undefined; this.actionHandler = undefined;
this.logger = undefined;
} }
async init(){ async init(){
@ -37,68 +39,95 @@ class UW {
console.log("[uw::main] loading configuration ..."); console.log("[uw::main] loading configuration ...");
} }
// logger init is the first thing that needs to run
try {
if (!this.logger) {
const loggingOptions = {
logToFile: false,
logToConsole: false,
fileOptions: {
// really the same stuff as consoleOptions
},
consoleOptions: {
enabled: true, // if logging is enabled at all
'debug': true,
'init': true,
'settings': true,
'keyboard': false,
'mousemove': false,
'actionHandler': false,
'comms': false,
'playerDetect': false,
// 'resizer': true,
// 'scaler': true,
// 'stretcher': true,
'videoRescan': false,
'arDetect': false,
'arDetect_verbose': false,
}
};
this.logger = new Logger(loggingOptions);
// await this.logger.init(); // not needed if logging options are provided at creation
}
} catch (e) {
console.error("logger init failed!", e)
}
// init() is re-run any time settings change // init() is re-run any time settings change
if (this.pageInfo) { if (this.pageInfo) {
if(Debug.debug){ // if this executes, logger must have been initiated at some point before this point
console.log("[uw::init] Destroying existing pageInfo", this.pageInfo); this.logger.log('info', 'debug', "[uw::init] Destroying existing pageInfo", this.pageInfo);
}
this.pageInfo.destroy(); this.pageInfo.destroy();
} }
if (this.comms) { if (this.comms) {
this.comms.destroy(); this.comms.destroy();
} }
if (!this.settings) { if (!this.settings) {
var ths = this; var ths = this;
this.settings = new Settings(undefined, () => ths.init()); this.settings = new Settings({updateCallback: (s) => {console.log("settings callback — ", s); ths.init()}, logger: this.logger});
await this.settings.init(); await this.settings.init();
} }
this.comms = new CommsClient('content-client-port', this.settings);
this.comms = new CommsClient('content-client-port', this.settings, this.logger);
// če smo razširitev onemogočili v nastavitvah, ne naredimo ničesar // če smo razširitev onemogočili v nastavitvah, ne naredimo ničesar
// If extension is soft-disabled, don't do shit // If extension is soft-disabled, don't do shit
var extensionMode = this.settings.getExtensionMode(); var extensionMode = this.settings.getExtensionMode();
if(Debug.debug) { this.logger.log('info', 'debug', "[uw::init] Extension mode:" + (extensionMode < 0 ? "disabled" : extensionMode == '1' ? 'basic' : 'full'));
console.log("[uw::init] Extension mode:" + (extensionMode < 0 ? "disabled" : extensionMode == '1' ? 'basic' : 'full'));
}
const isSiteDisabled = extensionMode === ExtensionMode.Disabled const isSiteDisabled = extensionMode === ExtensionMode.Disabled
if (isSiteDisabled) { if (isSiteDisabled) {
if (this.settings.getExtensionMode('@global') === ExtensionMode.Disabled) { if (this.settings.getExtensionMode('@global') === ExtensionMode.Disabled) {
if (Debug.debug) { this.logger.log('info', 'debug', "[uw::init] EXTENSION DISABLED, THEREFORE WONT BE STARTED")
console.log("[uw::init] EXTENSION DISABLED, THEREFORE WONT BE STARTED")
}
return; return;
} }
} }
try { try {
this.pageInfo = new PageInfo(this.comms, this.settings, extensionMode, isSiteDisabled); this.pageInfo = new PageInfo(this.comms, this.settings, this.logger, extensionMode, isSiteDisabled);
if(Debug.debug){ this.logger.log('info', 'debug', "[uw.js::setup] pageInfo initialized. Here's the object:", this.pageInfo);
console.log("[uw.js::setup] pageInfo initialized. Here's the object:", this.pageInfo);
}
this.comms.setPageInfo(this.pageInfo); this.comms.setPageInfo(this.pageInfo);
if(Debug.debug) { this.logger.log('info', 'debug', "[uw.js::setup] will try to initate ActionHandler. Settings are:", this.settings, this.settings.active)
console.log("[uw.js::setup] will try to initate ActionHandler. Settings are:", this.settings, this.settings.active)
}
// start action handler only if extension is enabled for this site // start action handler only if extension is enabled for this site
if (!isSiteDisabled) { if (!isSiteDisabled) {
this.actionHandler = new ActionHandler(this.pageInfo); this.actionHandler = new ActionHandler(this.pageInfo);
this.actionHandler.init(); this.actionHandler.init();
if(Debug.debug) { this.logger.log('info', 'debug', "[uw.js::setup] ActionHandler initiated:", this.actionHandler);
console.log("[uw.js::setup] ActionHandler initiated:", this.actionHandler);
}
} }
} catch (e) { } catch (e) {
console.log("[uw::init] FAILED TO START EXTENSION. Error:", e); this.logger.log('error', 'debug', "[uw::init] FAILED TO START EXTENSION. Error:", e);
} }

View File

@ -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.2.4.2", "version": "4.3.0",
"applications": { "applications": {
"gecko": { "gecko": {
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}" "id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
@ -55,5 +55,8 @@
], ],
"permissions": [ "permissions": [
"tabs", "storage", "activeTab", "<all_urls>", "webNavigation" "tabs", "storage", "activeTab", "<all_urls>", "webNavigation"
],
"optional_permissions": [
"downloads"
] ]
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div v-if="settingsInitialized">
<!-- POPUPS --> <!-- POPUPS -->
<div v-if="anyOpenedPopups" <div v-if="anyOpenedPopups"
@ -136,6 +136,7 @@ export default {
selectedTab: "general", selectedTab: "general",
selectedTabTitle: "General settings", selectedTabTitle: "General settings",
settings: {}, settings: {},
logger: {},
settingsInitialized: false, settingsInitialized: false,
editActionPopupVisible: false, editActionPopupVisible: false,
editActionIndex: -1, editActionIndex: -1,
@ -148,8 +149,15 @@ export default {
} }
}, },
async created () { async created () {
this.settings = new Settings(undefined, this.updateSettings); this.logger = new Logger({
logToFile: false,
logToConsole: false
});
await this.logger.init();
this.settings = new Settings({updateCallback: this.updateSettings, logger: this.logger});
await this.settings.init(); await this.settings.init();
this.settingsInitialized = true; this.settingsInitialized = true;
}, },
components: { components: {

View File

@ -33,7 +33,7 @@
Accurate preset will take a more conservative approach to determining aspect ratio, correcting aspect ratio only when Accurate preset will take a more conservative approach to determining aspect ratio, correcting aspect ratio only when
it's absolutely sure that the aspect ratio needs changing. This option results in fewer incorrect aspect ratio corrections, it's absolutely sure that the aspect ratio needs changing. This option results in fewer incorrect aspect ratio corrections,
but can also result in extension not correcting aspect ratio when it should. but can also result in extension not correcting aspect ratio when it should.
Strict preset is 'accurate' on stereoids. Strict preset is 'accurate' on steroids.
</div> </div>
<div class="flex flex-row row-padding"> <div class="flex flex-row row-padding">
@ -610,7 +610,6 @@ export default {
ctx.drawWindow(window,0, 0, 10, 10, "rgba(0,0,0,0)"); ctx.drawWindow(window,0, 0, 10, 10, "rgba(0,0,0,0)");
this.fallbackModeAvailable = true; this.fallbackModeAvailable = true;
} catch (e) { } catch (e) {
// console.log("DrawWindow failed:", e)
this.fallbackModeAvailable = false; this.fallbackModeAvailable = false;
} }
}, },
@ -634,7 +633,6 @@ export default {
return 'user-defined'; return 'user-defined';
}, },
setConfirmationThresholds(sens) { setConfirmationThresholds(sens) {
console.log("setting conf treshold", sens)
if (sens === 'sensitive') { if (sens === 'sensitive') {
this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold = 3; this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold = 3;
this.settings.active.arDetect.edgeDetection.confirmationThreshold = 1; this.settings.active.arDetect.edgeDetection.confirmationThreshold = 1;

View File

@ -116,13 +116,36 @@
</div> </div>
<div class="label"> <div class="label">
Reset settings Import, export, reset settings
</div> </div>
<div class="flex flex-row button-box"> <div class="flex flex-column">
<Button label="Reset settings" <div v-if="downloadPermissionError"
@click.native="resetSettings()" class="w100 center-text warning-lite"
> >
</Button> Exporting settings requires the 'downloads' permission. (If you want to export settings without granting 'downloads' permission, you can copy-paste settings from 'Super advanced settings' tab)
</div>
<div v-if="corruptedSettingsError"
class="w100 center-text warning-lite"
>
Settings import failed. The settings file is probably corrupted.
</div>
<div class="flex flex-row button-box">
<div class="button center-text flex flex-auto">
<label for="file-upload" class="w100 h100 block">
Import settings
</label>
<input id="file-upload"
type="file"
@input="importSettings"
/>
</div>
<Button label="Export settings"
@click.native="exportSettings()"
/>
<Button label="Reset settings"
@click.native="resetSettings()"
/>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -132,6 +155,7 @@ import Button from '../common/components/Button';
import Stretch from '../common/enums/stretch.enum'; import Stretch from '../common/enums/stretch.enum';
import ExtensionMode from '../common/enums/extension-mode.enum'; import ExtensionMode from '../common/enums/extension-mode.enum';
import VideoAlignment from '../common/enums/video-alignment.enum'; import VideoAlignment from '../common/enums/video-alignment.enum';
import BrowserDetect from '../ext/conf/BrowserDetect';
export default { export default {
components: { components: {
@ -146,6 +170,8 @@ export default {
ExtensionMode: ExtensionMode, ExtensionMode: ExtensionMode,
VideoAlignment: VideoAlignment, VideoAlignment: VideoAlignment,
stretchThreshold: 0, stretchThreshold: 0,
corruptedSettingsError: false,
downloadPermissionError: false,
} }
}, },
created () { created () {
@ -178,8 +204,77 @@ export default {
resetSettings() { resetSettings() {
this.settings.active = JSON.parse(JSON.stringify(this.settings.default)); this.settings.active = JSON.parse(JSON.stringify(this.settings.default));
this.settings.save(); this.settings.save();
},
async exportSettings() {
this.downloadPermissionError = false;
const blob = new Blob([JSON.stringify(this.settings.active)], {type: 'application/json'});
const fileUrl = URL.createObjectURL(blob);
try {
if (BrowserDetect.firefox) {
await browser.permissions.request({permissions: ['downloads']});
browser.downloads.download({saveAs: true, filename: 'ultrawidify-settings.json', url: fileUrl});
} else if (BrowserDetect.chrome) {
const ths = this;
chrome.permissions.request(
{permissions: ['downloads']},
(granted) => {
if (granted) {
ths.exportSettingsChrome(fileUrl);
} else {
ths.downloadPermissionError = true
}
}
)
}
} catch (e) {
this.downloadPermissionError = true;
}
},
exportSettingsChrome(fileUrl){
chrome.downloads.download({saveAs: true, filename: 'ultrawidify-settings.json', url: fileUrl});
},
async importSettings($event) {
let file, text, settingsObj;
this.corruptedSettingsError = false;
try {
file = $event.target.files[0];
} catch (e) {
console.error("error grabbing a file!");
this.corruptedSettingsError = true;
return;
}
try {
text = await file.text();
settingsObj = JSON.parse(text);
} catch (e) {
console.error("error parsing file to json");
this.corruptedSettingsError = true;
return;
}
// validate settings
for (const key in this.settings.default) {
if (!settingsObj[key]) {
console.error("corrupted settings!")
this.corruptedSettingsError = true;
return;
}
}
this.settings.active = settingsObj;
this.settings.save();
} }
} }
} }
</script> </script>
<style lang="scss" scoped>
input[type="file"] {
display: none;
}
</style>

View File

@ -104,11 +104,6 @@ export default {
} }
this.customArgumentValue = this.action.customArg; this.customArgumentValue = this.action.customArg;
} }
// console.log("this.actionList", ActionList, this.ActionList)
// for(const a in ActionList) {
// console.log(a);
// }
}, },
mounted() { mounted() {

View File

@ -1,6 +1,3 @@
// console.log("global browser", browser, global.browser)
// global.browser = require('webextension-polyfill')
import Vue from 'vue' import Vue from 'vue'
import App from './App' import App from './App'

View File

@ -1,5 +1,7 @@
<template> <template>
<div class="popup flex flex-column no-overflow"> <div v-if="settingsInitialized"
class="popup flex flex-column no-overflow"
>
<div class="header flex-row flex-nogrow flex-noshrink"> <div class="header flex-row flex-nogrow flex-noshrink">
<span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small> <span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small>
</div> </div>
@ -175,6 +177,7 @@ import ExecAction from './js/ExecAction.js';
import DefaultSettingsPanel from './panels/DefaultSettingsPanel'; import DefaultSettingsPanel from './panels/DefaultSettingsPanel';
import AboutPanel from './panels/AboutPanel'; import AboutPanel from './panels/AboutPanel';
import ExtensionMode from '../common/enums/extension-mode.enum'; import ExtensionMode from '../common/enums/extension-mode.enum';
import Logger from '../ext/lib/Logger';
export default { export default {
data () { data () {
@ -192,7 +195,9 @@ export default {
site: null, site: null,
currentZoom: 1, currentZoom: 1,
execAction: new ExecAction(), execAction: new ExecAction(),
settings: new Settings(undefined, () => this.updateConfig()), settings: {},
settingsInitialized: false,
logger: {},
siteTabDisabled: false, siteTabDisabled: false,
videoTabDisabled: false, videoTabDisabled: false,
canShowVideoTab: {canShow: true, warning: true}, canShowVideoTab: {canShow: true, warning: true},
@ -200,7 +205,16 @@ export default {
} }
}, },
async created() { async created() {
this.logger = new Logger({
logToFile: false,
logToConsole: false
});
await this.logger.init();
this.settings = new Settings({updateCallback: () => this.updateConfig(), logger: this.logger});
await this.settings.init(); await this.settings.init();
this.settingsInitialized = true;
this.port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p)); this.port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
this.execAction.setSettings(this.settings); this.execAction.setSettings(this.settings);
@ -243,14 +257,10 @@ export default {
}, },
getSite() { getSite() {
try { try {
if (Debug.debug) { this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
console.log("[popup.js] requesting current site");
}
this.port.postMessage({cmd: 'get-current-site'}); this.port.postMessage({cmd: 'get-current-site'});
} catch (e) { } catch (e) {
if (Debug.debug) { this.logger.log('error','popup','[popup::getSite] sending get-current-site failed for some reason. Reason:', e);
console.log("[popup::getSite] sending get-current-site failed for some reason. Reason:", e)
}
} }
}, },
getRandomColor() { getRandomColor() {
@ -293,10 +303,7 @@ export default {
this.canShowVideoTab = {canShow: canShow, warning: warning}; this.canShowVideoTab = {canShow: canShow, warning: warning};
}, },
processReceivedMessage(message, port) { processReceivedMessage(message, port) {
if (Debug.debug && Debug.comms) { this.logger.log('info', 'popup', '[popup::processReceivedMessage] received message:', message)
console.log("[popup.js] received message set-c", message);
console.log("[popup.js] message cloned set-c", JSON.parse(JSON.stringify(message)));
}
if (message.cmd === 'set-current-site'){ if (message.cmd === 'set-current-site'){
if (this.site) { if (this.site) {
@ -340,13 +347,21 @@ export default {
// Extension site disabled, embedded videos from non-blacklisted hosts show video settings // Extension site disabled, embedded videos from non-blacklisted hosts show video settings
// Extension site enabled show vido settings // Extension site enabled show vido settings
// note: this if statement is ever so slightly unnecessary
if (! this.settings.canStartExtension('@global')) { if (! this.settings.canStartExtension('@global')) {
if (this.selectedTab === 'video' || this.selectedTab === 'site') { // canStartExtension and getExtensionMode return disabled/false for non-whitelisted
this.selectTab('global'); // sites, even if extension mode is set to "whitelist only." This is problematic
// because in order to whitelist a given site, we need to set extension to global-
// enabled, whitelist the site, and then set extension to whitelist only. This makes
// for a bad user experience, so let's fix this.
if (this.settings.active.sites['@global'].mode === ExtensionMode.Disabled) {
if (this.selectedTab === 'video' || this.selectedTab === 'site') {
this.selectTab('global');
}
this.siteTabDisabled = true;
this.videoTabDisabled = true;
return;
} }
this.siteTabDisabled = true;
this.videoTabDisabled = true;
return;
} }
this.siteTabDisabled = false;; this.siteTabDisabled = false;;

View File

@ -161,7 +161,6 @@ export default {
} }
site = this.site; site = this.site;
} }
// console.log("SETTINGS FOR SITE", site, "option", option, JSON.parse(JSON.stringify(this.settings.active.sites)))
if (this.settings.active.sites[site]) { if (this.settings.active.sites[site]) {
return this.settings.active.sites[site][option]; return this.settings.active.sites[site][option];
} else { } else {

View File

@ -1,35 +1,38 @@
<template> <template>
<div class="flex flex-column" style="padding-bottom: 20px"> <div class="flex flex-column" style="padding-bottom: 20px">
<div class="label"> <!-- <div class="">
Video detection settings<br/><small>for {{site}}</small> <div class="label">Player picker</div>
</div> <div class="desc">
<div class="description">Video is just the moving picture bit without the player.</div> If extension doesn't detect player correctly, you can override it.
<div class=""> <small>(NOTE: this currently doesn't work for embedded videos)</small>
<div class="">
<input :checked="!videoManualQs"
@change="toggleVideoManualQs"
type="checkbox"
/> Detect automatically
</div> </div>
<div class="flex flex-column">
<div class="flex label-secondary form-label">Query selectors</div> <div>Meaning of outlines:</div>
<input type="text"
v-model="videoQs" <div class="flex flex-row flex-wrap">
:disabled="!videoManualQs" <div class="pp_video flex flex-nogrow"><code>&lt;video&gt;</code>&nbsp;element</div>
@change="updateVideoQuerySelector" <div class="pp_current flex flex-nogrow">Selected and not matched</div>
@blur="updateVideoQuerySelector" <div class="pp_matched flex flex-nogrow">Elements that match query selector</div>
/> <div class="pp_current_matched">Selected and matched, selector ok</div>
</div> <div class="pp_match_children">Selected and matched, selector too vague</div>
<div class="flex flex-column">
<div class="flex label-secondary form-label">Additional css</div>
<input type="text"
v-model="videoCss"
@change="updateVideoCss"
@blur="updateVideoCss"
/>
</div> </div>
</div> <div class="flex flex-row">
<ShortcutButton label="Move up"
/>
<ShortcutButton label="Move down"
/>
</div>
<div class="flex flex-row flex-wrap">
<QsElement selector="#test_id" />
<QsElement selector=".test_class" />
<template v-for="qse of currentElementQs" >
<QsElement :selector="qse" :key="qse" />
</template>
</div>
</div> -->
<div class="label"> <div class="label">
Player detection settings<br/><small>for {{site}}</small> Player detection settings<br/><small>for {{site}}</small>
@ -88,11 +91,44 @@
@blur="updatePlayerCss" @blur="updatePlayerCss"
> >
</textarea> </textarea>
</div>
<div class="label">
Video detection settings<br/><small>for {{site}}</small>
</div>
<div class="description">Video is just the moving picture bit without the player.</div>
<div class="">
<div class="">
<input :checked="!videoManualQs"
@change="toggleVideoManualQs"
type="checkbox"
/> Detect automatically
</div> </div>
<div class="flex flex-column">
<div class="flex label-secondary form-label">Query selectors</div>
<input type="text"
v-model="videoQs"
:disabled="!videoManualQs"
@change="updateVideoQuerySelector"
@blur="updateVideoQuerySelector"
/>
</div>
<div class="flex flex-column">
<div class="flex label-secondary form-label">Additional css</div>
<input type="text"
v-model="videoCss"
@change="updateVideoCss"
@blur="updateVideoCss"
/>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import ShortcutButton from '../../common/components/ShortcutButton.vue';
import QsElement from '../../common/components/QsElement.vue';
import QuerySelectorSetting from '../../common/components/QuerySelectorSetting.vue'; import QuerySelectorSetting from '../../common/components/QuerySelectorSetting.vue';
import ExtensionMode from '../../common/enums/extension-mode.enum'; import ExtensionMode from '../../common/enums/extension-mode.enum';
import VideoAlignment from '../../common/enums/video-alignment.enum'; import VideoAlignment from '../../common/enums/video-alignment.enum';
@ -100,6 +136,8 @@ import Stretch from '../../common/enums/stretch.enum';
export default { export default {
components: { components: {
QuerySelectorSetting, QuerySelectorSetting,
ShortcutButton,
QsElement,
}, },
data() { data() {
return { return {
@ -118,14 +156,12 @@ export default {
settings: Object, settings: Object,
}, },
created() { created() {
console.log("created!")
try { try {
this.videoManualQs = this.settings.active.sites[this.site].DOM.video.manual || this.videoManualQs; this.videoManualQs = this.settings.active.sites[this.site].DOM.video.manual || this.videoManualQs;
this.videoQs = this.settings.active.sites[this.site].DOM.video.querySelectors; this.videoQs = this.settings.active.sites[this.site].DOM.video.querySelectors;
this.videoCss = this.settings.active.sites[this.site].DOM.video.additionalCss; this.videoCss = this.settings.active.sites[this.site].DOM.video.additionalCss;
} catch (e) { } catch (e) {
// that's here just in case relevant settings for this site don't exist yet // that's here just in case relevant settings for this site don't exist yet
console.log("failed to load settings for the site — for video stuff")
} }
try { try {
@ -135,16 +171,13 @@ export default {
this.playerParentNodeIndex = this.settings.active.sites[this.site].DOM.player.videoAncestor; this.playerParentNodeIndex = this.settings.active.sites[this.site].DOM.player.videoAncestor;
} catch (e) { } catch (e) {
// that's here just in case relevant settings for this site don't exist yet // that's here just in case relevant settings for this site don't exist yet
console.log("failed to load settings for the site — for video stuff")
} }
try { try {
this.playerCss = this.settings.active.sites[this.site].css || ''; this.playerCss = this.settings.active.sites[this.site].css || '';
} catch (e) { } catch (e) {
// that's here just in case relevant settings for this site don't exist yet // that's here just in case relevant settings for this site don't exist yet
console.log("failed to load settings for the site — for video stuff")
} }
console.log("created — got settings:", this.settings)
}, },
methods: { methods: {
ensureSettings(scope) { ensureSettings(scope) {
@ -221,5 +254,29 @@ export default {
</script> </script>
<style> <style>
.pp_video {
margin: 2px;
padding: 5px;
border: 1px solid #00f;
}
.pp_current {
margin: 2px;
padding: 5px;
border: 1px solid #88f;
}
.pp_matched {
margin: 2px;
padding: 5px;
border: 1px dashed #fd2;
}
.pp_current_matched {
margin: 2px;
padding: 2px;
border: 2px solid #027a5c;
}
.pp_match_children {
margin: 2px;
padding: 2px;
border: 2px solid #f00;
}
</style> </style>

View File

@ -2,16 +2,20 @@
<div> <div>
<h2>What's new</h2> <h2>What's new</h2>
<p>Full changelog for older versions <a href="https://github.com/xternal7/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p> <p>Full changelog for older versions <a href="https://github.com/xternal7/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
<p class="label">4.2.4</p> <p class="label">4.3.0</p>
<ul> <ul>
<li>Improvements to player detection. More details in the <a href="https://stuff.tamius.net/sacred-texts/2019/08/31/ultrawidify-and-the-improper-cropping/" target="_blank">blog post</a>.</li> <li>Fixed an issue where videos would get incorrectly aligned following a window resize.</li>
<li><b>[4.2.4.1]</b> Fixed default settings for reddit</li> <li>Fixed all sorts of issues for videos hosted on v.reddit for new (and old) reddit</li>
<li><b>[4.2.4.1]</b> Manually specified query selectors are now also checked for compliance with player detection rules.</li> <li>Fixed the issue where setting extension to 'whitelist only' would disable 'site settings' in popup.</li>
<li><b>[4.2.4.2]</b> Additional bugfixes. Updated/fixed default settings.</li> <li>User-friendly way of importing-exporting settings (exporting settings requires 'download' permission)</li>
<li>Started using mutation observers to watch for changes in player size as well, but with some caveats.</li>
<li>Mutation observers are now used to detect both video and player size changes.</li>
<li>Settings patching has been reworked. Settings can now be patched incrementally.</li>
</ul>
<p>I'm also laying ground for some features that will make my life easier:</p>
<ul>
<li>Reworked how logging works internally, but this point still needs some work.</li>
</ul> </ul>
<p v-if="BrowserDetect.chrome"><b>Chrome users:</b> as a result of Chrome's shortcomings, there now exists one potential performance issue.
If you notice any performance issues, please contact me via github, email or reddit (see: 'report a problem' tab
of this popup).</p>
</div> </div>
</template> </template>
<script> <script>

View File

@ -9,6 +9,8 @@ https://vimeo.com/channels/staffpicks/169599296
## Reddit (v.reddit) ## Reddit (v.reddit)
https://redd.it/9rfg84 https://redd.it/9rfg84
https://www.reddit.com/r/Minecraft/comments/cvnh9d/had_no_idea_this_was_possible/
https://old.reddit.com/r/Guildwars2/comments/cxtf9r/the_rytlock_and_bangar_teaser/
## Streamable ## Streamable
@ -57,4 +59,10 @@ https://www.reddit.com/r/videos/comments/a137pj/daily_reminder_that_shelly_misca
~~Incorrect crop when fixing vertical videos with letterbox: https://www.youtube.com/watch?v=9DP0TbOQcOw — [Issue 48](https://github.com/xternal7/ultrawidify/issues/48)~~ ~~Incorrect crop when fixing vertical videos with letterbox: https://www.youtube.com/watch?v=9DP0TbOQcOw — [Issue 48](https://github.com/xternal7/ultrawidify/issues/48)~~
~~Incorrect crop on 4:3 in certain circumstances: https://www.reddit.com/r/videos/comments/a137pj/daily_reminder_that_shelly_miscavige_wife_of/ (embedded) — [Issue 54](https://github.com/xternal7/ultrawidify/issues/54)~~ ~~Incorrect crop on 4:3 in certain circumstances: https://www.reddit.com/r/videos/comments/a137pj/daily_reminder_that_shelly_miscavige_wife_of/ (embedded) — [Issue 54](https://github.com/xternal7/ultrawidify/issues/54)~~
# Examples for sites without official support
## Steam
https://store.steampowered.com/app/606880/GreedFall/

View File

@ -5,7 +5,6 @@ const WebpackShellPlugin = require('webpack-shell-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const ChromeExtensionReloader = require('webpack-chrome-extension-reloader'); const ChromeExtensionReloader = require('webpack-chrome-extension-reloader');
const { VueLoaderPlugin } = require('vue-loader'); const { VueLoaderPlugin } = require('vue-loader');
const { version } = require('./package.json');
const config = { const config = {
mode: process.env.NODE_ENV, mode: process.env.NODE_ENV,

5834
yarn.lock

File diff suppressed because it is too large Load Diff