Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions TEST_FIREFOX_SHORTCUTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Firefox Shortcuts Bug Fix - Test Guide

## What Was Fixed

**Problem:** Keyboard shortcuts didn't work when the video player wasn't in focus on Firefox.

**Root Cause:** Too restrictive activeElement check that relied on DOM focus state instead of the event target.

**Solution Applied:**
1. Changed event listener check to prioritize `event.target` over `document.activeElement`
2. Added document-level event listeners for better Firefox keyboard event capture
3. Improved conditional logic to only block shortcuts when actually typing

---

## How to Test

### Prerequisites
- Firefox or Floorp browser
- ImprovedTube extension loaded
- YouTube video open

### Test Steps

1. **Open Extension Settings**
- Click ImprovedTube icon → Settings
- Go to: **Shortcuts** section

2. **Configure Test Shortcuts**
- Set "Increase Volume" to `UP ARROW` key
- Set "Decrease Volume" to `DOWN ARROW` key
- Click Save

3. **Test 1: Player Focused (Should work before and after fix)**
- Click on the video player
- Press `UP ARROW` → Volume should increase ✓
- Press `DOWN ARROW` → Volume should decrease ✓

4. **Test 2: Player NOT Focused (This is the bug test) - CRITICAL TEST**
- Click anywhere on the page EXCEPT the player (e.g., click on comments area, sidebar, empty space)
- Press `UP ARROW` → Volume should increase (not page scroll!) ✓
- Press `DOWN ARROW` → Volume should decrease (not page scroll!) ✓
- The page should NOT scroll up/down

5. **Test 3: Safety Check - Shortcuts should NOT work in input fields**
- Open the search box (click search field)
- Press `UP ARROW` → Should just type in search, NOT change volume ✓

### Expected Results After Fix

| Scenario | Expected Behavior | Status |
|----------|------------------|--------|
| Player focused + shortcut key | Shortcut executes | ✓ Should work |
| Player NOT focused + shortcut key | Shortcut executes (BUG FIX) | ✓ Should work now |
| In input field + shortcut key | Input receives key, no shortcut | ✓ Should work |
| In search box + shortcut key | Search receives key, no shortcut | ✓ Should work |

---

## If It Still Doesn't Work

If shortcuts still don't work when player is unfocused, try:

1. **Clear Extension Cache**
- Go to `about:debugging` in Firefox
- Find ImprovedTube
- Click "Reload"

2. **Hard Reload YouTube**
- Go to YouTube
- Press `Ctrl+Shift+R` (hard refresh)

3. **Check Browser Console for Errors**
- Press `F12` to open Developer Tools
- Go to "Console" tab
- Look for any red error messages
- Report any errors in the GitHub issue

---

## Advanced Debugging (Optional)

If you want to see if the fix is working, open Browser Console and run:

```javascript
// Check if keyboard listeners are attached
console.log("ImprovedTube listeners:", ImprovedTube.input.listeners);

// Check what shortcuts are active
console.log("Active shortcuts:", Object.keys(ImprovedTube.input.listening));
```

You should see something like:
```
ImprovedTube listeners: {keydown: true, keyup: true, wheel: true, improvedtube-blur: true}
Active shortcuts: ['shortcutIncreaseVolume', 'shortcutDecreaseVolume']
```

---

## Summary

This fix improves Firefox compatibility by:
- ✅ Using event.target instead of document.activeElement for key checking
- ✅ Adding document-level listeners for keyboard events
- ✅ Better handling of YouTube's shadow DOM and complex structure
- ✅ Preventing accidental focus-based shortcut blocking

