diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 50a7e823e..584276f46 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1513,5 +1513,8 @@ }, "excludeShortsInPlayAll": { "message": "Exclude Shorts when using \"Play all\"" + }, + "disableHoldToPlay2x":{ + "message": "Disable hold to play 2x" } } diff --git a/js&css/extension/functions.js b/js&css/extension/functions.js index 4b6c9f742..7efb60030 100644 --- a/js&css/extension/functions.js +++ b/js&css/extension/functions.js @@ -1,3 +1,4 @@ +window.ImprovedTube = window.ImprovedTube || {}; /*-------------------------------------------------------------- >>> FUNCTIONS: /*-------------------------------------------------------------- @@ -6,4 +7,145 @@ extension.functions.getUrlParameter = function (url, parameter) { var match = url.match(new RegExp('(\\?|\\&)' + parameter + '=[^&]+')); if (match) {return match[0].substr(3);} -}; \ No newline at end of file +}; + +/*------------------------------------------------------------------------------ +DISABLE/ENABLE HOLD TO PLAY ON 2X SPEED (GLOBAL) +------------------------------------------------------------------------------*/ +ImprovedTube._holdToPlayListener = null; + +// DISABLE +ImprovedTube.disableHoldToPlay = function () { + console.log('[ImprovedTube] disableHoldToPlay called'); + + + // REMOVE PREVIOUS LISTENERS + if (this._holdToPlayListener) { + document.removeEventListener('keydown', this._holdToPlayListener, true); + document.removeEventListener('keyup', this._holdToPlayListener, true); + document.removeEventListener('mousedown', this._holdToPlayListener, true); + document.removeEventListener('mouseup', this._holdToPlayListener, true); + this._holdToPlayListener = null; + console.log('[ImprovedTube] Removed previous holdToPlay listeners'); + } + + + this._holdToPlayListener = (e) => { + // BLOCK SPACEBAR HOLD (block ALL keydown/keyup for Space) + if ((e.type === 'keydown' && e.code === 'Space') || + (e.type === 'keyup' && e.code === 'Space')) { + console.log('[ImprovedTube] Blocked spacebar event:', e.type, e); + e.stopImmediatePropagation(); + e.preventDefault(); + } + // BLOCK MOUSE HOLD + if ((e.type === 'mousedown' || e.type === 'mouseup') && e.target.tagName === 'VIDEO') { + console.log('[ImprovedTube] Blocked mouse event:', e.type, e); + e.stopImmediatePropagation(); + e.preventDefault(); + } + }; + + + document.addEventListener('keydown', this._holdToPlayListener, true); + document.addEventListener('keyup', this._holdToPlayListener, true); + document.addEventListener('mousedown', this._holdToPlayListener, true); + document.addEventListener('mouseup', this._holdToPlayListener, true); + console.log('[ImprovedTube] Attached holdToPlay listeners'); + + // REATTACH LISTENERS IF VIDEO ELEMENT CHANGES (YOUTUBE SPA NAVIGATION) + if (!this._holdToPlayVideoObserver) { + this._holdToPlayVideoObserver = new MutationObserver(() => { + // CHECK CHROME STORAGE FOR THE NEWEST VALUE + chrome.storage.local.get('disable_hold_to_play_2x', (result) => { + console.log('[ImprovedTube] MutationObserver: disable_hold_to_play_2x =', result.disable_hold_to_play_2x); + if (result.disable_hold_to_play_2x) { + ImprovedTube.disableHoldToPlay(); + } else { + ImprovedTube.enableHoldToPlay(); + } + }); + }); + const player = document.getElementById('movie_player') || document.querySelector('.html5-video-player'); + if (player) { + this._holdToPlayVideoObserver.observe(player, { childList: true, subtree: true }); + console.log('[ImprovedTube] MutationObserver attached to player'); + } + } +}; +// ENABLE +ImprovedTube.enableHoldToPlay = function () { + console.log('[ImprovedTube] enableHoldToPlay called'); + if (this._holdToPlayListener) { + document.removeEventListener('keydown', this._holdToPlayListener, true); + document.removeEventListener('keyup', this._holdToPlayListener, true); + document.removeEventListener('mousedown', this._holdToPlayListener, true); + document.removeEventListener('mouseup', this._holdToPlayListener, true); + this._holdToPlayListener = null; + console.log('[ImprovedTube] Removed holdToPlay listeners (enable)'); + } + if (this._holdToPlayVideoObserver) { + this._holdToPlayVideoObserver.disconnect(); + this._holdToPlayVideoObserver = null; + console.log('[ImprovedTube] MutationObserver disconnected (enable)'); + } +}; + +// LISTEN FOR STORAGE CHANGES TO UPDATE THE BEHAVIOR INSTANTLY +if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.onChanged) { + chrome.storage.onChanged.addListener(function(changes, area) { + if (area === 'local' && changes.disable_hold_to_play_2x) { + console.log('[ImprovedTube] chrome.storage.onChanged: disable_hold_to_play_2x =', changes.disable_hold_to_play_2x.newValue); + if (changes.disable_hold_to_play_2x.newValue) { + ImprovedTube.disableHoldToPlay(); + } else { + ImprovedTube.enableHoldToPlay(); + } + } + }); +} + +// CHECKS CHROME STORAGE ON CONTENT SCRIPT LOAD AND INITIALIZES +if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { + chrome.storage.local.get('disable_hold_to_play_2x', (result) => { + console.log('[ImprovedTube] Content script loaded. disable_hold_to_play_2x =', result.disable_hold_to_play_2x); + if (result.disable_hold_to_play_2x) { + // SCRIPT TAG INJECTION (TO CATCH EVENTS BEFORE YT DOES) + const code = ` + (function() { + function blockHoldToPlay(e) { + if ((e.type === 'keydown' && e.code === 'Space') || + (e.type === 'keyup' && e.code === 'Space')) { + console.log('[ImprovedTube injected] Blocked spacebar event:', e.type, e); + e.stopImmediatePropagation(); + e.preventDefault(); + } + if ((e.type === 'mousedown' || e.type === 'mouseup') && e.target.tagName === 'VIDEO') { + console.log('[ImprovedTube injected] Blocked mouse event:', e.type, e); + e.stopImmediatePropagation(); + e.preventDefault(); + } + } + window.addEventListener('keydown', blockHoldToPlay, true); + window.addEventListener('keyup', blockHoldToPlay, true); + window.addEventListener('mousedown', blockHoldToPlay, true); + window.addEventListener('mouseup', blockHoldToPlay, true); + console.log('[ImprovedTube injected] Hold-to-play block active'); + })(); + `; + const script = document.createElement('script'); + script.textContent = code; + (document.head || document.documentElement).appendChild(script); + script.remove(); + } + // RUN THE NORMAL CONTENT SCRIPT LOGIC + if (result.disable_hold_to_play_2x) { + ImprovedTube.disableHoldToPlay(); + } else { + ImprovedTube.enableHoldToPlay(); + } + }); +} +/*------------------------------------------------------------------------------ +END OF DISABLE/ENABLE HOLD TO PLAY ON 2X SPEED (GLOBAL) +------------------------------------------------------------------------------*/ \ No newline at end of file diff --git a/js&css/web-accessible/www.youtube.com/appearance.js b/js&css/web-accessible/www.youtube.com/appearance.js index ad491926f..248adca40 100644 --- a/js&css/web-accessible/www.youtube.com/appearance.js +++ b/js&css/web-accessible/www.youtube.com/appearance.js @@ -869,7 +869,7 @@ ImprovedTube.playerRevertTheaterButtonSize(); document.addEventListener('yt-page-data-updated', run); document.addEventListener('yt-navigate-finish', run); window.addEventListener('load', run); - etTimeout(run, 2000); // fallback for late loads + setTimeout(run, 2000); // fallback for late loads })(); /*------------------------------------------------------------------------------ diff --git a/js&css/web-accessible/www.youtube.com/player.js b/js&css/web-accessible/www.youtube.com/player.js index b00ad715e..806270273 100644 --- a/js&css/web-accessible/www.youtube.com/player.js +++ b/js&css/web-accessible/www.youtube.com/player.js @@ -268,7 +268,7 @@ window.addEventListener('load', () => { setTimeout(() => { clearInterval(waitFo } // else { } } } -} +} /*------------------------------------------------------------------------------ SUBTITLES ------------------------------------------------------------------------------*/ diff --git a/manifest.json b/manifest.json index 589992ce9..9f490d4b7 100644 --- a/manifest.json +++ b/manifest.json @@ -1,86 +1,97 @@ { - "manifest_version": 3, - "short_name": "ImprovedTube", - "name": "'Improve YouTube!' 🎧 (for YouTube & Videos)", - "description": "__MSG_description_ext__", - "version": "4", - "default_locale": "en", - "icons": { - "128": "menu/icons/128.png", - "16": "menu/icons/16.png", - "32": "menu/icons/32.png", - "48": "menu/icons/48.png" - }, - "browser_specific_settings": { - "gecko": { - "id": "{3c6bf0cc-3ae2-42fb-9993-0d33104fdcaf}" - } - }, - "background": { - "service_worker": "background.js" - }, - "action": { - "default_popup": "menu/index.html", - "default_area": "navbar" - }, - "options_page": "menu/index.html", - "options_ui": { - "page": "menu/index.html" - }, - "content_scripts": [ - { - "all_frames": true, - "css": [ - "js&css/extension/www.youtube.com/styles.css", - "js&css/extension/www.youtube.com/night-mode/night-mode.css", - "js&css/extension/www.youtube.com/general/general.css", - "js&css/extension/www.youtube.com/appearance/header/header.css", - "js&css/extension/www.youtube.com/appearance/player/player.css", - "js&css/extension/www.youtube.com/appearance/details/details.css", - "js&css/extension/www.youtube.com/appearance/sidebar/sidebar.css", - "js&css/extension/www.youtube.com/appearance/comments/comments.css" - ], - "exclude_matches": [ - "https://www.youtube.com/audiolibrary/*", - "https://www.youtube.com/tv*" - ], - "js": [ - "js&css/extension/core.js", - "js&css/extension/functions.js", - "js&css/extension/www.youtube.com/night-mode/night-mode.js", - "js&css/extension/www.youtube.com/general/general.js", - "js&css/extension/www.youtube.com/appearance/sidebar/sidebar.js", - "js&css/extension/www.youtube.com/appearance/comments/comments.js", - "js&css/extension/init.js" - ], - "matches": ["https://www.youtube.com/*"], - "run_at": "document_start" - } - ], - "host_permissions": ["https://www.youtube.com/*"], - "optional_permissions": ["downloads"], - "permissions": ["contextMenus", "storage"], - "web_accessible_resources": [ - { - "resources": [ - "menu/index.html", - "js&css/web-accessible/core.js", - "js&css/web-accessible/functions.js", - "js&css/web-accessible/www.youtube.com/appearance.js", - "js&css/web-accessible/www.youtube.com/player.js", - "js&css/web-accessible/www.youtube.com/themes.js", - "js&css/web-accessible/www.youtube.com/playlist.js", - "js&css/web-accessible/www.youtube.com/playlist-complete-playlist.js", - "js&css/web-accessible/www.youtube.com/playlist-cleaner.js", - "js&css/web-accessible/www.youtube.com/channel.js", - "js&css/web-accessible/www.youtube.com/shortcuts.js", - "js&css/web-accessible/www.youtube.com/blocklist.js", - "js&css/web-accessible/www.youtube.com/settings.js", - "js&css/web-accessible/www.youtube.com/last-watched-overlay.js", - "js&css/web-accessible/init.js", - "menu/icons/48.png" - ], - "matches": ["https://www.youtube.com/*"] - } - ] -} + "action": { + "default_area": "navbar", + "default_popup": "menu/index.html" + }, + "background": { + "service_worker": "background.js" + }, + "browser_specific_settings": { + "gecko": { + "id": "{3c6bf0cc-3ae2-42fb-9993-0d33104fdcaf}" + } + }, + "content_scripts": [ + { + "all_frames": true, + "css": [ + "js&css/extension/www.youtube.com/styles.css", + "js&css/extension/www.youtube.com/night-mode/night-mode.css", + "js&css/extension/www.youtube.com/general/general.css", + "js&css/extension/www.youtube.com/appearance/header/header.css", + "js&css/extension/www.youtube.com/appearance/player/player.css", + "js&css/extension/www.youtube.com/appearance/details/details.css", + "js&css/extension/www.youtube.com/appearance/sidebar/sidebar.css", + "js&css/extension/www.youtube.com/appearance/comments/comments.css" + ], + "exclude_matches": [ + "https://www.youtube.com/audiolibrary/*", + "https://www.youtube.com/tv*" + ], + "js": [ + "js&css/extension/core.js", + "js&css/extension/functions.js", + "js&css/extension/www.youtube.com/night-mode/night-mode.js", + "js&css/extension/www.youtube.com/general/general.js", + "js&css/extension/www.youtube.com/appearance/sidebar/sidebar.js", + "js&css/extension/www.youtube.com/appearance/comments/comments.js", + "js&css/extension/init.js" + ], + "matches": [ + "https://www.youtube.com/*" + ], + "run_at": "document_start" + } + ], + "default_locale": "en", + "description": "__MSG_description_ext__", + "host_permissions": [ + "https://www.youtube.com/*" + ], + "icons": { + "128": "menu/icons/128.png", + "16": "menu/icons/16.png", + "32": "menu/icons/32.png", + "48": "menu/icons/48.png" + }, + "manifest_version": 3, + "name": "'Improve YouTube!' \u00f0\u0178\u017d\u00a7 (for YouTube & Videos)", + "optional_permissions": [ + "downloads" + ], + "options_page": "menu/index.html", + "options_ui": { + "page": "menu/index.html" + }, + "permissions": [ + "contextMenus", + "storage" + ], + "short_name": "ImprovedTube", + "version": "4", + "web_accessible_resources": [ + { + "matches": [ + "https://www.youtube.com/*" + ], + "resources": [ + "menu/index.html", + "js&css/web-accessible/core.js", + "js&css/web-accessible/functions.js", + "js&css/web-accessible/www.youtube.com/appearance.js", + "js&css/web-accessible/www.youtube.com/player.js", + "js&css/web-accessible/www.youtube.com/themes.js", + "js&css/web-accessible/www.youtube.com/playlist.js", + "js&css/web-accessible/www.youtube.com/playlist-complete-playlist.js", + "js&css/web-accessible/www.youtube.com/playlist-cleaner.js", + "js&css/web-accessible/www.youtube.com/channel.js", + "js&css/web-accessible/www.youtube.com/shortcuts.js", + "js&css/web-accessible/www.youtube.com/blocklist.js", + "js&css/web-accessible/www.youtube.com/settings.js", + "js&css/web-accessible/www.youtube.com/last-watched-overlay.js", + "js&css/web-accessible/init.js", + "menu/icons/48.png" + ] + } + ] +} \ No newline at end of file diff --git a/menu/skeleton-parts/appearance.js b/menu/skeleton-parts/appearance.js index e08ddf30e..12b84bd8e 100644 --- a/menu/skeleton-parts/appearance.js +++ b/menu/skeleton-parts/appearance.js @@ -428,11 +428,9 @@ extension.skeleton.main.layers.section.appearance.on.click.player = { component: "switch", text: "hideTopLoadingBar", tags: "remove,hide" - }, + } } } - - }; /*-------------------------------------------------------------- diff --git a/menu/skeleton-parts/player.js b/menu/skeleton-parts/player.js index f6e928231..1b492d54d 100644 --- a/menu/skeleton-parts/player.js +++ b/menu/skeleton-parts/player.js @@ -838,6 +838,11 @@ extension.skeleton.main.layers.section.player.on.click = { component: 'switch', text: 'customMiniPlayer' }, + disable_hold_to_play_2x: { + component: 'switch', + text: 'disableHoldToPlay2x', + value: false, + }, forced_play_video_from_the_beginning: { component: 'switch', text: 'forcedPlayVideoFromTheBeginning'