diff --git a/background.js b/background.js index 0ea212b..9b09a0e 100644 --- a/background.js +++ b/background.js @@ -145,7 +145,7 @@ var Database = { }; }, 'objLegacy': function(objArguments, funcCallback) { - var objStore = Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase'); + var objStore = Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase'); var objQuery = objStore.openCursor(); @@ -226,7 +226,7 @@ var Database = { export: function(objRequest, funcResponse, funcProgress) { Node.series({ 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readonly').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readonly').objectStore('storeDatabase')); }, 'objGet': function(objArguments, funcCallback) { var objQuery = objArguments.objDatabase.openCursor(); @@ -254,7 +254,7 @@ var Database = { }, 'objDownload': function(objArguments, funcCallback) { chrome.downloads.download({ - 'url' : URL.createObjectURL(new Blob([ btoa(unescape(encodeURIComponent(JSON.stringify(objArguments.objGet)))) ], { + 'url' : URL.createObjectURL(new Blob([btoa(unescape(encodeURIComponent(JSON.stringify(objArguments.objGet))))], { 'type': 'text/plain' })), 'filename': new Date().getFullYear() + '.' + ('0' + (new Date().getMonth() + 1)).slice(-2) + '.' + ('0' + new Date().getDate()).slice(-2) + '.database', @@ -280,7 +280,7 @@ var Database = { return funcCallback(objRequest.objVideos); }, 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objVideo': function(objArguments, funcCallback) { if (objArguments.hasOwnProperty('intVideo') === false) { @@ -382,7 +382,7 @@ var Database = { reset: function(objRequest, funcResponse) { Node.series({ 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objClear': function(objArguments, funcCallback) { var objQuery = objArguments.objDatabase.clear(); @@ -484,7 +484,7 @@ var History = { }); }, 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objVideo': function(objArguments, funcCallback) { if (objArguments.hasOwnProperty('intVideo') === false) { @@ -793,7 +793,7 @@ var Youtube = { } }, 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objVideo': function(objArguments, funcCallback) { if (objArguments.hasOwnProperty('intVideo') === false) { @@ -908,7 +908,7 @@ var Youtube = { return funcCallback(objRequest); }, 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readonly').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readonly').objectStore('storeDatabase')); }, 'objGet': function(objArguments, funcCallback) { var objQuery = objArguments.objDatabase.index('strIdent').get(objArguments.objVideo.strIdent); @@ -943,7 +943,7 @@ var Youtube = { return funcCallback(objRequest); }, 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objGet': function(objArguments, funcCallback) { var objQuery = objArguments.objDatabase.index('strIdent').get(objArguments.objVideo.strIdent); @@ -1002,7 +1002,7 @@ var Youtube = { return funcCallback(objRequest); }, 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objGet': function(objArguments, funcCallback) { var objQuery = objArguments.objDatabase.index('strIdent').get(objArguments.objVideo.strIdent); @@ -1112,11 +1112,12 @@ var Search = { lookup: function(objRequest, funcResponse) { Node.series({ 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readonly').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readonly').objectStore('storeDatabase')); }, 'objGet': function(objArguments, funcCallback) { var objQuery = objArguments.objDatabase.index('intTimestamp').openCursor(null, 'prev'); + objQuery.skip = objRequest.intSkip; objQuery.results = []; objQuery.onsuccess = function() { @@ -1124,17 +1125,23 @@ var Search = { return funcCallback(objQuery.results); } - if (objQuery.results.length === 100) { + if (objQuery.results.length === objRequest.intLength) { return funcCallback(objQuery.results); } if (objQuery.result.value.strTitle.toLowerCase().indexOf(objRequest.strQuery.toLowerCase()) !== -1) { - objQuery.results.push({ - 'strIdent': objQuery.result.value.strIdent, - 'intTimestamp': objQuery.result.value.intTimestamp, - 'strTitle': objQuery.result.value.strTitle, - 'intCount': objQuery.result.value.intCount - }); + if (objQuery.skip !== 0) { + objQuery.skip -= 1; + + } else if (objQuery.skip === 0) { + objQuery.results.push({ + 'strIdent': objQuery.result.value.strIdent, + 'intTimestamp': objQuery.result.value.intTimestamp, + 'strTitle': objQuery.result.value.strTitle, + 'intCount': objQuery.result.value.intCount + }); + + } } objQuery.result.continue(); @@ -1156,7 +1163,7 @@ var Search = { delete: function(objRequest, funcResponse, funcProgress) { Node.series({ 'objDatabase': function(objArguments, funcCallback) { - return funcCallback(Database.objDatabase.transaction([ 'storeDatabase' ], 'readwrite').objectStore('storeDatabase')); + return funcCallback(Database.objDatabase.transaction(['storeDatabase'], 'readwrite').objectStore('storeDatabase')); }, 'objDelete': function(objArguments, funcCallback) { funcProgress({ @@ -1449,6 +1456,14 @@ Node.series({ window.localStorage.setItem('extensions.Youwatch.Condition.boolYouhist', String(true)); } + if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === null) { + window.localStorage.setItem('extensions.Youwatch.Visualization.boolFadeout', String(true)); + } + + if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === null) { + window.localStorage.setItem('extensions.Youwatch.Visualization.boolGrayout', String(true)); + } + if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolShowbadge') === null) { window.localStorage.setItem('extensions.Youwatch.Visualization.boolShowbadge', String(true)); } @@ -1538,9 +1553,21 @@ Node.series({ } - if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolShowbadge') === String(false)) { + if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === String(true)) { + chrome.tabs.insertCSS(objTab.id, { + 'code': '.youwatch-mark yt-img-shadow img { opacity:0.3; } .youwatch-mark yt-img-shadow { background-color:#FFFFFF; }' + }); + } + + if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === String(true)) { + chrome.tabs.insertCSS(objTab.id, { + 'code': '.youwatch-mark yt-img-shadow img { filter:grayscale(1.0); }' + }); + } + + if (window.localStorage.getItem('extensions.Youwatch.Visualization.boolShowbadge') === String(true)) { chrome.tabs.insertCSS(objTab.id, { - 'code': '.youwatch-mark:last-child:after { display:none !important; }' + 'code': '.youwatch-mark:last-child:after { background-color:#000000; border-radius:2px; color:#FFFFFF; content:"WATCHED"; font-size:11px; left:4px; opacity:0.8; padding:3px 4px 3px 4px; position:absolute; top:4px; }' }); } @@ -1613,7 +1640,7 @@ Node.series({ } }); }, { - 'urls': [ '*://*.ytimg.com/vi/*/*' ] + 'urls': ['*://*.ytimg.com/vi/*/*'] }); if (funcBrowser() === 'firefox') { @@ -1632,7 +1659,7 @@ Node.series({ 'requestHeaders': objData.requestHeaders }; },{ - 'urls': [ '*://www.youtube.com/youtubei/v1/*' ] + 'urls': ['*://www.youtube.com/youtubei/v1/*'] }, [ 'requestHeaders', 'blocking' @@ -1654,7 +1681,7 @@ Node.series({ 'requestHeaders': objData.requestHeaders }; },{ - 'urls': [ '*://www.youtube.com/youtubei/v1/*' ] + 'urls': ['*://www.youtube.com/youtubei/v1/*'] }, [ 'requestHeaders', 'blocking', diff --git a/content/index.html b/content/index.html index 91c6ad3..0b50684 100644 --- a/content/index.html +++ b/content/index.html @@ -137,6 +137,26 @@
+
+
Mark watched videos by slightly fading the thumbnail out.
+
+ +
+
+ +
+
Mark watched videos by converting the thumbnail to grayscale.
+
+ +
+
+
Show a textual badge in addition to graying out watched videos.
diff --git a/content/index.js b/content/index.js index 988fe96..6297cde 100644 --- a/content/index.js +++ b/content/index.js @@ -420,6 +420,72 @@ jQuery(window.document).ready(function() { .end() ; + jQuery('#idVisualization_Fadeout') + .on('click', function() { + window.localStorage.setItem('extensions.Youwatch.Visualization.boolFadeout', window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === String(false)); + + jQuery(this) + .find('i') + .eq(0) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === String(true) ? 'none' : 'block' + }) + .end() + .eq(1) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === String(true) ? 'block' : 'none' + }) + .end() + .end() + ; + }) + .find('i') + .eq(0) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === String(true) ? 'none' : 'block' + }) + .end() + .eq(1) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolFadeout') === String(true) ? 'block' : 'none' + }) + .end() + .end() + ; + + jQuery('#itVisualization_Grayout') + .on('click', function() { + window.localStorage.setItem('extensions.Youwatch.Visualization.boolGrayout', window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === String(false)); + + jQuery(this) + .find('i') + .eq(0) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === String(true) ? 'none' : 'block' + }) + .end() + .eq(1) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === String(true) ? 'block' : 'none' + }) + .end() + .end() + ; + }) + .find('i') + .eq(0) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === String(true) ? 'none' : 'block' + }) + .end() + .eq(1) + .css({ + 'display': window.localStorage.getItem('extensions.Youwatch.Visualization.boolGrayout') === String(true) ? 'block' : 'none' + }) + .end() + .end() + ; + jQuery('#idVisualization_Showbadge') .on('click', function() { window.localStorage.setItem('extensions.Youwatch.Visualization.boolShowbadge', window.localStorage.getItem('extensions.Youwatch.Visualization.boolShowbadge') === String(false)); @@ -487,7 +553,18 @@ jQuery(window.document).ready(function() { ; jQuery('#idSearch_Lookup') - .on('click', function() { + .data({ + 'intSkip' : 0 + }) + .on('click', function(objEvent) { + if (objEvent.originalEvent !== undefined) { + jQuery('#idSearch_Lookup') + .data({ + 'intSkip' : 0 + }) + ; + } + jQuery('#idSearch_Lookup') .addClass('disabled') .find('i') @@ -507,7 +584,9 @@ jQuery(window.document).ready(function() { objSearch.postMessage({ 'strMessage': 'searchLookup', 'objRequest': { - 'strQuery': jQuery('#idSearch_Query').val() + 'strQuery': jQuery('#idSearch_Query').val(), + 'intSkip': jQuery('#idSearch_Lookup').data('intSkip'), + 'intLength': 10 } }); }) @@ -538,143 +617,165 @@ jQuery(window.document).ready(function() { .end() ; - jQuery('#idSearch_Results') - .empty() - .append(jQuery('
') - .addClass('table') - .addClass('table-sm') - .css({ - 'margin': '0px' - }) - .append(jQuery('') - .append(jQuery('') - .append(jQuery('') - .attr({ - 'width': '1%' - }) - .css({ - 'border-top': 'none' - }) - .text('Time') - ) - .append(jQuery('') - .css({ - 'border-top': 'none' - }) - .text('Title') - ) - .append(jQuery('') - .attr({ - 'width': '1%' - }) - .css({ - 'border-top': 'none', - 'text-align': 'right' - }) - .text('Visits') - ) - .append(jQuery('') - .css({ - 'border-top': 'none' - }) - .attr({ - 'width': '1%' - }) + if (jQuery('#idSearch_Lookup').data('intSkip') === 0) { + jQuery('#idSearch_Results') + .empty() + .append(jQuery('
') + .addClass('table') + .addClass('table-sm') + .css({ + 'margin': '0px' + }) + .append(jQuery('') + .append(jQuery('') + .append(jQuery('') + .attr({ + 'width': '1%' + }) + .css({ + 'border-top': 'none' + }) + .text('Time') + ) + .append(jQuery('') + .css({ + 'border-top': 'none' + }) + .text('Title') + ) + .append(jQuery('') + .attr({ + 'width': '1%' + }) + .css({ + 'border-top': 'none', + 'text-align': 'right' + }) + .text('Visits') + ) + .append(jQuery('') + .css({ + 'border-top': 'none' + }) + .attr({ + 'width': '1%' + }) + ) ) ) + .append(jQuery('')) ) - .append(jQuery('') - .each(function() { - for (var objVideo of objData.objResponse.objVideos) { - jQuery(this) - .append(jQuery('') - .append(jQuery('') - .append(jQuery('
') - .css({ - 'white-space': 'nowrap' - }) - .text(moment(objVideo.intTimestamp).format('YYYY.MM.DD - HH:mm')) - ) + ; + } + + jQuery('#idSearch_Results').find('tbody') + .each(function() { + for (var objVideo of objData.objResponse.objVideos) { + jQuery(this) + .append(jQuery('') + .append(jQuery('') + .append(jQuery('
') + .css({ + 'white-space': 'nowrap' + }) + .text(moment(objVideo.intTimestamp).format('YYYY.MM.DD - HH:mm')) + ) + ) + .append(jQuery('') + .css({ + 'position': 'relative' + }) + .append(jQuery('
') + .css({ + 'left': '8px', + 'overflow': 'hidden', + 'position': 'absolute', + 'right': '-8px', + 'text-overflow': 'ellipsis', + 'white-space': 'nowrap' + }) + .append(jQuery('') + .attr({ + 'href': 'https://www.youtube.com/watch?v=' + objVideo.strIdent + }) + .text(objVideo.strTitle) ) - .append(jQuery('') + ) + ) + .append(jQuery('') + .append(jQuery('
') + .css({ + 'white-space': 'nowrap', + 'text-align': 'right' + }) + .text(objVideo.intCount) + ) + ) + .append(jQuery('') + .append(jQuery('
') + .css({ + 'white-space': 'nowrap' + }) + .append(jQuery('') + .addClass('far') + .addClass('fa-trash-alt') .css({ - 'position': 'relative' + 'cursor': 'pointer' }) - .append(jQuery('
') - .css({ - 'left': '8px', - 'overflow': 'hidden', - 'position': 'absolute', - 'right': '-8px', - 'text-overflow': 'ellipsis', - 'white-space': 'nowrap' - }) - .append(jQuery('') - .attr({ - 'href': 'https://www.youtube.com/watch?v=' + objVideo.strIdent - }) - .text(objVideo.strTitle) - ) - ) - ) - .append(jQuery('') - .append(jQuery('
') - .css({ - 'white-space': 'nowrap', - 'text-align': 'right' - }) - .text(objVideo.intCount) - ) - ) - .append(jQuery('') - .append(jQuery('
') - .css({ - 'white-space': 'nowrap' - }) - .append(jQuery('') - .addClass('far') - .addClass('fa-trash-alt') + .data({ + 'strIdent': objVideo.strIdent + }) + .on('click', function() { + jQuery('#idLoading_Container') .css({ - 'cursor': 'pointer' - }) - .data({ - 'strIdent': objVideo.strIdent - }) - .on('click', function() { - jQuery('#idLoading_Container') - .css({ - 'display': 'block' - }) - ; - - jQuery('#idLoading_Message') - .text('exporting database') - ; - - jQuery('#idLoading_Progress') - .text('...') - ; - - jQuery('#idLoading_Close') - .addClass('disabled') - ; - - objSearch.postMessage({ - 'strMessage': 'searchDelete', - 'objRequest': { - 'strIdent': jQuery(this).data('strIdent') - } - }); + 'display': 'block' }) - ) - ) + ; + + jQuery('#idLoading_Message') + .text('exporting database') + ; + + jQuery('#idLoading_Progress') + .text('...') + ; + + jQuery('#idLoading_Close') + .addClass('disabled') + ; + + objSearch.postMessage({ + 'strMessage': 'searchDelete', + 'objRequest': { + 'strIdent': jQuery(this).data('strIdent') + } + }); + }) ) ) - ; - } - }) - ) - ) + ) + ) + ; + } + }) + ; + + jQuery('#idSearch_Results').find('tr:last') + .each(function() { + new IntersectionObserver(function(objEntries, objObserver) { + if (objEntries[0].isIntersecting === true) { + objObserver.unobserve(objEntries[0].target); + + jQuery('#idSearch_Lookup') + .data({ + 'intSkip' : jQuery('#idSearch_Lookup').data('intSkip') + 10 + }) + ; + + jQuery('#idSearch_Lookup').triggerHandler('click'); + } + }).observe(this) + }) ; } diff --git a/manifest.json b/manifest.json index 2126a19..e514fb1 100644 --- a/manifest.json +++ b/manifest.json @@ -5,9 +5,9 @@ "description": "Automatically mark videos on Youtube that you have already watched.", "homepage_url": "https://sniklaus.com/", - "version": "4.0.9", + "version": "4.1.0", - "permissions": [ "alarms", "downloads", "history", "tabs", "cookies", "webRequest", "webRequestBlocking", "*://www.youtube.com/*", "*://*.ytimg.com/vi/*/*" ], + "permissions": ["alarms", "downloads", "history", "tabs", "cookies", "webRequest", "webRequestBlocking", "*://www.youtube.com/*", "*://*.ytimg.com/vi/*/*"], "icons": { "72": "content/icon.png" @@ -21,13 +21,13 @@ }, "background": { - "scripts": [ "background.js" ] + "scripts": ["background.js"] }, "content_scripts": [{ - "matches": [ "*://www.youtube.com/*" ], - "css": [ "youtube.css" ], - "js": [ "youtube.js" ] + "matches": ["*://www.youtube.com/*"], + "css": ["youtube.css"], + "js": ["youtube.js"] }], "browser_action": { diff --git a/youtube.css b/youtube.css index 1c1b665..70cb556 100644 --- a/youtube.css +++ b/youtube.css @@ -9,28 +9,3 @@ ytd-thumbnail-overlay-playback-status-renderer { ytd-thumbnail-overlay-time-status-renderer { padding:3px 4px 3px 4px !important; } - -/* youwatch watched fadeout */ - -.youwatch-mark yt-img-shadow { - background-color:#FFFFFF; -} - -.youwatch-mark yt-img-shadow img { - opacity:0.3; -} - -/* youwatch watched badge */ - -.youwatch-mark:last-child:after { - background-color:#000000; - border-radius:2px; - color:#FFFFFF; - content:"WATCHED"; - font-size:11px; - left:4px; - opacity:0.8; - padding:3px 4px 3px 4px; - position:absolute; - top:4px; -} diff --git a/youtube.js b/youtube.js index 93ebf5d..df3c398 100644 --- a/youtube.js +++ b/youtube.js @@ -72,18 +72,18 @@ chrome.runtime.onMessage.addListener(function(objData) { // ########################################################## window.setInterval(function() { + if (document.hidden === true) { + return; + } + objVideocache = window.document.querySelectorAll('a.ytd-thumbnail[href^="/watch?v="]'); objProgresscache = window.document.querySelectorAll('ytd-thumbnail-overlay-resume-playback-renderer'); - var strFingerprint = window.location.href + ':' + window.document.title + ':' + objVideocache.length + ':' + objProgresscache.length; - - if (strFingerprint === strLastchange) { + if (strLastchange === window.location.href + ':' + window.document.title + ':' + objVideocache.length + ':' + objProgresscache.length) { return; } - strLastchange = strFingerprint; + strLastchange = window.location.href + ':' + window.document.title + ':' + objVideocache.length + ':' + objProgresscache.length; refresh(); - - console.log('refreshed'); }, 300);