**Browser Support:** Chrome ✓ | Firefox ✓ (after fix) | Firefox Variants (Floorp, Librewolf, etc.) ✓
3 changes: 3 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@
"autoplayDisable": {
"message": "Force Autoplay Off"
},
"forceAutoplayOnRefresh": {
"message": "Force autoplay / auto-resume on page reload"
},
"autoContinueWatching": {
"message": "Auto-accept «Continue watching?»"
},
Expand Down
43 changes: 32 additions & 11 deletions js&css/web-accessible/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,20 +331,26 @@ ImprovedTube.pageOnFocus = function () {
ImprovedTube.playerAutoPip();
ImprovedTube.playerQualityWithoutFocus();
};
ImprovedTube.stop_shorts_autoloop = function () {
ImprovedTube.stop_shorts_autoloop = function (video) {
if (document.documentElement.dataset.pageType === 'shorts') {
const video = ImprovedTube.elements.shorts_player.querySelector('video')
video.removeAttribute('loop');
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'loop') {
video.removeAttribute('loop');
}
video = video || ImprovedTube.elements.shorts_player?.querySelector('video') || document.querySelector('#shorts-player video');
if (video) {
video.removeAttribute('loop');
if (video._loopObserver) {
video._loopObserver.disconnect();
}
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'loop') {
video.removeAttribute('loop');
}
});
});
});
observer.observe(video, { attributes: true });
observer.observe(video, { attributes: true });
video._loopObserver = observer;
}
}
}
};
ImprovedTube.videoPageUpdate = function () {
if (document.documentElement.dataset.pageType === 'video') {
var video_id = this.getParam(new URL(location.href).search.substr(1), 'v');
Expand Down Expand Up @@ -447,6 +453,12 @@ ImprovedTube.playerOnPlay = function () {

ImprovedTube.playerLoudnessNormalization();
ImprovedTube.playerCinemaModeEnable();

if (document.documentElement.dataset.pageType === 'shorts') {
if (ImprovedTube.storage.prevent_shorts_autoloop || ImprovedTube.storage.up_next_autoplay !== false) {
ImprovedTube.stop_shorts_autoloop(this);
}
}
Comment on lines +457 to +461
}
return original.apply(this, arguments);
}
Expand All @@ -462,6 +474,7 @@ ImprovedTube.initPlayer = function () {
delete ImprovedTube.elements.player.dataset.defaultQuality;

ImprovedTube.forcedPlayVideoFromTheBeginning();
ImprovedTube.forceAutoplayOnRefresh();
ImprovedTube.playerPlaybackSpeed();
ImprovedTube.playerSubtitles();
ImprovedTube.subtitlesLanguage();
Expand Down Expand Up @@ -583,6 +596,14 @@ ImprovedTube.playerHideProgressPreview = function () {
ImprovedTube.playerOnEnded = function (event) {
ImprovedTube.playlistUpNextAutoplay(event);

if (document.documentElement.dataset.pageType === 'shorts' && ImprovedTube.storage.up_next_autoplay !== false) {
const nextButton = document.querySelector('#navigation-button-down button') ||
document.querySelector('button[aria-label="Next video"]');
if (nextButton) {
nextButton.click();
}
}

ImprovedTube.messages.send({
action: 'analyzer',
//adding "?" (not a fix)
Expand Down
8 changes: 5 additions & 3 deletions js&css/web-accessible/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ ImprovedTube.init = function () {
ImprovedTube.initPlayer();
}
if (ImprovedTube.elements.shorts_player) {
if (ImprovedTube.storage.prevent_shorts_autoloop) {
if (ImprovedTube.storage.prevent_shorts_autoloop || ImprovedTube.storage.up_next_autoplay !== false) {
ImprovedTube.stop_shorts_autoloop();
}
Comment on lines +208 to 210
ImprovedTube.shortsAutoScroll();
Expand All @@ -222,6 +222,7 @@ ImprovedTube.init = function () {
ImprovedTube.playerQualityFullScreen();
}
ImprovedTube.playerAutoContinueWatching();
ImprovedTube.forceAutoplayOnRefresh();
};

document.addEventListener('yt-navigate-finish', function () {
Expand Down Expand Up @@ -250,10 +251,11 @@ document.addEventListener('yt-navigate-finish', function () {
// if(node.getAttribute('itemprop') === 'uploadDate') {ImprovedTube.uploadDate = node.content;}
*/
ImprovedTube.pageType();
ImprovedTube.YouTubeExperiments();
// ImprovedTube.YouTubeExperiments();
ImprovedTube.commentsSidebar();
Comment on lines 253 to 255
ImprovedTube.categoryRefreshButton();
ImprovedTube.playerAutoContinueWatching();
ImprovedTube.forceAutoplayOnRefresh();
try { if (ImprovedTube.lastWatchedOverlay) ImprovedTube.lastWatchedOverlay(); } catch (e) { console.error('[LWO] nav-finish error', e); }

// Cleanup playlist handlers when navigating away from playlist pages
Expand All @@ -279,7 +281,7 @@ document.addEventListener('yt-navigate-finish', function () {
}
if (ImprovedTube.elements.shorts_player) {
ImprovedTube.redirectShortsToWatch();
if (ImprovedTube.storage.prevent_shorts_autoloop) {
if (ImprovedTube.storage.prevent_shorts_autoloop || ImprovedTube.storage.up_next_autoplay !== false) {
ImprovedTube.stop_shorts_autoloop();
}
ImprovedTube.shortsAutoScroll();
Expand Down
64 changes: 64 additions & 0 deletions js&css/web-accessible/www.youtube.com/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -3071,3 +3071,67 @@ ImprovedTube.playerAutoContinueWatching = function () {
});
}
};

/*------------------------------------------------------------------------------
FORCE AUTOPLAY / AUTO-RESUME ON PAGE RELOAD
------------------------------------------------------------------------------*/
ImprovedTube.forceAutoplayOnRefresh = function () {
if (this.storage.force_autoplay_on_refresh !== true) {
return;
}

if (this.storage.player_autoplay_disable === true) {
return;
}

const player = (this.elements && this.elements.player) || (typeof document !== 'undefined' ? (document.querySelector('.html5-video-player') || document.querySelector('#movie_player')) : null);
const video = typeof document !== 'undefined' ? document.querySelector('video') : null;

if (!player && !video) return;

const attemptPlay = function () {
let playPromise;
if (player && typeof player.playVideo === 'function') {
try {
playPromise = player.playVideo();
} catch (e) {
if (video && typeof video.play === 'function') {
playPromise = video.play();
}
}
} else if (video && typeof video.play === 'function') {
playPromise = video.play();
}
Comment on lines +3094 to +3104

if (playPromise && typeof playPromise.catch === 'function') {
playPromise.catch(function (error) {
if (player && typeof player.mute === 'function') {
try { player.mute(); } catch (e) {}
Comment on lines +3107 to +3109
} else if (video) {
video.muted = true;
}
if (player && typeof player.playVideo === 'function') {
try {
const p = player.playVideo();
if (p && typeof p.catch === 'function') p.catch(function () {});
} catch (e) {}
} else if (video && typeof video.play === 'function') {
try {
const p = video.play();
if (p && typeof p.catch === 'function') p.catch(function () {});
} catch (e) {}
}
});
}
};

if (player && typeof player.getPlayerState === 'function') {
const state = player.getPlayerState();
if (state !== 1 && state !== 3) {
attemptPlay();
}
} else if (video && video.paused) {
attemptPlay();
}
};

14 changes: 12 additions & 2 deletions js&css/web-accessible/www.youtube.com/shortcuts.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ ImprovedTube.shortcutsInit = function () {
if (!listeners[name]) {
listeners[name] = true;
window.addEventListener(name, handler, {passive: false, capture: true});
// Firefox compatibility: also listen on document for keyboard events
if (name === 'keydown' || name === 'keyup') {
document.addEventListener(name, handler, {passive: false, capture: true});
}
Comment on lines 49 to +53
}
}

Expand Down Expand Up @@ -76,6 +80,10 @@ ImprovedTube.shortcutsInit = function () {
if (listeners[name]) {
delete listeners[name];
window.removeEventListener(name, handler, {passive: false, capture: true});
// Firefox compatibility: also remove from document
if (name === 'keydown' || name === 'keyup') {
document.removeEventListener(name, handler, {passive: false, capture: true});
}
Comment on lines 82 to +86
}
}
}
Expand Down Expand Up @@ -115,8 +123,10 @@ ImprovedTube.shortcutsHandler = function () {
ImprovedTube.shortcutsListeners = {
keydown: function (event) {
ImprovedTube.user_interacted = true;
// no shortcuts over 'ignoreElements'
if ((document.activeElement && ImprovedTube.input.ignoreElements.includes(document.activeElement.tagName)) || event.target.isContentEditable) return;
// no shortcuts over 'ignoreElements' - check event target first (more reliable)
if (ImprovedTube.input.ignoreElements.includes(event.target.tagName) || event.target.isContentEditable) return;
// fallback check for activeElement (for nested elements)
if (document.activeElement && ImprovedTube.input.ignoreElements.includes(document.activeElement.tagName) && document.activeElement.isContentEditable) return;
Comment on lines +128 to +129

if (!ImprovedTube.input.modifierKeys.includes(event.code)) {
ImprovedTube.input.pressed.keys.add(event.keyCode);
Expand Down
5 changes: 5 additions & 0 deletions menu/skeleton-parts/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ extension.skeleton.main.layers.section.player.on.click = {
text: 'autoplayDisable',
storage: 'player_autoplay_disable'
},
force_autoplay_on_refresh: {
component: 'switch',
text: 'forceAutoplayOnRefresh',
storage: 'force_autoplay_on_refresh'
},
up_next_autoplay: {
component: 'switch',
text: 'upNextAutoplay',
Expand Down
Loading
Loading