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
* 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
@ -14,7 +30,6 @@
* **[4.2.4.2]** Additional bugfixes. Updated/fixed default settings.
### v4.2.3 / 4.2.3.x
* Fixed twitchy behaviour on Twitch, Facebook and Twatter. Here's a [blog post](https://stuff.tamius.net/sacred-texts/2019/08/24/ultrawidify-the-twitchy-twitch-problem/) that covers the issue in more detail.
* Cropping now uses user styles (as opposed to modifying element's style attribute)
* Fixed the issue where one-pixel letterbox would result in constant aspect ratio corrections.
@ -22,8 +37,8 @@
* **[4.2.3.1]** fixed some bugs in popup.
### 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
* Fixed bug where custom CSS didn't get applied to pages

View File

@ -2,17 +2,13 @@
## Build platform
The extension is built on a PC running Manjaro Linux. Yarn is the package manager of choice.
Yarn version: 1.16.0
Node version: v11.15.0
The extension is built on a PC running Manjaro Linux. npm and node are installed from repositories/aur.
## 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

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",
"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.",
"author": "Tamius Han <tamius.han@gmail.com>",
"scripts": {
@ -11,6 +11,7 @@
"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-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",
"watch": "npm run build -- --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_ZIP_DIR = path.join(__dirname, '../dist-zip');
const extractExtensionData = () => {
const extPackageJson = require('../package.json');
const extPackageJson = require('../src/manifest.json');
return {
name: extPackageJson.name,
@ -40,8 +41,10 @@ const buildZip = (src, dist, zipFilename) => {
};
const main = () => {
const browser = process.argv[2];
const {name, version} = extractExtensionData();
const zipFilename = `${name}-v${version}.zip`;
const zipFilename = `${name}-${version}-${browser}.zip`;
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,
// scaler: true,
// debugStorage: true,
// comms: false,
// comms: true,
// showArDetectCanvas: true,
// flushStoredSettings: true,

View File

@ -1,8 +1,9 @@
// How to use:
// version: {ExtensionConf object, but only properties that get overwritten}
const ExtensionConfPatch = {
'4.2.0': {
const ExtensionConfPatch = [
{
forVersion: '4.2.0',
sites: {
"old.reddit.com" : {
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;

View File

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

View File

@ -5,6 +5,7 @@ import ExtensionMode from '../../common/enums/extension-mode.enum';
class ActionHandler {
constructor(pageInfo) {
this.logger = pageInfo.logger;
this.pageInfo = pageInfo;
this.settings = pageInfo.settings;
@ -13,9 +14,7 @@ class ActionHandler {
}
init() {
if (Debug.debug) {
console.log("[ActionHandler::init] starting init");
}
this.logger.log('info', 'debug', "[ActionHandler::init] starting init");
this.keyUpActions = [];
this.keyDownActions = [];
@ -105,15 +104,13 @@ class ActionHandler {
document.addEventListener('keyup', (event) => ths.handleKeyup(event) );
this.pageInfo.setActionHandler(this);
if (Debug.debug) {
console.log("[ActionHandler::init] initialization complete");
}
this.logger.log('info', 'debug', "[ActionHandler::init] initialization complete");
}
registerHandleMouse(videoData) {
if (Debug.debug && Debug.mousemove) {
console.log("[ActionHandler::registerHandleMouse] registering handle mouse for videodata:", videoData)
}
this.logger.log('info', ['actionHandler', 'mousemove'], "[ActionHandler::registerHandleMouse] registering handle mouse for videodata:", videoData)
var ths = this;
if (videoData.player && videoData.player.element) {
videoData.player.element.addEventListener('mousemove', (event) => ths.handleMouseMove(event, videoData));
@ -139,10 +136,10 @@ class ActionHandler {
preventAction() {
var activeElement = document.activeElement;
if(Debug.debug && Debug.keyboard) {
Debug.debug = false; // temp disable to avoid recursing;
if(this.logger.canLog('keyboard')) {
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(),
"\nis tag one of defined inputs? (yes->prevent):", this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1,
"\nis role = textbox? (yes -> prevent):", activeElement.getAttribute("role") === "textbox",
@ -157,7 +154,7 @@ class ActionHandler {
"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
@ -193,15 +190,11 @@ class ActionHandler {
}
execAction(actions, event, videoData) {
if(Debug.debug && Debug.keyboard ){
console.log("%c[ActionHandler::execAction] Trying to find and execute action for event. Actions/event: ", "color: #ff0", actions, event);
}
this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] Trying to find and execute action for event. Actions/event: ", "color: #ff0", actions, event);
for (var action of actions) {
if (this.isActionMatch(action.shortcut, event)) {
if(Debug.debug && Debug.keyboard ){
console.log("%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action);
}
this.logger.log('info', 'keyboard', "%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action);
for (var cmd of action.cmd) {
if (action.scope === 'page') {
@ -249,14 +242,10 @@ class ActionHandler {
handleKeyup(event) {
if(Debug.debug && Debug.keyboard ){
console.log("%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keyup: ", event.keyup, "event:", event);
}
this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keyup: ", event.keyup, "event:", event);
if (this.preventAction()) {
if (Debug.debug && Debug.keyboard) {
console.log("[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing.");
}
this.logger.log('info', 'keyboard', "[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing.");
return;
}
@ -264,14 +253,10 @@ class ActionHandler {
}
handleKeydown(event) {
if(Debug.debug && Debug.keyboard ){
console.log("%c[ActionHandler::handleKeydown] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event);
}
this.logger.log('info', 'keyboard', "%c[ActionHandler::handleKeydown] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event)
if (this.preventAction()) {
if (Debug.debug && Debug.keyboard) {
console.log("[ActionHandler::handleKeydown] we are in a text box or something. Doing nothing.");
}
this.logger.log('info', 'keyboard', "[ActionHandler::handleKeydown] we are in a text box or something. Doing nothing.");
return;
}
@ -279,9 +264,7 @@ class ActionHandler {
}
handleMouseMove(event, videoData) {
if (Debug.debug && Debug.mousemove) {
console.log("[ActionHandler::handleMouseMove] mouse move is being handled.\nevent:", event, "\nvideo data:", videoData);
}
this.logger.log('info', 'keyboard', "[ActionHandler::handleMouseMove] mouse move is being handled.\nevent:", event, "\nvideo data:", videoData);
videoData.panHandler(event);
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 {
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.default = ExtensionConf;
this.default['version'] = this.getExtensionVersion();
@ -23,11 +28,9 @@ class Settings {
if(currentBrowser.firefox) {
browser.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) {
console.log("[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
if (changes['uwSettings'] && changes['uwSettings'].newValue) {
console.log("[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
}
this.logger.log('info', 'settings', "[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) {
this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
}
if(changes['uwSettings'] && changes['uwSettings'].newValue) {
ths.setActive(JSON.parse(changes.uwSettings.newValue));
@ -37,17 +40,15 @@ class Settings {
try {
updateCallback(ths);
} catch (e) {
console.log("[Settings] CALLING UPDATE CALLBACK FAILED.")
this.logger.log('error', 'settings', "[Settings] CALLING UPDATE CALLBACK FAILED.")
}
}
});
} else if (currentBrowser.chrome) {
chrome.storage.onChanged.addListener( (changes, area) => {
if (Debug.debug && Debug.debugStorage) {
console.log("[Settings::<storage/on change>] Settings have been changed outside of here. Updating active settings. Changes:", changes, "storage area:", area);
if (changes['uwSettings'] && changes['uwSettings'].newValue) {
console.log("[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
}
this.logger.log('info', 'settings', "[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) {
this.logger.log('info', 'settings',"[Settings::<storage/on change>] new settings object:", JSON.parse(changes.uwSettings.newValue));
}
if(changes['uwSettings'] && changes['uwSettings'].newValue) {
ths.setActive(JSON.parse(changes.uwSettings.newValue));
@ -57,7 +58,7 @@ class Settings {
try {
updateCallback(ths);
} 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() {
const settings = await this.get();
this.version = this.getExtensionVersion();
// |—> on first setup, settings is undefined & settings.version is haram
// | since new installs ship with updates by default, no patching is
// | needed. In this case, we assume we're on the current version
const oldVersion = (settings && settings.version) || this.getExtensionVersion();
const currentVersion = this.getExtensionVersion();
const oldVersion = (settings && settings.version) || this.version;
if(Debug.debug) {
console.log("[Settings::init] Configuration fetched from storage:", settings,
"\nlast saved with:", settings.version,
"\ncurrent version:", currentVersion
);
this.logger.log('info', 'settings', "[Settings::init] Configuration fetched from storage:", settings,
"\nlast saved with:", settings.version,
"\ncurrent version:", this.version
);
if (Debug.flushStoredSettings) {
console.log("%c[Settings::init] Debug.flushStoredSettings is true. Using default settings", "background: #d00; color: #ffd");
Debug.flushStoredSettings = false; // don't do it again this session
this.active = this.getDefaultSettings();
this.active.version = currentVersion;
this.set(this.active);
return this.active;
}
// if (Debug.flushStoredSettings) {
// 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
// this.active = this.getDefaultSettings();
// this.active.version = this.version;
// this.set(this.active);
// return this.active;
// }
}
// if there's no settings saved, return default settings.
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.version = currentVersion;
this.set(this.active);
this.active.version = this.version;
await this.save();
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
this.active = settings;
// check if extension has been updated. If not, return settings as they were retreived
if (oldVersion == currentVersion) {
if(Debug.debug) {
console.log("[Settings::init] extension was saved with current version of ultrawidify. Returning object as-is.");
}
// 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')) {
this.active = this.getDefaultSettings();
this.active.version = this.version;
await this.save();
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
// new version. In addition to that, we remove old keys that are no longer used.
const patched = ObjectCopy.addNew(settings, this.default);
if(Debug.debug) {
console.log("[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default,);
}
this.logger.log('info', 'settings',"[Settings.init] Results from ObjectCopy.addNew()?", patched, "\n\nSettings from storage", settings, "\ndefault?", this.default);
if(patched){
if (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
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;
// update settings version to current
this.active.version = currentVersion;
this.active.version = this.version;
this.set(this.active);
await this.save();
return this.active;
}
@ -172,13 +264,7 @@ class Settings {
});
}
if (Debug.debug && Debug.debugStorage) {
try {
console.log("[Settings::get] Got settings:", JSON.parse(ret.uwSettings));
} catch (e) {
console.log("[Settings::get] No settings.")
}
}
this.logger.log('info', 'settings', 'Got settings:', ret && ret.uwSettings && JSON.parse(ret.uwSettings));
try {
return JSON.parse(ret.uwSettings);
@ -188,13 +274,12 @@ class Settings {
}
async set(extensionConf) {
if (Debug.debug && Debug.debugStorage) {
console.log("[Settings::set] setting new settings:", extensionConf)
}
extensionConf.version = this.version;
this.logger.log('info', 'settings', "[Settings::set] setting new settings:", extensionConf)
if (currentBrowser.firefox || currentBrowser.edge) {
extensionConf.version = this.version;
return this.useSync ? browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)}): browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
return browser.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
} else if (currentBrowser.chrome) {
return chrome.storage.local.set( {'uwSettings': JSON.stringify(extensionConf)});
}
@ -213,7 +298,7 @@ class Settings {
console.log("[Settings::save] Saving active settings:", this.active);
}
this.set(this.active);
await this.set(this.active);
}
async rollback() {
@ -224,12 +309,6 @@ class Settings {
return JSON.parse(JSON.stringify(this.default));
}
setDefaultSettings() {
this.default.version = this.getExtensionVersion();
this.set(this.default);
}
// -----------------------------------------
// Nastavitve za posamezno stran
// Config for a given page:
@ -266,10 +345,7 @@ class Settings {
site = window.location.hostname;
if (!site) {
if (Debug.debug) {
console.log("[Settings::canStartExtension] window.location.hostname is null or undefined:", window.location.hostname)
console.log("active settings:", this.active)
}
this.logger.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
return ExtensionMode.Disabled;
}
}
@ -291,9 +367,8 @@ class Settings {
}
} catch(e){
if(Debug.debug){
console.log("[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\n\nerror:", e, "\n\nSettings object:", this)
}
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)
return ExtensionMode.Disabled;
}
}
@ -304,8 +379,7 @@ class Settings {
site = window.location.hostname;
if (!site) {
console.log("[Settings::canStartExtension] window.location.hostname is null or undefined:", window.location.hostname)
console.log("active settings:", this.active)
this.logger.log('info', 'settings', `[Settings::canStartExtension] window.location.hostname is null or undefined: ${window.location.hostname} \nactive settings:`, this.active);
return false;
}
}
@ -331,10 +405,8 @@ class Settings {
} else {
return false;
}
} catch(e){
if(Debug.debug){
console.log("[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\nSettings object:", this)
}
} catch(e) {
this.logger.log('error', 'settings', "[Settings.js::canStartExtension] Something went wrong — are settings defined/has init() been called?\nSettings object:", this);
return false;
}
}
@ -356,9 +428,7 @@ class Settings {
return this.active.sites[site].keyboardShortcutsEnabled === ExtensionMode.Enabled;
}
} catch (e) {
if (Debug.debug) {
console.error("[Settings.js::keyboardDisabled] something went wrong:", e);
}
this.logger.log('info', 'settings',"[Settings.js::keyboardDisabled] something went wrong:", e);
return false;
}
}
@ -389,12 +459,12 @@ class Settings {
const csar = this.canStartAutoAr(site);
Debug.debug = true;
console.log("[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'],
"\nAutoar mode (global)?", this.active.sites['@global'].autoar,
`\nAutoar mode (${site})`, this.active.sites[site] ? this.active.sites[site].autoar : '<not defined>',
"\nCan autoar be started?", csar
);
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'],
"\nAutoar mode (global)?", this.active.sites['@global'].autoar,
`\nAutoar mode (${site})`, this.active.sites[site] ? this.active.sites[site].autoar : '<not defined>',
"\nCan autoar be started?", csar
);
}
// if site is not defined, we use default mode:
@ -405,10 +475,10 @@ class Settings {
if (this.active.sites['@global'].autoar === ExtensionMode.Enabled) {
return this.active.sites[site].autoar !== ExtensionMode.Disabled;
} 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;
} 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;
}
}

View File

@ -12,6 +12,7 @@ import AspectRatio from '../../../common/enums/aspect-ratio.enum';
class ArDetector {
constructor(videoData){
this.logger = videoData.logger;
this.conf = videoData;
this.video = videoData.video;
this.settings = videoData.settings;
@ -36,9 +37,7 @@ class ArDetector {
this._nextTick = false;
this.canDoFallbackMode = false;
if (Debug.init) {
console.log("[ArDetector::ctor] creating new ArDetector. arid:", this.arid);
}
this.logger.log('info', 'init', `[ArDetector::ctor] creating new ArDetector. arid: ${this.arid}`);
}
setManualTick(manualTick) {
@ -50,9 +49,7 @@ class ArDetector {
}
init(){
if (Debug.debug || Debug.init) {
console.log("[ArDetect::init] Initializing autodetection. arid:", this.arid);
}
this.logger.log('info', 'init', `[ArDetect::init] <@${this.arid}> Initializing autodetection.`);
try {
if (this.settings.canStartAutoAr()) {
@ -61,36 +58,27 @@ class ArDetector {
throw "Settings prevent autoar from starting"
}
} catch (e) {
if (Debug.debug) {
console.log("%c[ArDetect::init] INITIALIZATION FAILED!\n", _ard_console_stop, e);
}
this.logger.log('error', 'init', `%c[ArDetect::init] <@${this.arid}> Initialization failed.`, _ard_console_stop, e);
}
}
destroy(){
if(Debug.debug || Debug.init) {
console.log(`[ArDetect::destroy] <arid:${this.arid}>`)
}
this.logger.log('info', 'init', `%c[ArDetect::destroy] <@${this.arid}> Destroying aard.`, _ard_console_stop, e);
// this.debugCanvas.destroy();
this.stop();
}
setup(cwidth, cheight){
if(Debug.debug || Debug.init) {
console.log("[ArDetect::setup] Starting autodetection setup. arid:", this.arid);
}
this.logger.log('info', 'init', `[ArDetect::setup] <@${this.arid}> Starting autodetection setup.`);
//
// [-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
// not do any other setup until this issue is fixed
//
if(this.video.videoWidth === 0 || this.video.videoHeight === 0 ){
if(Debug.debug){
console.log("[ArDetector::setup] video has no width or height!", this.video.videoWidth,"×", this.video.videoHeight)
}
this.logger.log('warn', 'debug', `[ArDetect::setup] <@${this.arid}> This video has zero width or zero height. Dimensions: ${this.video.videoWidth} × ${this.video.videoHeight}`);
this.scheduleInitRestart();
return;
}
@ -170,9 +158,7 @@ class ArDetector {
//
if (this.fallbackMode) {
if(Debug.debug) {
console.log("%c[ArDetect::setup] WARNING: CANVAS RESET DETECTED - recalculating guardLine", "background: #000; color: #ff2" )
}
this.logger.log('warn', 'debug', `[ArDetect::setup] <@${this.arid}> WARNING: CANVAS RESET DETECTED/we're in fallback mode - recalculating guardLine`, "background: #000; color: #ff2");
// blackbar, imagebar
this.guardLine.reset();
}
@ -214,9 +200,8 @@ class ArDetector {
}
start() {
if (Debug.debug) {
console.log("%c[ArDetect::setup] Starting automatic aspect ratio detection.", _ard_console_start);
}
this.logger.log('info', 'debug', `"%c[ArDetect::start] <@${this.arid}> Starting automatic aspect ratio detection`, _ard_console_start);
if (this.conf.resizer.lastAr.type === AspectRatio.Automatic) {
// ensure first autodetection will run in any case
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.
this._paused = false;
this._halted = false;
this._paused = false;
}
unpause() {
@ -250,9 +236,7 @@ class ArDetector {
}
stop(){
if(Debug.debug){
console.log("%c[ArDetect::_ard_stop] Stopping automatic aspect ratio detection", _ard_console_stop);
}
this.logger.log('info', 'debug', `"%c[ArDetect::stop] <@${this.arid}> Stopping automatic aspect ratio detection`, _ard_console_stop);
this._halted = true;
// this.conf.resizer.setArLastAr();
}
@ -272,21 +256,15 @@ class ArDetector {
let exitedRetries = 10;
while (!this._exited && exitedRetries --> 0) {
if (Debug.debug) {
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 ...")
}
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 ...`);
await this.sleep(this.settings.active.arDetect.timers.tickrate);
}
if (!this._exited) {
if (Debug.debug) {
console.log("[ArDetector::main] Previous instance didn't exit in time. Not starting a new one.")
}
this.logger.log('error', 'debug', `[ArDetect::main] <@${this.arid}> Previous instance didn't exit in time. Not starting a new one.`);
return;
}
if (Debug.debug) {
console.log("%c[ArDetect::main] Main autodetection loop started.", _ard_console_start);
}
this.logger.log('info', 'debug', `%c[ArDetect::main] <@${this.arid}> Previous instance didn't exit in time. Not starting a new one.`);
// we need to unhalt:
this._halted = false;
@ -313,9 +291,7 @@ class ArDetector {
try {
this.frameCheck();
} catch (e) {
if (Debug.debug) {
console.log("%c[ArDetector::main] Frame check failed:", "color: #000, background: #f00", e);
}
this.logger.log('error', 'debug', `%c[ArDetect::main] <@${this.arid}> Frame check failed:`, "color: #000, background: #f00", e);
}
if (Debug.performanceMetrics) {
@ -329,9 +305,7 @@ class ArDetector {
await this.sleep(this.settings.active.arDetect.timers.tickrate);
}
if (Debug.debug) {
console.log(`%c[ArDetect::main] Main autodetection loop exited. Halted? ${this._halted}`, _ard_console_stop);
}
this.logger.log('info', 'debug', `%c[ArDetect::main] <@${this.arid}> Main autodetection loop exited. Halted? ${this._halted}`, _ard_console_stop);
this._exited = true;
}
@ -376,8 +350,10 @@ class ArDetector {
this.setupTimer = setTimeout(function(){
ths.setupTimer = null;
try{
ths.main();
}catch(e){console.log("[ArDetector::scheduleInitRestart] Failed to start init(). Error:",e)}
ths.main();
} catch(e) {
this.logger('error', 'debug', `[ArDetector::scheduleInitRestart] <@${this.arid}> Failed to start main(). Error:`,e);
}
ths = null;
},
timeout
@ -402,37 +378,14 @@ class ArDetector {
}
canvasReadyForDrawWindow(){
if(Debug.debug)
console.log("%c[ArDetect::_ard_canvasReadyForDrawWindow] (?)", "color: #44f", this.canvas.height == window.innerHeight, "(ard_height:", this.canvas.height, "| window height:", window.innerHeight, ")");
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.`)
return this.canvas.height == window.innerHeight
}
getTimeout(baseTimeout, 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;
}
//#endregion
@ -491,9 +444,7 @@ class ArDetector {
var trueHeight = this.canvas.height * zoomFactor - letterbox;
if(edges.top > 1 && edges.top <= this.settings.active.arDetect.fallbackMode.noTriggerZonePx ){
if(Debug.debug && Debug.debugArDetect) {
console.log("Edge is in the no-trigger zone. Aspect ratio change is not triggered.")
}
this.logger.log('info', 'arDetect', `%c[ArDetect::calculateArFromEdges] <@${this.arid}> Edge is in the no-trigger zone. Aspect ratio change is not triggered.`)
return;
}
@ -508,7 +459,6 @@ class ArDetector {
}
processAr(trueAr){
let actualHeight = 0; // purely for fallback mode
this.detectedAr = trueAr;
// poglejmo, če se je razmerje stranic spremenilo
@ -529,33 +479,22 @@ class ArDetector {
// ali je sprememba v mejah dovoljenega? Če da -> fertik
// is ar variance within acceptable levels? If yes -> we done
if(Debug.debug && Debug.debugArDetect)
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);
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);
if (arDiff < trueAr * this.settings.active.arDetect.allowedArVariance){
if(Debug.debug && Debug.debugArDetect)
console.log("%c[ArDetect::processAr] aspect ratio change denied — diff %:", "background: #740; color: #fa2", arDiff_percent)
this.logger.log('info', 'arDetect', `%c[ArDetect::processAr] <@${this.arid}> Aspect ratio change denied — diff %: ${arDiff_percent}`, "background: #740; color: #fa2");
return;
}
else if(Debug.debug && Debug.debugArDetect){
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', 'arDetect', `%c[ArDetect::processAr] <@${this.arid}> aspect ratio change accepted — diff %: ${arDiff_percent}`, "background: #153; color: #4f9");
}
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});
}
frameCheck(){
if(! this.video){
if(Debug.debug || Debug.warnings_critical) {
console.log("[ArDetect::frameCheck] Video went missing. Destroying current instance of videoData.")
}
this.logger.log('error', 'debug', `%c[ArDetect::frameCheck] <@${this.arid}> Video went missing. Destroying current instance of videoData.`);
this.conf.destroy();
return;
}
@ -574,9 +513,8 @@ class ArDetector {
this.blackframeContext.drawImage(this.video, 0, 0, this.blackframeCanvas.width, this.blackframeCanvas.height);
this.fallbackMode = false;
} catch (e) {
if(Debug.debug && Debug.debugArDetect) {
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);
}
this.logger.log('error', 'arDetect', `%c[ArDetect::frameCheck] <@${this.arid}> %c[ArDetect::frameCheck] can't draw image on canvas. ${this.canDoFallbackMode ? 'Trying canvas.drawWindow instead' : 'Doing nothing as browser doesn\'t support fallback mode.'}`, "color:#000; backgroud:#f51;", e);
// nothing to see here, really, if fallback mode isn't supported by browser
if (! this.canDoFallbackMode) {
return;
@ -607,28 +545,20 @@ class ArDetector {
try {
this.context.drawWindow(window, this.canvasDrawWindowHOffset, 0, this.canvas.width, this.canvas.height, "rgba(0,0,128,1)");
} 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
}
// draw blackframe sample from our main sample:
this.blackframeContext.drawImage(this.canvas, this.blackframeCanvas.width, this.blackframeCanvas.height)
if (Debug.debug) {
console.log("%c[ArDetect::frameCheck] canvas.drawImage seems to have worked", "color:#000; backgroud:#2f5;");
}
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] canvas.drawImage seems to have worked`, "color:#000; backgroud:#2f5;");
}
const bfanalysis = this.blackframeTest();
if (bfanalysis.isBlack) {
// we don't do any corrections on frames confirmed black
if (Debug.debug && Debug.arDetect) {
console.log("%c[ArDetect::frameCheck] Black frame analysis suggests this frame is black or too dark. Doing nothing,", "color: #fa3", bfanalysis);
}
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);
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.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;
}
@ -669,10 +597,7 @@ class ArDetector {
// če ni padla nobena izmed funkcij, potem se razmerje stranic ni spremenilo
// if both succeed, then aspect ratio hasn't changed.
if (!guardLineOut.imageFail && !guardLineOut.blackbarFail) {
if(Debug.debug && Debug.debugArDetect){
console.log(`%c[ArDetect::frameCheck] guardLine tests were successful. (no imagefail and no blackbarfail)\n`, "color: #afa", guardLineOut);
}
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] guardLine tests were successful. (no imagefail and no blackbarfail)\n`, "color: #afa", guardLineOut);
return;
}
@ -709,25 +634,20 @@ class ArDetector {
if(guardLineOut.blackbarFail || guardLineOut.imageFail){
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){
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.guardLine.reset();
}
triggerTimeout = this.getTimeout(baseTimeout, startTime);
this.scheduleFrameCheck(triggerTimeout);
return;
}
}
} catch(e) {
if(Debug.debug) {
console.log("[ArDetect.js::frameCheck] something went wrong when checking for pillarbox. Error:\n", e)
}
this.logger.log('info', 'arDetect', `[ArDetect::frameCheck] something went wrong while checking for pillarbox. Error:\n`, e);
}
// 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);
if(Debug.debug && Debug.debugArDetect){
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);
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] edgeDetector returned this\n`, "color: #aaf", edgePost);
if (edgePost.status !== EdgeStatus.AR_KNOWN){
// rob ni bil zaznan, zato ne naredimo ničesar.
// no edge was detected. Let's leave things as they were
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);
}
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Edge wasn't detected with findBars`, "color: #fa3", edgePost, "EdgeStatus.AR_KNOWN:", EdgeStatus.AR_KNOWN);
return;
}
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){
console.log(`%c[ArDetect::frameCheck] Triggering aspect ration change! new ar: ${newAr}`, "color: #aaf");
}
this.logger.log('info', 'arDetect_verbose', `%c[ArDetect::frameCheck] Triggering aspect ration change! new ar: ${newAr}`, "color: #aaf");
// we also know edges for guardline, so set them.
// we need to be mindful of fallbackMode though
// if edges are okay and not invalid, we also
@ -800,7 +696,12 @@ class ArDetector {
} catch (e) {
// edges weren't gucci, so we'll just reset
// 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()});
}
}
@ -815,10 +716,7 @@ class ArDetector {
blackframeTest() {
if (this.blackLevel === undefined) {
if (Debug.debug && Debug.debugArDetect) {
console.log("[ArDetect::frameCheck] black level undefined, resetting");
}
this.logger.log('info', 'arDetect_verbose', "[ArDetect::blackframeTest] black level undefined, resetting");
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
if(! fallbackMode && (! this.blackbar.top || ! this.blackbar.bottom)) {
// console.log("NO EDGE WAS DETECTED. THIS TEST IS POINTLESS. btw guardline")
return { success: true };
}

View File

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

View File

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

View File

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

View File

@ -9,7 +9,8 @@ if(Debug.debug)
class PageInfo {
constructor(comms, settings, extensionMode, readOnly = false){
constructor(comms, settings, logger, extensionMode, readOnly = false){
this.logger = logger;
this.hasVideos = false;
this.siteDisabled = false;
this.videos = [];
@ -20,6 +21,7 @@ class PageInfo {
this.extensionMode = extensionMode;
this.readOnly = readOnly;
if (comms){
this.comms = comms;
}
@ -64,9 +66,7 @@ class PageInfo {
}
destroy() {
if(Debug.debug || Debug.init){
console.log("[PageInfo::destroy] destroying all videos!")
}
this.logger.log('info', ['debug', 'init'], "[PageInfo::destroy] destroying all videos!")
if(this.rescanTimer){
clearTimeout(this.rescanTimer);
}
@ -75,7 +75,7 @@ class PageInfo {
this.comms.unregisterVideo(video.id)
video.destroy();
} 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;
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;
if(rescanReason == RescanReason.PERIODIC){
if (Debug.debug && Debug.videoRescan && Debug.periodic) {
console.log("[PageInfo::rescan] Scheduling normal rescan:")
}
this.scheduleRescan(RescanReason.PERIODIC);
}
return;
}
var videoExists = false;
var video, v;
// add new videos
this.hasVideos = false;
var videoExists = false;
var video, v;
for (video of vids) {
// če najdemo samo en video z višino in širino, to pomeni, da imamo na strani veljavne videe
// če trenutni video nima definiranih teh vrednostih, preskočimo vse nadaljnja preverjanja
// <===[:::::::]===>
// 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) {
// če najdemo samo en video z višino in širino, to pomeni, da imamo na strani veljavne videe
// če trenutni video nima definiranih teh vrednostih, preskočimo vse nadaljnja preverjanja
// <===[:::::::]===>
// 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) {
// in lite mode, we're done. This is all the info we want, but we want to actually start doing
// things that interfere with the website. We still want to be runnig a rescan, tho.
if (this.readOnly) {
// in lite mode, we're done. This is all the info we want, but we want to actually start doing
// things that interfere with the website. We still want to be runnig a rescan, tho.
if(rescanReason == RescanReason.PERIODIC){
this.scheduleRescan(RescanReason.PERIODIC);
if(rescanReason == RescanReason.PERIODIC){
this.scheduleRescan(RescanReason.PERIODIC);
}
return;
}
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 {
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) {
// č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
// 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
if (Debug.debug) {
console.log("rescan error: — destroying all videoData objects",e);
}
this.logger.log('error', 'debug', "rescan error: — destroying all videoData objects",e);
for (const v of this.videos) {
v.destroy();
}
@ -275,9 +271,7 @@ class PageInfo {
ths = null;
}, this.settings.active.pageInfo.timeouts.rescan, RescanReason.PERIODIC)
} catch(e) {
if(Debug.debug){
console.log("[PageInfo::scheduleRescan] scheduling rescan failed. Here's why:",e)
}
this.logger.log('error', 'debug', "[PageInfo::scheduleRescan] scheduling rescan failed. Here's why:",e)
}
}
@ -289,23 +283,19 @@ class PageInfo {
var ths = this;
this.rescanTimer = setTimeout(function(){
ths.rescanTimer = null;
this.urlCheckTimer = setTimeout(function(){
ths.urlCheckTimer = null;
ths.ghettoUrlCheck();
ths = null;
}, this.settings.active.pageInfo.timeouts.urlCheck)
} catch(e){
if(Debug.debug){
console.error("[PageInfo::scheduleUrlCheck] scheduling URL check failed. Here's why:",e)
}
this.logger.log('error', 'debug', "[PageInfo::scheduleUrlCheck] scheduling URL check failed. Here's why:",e)
}
}
ghettoUrlCheck() {
if (this.lastUrl != window.location.href){
if(Debug.debug && Debug.periodic){
console.log("[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!");
}
this.logger.log('error', 'videoRescan', "[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!");
this.rescan(RescanReason.URL_CHANGE);
this.lastUrl = window.location.href;
@ -369,7 +359,7 @@ class PageInfo {
startArDetection(playingOnly){
if (Debug.debug) {
console.log('[PageInfo::startArDetection()] starting automatic ar detection!')
this.logger.log('info', 'debug', '[PageInfo::startArDetection()] starting automatic ar detection!')
}
if (playingOnly) {
for(var vd of this.videos){
@ -399,16 +389,12 @@ class PageInfo {
}
setAr(ar, playingOnly){
if (Debug.debug) {
console.log('[PageInfo::setAr] aspect ratio:', ar, "playing only?", playingOnly)
}
this.logger.log('info', 'debug', '[PageInfo::setAr] aspect ratio:', ar, "playing only?", playingOnly)
if (ar.type !== AspectRatio.Automatic) {
this.stopArDetection(playingOnly);
} else {
if (Debug.debug) {
console.log('[PageInfo::setAr] aspect ratio is auto');
}
this.logger.log('info', 'debug', '[PageInfo::setAr] aspect ratio is auto');
try {
for (var vd of this.videos) {
@ -417,7 +403,7 @@ class PageInfo {
}
}
} catch (e) {
console.log("???", e);
this.logger.log('error', 'debug', "???", e);
}
this.initArDetection(playingOnly);
this.startArDetection(playingOnly);
@ -440,16 +426,16 @@ class PageInfo {
}
}
setvideoAlignment(videoAlignment, playingOnly) {
setVideoAlignment(videoAlignment, playingOnly) {
if (playingOnly) {
for(var vd of this.videos) {
if (vd.isPlaying()) {
vd.setvideoAlignment(videoAlignment)
vd.setVideoAlignment(videoAlignment)
}
}
} else {
for(var vd of this.videos) {
vd.setvideoAlignment(videoAlignment)
vd.setVideoAlignment(videoAlignment)
}
}
}

View File

@ -34,24 +34,49 @@ if(Debug.debug)
class PlayerData {
constructor(videoData) {
this.videoData = videoData;
this.video = videoData.video;
this.settings = videoData.settings;
this.extensionMode = videoData.extensionMode;
this.element = undefined;
this.dimensions = undefined;
this.overlayNode = undefined;
try {
this.logger = videoData.logger;
this.videoData = videoData;
this.video = videoData.video;
this.settings = videoData.settings;
this.extensionMode = videoData.extensionMode;
this.invalid = false;
this.element = this.getPlayer();
this.dimensions = undefined;
this.overlayNode = undefined;
if (this.extensionMode === ExtensionMode.Enabled) {
this.getPlayerDimensions();
// this happens when we don't find a matching player element
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(){
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(){
this.startChangeDetection();
@ -68,10 +93,47 @@ class PlayerData {
}
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(){
clearTimeout(this.watchTimeout);
this.observer.disconnect();
}
makeOverlay() {
@ -117,113 +179,13 @@ class PlayerData {
}
unmarkPlayer() {
if (Debug.debug) {
console.log("[PlayerData::unmarkPlayer] unmarking player!")
}
this.logger.log('info', 'debug', "[PlayerData::unmarkPlayer] unmarking player!")
if (this.playerIdElement) {
this.playerIdElement.remove();
}
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) {
for (let i = 0, len = collection.length; i < len; i++) {
if (collection[i] == element) {
@ -233,7 +195,7 @@ class PlayerData {
return false;
}
getPlayer(isFullScreen) {
getPlayer() {
const host = window.location.host;
let element = this.video.parentNode;
const videoWidth = this.video.offsetWidth, videoHeight = this.video.offsetHeight;
@ -241,197 +203,180 @@ class PlayerData {
let scorePenalty = 0;
let score;
if(! element ){
if(Debug.debug) {
console.log("[PlayerDetect::_pd_getPlayer] element is not valid, doing nothing.", element)
}
if(this.element) {
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;
try {
if(! element ){
this.logger.log('info', 'debug', "[PlayerDetect::_pd_getPlayer] element is not valid, doing nothing.", element)
if(this.element) {
const ths = this;
}
if (element) {
return element;
}
} else if (this.settings.active.sites[host].DOM.player.querySelectors) {
const allSelectors = document.querySelectorAll(this.settings.active.sites[host].DOM.player.querySelectors);
this.element = undefined;
this.dimensions = undefined;
return;
}
// actually we'll also score this branch in a similar way we score the regular, auto branch
while (element) {
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'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;
let parentsLeft = this.settings.active.sites[host].DOM.player.videoAncestor - 1;
while (parentsLeft --> 0) {
element = element.parentNode;
}
if (element) {
return element;
}
} 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
score -= (scorePenalty++) * 20;
// push the element on the queue/stack:
elementQ.push({
score: score,
element: element,
});
element = element.parentNode;
}
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;
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
// remove weird elements, those would break our stuff
if ( element.offsetWidth == 0 || element.offsetHeight == 0){
if (element.id.indexOf('player') !== -1) { // prefer elements with 'player' in id
score += 75;
}
// 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;
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
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,
});
if (elementQ.length) {
// return element with biggest score
return elementQ.sort( (a,b) => b.score - a.score)[0].element;
}
element = element.parentNode;
}
if (elementQ.length) {
// return element with biggest score
return elementQ.sort( (a,b) => b.score - a.score)[0].element;
// if no candidates were found, something is obviously very, _very_ wrong.
// we return nothing. Player will be marked as invalid and setup will stop.
// 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) {
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() {
this.getPlayerDimensions();
this.checkPlayerSizeChange();
}
checkPlayerSizeChange(){
if(Debug.debug){
if(this.element == undefined){
// return true;
}
// if(!this.dimensions) {
// return true;
// }
// 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.dimensions) {
if (this.dimensions && this.dimensions.fullscreen){
} else if (this.dimensions && this.dimensions.fullscreen){
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) {
console.log("[PlayerDetect] player element isnt defined");
if(! this.element) {
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.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();
return true;
} else if(this.dimensions.width != this.element.offsetWidth || this.dimensions.height != this.element.offsetHeight ){
this.element = this.getPlayer();
// if size doesn't match, update & return true
if (!this.dimensions
|| this.dimensions.width != this.element.offsetWidth
|| 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 false;
}
@ -450,9 +395,7 @@ class PlayerData {
return false;
}
if(Debug.debug) {
console.log("[PlayerData::checkFullscreenChange] this.dimensions is not defined. Assuming fs change happened and setting default values.")
}
this.logger.log('info', 'debug', "[PlayerData::checkFullscreenChange] this.dimensions is not defined. Assuming fs change happened and setting default values.")
this.dimensions = {
fullscreen: isFs,

View File

@ -6,6 +6,8 @@ import ArDetector from '../ar-detect/ArDetector';
class VideoData {
constructor(video, settings, pageInfo){
this.vdid = (Math.random()*100).toFixed();
this.logger = pageInfo.logger;
this.arSetupComplete = false;
this.video = video;
this.destroyed = false;
@ -13,85 +15,142 @@ class VideoData {
this.pageInfo = pageInfo;
this.extensionMode = pageInfo.extensionMode;
this.vdid = (Math.random()*100).toFixed();
this.userCssClassName = `uw-fuck-you-and-do-what-i-tell-you_${this.vdid}`;
// We'll replace cssWatcher (in resizer) with mutationObserver
// We only init observers once player is confirmed valid
const observerConf = {
attributes: true,
// attributeFilter: ['style', 'class'],
attributeOldValue: true,
};
this.observer = new MutationObserver(this.onVideoDimensionsChanged);
this.observer.observe(video, observerConf);
// POZOR: VRSTNI RED JE POMEMBEN (arDetect mora bit zadnji)
// NOTE: ORDERING OF OBJ INITIALIZATIONS IS IMPORTANT (arDetect needs to go last)
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
// player dimensions need to be in:
// this.player.dimensions
// apply default align and stretch
if (Debug.init) {
console.log("%c[VideoData::ctor] Initial resizer reset!", {background: '#afd', color: '#132'});
}
this.logger.log('info', 'debug', "%c[VideoData::ctor] Initial resizer reset!", {background: '#afd', color: '#132'});
this.resizer.reset();
if (Debug.init) {
console.log("[VideoData::ctor] Created videoData with vdid", this.vdid,"\nextension mode:", this.extensionMode);
}
this.logger.log('info', ['debug', 'init'], '[VideoData::ctor] Created videoData with vdid', this.vdid, '\nextension mode:', this.extensionMode)
this.pageInfo.initMouseActionHandler(this);
this.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) {
if (!mutationList || this.video === undefined) { // something's wrong
if (observer && this.video) {
async fallbackChangeDetection() {
while (!this.destroyed && !this.invalid) {
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();
}
return;
}
for (let mutation of mutationList) {
if (mutation.type === 'attributes') {
if (mutation.attributeName === 'class') {
if (!this.video.classList.contains(this.userCssClassName)) {
// force the page to include our class in classlist, if the classlist has been removed
this.video.classList.add(this.userCssClassName);
// } else if () {
// this bug should really get
} else {
this.restoreAr();
}
} 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);
}
}
if (mutation.type === 'attributes'
&& mutation.attributeName === 'class'
&& !context.video.classList.contains(this.userCssClassName) ) {
// force the page to include our class in classlist, if the classlist has been removed
// 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
// removed. classList.add() will _still_ trigger mutation (even if classlist wouldn't change).
// This is a problem because INFINITE RECURSION TIME, and we _really_ don't want that.
context.video.classList.add(this.userCssClassName);
break;
}
}
// 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(){
if(this.destroyed) {
if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
}
@ -101,7 +160,7 @@ class VideoData {
}
initArDetection() {
if(this.destroyed) {
if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
}
@ -115,10 +174,8 @@ class VideoData {
}
startArDetection() {
if (Debug.debug) {
console.log("[VideoData::startArDetection] starting AR detection")
}
if(this.destroyed) {
this.logger.log('info', 'debug', "[VideoData::startArDetection] starting AR detection")
if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
}
@ -129,7 +186,7 @@ class VideoData {
}
rebootArDetection() {
if(this.destroyed) {
if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
}
@ -143,37 +200,29 @@ class VideoData {
}
destroy() {
if(Debug.debug || Debug.init){
console.log(`[VideoData::destroy] <vdid:${this.vdid}> received destroy command`);
}
this.logger.log('info', ['debug', 'init'], `[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.destroyed = true;
if (this.arDetector){
try {
this.arDetector.stop();
this.arDetector.destroy();
} catch (e) {}
}
try {
this.arDetector.stop();
this.arDetector.destroy();
} catch (e) {}
this.arDetector = undefined;
if (this.resizer){
try {
this.resizer.destroy();
} catch (e) {}
}
try {
this.resizer.destroy();
} catch (e) {}
this.resizer = undefined;
if (this.player){
try {
this.player.destroy();
} catch (e) {}
}
if (this.observer) {
try {
this.observer.disconnect();
} catch (e) {}
}
try {
this.player.destroy();
} catch (e) {}
try {
this.observer.disconnect();
} catch (e) {}
this.player = undefined;
this.video = undefined;
}
@ -189,7 +238,7 @@ class VideoData {
}
resume(){
if(this.destroyed) {
if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
}
@ -200,9 +249,7 @@ class VideoData {
this.player.start();
}
} catch (e) {
if(Debug.debug){
console.log("[VideoData.js::resume] cannot resume for reasons. Will destroy videoData. Error here:", e);
}
this.logger.log('error', 'debug', "[VideoData.js::resume] cannot resume for reasons. Will destroy videoData. Error here:", e);
this.destroy();
}
}
@ -226,22 +273,37 @@ class VideoData {
}
setLastAr(lastAr){
if (this.invalid) {
return;
}
this.resizer.setLastAr(lastAr);
}
setAr(ar, lastAr){
if (this.invalid) {
return;
}
this.resizer.setAr(ar, lastAr);
}
resetAr() {
if (this.invalid) {
return;
}
this.resizer.reset();
}
resetLastAr() {
if (this.invalid) {
return;
}
this.resizer.setLastAr('original');
}
panHandler(event, forcePan) {
if (this.invalid) {
return;
}
if(this.destroyed) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
return;
@ -254,34 +316,58 @@ class VideoData {
}
setPanMode(mode) {
if (this.invalid) {
return;
}
this.resizer.setPanMode(mode);
}
setvideoAlignment(videoAlignment) {
this.resizer.setvideoAlignment(videoAlignment);
setVideoAlignment(videoAlignment) {
if (this.invalid) {
return;
}
this.resizer.setVideoAlignment(videoAlignment);
}
restoreAr(){
if (this.invalid) {
return;
}
this.resizer.restore();
}
setStretchMode(stretchMode){
if (this.invalid) {
return;
}
this.resizer.setStretchMode(stretchMode);
}
setZoom(zoomLevel, no_announce){
if (this.invalid) {
return;
}
this.resizer.setZoom(zoomLevel, no_announce);
}
zoomStep(step){
if (this.invalid) {
return;
}
this.resizer.zoomStep(step);
}
announceZoom(scale){
if (this.invalid) {
return;
}
this.pageInfo.announceZoom(scale);
}
markPlayer(name, color) {
if (this.invalid) {
return;
}
if (this.player) {
this.player.markPlayer(name, color)
}
@ -291,12 +377,39 @@ class VideoData {
}
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;
}
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;

View File

@ -15,11 +15,14 @@ if(Debug.debug) {
class Resizer {
constructor(videoData) {
this.resizerId = (Math.random(99)*100).toFixed(0);
this.conf = videoData;
this.logger = videoData.logger;
this.video = videoData.video;
this.settings = videoData.settings;
this.extensionMode = videoData.extensionMode;
this.scaler = new Scaler(this.conf);
this.stretcher = new Stretcher(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.destroyed = false;
this.resizerId = (Math.random(99)*100).toFixed(0);
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;
} else {
this.canPan = false;
@ -65,9 +66,7 @@ class Resizer {
}
destroy(){
if(Debug.debug || Debug.init){
console.log(`[Resizer::destroy] <rid:${this.resizerId}> received destroy command.`);
}
this.logger.log('info', ['debug', 'init'], `[Resizer::destroy] <rid:${this.resizerId}> received destroy command.`);
this.destroyed = true;
}
@ -82,9 +81,7 @@ class Resizer {
var ratioOut;
if (!this.conf.video) {
if (Debug.debug) {
console.log("[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
}
this.logger.log('info', 'debug', "[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
this.conf.destroy();
return null;
}
@ -93,9 +90,7 @@ class Resizer {
if (! this.conf.player.dimensions) {
ratioOut = screen.width / screen.height;
} else {
if (Debug.debug && Debug.resizer) {
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)
}
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)
ratioOut = this.conf.player.dimensions.width / this.conf.player.dimensions.height;
}
@ -114,9 +109,7 @@ class Resizer {
ar.ratio = ratioOut < fileAr ? ratioOut : fileAr;
}
else if(ar.type === AspectRatio.Reset){
if(Debug.debug){
console.log("[Scaler.js::modeToAr] Using original aspect ratio -", fileAr);
}
this.logger.log('info', 'debug', "[Scaler.js::modeToAr] Using original aspect ratio -", fileAr);
ar.ratio = fileAr;
} else {
return null;
@ -131,9 +124,7 @@ class Resizer {
return;
}
if(Debug.debug){
console.log('[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', ar)
}
this.logger.log('info', 'debug', '[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', ar)
if (ar == null) {
return;
@ -162,17 +153,13 @@ class Resizer {
// check if property value is on the list of allowed values
// if it's not, we aren't allowed to start aard
if (bannedProperties[prop].allowedValues.indexOf(styleValue) === -1) {
if (Debug.debug) {
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.")
}
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.")
return;
}
} else {
// no allowed values, no problem. We have forbidden property
// and this means aard can't start.
if (Debug.debug) {
console.log("%c[Resizer::setAr] video style contains forbidden css property: ", "color: #900, background: #100", prop, " — we aren't allowed to start autoar.")
}
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.")
return;
}
}
@ -191,9 +178,7 @@ class Resizer {
// I'm not sure whether they do. Check that.
ar = this.calculateRatioForLegacyOptions(ar);
if (! ar) {
if (Debug.debug && Debug.resizer) {
console.log(`[Resizer::setAr] <${this.resizerId}> Something wrong with ar or the player. Doing nothing.`);
}
this.logger.log('info', 'resizer', `[Resizer::setAr] <${this.resizerId}> Something wrong with ar or the player. Doing nothing.`);
return;
}
this.lastAr = {type: ar.type, ratio: ar.ratio}
@ -206,12 +191,11 @@ class Resizer {
}
if (! this.video) {
// console.log("No video detected.")
this.conf.destroy();
}
// // pause AR on basic stretch, unpause when using other mdoes
// fir sine reason unpause doesn't unpause. investigate that later
// pause AR on basic stretch, unpause when using other modes
// for sine reason unpause doesn't unpause. investigate that later
try {
if (this.stretcher.mode === Stretch.Basic) {
this.conf.arDetector.pause();
@ -229,16 +213,12 @@ class Resizer {
var stretchFactors = this.scaler.calculateCrop(ar);
if(! stretchFactors || stretchFactors.error){
if(Debug.debug){
console.log("[Resizer::setAr] <rid:"+this.resizerId+"> failed to set AR due to problem with calculating crop. Error:", (stretchFactors ? stretchFactors.error : stretchFactors));
}
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));
if (stretchFactors.error === 'no_video'){
this.conf.destroy();
}
if (stretchFactors.error === 'illegal_video_dimensions') {
if(Debug.debug){
console.log("[Resizer::setAr] <rid:"+this.resizerId+"> Illegal video dimensions found. We will pause everything.");
}
this.logger.log('error', 'debug', `[Resizer::setAr] <rid:${this.resizerId}> Illegal video dimensions found. We will pause everything.`)
}
return;
}
@ -246,25 +226,17 @@ class Resizer {
this.stretcher.applyConditionalStretch(stretchFactors, ar.ratio);
}
if (Debug.debug) {
console.log("[Resizer::setAr] Processed stretch factors for ", this.stretcher.mode === Stretch.NoStretch ? 'stretch-free crop.' : 'crop with conditional stretch.', 'Stretch factors are:', stretchFactors);
}
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);
} else if (this.stretcher.mode === Stretch.Hybrid) {
var stretchFactors = this.stretcher.calculateStretch(ar.ratio);
if (Debug.debug) {
console.log('[Resizer::setAr] Processed stretch factors for hybrid stretch/crop. Stretch factors are:', stretchFactors);
}
this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for hybrid stretch/crop. Stretch factors are:', stretchFactors);
} else if (this.stretcher.mode === Stretch.Basic) {
var stretchFactors = this.stretcher.calculateBasicStretch();
if (Debug.debug) {
console.log('[Resizer::setAr] Processed stretch factors for basic stretch. Stretch factors are:', stretchFactors);
}
this.logger.log('info', 'debug', '[Resizer::setAr] Processed stretch factors for basic stretch. Stretch factors are:', stretchFactors);
} else {
var stretchFactors = {xFactor: 1, yFactor: 1}
if (Debug.debug) {
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.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);
}
this.zoom.applyZoom(stretchFactors);
@ -293,7 +265,6 @@ class Resizer {
}
panHandler(event, forcePan) {
// console.log("this.conf.canPan:", this.conf.canPan)
if (this.canPan || forcePan) {
if(!this.conf.player || !this.conf.player.element) {
return;
@ -306,10 +277,7 @@ class Resizer {
const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth;
const relativeY = (event.pageY - player.offsetTop) / player.offsetHeight;
if (Debug.debug && Debug.mousemove) {
console.log("[Resizer::panHandler] mousemove.pageX, pageY:", event.pageX, event.pageY,
"\nrelativeX/Y:", relativeX, relativeY)
}
this.logger.log('info', 'mousemove', "[Resizer::panHandler] mousemove.pageX, pageY:", event.pageX, event.pageY, "\nrelativeX/Y:", relativeX, relativeY)
this.setPan(relativeX, relativeY);
}
@ -329,21 +297,16 @@ class Resizer {
this.pan.relativeOffsetX = -(relativeMousePosX * 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();
}
setvideoAlignment(videoAlignment) {
setVideoAlignment(videoAlignment) {
this.videoAlignment = videoAlignment;
this.restore();
}
restore() {
if(Debug.debug){
console.log("[Resizer::restore] <rid:"+this.resizerId+"> attempting to restore aspect ratio. this & settings:", {'a_lastAr': this.lastAr, 'this': this, "settings": this.settings} );
}
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} );
// this is true until we verify that css has actually been applied
if(this.lastAr.type === AspectRatio.Initial){
@ -351,7 +314,9 @@ class Resizer {
}
else {
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)
}
@ -405,9 +370,7 @@ class Resizer {
computeOffsets(stretchFactors){
if (Debug.debug) {
console.log("[Resizer::computeOffsets] <rid:"+this.resizerId+"> video will be aligned to ", this.settings.active.sites['@global'].videoAlignment);
}
this.logger.log('info', 'debug', "[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 hdiff = this.conf.player.dimensions.height - this.conf.video.offsetHeight;
@ -436,16 +399,14 @@ class Resizer {
}
}
if(Debug.debug) {
console.log("[Resizer::_res_computeOffsets] <rid:"+this.resizerId+"> calculated offsets:\n\n",
'---- data in ----\n',
'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},
'stretch factors: ', stretchFactors,
'pan & zoom: ', this.pan, this.zoom,
'\n\n---- data out ----\n',
'translate:', translate);
}
this.logger.log('info', 'debug', "[Resizer::_res_computeOffsets] <rid:"+this.resizerId+"> calculated offsets:\n\n",
'---- data in ----\n',
'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},
'stretch factors: ', stretchFactors,
'pan & zoom: ', this.pan, this.zoom,
'\n\n---- data out ----\n',
'translate:', translate);
return translate;
}
@ -507,18 +468,13 @@ class Resizer {
// apply extra CSS here. In case of duplicated properties, extraCss overrides
// default styleString
if (! this.video) {
if(Debug.debug) {
console.log("[Resizer::applyCss] <rid:"+this.resizerId+"> Video went missing, doing nothing.");
}
this.logger.log('warn', 'debug', "[Resizer::applyCss] <rid:"+this.resizerId+"> Video went missing, doing nothing.");
this.conf.destroy();
return;
}
if (Debug.debug && Debug.resizer) {
console.log("[Resizer::applyCss] <rid:"+this.resizerId+"> will apply css.", {stretchFactors, translate, video: this.video});
}
this.logger.log('info', 'resizer', "[Resizer::applyCss] <rid:"+this.resizerId+"> will apply css.", {stretchFactors, translate});
// save stuff for quick tests (before we turn numbers into css values):
this.currentVideoSettings = {
@ -539,7 +495,15 @@ class Resizer {
// add remaining elements
if (stretchFactors) {
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

View File

@ -11,6 +11,7 @@ class Scaler {
// functions
constructor(videoData) {
this.conf = videoData;
this.logger = videoData.logger;
}
@ -25,9 +26,7 @@ class Scaler {
var ratioOut;
if (!this.conf.video) {
if(Debug.debug){
console.log("[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
}
this.logger.log('error', 'debug', "[Scaler.js::modeToAr] No video??",this.conf.video, "killing videoData");
this.conf.destroy();
return null;
}
@ -59,9 +58,7 @@ class Scaler {
return ratioOut;
}
else if(ar.type === AspectRatio.Reset){
if(Debug.debug){
console.log("[Scaler.js::modeToAr] Using original aspect ratio -", fileAr)
}
this.logger.log('info', 'debug', "[Scaler.js::modeToAr] Using original aspect ratio -", fileAr)
ar.ar = fileAr;
return fileAr;
}
@ -71,9 +68,7 @@ class Scaler {
calculateCrop(ar) {
if(!this.conf.video){
if (Debug.debug) {
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.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);
this.conf.destroy();
return {error: "no_video"};
@ -81,9 +76,7 @@ class Scaler {
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
// mr officer will let you go with a warning this time around
if (Debug.debug) {
console.log("[Scaler::calculateCrop] Video has illegal dimensions. Video dimensions:", this.conf.video && this.conf.video.videoWidth, '×', this.conf.video && this.conf.video.videoHeight);
}
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);
return {error: "illegal_video_dimensions"};
}
@ -94,20 +87,14 @@ class Scaler {
// handle fuckie-wuckies
if (!ar.ratio){
if (Debug.debug && Debug.scaler) {
console.log("[Scaler::calculateCrop] no ar?", ar.ratio, " -- we were given this mode:", ar);
}
this.logger.log('error', 'scaler', "[Scaler::calculateCrop] no ar?", ar.ratio, " -- we were given this mode:", ar);
return {error: "no_ar", ratio: ar.ratio};
}
if (Debug.debug && Debug.scaler) {
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);
}
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);
if( (! this.conf.player.dimensions) || this.conf.player.dimensions.width === 0 || this.conf.player.dimensions.height === 0 ){
if (Debug.debug && Debug.scaler) {
console.log("[Scaler::calculateCrop] ERROR — no (or invalid) this.conf.player.dimensions:",this.conf.player.dimensions);
}
this.logger.log('error', 'scaler', "[Scaler::calculateCrop] ERROR — no (or invalid) this.conf.player.dimensions:",this.conf.player.dimensions);
return {error: "this.conf.player.dimensions_error"};
}
@ -124,9 +111,7 @@ class Scaler {
}
if (Debug.debug && Debug.scaler) {
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);
}
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);
var videoDimensions = {
xFactor: 1,
@ -135,16 +120,9 @@ class Scaler {
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){
// 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)
// 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.yFactor = videoDimensions.xFactor;
} else {
@ -152,9 +130,7 @@ class Scaler {
videoDimensions.yFactor = videoDimensions.xFactor;
}
if (Debug.debug && Debug.scaler) {
console.log("[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
}
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
return videoDimensions;
}

View File

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

View File

@ -6,12 +6,14 @@ import Debug from '../../conf/Debug';
class Zoom {
// functions
constructor(videoData) {
this.conf = videoData;
this.logger = videoData.logger;
this.scale = 1;
this.logScale = 0;
this.scaleStep = 0.1;
this.minScale = -1; // 50% (log2(0.5) = -1)
this.maxScale = 3; // 800% (log2(8) = 3)
this.conf = videoData;
}
reset(){
@ -30,18 +32,14 @@ class Zoom {
this.scale = Math.pow(2, this.logScale);
if (Debug.debug) {
console.log("[Zoom::zoomStep] changing zoom by", amount, ". New zoom level:", this.scale);
}
this.logger.log('info', 'debug', "[Zoom::zoomStep] changing zoom by", amount, ". New zoom level:", this.scale);
this.conf.restoreAr();
this.conf.announceZoom(this.scale);
}
setZoom(scale, no_announce){
if (Debug.debug) {
console.log("[Zoom::setZoom] Setting zoom to", scale, "!");
}
this.logger.log('info', 'debug', "[Zoom::setZoom] Setting zoom to", scale, "!");
// NOTE: SCALE IS NOT LOGARITHMIC
if(scale < Math.pow(2, this.minScale)) {
@ -62,16 +60,12 @@ class Zoom {
if (!stretchFactors) {
return;
}
if (Debug.debug) {
console.log("[Zoom::setZoom] Applying zoom. Stretch factors pre:", stretchFactors, " —> scale:", this.scale);
}
this.logger.log('info', 'debug', "[Zoom::setZoom] Applying zoom. Stretch factors pre:", stretchFactors, " —> scale:", this.scale);
stretchFactors.xFactor *= this.scale;
stretchFactors.yFactor *= this.scale;
if (Debug.debug) {
console.log("[Zoom::setZoom] Applying zoom. Stretch factors post:", stretchFactors);
}
this.logger.log('info', 'debug', "[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 CommsServer from './lib/comms/CommsServer';
import Settings from './lib/Settings';
import Logger from './lib/Logger';
var BgVars = {
arIsActive: true,
@ -30,8 +30,14 @@ class UWServer {
}
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();
this.comms = new CommsServer(this);
@ -42,7 +48,6 @@ class UWServer {
chrome.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)});
}
console.log("will schedule gcframe")
this.scheduleGc();
}
@ -54,18 +59,13 @@ class UWServer {
async injectCss(css, sender) {
try {
if (Debug.debug) {
console.log("[uwbg::injectCss] Injecting CSS:", css, sender);
}
if (BrowserDetect.firefox || BrowserDetect.edge) {
browser.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId});
} else if (BrowserDetect.chrome) {
chrome.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId});
}
} catch (e) {
if (Debug.debug) {
console.error("Error while injecting css:", {error: e, css, sender});
}
this.logger.log('error','debug', '[UwServer::injectCss] Error while injecting css:', {error: e, 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
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) {
@ -99,7 +101,6 @@ class UWServer {
clearTimeout(ths._gctimeout);
ths.gcFrames();
ths._gctimeoutgcTimeout = ths.scheduleGc(5000);
}, timeout);
}
@ -124,26 +125,20 @@ class UWServer {
async onTabSwitched(activeInfo){
this.hasVideos = false;
if(Debug.debug)
console.log("[uw-bg::onTabSwitched] TAB CHANGED, GETTING INFO FROM MAIN TAB");
try {
this.currentTabId = activeInfo.tabId; // just for readability
var tab;
let tab;
if (BrowserDetect.firefox) {
var tab = await browser.tabs.get(this.currentTabId);
tab = await browser.tabs.get(this.currentTabId);
} 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.logger.log('info', 'debug', '[UwServer::onTabSwitched] user switched tab. New site:', this.currentSite);
} catch(e) {
console.log(e);
}
if(Debug.debug) {
console.log("TAB SWITCHED!", this.currentSite)
this.logger.log('error', 'debug', '[UwServer::onTabSwitched] there was a problem getting currnet site:', e)
}
this.selectedSubitem = {
@ -176,9 +171,7 @@ class UWServer {
}
registerVideo(sender) {
if (Debug.debug && Debug.comms) {
console.log("[UWServer::registerVideo] registering video.\nsender:", sender);
}
this.logger.log('info', 'comms', '[UWServer::registerVideo] Registering video.\nsender:', sender);
const tabHostname = this.extractHostname(sender.tab.url);
const frameHostname = this.extractHostname(sender.url);
@ -221,15 +214,11 @@ class UWServer {
}
}
if (Debug.debug && Debug.comms) {
console.log("[UWServer::registerVideo] video registered. current videoTabs:", this.videoTabs);
}
this.logger.log('info', 'comms', '[UWServer::registerVideo] Video registered. current videoTabs:', this.videoTabs);
}
unregisterVideo(sender) {
if (Debug.debug && Debug.comms) {
console.log("[UWServer::unregisterVideo] unregistering video.\nsender:", sender);
}
this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Unregistering video.\nsender:', sender);
if (this.videoTabs[sender.tab.id]) {
if ( Object.keys(this.videoTabs[sender.tab.id].frames).length <= 1) {
delete this.videoTabs[sender.tab.id]
@ -239,15 +228,11 @@ class UWServer {
}
}
}
if (Debug.debug && Debug.comms) {
console.log("[UWServer::ungisterVideo] video unregistered. current videoTabs:", this.videoTabs);
}
this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Video has been unregistered. Current videoTabs:', this.videoTabs);
}
setSelectedTab(menu, subitem) {
if (Debug.debug && Debug.comms) {
console.log("[uw-bg::setSelectedTab] saving selected tab for", menu, ":", subitem)
}
this.logger.log('info', 'comms', '[UwServer::setSelectedTab] saving selected tab for', menu, ':', subitem);
this.selectedSubitem[menu] = subitem;
}

View File

@ -5,6 +5,7 @@ import Settings from './lib/Settings';
import ActionHandler from './lib/ActionHandler';
import CommsClient from './lib/comms/CommsClient';
import PageInfo from './lib/video-data/PageInfo';
import Logger from './lib/Logger';
if(Debug.debug){
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.settings = undefined;
this.actionHandler = undefined;
this.logger = undefined;
}
async init(){
@ -37,68 +39,95 @@ class UW {
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
if (this.pageInfo) {
if(Debug.debug){
console.log("[uw::init] Destroying existing pageInfo", this.pageInfo);
}
// if this executes, logger must have been initiated at some point before this point
this.logger.log('info', 'debug', "[uw::init] Destroying existing pageInfo", this.pageInfo);
this.pageInfo.destroy();
}
if (this.comms) {
this.comms.destroy();
}
if (!this.settings) {
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();
}
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
// If extension is soft-disabled, don't do shit
var extensionMode = this.settings.getExtensionMode();
if(Debug.debug) {
console.log("[uw::init] Extension mode:" + (extensionMode < 0 ? "disabled" : extensionMode == '1' ? 'basic' : 'full'));
}
this.logger.log('info', 'debug', "[uw::init] Extension mode:" + (extensionMode < 0 ? "disabled" : extensionMode == '1' ? 'basic' : 'full'));
const isSiteDisabled = extensionMode === ExtensionMode.Disabled
if (isSiteDisabled) {
if (this.settings.getExtensionMode('@global') === ExtensionMode.Disabled) {
if (Debug.debug) {
console.log("[uw::init] EXTENSION DISABLED, THEREFORE WONT BE STARTED")
}
this.logger.log('info', 'debug', "[uw::init] EXTENSION DISABLED, THEREFORE WONT BE STARTED")
return;
}
}
try {
this.pageInfo = new PageInfo(this.comms, this.settings, extensionMode, isSiteDisabled);
if(Debug.debug){
console.log("[uw.js::setup] pageInfo initialized. Here's the object:", this.pageInfo);
}
this.pageInfo = new PageInfo(this.comms, this.settings, this.logger, extensionMode, isSiteDisabled);
this.logger.log('info', 'debug', "[uw.js::setup] pageInfo initialized. Here's the object:", this.pageInfo);
this.comms.setPageInfo(this.pageInfo);
if(Debug.debug) {
console.log("[uw.js::setup] will try to initate ActionHandler. Settings are:", this.settings, this.settings.active)
}
this.logger.log('info', 'debug', "[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
if (!isSiteDisabled) {
this.actionHandler = new ActionHandler(this.pageInfo);
this.actionHandler.init();
if(Debug.debug) {
console.log("[uw.js::setup] ActionHandler initiated:", this.actionHandler);
}
this.logger.log('info', 'debug', "[uw.js::setup] ActionHandler initiated:", this.actionHandler);
}
} 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,
"name": "Ultrawidify",
"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": {
"gecko": {
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"
@ -55,5 +55,8 @@
],
"permissions": [
"tabs", "storage", "activeTab", "<all_urls>", "webNavigation"
],
"optional_permissions": [
"downloads"
]
}

View File

@ -1,5 +1,5 @@
<template>
<div>
<div v-if="settingsInitialized">
<!-- POPUPS -->
<div v-if="anyOpenedPopups"
@ -136,6 +136,7 @@ export default {
selectedTab: "general",
selectedTabTitle: "General settings",
settings: {},
logger: {},
settingsInitialized: false,
editActionPopupVisible: false,
editActionIndex: -1,
@ -148,8 +149,15 @@ export default {
}
},
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();
this.settingsInitialized = true;
},
components: {

View File

@ -33,7 +33,7 @@
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,
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 class="flex flex-row row-padding">
@ -610,7 +610,6 @@ export default {
ctx.drawWindow(window,0, 0, 10, 10, "rgba(0,0,0,0)");
this.fallbackModeAvailable = true;
} catch (e) {
// console.log("DrawWindow failed:", e)
this.fallbackModeAvailable = false;
}
},
@ -634,7 +633,6 @@ export default {
return 'user-defined';
},
setConfirmationThresholds(sens) {
console.log("setting conf treshold", sens)
if (sens === 'sensitive') {
this.settings.active.arDetect.edgeDetection.singleSideConfirmationThreshold = 3;
this.settings.active.arDetect.edgeDetection.confirmationThreshold = 1;

View File

@ -116,13 +116,36 @@
</div>
<div class="label">
Reset settings
Import, export, reset settings
</div>
<div class="flex flex-row button-box">
<Button label="Reset settings"
@click.native="resetSettings()"
<div class="flex flex-column">
<div v-if="downloadPermissionError"
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>
</template>
@ -132,6 +155,7 @@ import Button from '../common/components/Button';
import Stretch from '../common/enums/stretch.enum';
import ExtensionMode from '../common/enums/extension-mode.enum';
import VideoAlignment from '../common/enums/video-alignment.enum';
import BrowserDetect from '../ext/conf/BrowserDetect';
export default {
components: {
@ -146,6 +170,8 @@ export default {
ExtensionMode: ExtensionMode,
VideoAlignment: VideoAlignment,
stretchThreshold: 0,
corruptedSettingsError: false,
downloadPermissionError: false,
}
},
created () {
@ -178,8 +204,77 @@ export default {
resetSettings() {
this.settings.active = JSON.parse(JSON.stringify(this.settings.default));
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>
<style lang="scss" scoped>
input[type="file"] {
display: none;
}
</style>

View File

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

View File

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

View File

@ -1,5 +1,7 @@
<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">
<span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small>
</div>
@ -175,6 +177,7 @@ import ExecAction from './js/ExecAction.js';
import DefaultSettingsPanel from './panels/DefaultSettingsPanel';
import AboutPanel from './panels/AboutPanel';
import ExtensionMode from '../common/enums/extension-mode.enum';
import Logger from '../ext/lib/Logger';
export default {
data () {
@ -192,7 +195,9 @@ export default {
site: null,
currentZoom: 1,
execAction: new ExecAction(),
settings: new Settings(undefined, () => this.updateConfig()),
settings: {},
settingsInitialized: false,
logger: {},
siteTabDisabled: false,
videoTabDisabled: false,
canShowVideoTab: {canShow: true, warning: true},
@ -200,7 +205,16 @@ export default {
}
},
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();
this.settingsInitialized = true;
this.port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
this.execAction.setSettings(this.settings);
@ -243,14 +257,10 @@ export default {
},
getSite() {
try {
if (Debug.debug) {
console.log("[popup.js] requesting current site");
}
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
this.port.postMessage({cmd: 'get-current-site'});
} catch (e) {
if (Debug.debug) {
console.log("[popup::getSite] sending get-current-site failed for some reason. Reason:", e)
}
this.logger.log('error','popup','[popup::getSite] sending get-current-site failed for some reason. Reason:', e);
}
},
getRandomColor() {
@ -293,10 +303,7 @@ export default {
this.canShowVideoTab = {canShow: canShow, warning: warning};
},
processReceivedMessage(message, port) {
if (Debug.debug && Debug.comms) {
console.log("[popup.js] received message set-c", message);
console.log("[popup.js] message cloned set-c", JSON.parse(JSON.stringify(message)));
}
this.logger.log('info', 'popup', '[popup::processReceivedMessage] received message:', message)
if (message.cmd === 'set-current-site'){
if (this.site) {
@ -340,13 +347,21 @@ export default {
// Extension site disabled, embedded videos from non-blacklisted hosts show video settings
// Extension site enabled show vido settings
// note: this if statement is ever so slightly unnecessary
if (! this.settings.canStartExtension('@global')) {
if (this.selectedTab === 'video' || this.selectedTab === 'site') {
this.selectTab('global');
// canStartExtension and getExtensionMode return disabled/false for non-whitelisted
// 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;;

View File

@ -161,7 +161,6 @@ export default {
}
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]) {
return this.settings.active.sites[site][option];
} else {

View File

@ -1,35 +1,38 @@
<template>
<div class="flex flex-column" style="padding-bottom: 20px">
<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 class="">
<div class="label">Player picker</div>
<div class="desc">
If extension doesn't detect player correctly, you can override it.
<small>(NOTE: this currently doesn't work for embedded videos)</small>
</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>Meaning of outlines:</div>
<div class="flex flex-row flex-wrap">
<div class="pp_video flex flex-nogrow"><code>&lt;video&gt;</code>&nbsp;element</div>
<div class="pp_current flex flex-nogrow">Selected and not matched</div>
<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 class="pp_match_children">Selected and matched, selector too vague</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">
Player detection settings<br/><small>for {{site}}</small>
@ -88,11 +91,44 @@
@blur="updatePlayerCss"
>
</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 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>
</template>
<script>
import ShortcutButton from '../../common/components/ShortcutButton.vue';
import QsElement from '../../common/components/QsElement.vue';
import QuerySelectorSetting from '../../common/components/QuerySelectorSetting.vue';
import ExtensionMode from '../../common/enums/extension-mode.enum';
import VideoAlignment from '../../common/enums/video-alignment.enum';
@ -100,6 +136,8 @@ import Stretch from '../../common/enums/stretch.enum';
export default {
components: {
QuerySelectorSetting,
ShortcutButton,
QsElement,
},
data() {
return {
@ -118,14 +156,12 @@ export default {
settings: Object,
},
created() {
console.log("created!")
try {
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.videoCss = this.settings.active.sites[this.site].DOM.video.additionalCss;
} catch (e) {
// 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 {
@ -135,16 +171,13 @@ export default {
this.playerParentNodeIndex = this.settings.active.sites[this.site].DOM.player.videoAncestor;
} catch (e) {
// 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 {
this.playerCss = this.settings.active.sites[this.site].css || '';
} catch (e) {
// 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: {
ensureSettings(scope) {
@ -221,5 +254,29 @@ export default {
</script>
<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>

View File

@ -2,16 +2,20 @@
<div>
<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 class="label">4.2.4</p>
<p class="label">4.3.0</p>
<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><b>[4.2.4.1]</b> Fixed default settings for 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><b>[4.2.4.2]</b> Additional bugfixes. Updated/fixed default settings.</li>
<li>Fixed an issue where videos would get incorrectly aligned following a window resize.</li>
<li>Fixed all sorts of issues for videos hosted on v.reddit for new (and old) reddit</li>
<li>Fixed the issue where setting extension to 'whitelist only' would disable 'site settings' in popup.</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>
<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>
</template>
<script>

View File

@ -9,6 +9,8 @@ https://vimeo.com/channels/staffpicks/169599296
## Reddit (v.reddit)
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
@ -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 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 ChromeExtensionReloader = require('webpack-chrome-extension-reloader');
const { VueLoaderPlugin } = require('vue-loader');
const { version } = require('./package.json');
const config = {
mode: process.env.NODE_ENV,

5834
yarn.lock

File diff suppressed because it is too large Load Diff