diff --git a/js/conf/ExtensionConf.js b/js/conf/ExtensionConf.js index 7e1f01c..e0c4d63 100644 --- a/js/conf/ExtensionConf.js +++ b/js/conf/ExtensionConf.js @@ -41,7 +41,7 @@ var ExtensionConf = { ignoreEdgeMargin: 0.20, // we ignore anything that pokes over the black line this close to the edge // (relative to width of the sample) imageTestTreshold: 0.1, // when testing for image, this much pixels must be over blackbarTreshold - edgeTolerancePx: 3, // black edge violation is performed this far from reported 'last black pixel' + edgeTolerancePx: 2, // black edge violation is performed this far from reported 'last black pixel' edgeTolerancePercent: null // unused. same as above, except use % of canvas height instead of pixels }, fallbackMode: { diff --git a/js/lib/VideoData.js b/js/lib/VideoData.js index 3b9f37b..3df1b16 100644 --- a/js/lib/VideoData.js +++ b/js/lib/VideoData.js @@ -1,6 +1,7 @@ class VideoData { constructor(video){ + this.arSetupComplete = false; this.video = video; // POZOR: VRSTNI RED JE POMEMBEN (arDetect mora bit zadnji) @@ -14,8 +15,17 @@ class VideoData { // this.player.dimensions } + firstTimeArdInit(){ + if(! this.arSetupComplete){ + this.arDetector = new ArDetector(this); + } + } + initArDetection() { - this.arDetector.init(); + if(ths.arDetector) + this.arDetector.init(); + else + this.arDetector = new ArDetector(this); } startArDetection() { @@ -23,7 +33,15 @@ class VideoData { } destroy() { - this.arDetector.stop(); + if(this.arDetector){ + this.arDetector.stop(); + this.arDetector.destroy(); + } + this.arDetector = null; + if(this.resizer){ + this.resizer.destroy(); + } + this.video = null; } setLastAr(lastAr){ diff --git a/js/modules/ArDetect.js b/js/modules/ArDetect.js index c243256..f4595ad 100644 --- a/js/modules/ArDetect.js +++ b/js/modules/ArDetect.js @@ -28,6 +28,10 @@ class ArDetector { this.setup(ExtensionConf.arDetect.hSamples, ExtensionConf.arDetect.vSamples); } + destroy(){ + this.debugCanvas.destroy(); + } + setup(cwidth, cheight){ if(Debug.debug){ console.log("[ArDetect::setup] Starting autodetection setup"); @@ -73,7 +77,7 @@ class ArDetector { if(this.video.videoWidth === 0 || this.video.videoHeight === 0 ){ if(! this.timer) - this.setupTimer = setTimeout(_arSetup, 100); + this.setupTimer = setTimeout(this.init(), 100); return; } @@ -145,6 +149,8 @@ class ArDetector { this.debugCanvas.init({width: cwidth, height: cheight}); // DebugCanvas.draw("test marker","test","rect", {x:5, y:5}, {width: 5, height: 5}); } + + this.conf.arSetupComplete = true; } start(){ @@ -332,8 +338,8 @@ class ArDetector { if(! this.video){ if(Debug.debug || Debug.warnings_critical) - console.log("[ArDetect::_ard_vdraw] Video went missing. Stopping current instance of automatic detection.") - this.stop(); + console.log("[ArDetect::_ard_vdraw] Video went missing. Destroying current instance of videoData.") + this.conf.destroy(); return; } @@ -350,8 +356,8 @@ class ArDetector { var how_far_treshold = 8; // how much can the edge pixel vary (*4) - if(this.video == null || this.video.ended ){ - // we slow down if ended or null. Detecting is pointless. + if(this.video.ended ){ + // we slow down if ended. Detecting is pointless. this.scheduleFrameCheck(ExtensionConf.arDetect.timer_paused); return false; @@ -502,7 +508,7 @@ class ArDetector { // let's chec if we ever reset CSS. If we haven't, then we do so. If we did, then we don't. // while resetting the CSS, we also reset guardline top and bottom back to null. - if(! GlobalVars.arDetect.noLetterboxCanvasReset){ + if(! this.noLetterboxCanvasReset){ this.conf.resizer.reset({type: "auto", ar: null}); this.guardLine.top = null; this.guardLine.bottom = null; @@ -518,7 +524,7 @@ class ArDetector { // css resetiral enkrat na video/pageload namesto vsakič, ko so za nekaj časa obrobe odstranejene // if we look further we need to reset this value back to false. Otherwise we'll only get CSS reset once // per video/pageload instead of every time letterbox goes away (this can happen more than once per vid) - GlobalVars.arDetect.noLetterboxCanvasReset = false; + this.noLetterboxCanvasReset = false; // let's do a quick test to see if we're on a black frame // TODO: reimplement but with less bullshit @@ -542,7 +548,7 @@ class ArDetector { if (fallbackMode && guardLineOut.blackbarFail) { this.conf.resizer.reset({type: "auto", ar: null}); this.guardLine.reset(); - this.arDetect.noLetterboxCanvasReset = true; + this.noLetterboxCanvasReset = true; triggerTimeout = this.getTimeout(baseTimeout, startTime); this.scheduleFrameCheck(triggerTimeout); //no letterbox, no problem @@ -565,7 +571,7 @@ class ArDetector { // If aspect ratio changes from narrower to wider, we first check for presence of pillarbox. Presence of pillarbox indicates // a chance of a logo on black background. We could cut easily cut too much. Because there's a somewhat significant chance // that we will cut too much, we rather avoid doing anything at all. There's gonna be a next chance. - + try{ if(guardLineOut.blackbarFail || guardLineOut.imageFail){ if(this.edgeDetector.findBars(image, null, EdgeDetectPrimaryDirection.HORIZONTAL).status === 'ar_known'){ @@ -573,7 +579,7 @@ class ArDetector { console.log("[ArDetect::_ard_vdraw] Detected blackbar violation and pillarbox. Resetting to default aspect ratio."); } - if(! guardLineResult){ + if(guardLineOut.blackbarFail){ this.conf.resizer.reset({type: "auto", ar: null}); this.guardLine.reset(); } @@ -584,6 +590,7 @@ class ArDetector { return; } } + }catch(e) {console.log("deeee",e)} // pa poglejmo, kje se končajo črne letvice na vrhu in na dnu videa. // let's see where black bars end. diff --git a/js/modules/DebugCanvas.js b/js/modules/DebugCanvas.js index 6905872..2c60d75 100644 --- a/js/modules/DebugCanvas.js +++ b/js/modules/DebugCanvas.js @@ -34,6 +34,10 @@ class DebugCanvas { console.log("debug canvas is:", this.canvas, "context:", this.context) } + destroy(){ + this.canvas.remove(); + } + setBuffer(buffer) { // this.imageBuffer = buffer.splice(0); this.imageBuffer = new Uint8ClampedArray(buffer); @@ -77,8 +81,8 @@ class DebugCanvas { } DebugCanvasClasses = { - VIOLATION: {color: '#ff4400', colorRgb: [255, 68, 0], text: 'violation (general)'}, - WARN: {color: '#d08539', colorRgb: [208, 133, 57], text: 'lesser violation (general)'}, + VIOLATION: {color: '#ff0000', colorRgb: [255, 00, 0], text: 'violation (general)'}, + WARN: {color: '#d0d039', colorRgb: [208, 208, 57], text: 'lesser violation (general)'}, GUARDLINE_BLACKBAR: {color: '#3333FF', colorRgb: [51, 51, 255], text: 'guardline/blackbar (expected value)'}, GUARDLINE_IMAGE: {color: '#000088', colorRgb: [0, 0, 136], text: 'guardline/image (expected value)'}, diff --git a/js/modules/PageInfo.js b/js/modules/PageInfo.js index 3130bb2..a6b7821 100644 --- a/js/modules/PageInfo.js +++ b/js/modules/PageInfo.js @@ -12,33 +12,69 @@ class PageInfo { } rescan(count){ + try{ var vids = document.getElementsByTagName('video'); if(!vids || vids.length == 0){ this.hasVideos = false; + + this.scheduleRescan(); return; } // debugger; // add new videos - for(var video of vids){ - var existing = this.videos.find( (x) => { - if (x == video.video) - return x; - if (x.currentSrc == video.video.currentSrc){ - return x; - } - }) + // for(var video of vids){ + // var existing = this.videos.find( (x) => { + // if (video && x == video.video) + // return x; + // if (video && x.currentSrc == video.video.currentSrc){ + // return x; + // } + // }) - if(existing){ - video.video = existing; + // if(existing){ + // video.video = existing; + // } else { + // this.videos.push( + // new VideoData(video) + // ); + // } + // } + if(this.videos.length > 0){ + if(vids[0] == this.videos[0].video){ + // do nothing } else { - this.videos.push( - new VideoData(video) - ); + this.videos[0].destroy(); + this.videos[0] = new VideoData(vids[0]); } + } else { + this.videos.push(new VideoData(vids[0])); } + + console.log("Rescan complete. Total videos?", this.videos.length) + }catch(e){ + console.log("rescan error:",e) + } + this.scheduleRescan(); + } + + scheduleRescan(){ + try{ + if(this.rescanTimer){ + clearTimeout(this.rescanTimer); + } + + var ths = this; + + + this.rescanTimer = setTimeout(function(){ + ths.rescanTimer = null; + ths.rescan(); + ths = null; + }, 1000) + }catch(e){console.log("eee",e)} } initArDetection(){ diff --git a/js/modules/Resizer.js b/js/modules/Resizer.js index f193e22..5120eae 100644 --- a/js/modules/Resizer.js +++ b/js/modules/Resizer.js @@ -30,8 +30,13 @@ class Resizer { this.restore_wd = false; this.lastAr = {type: 'original'}; + this.destroyed = false; } + destroy(){ + this.destroyed = true; + this.stopCssWatcher(); + } setAr(ar, lastAr){ if(Debug.debug){ @@ -50,15 +55,17 @@ class Resizer { if (! this.video) { // console.log("No video detected.") - // this.videoData.destroy(); + this.videoData.destroy(); } - var dimensions = Scaler.calculateCrop(ar, this.video, this.conf.player.dimensions); - if(dimensions.error){ + if(! dimensions || dimensions.error){ if(Debug.debug){ - console.log("[Resizer::setAr] failed to set AR due to problem with calculating crop. Error:", dimensions.error) + console.log("[Resizer::setAr] failed to set AR due to problem with calculating crop. Error:", (dimensions ? dimensions.error : dimensions)); + } + if(dimensions.error === 'no_video'){ + this.conf.destroy(); } return; } @@ -75,6 +82,9 @@ class Resizer { var cssOffsets = this.computeOffsets(dimensions); this.applyCss(cssOffsets, stretchFactors); + + if(! this.destroyed) + this.startCssWatcher(); } setLastAr(override){ @@ -101,10 +111,18 @@ class Resizer { } startCssWatcher(){ - this.cssWatcherTimeout = setInterval(this.cssWatcher, 200); + // this.haltCssWatcher = false; + if(!this.cssWatcherTimeout){ + if(Debug.debug) + console.log("[Resizer.js] STARTING CSS WATCHER") + + this.cssWatcherTimeout = setInterval(this.cssWatcher, 200, this); + } } stopCssWatcher(){ + if(Debug.debug) console.log("[Resizer.js] STOPPING CSS WATCHER!") + clearInterval(this.cssWatcherTimeout); } @@ -190,12 +208,20 @@ class Resizer { applyCss(dimensions, stretchFactors){ - if(this.video == undefined || this.video == null){ + if (! this.video ){ if(Debug.debug) console.log("[Resizer::_res_applyCss] Video went missing, doing nothing."); + this.conf.destroy(); return; } + // save stuff for quick tests (before we turn numbers into css values): + this.currentVideoSettings = { + validFor: this.conf.player.dimensions, + videoWidth: dimensions.width, + videoHeight: dimensions.height + } + if(Debug.debug) console.log("[Resizer::_res_applyCss] Starting to apply css. this is what we're getting in:", dimensions); @@ -284,6 +310,9 @@ class Resizer { styleString += styleArray[i] + "; "; this.setStyleString(styleString); + + + } setStyleString (styleString, count = 0) { @@ -322,21 +351,31 @@ class Resizer { } } - cssWatcher(){ - + cssWatcher(ths){ // this means we haven't set our CSS yet, or that we changed video. - if(! this.currentCss.top) + if(! ths.currentCss.top) return; - // this means video went missing. - if(! this.video) + // this means video went missing. videoData will be re-initialized when the next video is found + if(! ths.video){ + ths.conf.destroy(); return; + } // // our current css is fucky? Null, undefined and 0 are invalid values. // if(! GlobalVars.currentCss.width || ! GlobalVars.currentCss.height ) // return; + + // first, a quick test: + if (ths.currentVideoSettings.validFor == ths.conf.player.dimensions ){ + if (ths.currentVideoSettings.videoWidth != ths.video.offsetWidth || + ths.currentVideoSettings.videoHeight != ths.video.offsetHeight){ + ths.restore(); + return; + } + } - var styleArrayStr = this.video.getAttribute('style'); + var styleArrayStr = ths.video.getAttribute('style'); if (styleArrayStr){ var styleArray = styleArrayStr.split(";"); @@ -349,24 +388,24 @@ class Resizer { if (styleArray[i].startsWith("top:")){ // don't force css restore if currentCss.top is not defined - if(this.currentCss.top && styleArray[i] != this.currentCss.top){ + if(ths.currentCss.top && styleArray[i] != ths.currentCss.top){ if(Debug.debug){ console.log("[Resizer::_res_antiCssOverride] SOMEBODY TOUCHED MA SPAGHETT (our CSS got overriden, restoring our css)"); - console.log("[Resizer::_res_antiCssOverride] MA SPAGHETT: top:", this.currentCss.top, "left:", this.currentCss.left, "thing that touched ma spaghett", styleArrayStr); + console.log("[Resizer::_res_antiCssOverride] MA SPAGHETT: top:", ths.currentCss.top, "left:", ths.currentCss.left, "thing that touched ma spaghett", styleArrayStr); } - _res_restore(); + ths.restore(); return; } stuffChecked++; } else if(styleArray[i].startsWith("left:")){ // don't force css restore if currentCss.left is not defined - if(this.currentCss.left && styleArray[i] != this.currentCss.left){ + if(ths.currentCss.left && styleArray[i] != ths.currentCss.left){ if(Debug.debug){ console.log("[Resizer::_res_antiCssOverride] SOMEBODY TOUCHED MA SPAGHETT (our CSS got overriden, restoring our css)"); - console.log("[Resizer::_res_antiCssOverride] MA SPAGHETT: width:", this.currentCss.width, "height:", this.currentCss.height, "thing that touched ma spaghett", styleArrayStr); + console.log("[Resizer::_res_antiCssOverride] MA SPAGHETT: width:", ths.currentCss.width, "height:", ths.currentCss.height, "thing that touched ma spaghett", styleArrayStr); } - _res_restore(); + ths.restore(); return; } stuffChecked++; diff --git a/js/modules/Scaler.js b/js/modules/Scaler.js index 85a711e..862cf66 100644 --- a/js/modules/Scaler.js +++ b/js/modules/Scaler.js @@ -57,21 +57,7 @@ class Scaler { } static calculateCrop(mode, video, playerDimensions) { - // if 'ar' is string, we'll handle that in legacy wrapper - var ar = 0; - if(isNaN(mode)){ - ar = this.modeToAr(mode); - } else { - ar = mode; - } - // handle fuckie-wuckies - if (! ar){ - return null; - } - - if(Debug.debug) - console.log("[Scaler::calculateCrop] trying to set ar. args are: ar->",ar,"; playerDimensions->",playerDimensions.width, "×", playerDimensions.height, "| obj:", playerDimensions); if(!video || video.videoWidth == 0 || video.videoHeight == 0){ if(Debug.debug) @@ -79,6 +65,25 @@ class Scaler { return {error: "no_video"}; } + + // if 'ar' is string, we'll handle that in legacy wrapper + var ar = 0; + if(isNaN(mode)){ + ar = Scaler.modeToAr(mode); + } else { + ar = mode; + } + + // handle fuckie-wuckies + if (! ar){ + if(Debug.debug) + console.log("[Scaler::calculateCrop] no ar?", ar, " -- we were given this mode:", mode); + return {error: "no_ar", ar: ar}; + } + + if(Debug.debug) + console.log("[Scaler::calculateCrop] trying to set ar. args are: ar->",ar,"; playerDimensions->",playerDimensions.width, "×", playerDimensions.height, "| obj:", playerDimensions); + if( (! playerDimensions) || playerDimensions.width === 0 || playerDimensions.height === 0 ){ if(Debug.debug) console.log("[Scaler::calculateCrop] ERROR — no (or invalid) playerDimensions:",playerDimensions);