iv-org / invidious

Invidious is an alternative front-end to YouTube

Home Page:https://invidious.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Bug] Randomly after changing video quality, control bar and mouse cursor no longer auto-hide

nyanpasu64 opened this issue · comments

Describe the bug
After changing the video resolution in Invidious, sometimes the seek bar and mouse cursor no longer auto-hide after inactivity.

Steps to Reproduce

  1. Load a video.
  2. Hover the gear to switch video resolutions.
  3. Move the mouse cursor up and down the list, click a resolution, etc.

Logs

According to #3011, Invidious is running an outdated video.js 7.12.1. I cloned that version locally to help debug.

I've traced the bug to player.js, functions userActive(bool) and listenForUserActivity_(). The latter function registers handlers for when the mouse enters and exits the control bar. When the mouse enters controlBar.on('mouseenter', the code sets this.player().options_.inactivityTimeout = 0, and when it exits controlBar.on('mouseleave', the code restores the original value using this.player().options_.inactivityTimeout = this.player().cache_.inactivityTimeout.

  • Sidenote: this will cause problems if you try programmatically changing the inactivity timeout while the mouse is over the control bar. I don't know if this is allowed by the API, and if not it's not a bug.

The problem occurs when the mouseenter event fires multiple times in succession without a mouseleave event in between, or mouseleave fails to fire when exiting the control bar. In the first case, this.player().cache_.inactivityTimeout gets overwritten a second time with this.player().options_.inactivityTimeout (which is now zero). In the second case, this.player().options_.inactivityTimeout never gets restored (and when you mouse over the control bar again, the cached value gets overwritten with 0). Either way, the control bar no longer auto-hides after 2 seconds (the vjs-user-active class is stuck on and vjs-user-inactive never gets set).

You can test this by pasting the following JS snippet into F12 console, then playing with the quality menu:

gLevel = 0;
player.controlBar.on('mouseenter', () => {
	console.log(".".repeat(gLevel) + "{")
	gLevel++;
});
player.controlBar.on('mouseleave', () => {
	gLevel--;
	console.log(".".repeat(gLevel) + "}")
});
  • mouseleave does not trigger when moving the mouse from the control bar's bounding box onto the video quality menu, but only when moving the mouse out of the quality menu.
  • Sometimes when clicking a quality setting, mouseleave does not fire.
  • Sometimes when moving the mouse up and down the control bar and video quality menu, mouseenter fires twice in a row.
    • Whenever this happens, my script prints leading periods before the braces, indicating that mouseenter has fired reentrantly.

I do not know if this bug occurs because the browser fires multiple mouseenter events or fails to fire mouseleave, or because video.js's Component system is dropping events.

Assuming it's a broken browser behavior that cannot be worked around, to fix this bug, on mouseenter I would avoid overwriting this.player().cache_.inactivityTimeout if it's already set (or a separate flag is set), and on mouseleave I would clear its value (or a separate "is cached" flag).

  • Upstream, a related fix was implemented in videojs/video.js#7383 (they check that the current value is nonzero before writing it into cache).

Screenshots
waterfox_JbzlyHugAa

Additional context

  • Browser (if applicable): Windows 7 with Waterfox and Supermium, Windows 11 with Firefox (replicated on fresh profile)

Looking at the video.js PR, it seems this was already reported in #1263 (but I did not find it through search), but still not fixed.

#1263

pending fix: #4439