diff --git a/CHANGELOG.md b/CHANGELOG.md index 1795403..ad38a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,18 @@ ### Plans for the future -* Allow users to set autodetection sensitivity * Settings page looks ugly af right now. Maybe fix it some time later -### v4.0.1 (current) + +### v4.1.0 (current) + +* Added ability to add custom CSS to page +* Fixed video alignment issues on old.reddit. Disabled extension on imgur by default. +* Extension now works on vimeo again +* **UX:** Renamed 'about' to 'report a problem' in order to make contact info more discoverable + + +### v4.0.1 * Fixed bug where sites using 'default' option in 'Extension mode' settings would be disabled, even if extension was not. * Fixed bug where extension sometimes wouldn't work on Netflix. @@ -21,12 +29,11 @@ * Black frame detection has been implemented and improved. Some cases (but not all) of text on black background causing aspect ratio corrections have also been fixed. * Autodetection frequency increased from roughly once every 0.6 seconds to about 3 checks per second. * Fixed the bug where autodetectin didn't calculate aspect ratio correctly. This bug would manifest in extension cropping too much even though the edge was clearly defined. It most commonly occured in videos of aspect ratio <1 that contained letterbox. [ex 1]( https://www.youtube.com/watch?v=9DP0TbOQcOw), [ex 2](https://www.reddit.com/r/videos/comments/a137pj/daily_reminder_that_shelly_miscavige_wife_of/) - * Black frame detection has been implemented and improved. Some cases (but not all) of text on black background causing aspect ratio corrections have also been fixed. * **Settings page was re-added** * This includes a page for adding new aspect ratios and keyboard shortcuts. This feature is experimental. - * It's possible to tweak autodetection sensitivity and frequency. + * It's possible to tweak autodetection sensitivity and frequency — in slightly more user-friendly way as well * It's also possible to tweak autodetection settings in detail. - * It's now possible to reset settings to default + * It's now possible to reset settings to default * Rewrote keyboard shortcuts and changed how they're handled. Massively. * You can now select which specific video on the page you control, provided each video is in its separate iframe * While I wasn't looking, Netflix started supporting ultrawide monitors on its own. Netflix' implementation clashes with my own, though, so I've decided to disable autodetection on videos that netflix already cropped on their own. Manual aspect ratio changes are still possible, but they're off. You've been warned. @@ -35,7 +42,7 @@ ~~### v3.3.0~~ -~~This will probably get promoted to 4.0, continuing the trend of version something.3 not happening. Eulul~~ +~~This will probably get promoted to 4.0, continuing the trend of version something. 3 not happening. Eulul~~ * ~~Basic mode added~~ * ~~Per-site controls in popup (to control embedded videos)~~ diff --git a/package.json b/package.json index 5ad3f7f..1c70862 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "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 ", "scripts": { + "start": "cross-env HMR=true npm run build:dev -- --watch", "build": "cross-env NODE_ENV=production BROWSER=firefox webpack --hide-modules", "build-chrome": "cross-env NODE_ENV=production BROWSER=chrome webpack --hide-modules", "build-edge": "cross-env NODE_ENV=production BROWSER=edge webpack --hide-modules", diff --git a/src/common/components/QuerySelectorSetting.vue b/src/common/components/QuerySelectorSetting.vue new file mode 100644 index 0000000..3f67375 --- /dev/null +++ b/src/common/components/QuerySelectorSetting.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/ext/conf/Debug.js b/src/ext/conf/Debug.js index b047a89..2c6cb5d 100644 --- a/src/ext/conf/Debug.js +++ b/src/ext/conf/Debug.js @@ -6,9 +6,8 @@ var Debug = { // performanceMetrics: true, // should not be affected by debug.debug in order to allow benchmarking of the impact logging in console has // init: true, // debug: true, - // debug: false, // keyboard: true, - // debugResizer: true, + // resizer: true, // debugArDetect: true, // scaler: true, // debugStorage: false, @@ -18,7 +17,7 @@ var Debug = { // showArDetectCanvas: true, // flushStoredSettings: true, // flushStoredSettings: false, - // playerDetectDebug: true, + // playerDetect: true, // periodic: true, // videoRescan: true, // mousemove: true, diff --git a/src/ext/conf/ExtensionConf.js b/src/ext/conf/ExtensionConf.js index 76c0802..49132ae 100644 --- a/src/ext/conf/ExtensionConf.js +++ b/src/ext/conf/ExtensionConf.js @@ -919,6 +919,51 @@ var ExtensionConf = { } } }, + "old.reddit.com" : { + mode: ExtensionMode.Enabled, + autoar: currentBrowser.firefox ? ExtensionMode.Enabled : ExtensionMode.Disabled, + override: false, + type: 'official', + stretch: Stretch.Default, + videoAlignment: VideoAlignment.Default, + keyboardShortcutsEnabled: ExtensionMode.Default, + DOM: { + video: { + manual: false, + querySelectors: '', + additionalCss: '', + }, + player: { + manual: true, + useRelativeAncestor: true, + videoAncestor: 1, + } + }, + css: '', + }, + "vimeo.com": { + mode: 3, + autoar: 3, + type: 'official', + stretch: -1, + videoAlignment: -1, + keyboardShortcutsEnabled: 0, + DOM: { + player: { + manual: true, + querySelectors: ".player_outro_area", + useRelativeAncestor: false, + }, + }, + css: ".player_outro_area {\n width: 100% !important;\n display: flex !important;\n justify-content: center !important;\n}\n\n.player_container, .player {\n width: 100% !important; \n}" + }, + "imgur.com": { + mode: -1, + autoar: -1, + autoarFallback: 0, + stretch: -1, + videoAlignment: 1 + }, } } diff --git a/src/ext/lib/Settings.js b/src/ext/lib/Settings.js index b6e6634..91b6eba 100644 --- a/src/ext/lib/Settings.js +++ b/src/ext/lib/Settings.js @@ -143,6 +143,14 @@ 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.") + } + } + try { return JSON.parse(ret.uwSettings); } catch(e) { @@ -151,7 +159,7 @@ class Settings { } async set(extensionConf) { - if (Debug.debug) { + if (Debug.debug && Debug.debugStorage) { console.log("[Settings::set] setting new settings:", extensionConf) } @@ -172,7 +180,7 @@ class Settings { } async save() { - if (Debug.debug) { + if (Debug.debug && Debug.storage) { console.log("[Settings::save] Saving active settings:", this.active); } @@ -228,8 +236,10 @@ 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) + if (Debug.debug) { + console.log("[Settings::canStartExtension] window.location.hostname is null or undefined:", window.location.hostname) + console.log("active settings:", this.active) + } return ExtensionMode.Disabled; } } @@ -280,17 +290,17 @@ class Settings { // } try{ // if site is not defined, we use default mode: - if (! this.active.sites[site]) { - return this.active.sites['@global'].mode === ExtensionMode.Enabled; - } + if (! this.active.sites[site]) { + return this.active.sites['@global'].mode === ExtensionMode.Enabled; + } - if(this.active.sites['@global'].mode === ExtensionMode.Enabled) { - return this.active.sites[site].mode !== ExtensionMode.Disabled; - } else if (this.active.sites['@global'].mode === ExtensionMode.Whitelist) { - return this.active.sites[site].mode === ExtensionMode.Enabled; - } else { - return false; - } + if(this.active.sites['@global'].mode === ExtensionMode.Enabled) { + return this.active.sites[site].mode !== ExtensionMode.Disabled; + } else if (this.active.sites['@global'].mode === ExtensionMode.Whitelist) { + return this.active.sites[site].mode === ExtensionMode.Enabled; + } 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) diff --git a/src/ext/lib/ar-detect/ArDetector.js b/src/ext/lib/ar-detect/ArDetector.js index e2f91b1..cfc7f83 100644 --- a/src/ext/lib/ar-detect/ArDetector.js +++ b/src/ext/lib/ar-detect/ArDetector.js @@ -572,8 +572,8 @@ class ArDetector { // this means canvas needs to be resized, so we'll just re-run setup with all those new parameters this.stop(); - var newCanvasWidth = window.innerHeight * (this.video.videoWidth / this.video.videoHeight); - var newCanvasHeight = window.innerHeight; + let newCanvasWidth = window.innerHeight * (this.video.videoWidth / this.video.videoHeight); + let newCanvasHeight = window.innerHeight; if (this.conf.resizer.videoAlignment === VideoAlignment.Center) { this.canvasDrawWindowHOffset = Math.round((window.innerWidth - newCanvasWidth) * 0.5); @@ -952,7 +952,6 @@ class ArDetector { ); if (currentMax > this.blackLevel + blthreshold) { - console.log("CURRENT MAX:", currentMax, "BLACK LEVEL, threshold, bl+t", this.blackLevel, blthreshold, this.blackLevel+blthreshold) // we search no further if (currentMin < this.blackLevel) { this.blackLevel = currentMin; diff --git a/src/ext/lib/comms/CommsClient.js b/src/ext/lib/comms/CommsClient.js index 9493d92..82c7d78 100644 --- a/src/ext/lib/comms/CommsClient.js +++ b/src/ext/lib/comms/CommsClient.js @@ -151,6 +151,10 @@ class CommsClient { return Promise.resolve(true); } + async sendMessage(message) { + await this.sendMessage_nonpersistent(message); + } + registerVideo(){ if (Debug.debug && Debug.comms) { console.log(`[CommsClient::registerVideo] <${this.commsId}>`, "Registering video for current page."); diff --git a/src/ext/lib/comms/CommsServer.js b/src/ext/lib/comms/CommsServer.js index 9766aff..b8f44d0 100644 --- a/src/ext/lib/comms/CommsServer.js +++ b/src/ext/lib/comms/CommsServer.js @@ -13,7 +13,7 @@ class CommsServer { if (BrowserDetect.firefox) { browser.runtime.onConnect.addListener(p => ths.onConnect(p)); - browser.runtime.onMessage.addListener(m => ths.processReceivedMessage_nonpersistent(m)); + browser.runtime.onMessage.addListener((m, sender) => ths.processReceivedMessage_nonpersistent(m, sender)); } else { chrome.runtime.onConnect.addListener(p => ths.onConnect(p)); chrome.runtime.onMessage.addListener((m, sender, callback) => ths.processReceivedMessage_nonpersistent(m, sender, callback)); @@ -215,6 +215,15 @@ class CommsServer { if (Debug.debug && Debug.comms) { console.log("%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); + return; + } + if (message.cmd === 'remove-css') { + this.server.removeCss(message.cssString, sender); + return; + } if (message.forwardToContentScript) { if (Debug.debug && Debug.comms) { diff --git a/src/ext/lib/video-data/PageInfo.js b/src/ext/lib/video-data/PageInfo.js index a361ecd..e27ea5e 100644 --- a/src/ext/lib/video-data/PageInfo.js +++ b/src/ext/lib/video-data/PageInfo.js @@ -27,6 +27,18 @@ class PageInfo { this.scheduleUrlCheck(); this.currentZoomScale = 1; + + try { + const playerStyleString = this.settings.active.sites[window.location.host].css; + if (playerStyleString) { + this.comms.sendMessage({ + cmd: 'inject-css', + cssString: playerStyleString + }); + } + } catch (e) { + // do nothing. It's ok if there's no special settings for the player element + } } destroy() { @@ -40,6 +52,18 @@ class PageInfo { this.comms.unregisterVideo(video.id) video.destroy(); } + + try { + playerStyleString = this.settings.active.sites[window.location.host].css; + if (playerStyleString) { + this.comms.sendMessage({ + cmd: 'remove-css', + cssString: playerStyleString + }); + } + } catch (e) { + // do nothing. It's ok if there's no special settings for the player element + } } reset() { @@ -65,16 +89,34 @@ class PageInfo { this.actionHandlerInitQueue = []; } + getVideos(host) { + if (this.settings.active.sites[host] + && this.settings.active.sites[host].DOM + && this.settings.active.sites[host].DOM.video + && this.settings.active.sites[host].DOM.video.manual + && this.settings.active.sites[host].DOM.video.querySelector){ + const videos = document.querySelectorAll(this.settings.active.sites[host].DOM.video.querySelector); + + if (videos.length) { + return videos; + } + } + return document.getElementsByTagName('video'); + } + rescan(rescanReason){ const oldVideoCount = this.videos.length; try{ - var vids = document.getElementsByTagName('video'); + var vids = this.getVideos(window.location.host); if(!vids || vids.length == 0){ 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; @@ -186,12 +228,11 @@ class PageInfo { var ths = this; - - this.rescanTimer = setTimeout(function(rr){ + this.rescanTimer = setTimeout(function(rescanReason){ ths.rescanTimer = null; - ths.rescan(rr); + ths.rescan(rescanReason); ths = null; - }, rescanReason === this.settings.active.pageInfo.timeouts.rescan, RescanReason.PERIODIC) + }, this.settings.active.pageInfo.timeouts.rescan, RescanReason.PERIODIC) } catch(e) { if(Debug.debug){ console.log("[PageInfo::scheduleRescan] scheduling rescan failed. Here's why:",e) @@ -212,16 +253,16 @@ class PageInfo { ths.ghettoUrlCheck(); ths = null; }, this.settings.active.pageInfo.timeouts.urlCheck) - }catch(e){ + } catch(e){ if(Debug.debug){ - console.log("[PageInfo::scheduleUrlCheck] scheduling URL check failed. Here's why:",e) + console.error("[PageInfo::scheduleUrlCheck] scheduling URL check failed. Here's why:",e) } } } ghettoUrlCheck() { if (this.lastUrl != window.location.href){ - if(Debug.debug){ + if(Debug.debug && Debug.periodic){ console.log("[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!"); } diff --git a/src/ext/lib/video-data/PlayerData.js b/src/ext/lib/video-data/PlayerData.js index d11defb..a3ce545 100644 --- a/src/ext/lib/video-data/PlayerData.js +++ b/src/ext/lib/video-data/PlayerData.js @@ -224,16 +224,23 @@ class PlayerData { } + collectionHas(collection, element) { + for (let i = 0, len = collection.length; i < len; i++) { + if (collection[i] == element) { + return true; + } + } + return false; + } - getPlayerDimensions(elementNames){ - // element names — reserved for future use. If element names are provided, this function should return first element that - // has classname or id that matches at least one in the elementNames array. - var element = this.video.parentNode; + getPlayer(isFullScreen) { + const host = window.location.host; + let element = this.video.parentNode; if(! element ){ - if(Debug.debug) - console.log("[PlayerDetect::_pd_getPlayerDimensions] element is not valid, doing nothing.", element) - + if(Debug.debug) { + console.log("[PlayerDetect::_pd_getPlayer] element is not valid, doing nothing.", element) + } if(this.element) { const ths = this; } @@ -242,8 +249,32 @@ class PlayerData { return; } - var isFullScreen = PlayerData.isFullScreen(); - + if (this.settings.active.sites[host] + && this.settings.active.sites[host].DOM + && this.settings.active.sites[host].DOM.player + && this.settings.active.sites[host].DOM.player.manual) { + if (this.settings.active.sites[host].DOM.player.useRelativeAncestor + && this.settings.active.sites[host].DOM.player.videoAncestor) { + + let parentsLeft = this.settings.active.sites[host].DOM.player.videoAncestor - 1; + while (parentsLeft --> 0) { + element = element.parentNode; + } + if (element) { + return element; + } + } else if (this.settings.active.sites[host].DOM.player.querySelectors) { + const allSelectors = document.querySelectorAll(this.settings.active.sites[host].DOM.player.querySelectors); + while (element && !this.collectionHas(allSelectors, element)) { + element = element.parentNode; + } + if (element) { + return element; + } + } + } + + 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