Added loading spinner when video is buffering (#7487)

* Added loading spinner when video is buffering

* Only show if buffering for more than 500ms
This commit is contained in:
Peaches_MLG authored and GitHub committed 2026-10-20 12:18:36 -04:00
1 parent ecc5200f38
commit 34a0d9b314
2 files changed
+32

No files matched your search

@@ -28,6 +28,7 @@ import 'elements/emby-ratingbutton/emby-ratingbutton';
import 'styles/videoosd.scss';
import shell from 'scripts/shell';
import SubtitleSync from 'components/subtitlesync/subtitlesync';
import loading from 'components/loading/loading';
import { appRouter } from 'components/router/appRouter';
import { ServerConnections } from 'lib/jellyfin-apiclient';
import LibraryMenu from 'scripts/libraryMenu';
@@ -578,6 +579,22 @@ export default function (view) {
view.querySelector('.osdMediaStatus').classList.add('hide');
}
let loadingTimeout;
function onWaiting() {
loadingTimeout = setTimeout(() => {
loading.show();
}, 500);
}
function onCanPlay() {
if (loadingTimeout) {
clearTimeout(loadingTimeout);
loadingTimeout = null;
}
loading.hide();
}
function bindToPlayer(player) {
if (player !== currentPlayer) {
releaseCurrentPlayer();
@@ -599,6 +616,8 @@ export default function (view) {
Events.on(player, 'mediastreamschange', onMediaStreamsChanged);
Events.on(player, 'beginFetch', onBeginFetch);
Events.on(player, 'endFetch', onEndFetch);
Events.on(player, 'waiting', onWaiting);
Events.on(player, 'canplay', onCanPlay);
resetUpNextDialog();
if (player.isFetching) {
@@ -607,6 +626,11 @@ export default function (view) {
}
function releaseCurrentPlayer() {
if (loadingTimeout) {
clearTimeout(loadingTimeout);
loadingTimeout = null;
}
destroyStats();
destroySubtitleSync();
resetUpNextDialog();
@@ -624,6 +648,8 @@ export default function (view) {
Events.off(player, 'mediastreamschange', onMediaStreamsChanged);
Events.off(player, 'beginFetch', onBeginFetch);
Events.off(player, 'endFetch', onEndFetch);
Events.off(player, 'waiting', onWaiting);
Events.off(player, 'canplay', onCanPlay);
currentPlayer = null;
}
}
+6
View File
@@ -984,6 +984,7 @@ export class HtmlVideoPlayer {
videoElement.removeEventListener('click', this.onClick);
videoElement.removeEventListener('dblclick', this.onDblClick);
videoElement.removeEventListener('waiting', this.onWaiting);
videoElement.removeEventListener('canplay', this.onCanPlay);
videoElement.removeEventListener('error', this.onError); // bound in htmlMediaHelper
resetSrc(videoElement);
@@ -1186,6 +1187,10 @@ export class HtmlVideoPlayer {
Events.trigger(this, 'waiting');
};
onCanPlay = () => {
Events.trigger(this, 'canplay');
};
/**
* @private
* @param e {Event} The event received from the `<video>` element
@@ -1846,6 +1851,7 @@ export class HtmlVideoPlayer {
videoElement.addEventListener('click', this.onClick);
videoElement.addEventListener('dblclick', this.onDblClick);
videoElement.addEventListener('waiting', this.onWaiting);
videoElement.addEventListener('canplay', this.onCanPlay);
if (options.backdropUrl) {
videoElement.poster = options.backdropUrl;
}