diff --git a/goodtube.user.js b/goodtube.user.js index 300889d..8aaa7d5 100644 --- a/goodtube.user.js +++ b/goodtube.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name GoodTube // @namespace http://tampermonkey.net/ -// @version 4.504 +// @version 4.505 // @description Loads Youtube videos from different sources. Also removes ads, shorts, etc. // @author GoodTube // @match https://*.youtube.com/* @@ -431,7 +431,7 @@ let goodTube_updateChapters = false; let goodTube_chapterTitleInterval = false; let goodTube_chaptersChangeInterval = false; - let goodTube_selectHighestManifestQualityTimeout = false; + let goodTube_updateManifestQualityTimeout = false; // Init function goodTube_player_init() { @@ -1943,15 +1943,8 @@ type: manifestType }); - // Show the correct quality menu item - let qualityButtons = document.querySelectorAll('.vjs-quality-selector'); - if (qualityButtons.length === 2) { - qualityButtons[0].style.display = 'none'; - qualityButtons[1].style.display = 'block'; - } - - // Select the highest DASH quality - goodTube_player_selectHighestManifestQuality(); + // Update manifest quality menu + goodTube_player_updateManifestQualityMenu(); } // Piped (HD) @@ -1983,15 +1976,8 @@ type: manifestType }); - // Show the correct quality menu item - let qualityButtons = document.querySelectorAll('.vjs-quality-selector'); - if (qualityButtons.length === 2) { - qualityButtons[0].style.display = 'none'; - qualityButtons[1].style.display = 'block'; - } - - // Select the highest quality - goodTube_player_selectHighestManifestQuality(); + // Update manifest quality menu + goodTube_player_updateManifestQualityMenu(); } @@ -2024,6 +2010,7 @@ }) // If there's any issues loading the video data, try again (after configured delay time) .catch((error) => { + console.log(error); if (typeof goodTube_pendingRetry['loadVideoData'] !== 'undefined') { clearTimeout(goodTube_pendingRetry['loadVideoData']); } @@ -2037,46 +2024,144 @@ }); } - // Select highest quality by default (when using a manifest file) - function goodTube_player_selectHighestManifestQuality() { - // This stops it from ever accidentially firing twice - if (goodTube_selectHighestManifestQualityTimeout) { - clearTimeout(goodTube_selectHighestManifestQualityTimeout); + // Update manifest quality menu + function goodTube_player_updateManifestQualityMenu() { + // This stops this function from ever accidentially firing twice + if (goodTube_updateManifestQualityTimeout) { + clearTimeout(goodTube_updateManifestQualityTimeout); } // Find and click the highest quality button (if it can't be found, this will call itself again until it works) - let qualityMenus = document.querySelectorAll('.vjs-quality-selector'); - if (qualityMenus && typeof qualityMenus[1] !== 'undefined') { - let highestQualityButton = qualityMenus[1].querySelector('li:first-child'); - if (highestQualityButton) { - highestQualityButton.click(); + let qualityButtons = document.querySelectorAll('.vjs-quality-selector'); + if (qualityButtons && typeof qualityButtons[1] !== 'undefined') { + if (qualityButtons.length === 2) { + // Show the correct quality menu item + qualityButtons[0].style.display = 'none'; + qualityButtons[1].style.display = 'block'; - let highestQualityButtonText = highestQualityButton.querySelector('.vjs-menu-item-text').innerHTML; + // Target the manifest quality menu + let manifestQualityMenu = qualityButtons[1].querySelector('ul'); - // Debug message - if (goodTube_debug) { - console.log('[GoodTube] Selecting highest quality - '+highestQualityButtonText); - } - } - else { - if (goodTube_selectHighestManifestQualityTimeout) { - clearTimeout(goodTube_selectHighestManifestQualityTimeout); + // Check if the first menu item is "Always use max" + let firstMenuItem = manifestQualityMenu.querySelector('li.vjs-menu-item:first-child .vjs-menu-item-text'); + + // If it's not populated yet, try again + if (!firstMenuItem) { + if (goodTube_updateManifestQualityTimeout) { + clearTimeout(goodTube_updateManifestQualityTimeout); + } + + goodTube_updateManifestQualityTimeout = setTimeout(goodTube_player_updateManifestQualityMenu, 100); + return; } - goodTube_selectHighestManifestQualityTimeout = setTimeout(goodTube_player_selectHighestManifestQuality, 100); - return; + // Does the 'always use max' menu item exist? + let alwaysMaxMenuItem = firstMenuItem; + + // If not + if (firstMenuItem.innerHTML !== 'Always use max') { + // Add the 'always use max' menu item + alwaysMaxMenuItem = document.createElement('li'); + alwaysMaxMenuItem.classList.add('vjs-menu-item'); + alwaysMaxMenuItem.classList.add('always-max'); + alwaysMaxMenuItem.innerHTML = ` + Always use max + + `; + alwaysMaxMenuItem.addEventListener('click', goodTube_player_selectHighestManifestQuality); + manifestQualityMenu.prepend(alwaysMaxMenuItem); + + // Add a click action to all the other menu options (this turns off 'always use max') + let otherMenuItems = manifestQualityMenu.querySelectorAll('li.vjs-menu-item:not(.always-max)'); + otherMenuItems.forEach((otherMenuItem) => { + otherMenuItem.addEventListener('click', goodTube_player_turnOffHighestManifestQuality); + + // For some reason we need this to support mobile devices, but not for other event listeners here? Weird. + otherMenuItem.addEventListener('touchstart', goodTube_player_turnOffHighestManifestQuality); + }); + } + + // Check the cookie, are we always using max? + let alwaysUseMax = goodTube_helper_getCookie('goodTube_alwaysUseMax'); + + // If we are, then select the highest quality + if (alwaysUseMax && alwaysUseMax === 'true') { + goodTube_player_selectHighestManifestQuality(); + } } } else { - if (goodTube_selectHighestManifestQualityTimeout) { - clearTimeout(goodTube_selectHighestManifestQualityTimeout); + if (goodTube_updateManifestQualityTimeout) { + clearTimeout(goodTube_updateManifestQualityTimeout); } - goodTube_selectHighestManifestQualityTimeout = setTimeout(goodTube_player_selectHighestManifestQuality, 100); + goodTube_updateManifestQualityTimeout = setTimeout(goodTube_player_updateManifestQualityMenu, 100); return; } } + // Select the highest manifest quality + let goodTube_dontTurnOffMaxFromClick = false; + function goodTube_player_selectHighestManifestQuality() { + // Set the cookie to remember this + goodTube_helper_setCookie('goodTube_alwaysUseMax', 'true'); + + // Find the manifest quality menu + let qualityMenu = document.querySelectorAll('.vjs-quality-selector')[1]; + + // Find the highest quality button (second in the list) + let highestQualityButton = qualityMenu.querySelectorAll('li.vjs-menu-item')[1]; + + // Ensure the click doesn't turn off the max option + goodTube_dontTurnOffMaxFromClick = true; + + // Click it + highestQualityButton.click(); + + // Add an auto selected class (half white) + highestQualityButton.classList.add('vjs-auto-selected'); + + // Deselect it + highestQualityButton.classList.remove('vjs-selected'); + + // Select the 'Always use max option' + qualityMenu.querySelector('li.always-max').classList.add('vjs-selected'); + + // Debug message + if (goodTube_debug) { + console.log('[GoodTube] Selecting highest quality - '+highestQualityButton.querySelector('.vjs-menu-item-text').innerHTML); + } + } + + // Turn off the highest manifest quality option + function goodTube_player_turnOffHighestManifestQuality() { + // Allow this once only, so the max quality selection doesn't turn itself off! + if (goodTube_dontTurnOffMaxFromClick) { + goodTube_dontTurnOffMaxFromClick = false; + return; + } + + // Set the cookie to remember this + goodTube_helper_setCookie('goodTube_alwaysUseMax', 'false'); + + // Find the manifest quality menu + let qualityMenu = document.querySelectorAll('.vjs-quality-selector')[1]; + + // Find the 'always use max' quality button + let alwaysMaxMenuItem = qualityMenu.querySelector('li.always-max'); + + // Remove the selected class + if (alwaysMaxMenuItem.classList.contains('vjs-selected')) { + alwaysMaxMenuItem.classList.remove('vjs-selected'); + } + + // Remove any auto selected classes + let autoSelectedItem = qualityMenu.querySelector('li.vjs-auto-selected') + if (autoSelectedItem) { + autoSelectedItem.classList.remove('vjs-auto-selected'); + } + } + // Load chapters function goodTube_player_loadChapters(player, description, totalDuration) { // Clear any existing chapters @@ -4208,9 +4293,7 @@ background-color: rgba(35, 35, 35, 0.75); } - .video-js .vjs-menu li.vjs-menu-item:not(.vjs-selected), - .video-js .vjs-menu li.vjs-menu-item:not(.vjs-selected):focus, - .video-js .vjs-menu li.vjs-menu-item:not(.vjs-selected):active { + .video-js .vjs-menu li.vjs-menu-item:not(.vjs-selected) { background-color: transparent !important; color: #ffffff !important; } @@ -4324,7 +4407,8 @@ padding-bottom: 12px !important; } - .video-js .vjs-menu li.vjs-menu-item:not(.vjs-selected):hover { + .video-js .vjs-menu li.vjs-menu-item:not(.vjs-selected):hover, + .video-js .vjs-menu li.vjs-menu-item.vjs-auto-selected { background-color: rgba(255, 255, 255, .2) !important; color: #ffffff !important; } @@ -5602,7 +5686,6 @@ }) .then(response => response.text()) .then(data => { - // console.log('success', data); // Stop if this is no longer a pending download if (typeof goodTube_pendingDownloads[youtubeId] === 'undefined') { return; @@ -5730,8 +5813,6 @@ }) // If anything went wrong, try again .catch((error) => { - // console.log('error', error); - if (typeof goodTube_pendingRetry['download_'+youtubeId] !== 'undefined') { clearTimeout(goodTube_pendingRetry['download_'+youtubeId]); }