added loading indicator
This commit is contained in:
@@ -939,6 +939,39 @@ body.theme-light .setting-item select option {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-loading {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 0, 0.45);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-card.is-loading .video-loading,
|
||||||
|
.favorite-card.is-loading .video-loading {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-loading-spinner {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.35);
|
||||||
|
border-top-color: var(--text-primary);
|
||||||
|
animation: video-card-spinner 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes video-card-spinner {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.uploader-link:hover {
|
.uploader-link:hover {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ App.favorites = App.favorites || {};
|
|||||||
<button class="video-menu-item" type="button" data-action="download" role="menuitem">Download</button>
|
<button class="video-menu-item" type="button" data-action="download" role="menuitem">Download</button>
|
||||||
</div>
|
</div>
|
||||||
<img src="${item.thumb}" alt="${item.title}">
|
<img src="${item.thumb}" alt="${item.title}">
|
||||||
|
<div class="video-loading" aria-hidden="true">
|
||||||
|
<div class="video-loading-spinner"></div>
|
||||||
|
</div>
|
||||||
<div class="favorite-info">
|
<div class="favorite-info">
|
||||||
<h4>${item.title}</h4>
|
<h4>${item.title}</h4>
|
||||||
${uploaderText ? `<p><button class="uploader-link" type="button" data-uploader="${uploaderText}">${uploaderText}</button></p>` : ''}
|
${uploaderText ? `<p><button class="uploader-link" type="button" data-uploader="${uploaderText}">${uploaderText}</button></p>` : ''}
|
||||||
@@ -120,7 +123,11 @@ App.favorites = App.favorites || {};
|
|||||||
if (App.videos && typeof App.videos.attachNoReferrerRetry === 'function') {
|
if (App.videos && typeof App.videos.attachNoReferrerRetry === 'function') {
|
||||||
App.videos.attachNoReferrerRetry(thumb);
|
App.videos.attachNoReferrerRetry(thumb);
|
||||||
}
|
}
|
||||||
card.onclick = () => App.player.open(item.meta || item);
|
card.onclick = () => {
|
||||||
|
if (card.classList.contains('is-loading')) return;
|
||||||
|
card.classList.add('is-loading');
|
||||||
|
App.player.open(item.meta || item, { originEl: card });
|
||||||
|
};
|
||||||
const favoriteBtn = card.querySelector('.favorite-btn');
|
const favoriteBtn = card.querySelector('.favorite-btn');
|
||||||
if (favoriteBtn) {
|
if (favoriteBtn) {
|
||||||
favoriteBtn.onclick = (event) => {
|
favoriteBtn.onclick = (event) => {
|
||||||
|
|||||||
@@ -29,10 +29,22 @@ App.player = App.player || {};
|
|||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
App.player.open = async function(source) {
|
App.player.open = async function(source, opts) {
|
||||||
const modal = document.getElementById('video-modal');
|
const modal = document.getElementById('video-modal');
|
||||||
const video = document.getElementById('player');
|
const video = document.getElementById('player');
|
||||||
if (!modal || !video) return;
|
const originEl = opts && opts.originEl ? opts.originEl : null;
|
||||||
|
const clearLoading = () => {
|
||||||
|
if (originEl) {
|
||||||
|
originEl.classList.remove('is-loading');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (originEl) {
|
||||||
|
originEl.classList.add('is-loading');
|
||||||
|
}
|
||||||
|
if (!modal || !video) {
|
||||||
|
clearLoading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const useMobileFullscreen = isMobilePlayback() || isTvPlayback();
|
const useMobileFullscreen = isMobilePlayback() || isTvPlayback();
|
||||||
let playbackStarted = false;
|
let playbackStarted = false;
|
||||||
|
|
||||||
@@ -60,6 +72,7 @@ App.player = App.player || {};
|
|||||||
if (App.ui && App.ui.showError) {
|
if (App.ui && App.ui.showError) {
|
||||||
App.ui.showError('Unable to play this stream.');
|
App.ui.showError('Unable to play this stream.');
|
||||||
}
|
}
|
||||||
|
clearLoading();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const refererParam = resolved.referer ? `&referer=${encodeURIComponent(resolved.referer)}` : '';
|
const refererParam = resolved.referer ? `&referer=${encodeURIComponent(resolved.referer)}` : '';
|
||||||
@@ -128,6 +141,7 @@ App.player = App.player || {};
|
|||||||
const startPlayback = () => {
|
const startPlayback = () => {
|
||||||
if (playbackStarted) return;
|
if (playbackStarted) return;
|
||||||
playbackStarted = true;
|
playbackStarted = true;
|
||||||
|
clearLoading();
|
||||||
const playPromise = video.play();
|
const playPromise = video.play();
|
||||||
if (playPromise && typeof playPromise.catch === 'function') {
|
if (playPromise && typeof playPromise.catch === 'function') {
|
||||||
playPromise.catch(() => {});
|
playPromise.catch(() => {});
|
||||||
@@ -152,6 +166,7 @@ App.player = App.player || {};
|
|||||||
startPlayback();
|
startPlayback();
|
||||||
state.hlsPlayer.on(window.Hls.Events.ERROR, function(event, data) {
|
state.hlsPlayer.on(window.Hls.Events.ERROR, function(event, data) {
|
||||||
if (data && data.fatal) {
|
if (data && data.fatal) {
|
||||||
|
clearLoading();
|
||||||
if (App.ui && App.ui.showError) {
|
if (App.ui && App.ui.showError) {
|
||||||
App.ui.showError('Unable to play this stream.');
|
App.ui.showError('Unable to play this stream.');
|
||||||
}
|
}
|
||||||
@@ -166,6 +181,7 @@ App.player = App.player || {};
|
|||||||
if (App.ui && App.ui.showError) {
|
if (App.ui && App.ui.showError) {
|
||||||
App.ui.showError('HLS is not supported in this browser.');
|
App.ui.showError('HLS is not supported in this browser.');
|
||||||
}
|
}
|
||||||
|
clearLoading();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -174,6 +190,7 @@ App.player = App.player || {};
|
|||||||
}
|
}
|
||||||
|
|
||||||
video.onerror = () => {
|
video.onerror = () => {
|
||||||
|
clearLoading();
|
||||||
if (App.ui && App.ui.showError) {
|
if (App.ui && App.ui.showError) {
|
||||||
App.ui.showError('Video failed to load.');
|
App.ui.showError('Video failed to load.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,9 @@ App.videos = App.videos || {};
|
|||||||
<button class="video-menu-item" type="button" data-action="download" role="menuitem">Download</button>
|
<button class="video-menu-item" type="button" data-action="download" role="menuitem">Download</button>
|
||||||
</div>
|
</div>
|
||||||
<img src="${v.thumb}" alt="${v.title}">
|
<img src="${v.thumb}" alt="${v.title}">
|
||||||
|
<div class="video-loading" aria-hidden="true">
|
||||||
|
<div class="video-loading-spinner"></div>
|
||||||
|
</div>
|
||||||
<h4>${v.title}</h4>
|
<h4>${v.title}</h4>
|
||||||
${uploaderText ? `<p class="video-meta"><button class="uploader-link" type="button" data-uploader="${uploaderText}">${uploaderText}</button></p>` : ''}
|
${uploaderText ? `<p class="video-meta"><button class="uploader-link" type="button" data-uploader="${uploaderText}">${uploaderText}</button></p>` : ''}
|
||||||
${durationText ? `<p class="video-duration">${durationText}</p>` : ''}
|
${durationText ? `<p class="video-duration">${durationText}</p>` : ''}
|
||||||
@@ -183,7 +186,11 @@ App.videos = App.videos || {};
|
|||||||
App.videos.closeAllMenus();
|
App.videos.closeAllMenus();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
card.onclick = () => App.player.open(v);
|
card.onclick = () => {
|
||||||
|
if (card.classList.contains('is-loading')) return;
|
||||||
|
card.classList.add('is-loading');
|
||||||
|
App.player.open(v, { originEl: card });
|
||||||
|
};
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
state.renderedVideoIds.add(v.id);
|
state.renderedVideoIds.add(v.id);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user