feat: integrate lightbox for media images and improve media session handling
- Add lightbox support to song/playlist cover images by adding lb-trigger class and data-lightbox attributes - Prevent default click behavior in lightbox.js to avoid navigation when opening image modal - Update player UI to conditionally enable/disable lightbox on album art based on cover presence - Set navigator.mediaSession.playbackState proactively during audio reassignment to prevent OS throttling - Wrap media session seek handlers in try-catch blocks for compatibility with mobile streaming sources
This commit is contained in:
parent
5eadf57068
commit
df14aa8975
|
|
@ -46,6 +46,8 @@
|
|||
document.addEventListener('click', (e) => {
|
||||
const trigger = e.target.closest('[data-lightbox]');
|
||||
if (trigger) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
open(trigger.src || trigger.dataset.src, trigger.alt);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
titleEl.textContent = 'Nothing playing';
|
||||
artistEl.textContent = '';
|
||||
coverEl.src = '/static/vendor/cover-placeholder.svg';
|
||||
coverEl.removeAttribute('data-lightbox');
|
||||
coverEl.classList.remove('lb-trigger');
|
||||
queueInfoEl.textContent = '';
|
||||
updatePlayerSocial(null);
|
||||
return;
|
||||
|
|
@ -43,6 +45,13 @@
|
|||
titleEl.textContent = cur.title;
|
||||
artistEl.textContent = cur.artist || '';
|
||||
coverEl.src = cur.cover || '/static/vendor/cover-placeholder.svg';
|
||||
if (cur.cover) {
|
||||
coverEl.setAttribute('data-lightbox', '');
|
||||
coverEl.classList.add('lb-trigger');
|
||||
} else {
|
||||
coverEl.removeAttribute('data-lightbox');
|
||||
coverEl.classList.remove('lb-trigger');
|
||||
}
|
||||
queueInfoEl.textContent = state.queue.length > 1
|
||||
? `${state.index + 1} / ${state.queue.length}`
|
||||
: '';
|
||||
|
|
@ -73,6 +82,9 @@
|
|||
? [{ src: new URL(cur.cover, window.location.origin).href, sizes: '512x512', type: 'image/jpeg' }]
|
||||
: [],
|
||||
});
|
||||
// Proactively mark as playing so the OS doesn't throttle during the
|
||||
// brief gap when audio.src is reassigned (which fires a pause event).
|
||||
navigator.mediaSession.playbackState = 'playing';
|
||||
}
|
||||
|
||||
function playCurrent() {
|
||||
|
|
@ -126,9 +138,10 @@
|
|||
navigator.mediaSession.setActionHandler('pause', () => audio.pause());
|
||||
navigator.mediaSession.setActionHandler('nexttrack', () => next());
|
||||
navigator.mediaSession.setActionHandler('previoustrack', () => prev());
|
||||
navigator.mediaSession.setActionHandler('seekto', (d) => { audio.currentTime = d.seekTime; });
|
||||
navigator.mediaSession.setActionHandler('seekbackward', (d) => { audio.currentTime = Math.max(0, audio.currentTime - (d.seekOffset || 10)); });
|
||||
navigator.mediaSession.setActionHandler('seekforward', (d) => { audio.currentTime = Math.min(audio.duration || Infinity, audio.currentTime + (d.seekOffset || 10)); });
|
||||
// seek handlers may throw on some mobile browsers for streaming sources
|
||||
try { navigator.mediaSession.setActionHandler('seekto', (d) => { audio.currentTime = d.seekTime; }); } catch (_) {}
|
||||
try { navigator.mediaSession.setActionHandler('seekbackward', (d) => { audio.currentTime = Math.max(0, audio.currentTime - (d.seekOffset || 10)); }); } catch (_) {}
|
||||
try { navigator.mediaSession.setActionHandler('seekforward', (d) => { audio.currentTime = Math.min(audio.duration || Infinity, audio.currentTime + (d.seekOffset || 10)); }); } catch (_) {}
|
||||
}
|
||||
|
||||
repeatBtn.addEventListener('click', () => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<input type="checkbox" class="song-select" value="<%= s.id %>" aria-label="Select <%= s.title %>">
|
||||
<% } %>
|
||||
<% if (s.coverPath) { %>
|
||||
<img src="/media/<%= s.coverPath %>" alt="" class="song-cover" />
|
||||
<img src="/media/<%= s.coverPath %>" alt="" class="song-cover lb-trigger" data-lightbox />
|
||||
<% } else { %>
|
||||
<div class="song-cover cover-fallback">♪</div>
|
||||
<% } %>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<% featured.forEach((p) => { %>
|
||||
<a class="card" href="/playlists/<%= p.slug %>" data-playlist-id="<%= p.id %>">
|
||||
<% if (p.coverPath) { %>
|
||||
<img src="/media/<%= p.coverPath %>" alt="" />
|
||||
<img src="/media/<%= p.coverPath %>" alt="" class="lb-trigger" data-lightbox />
|
||||
<% } else { %>
|
||||
<div class="cover-fallback">🎧</div>
|
||||
<% } %>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<% recentlyLiked.forEach((s) => { %>
|
||||
<a href="/songs/<%= s.slug %>" class="liked-card">
|
||||
<% if (s.coverPath) { %>
|
||||
<img src="/media/<%= s.coverPath %>" alt="" class="liked-card-cover">
|
||||
<img src="/media/<%= s.coverPath %>" alt="" class="liked-card-cover lb-trigger" data-lightbox>
|
||||
<% } else { %>
|
||||
<div class="liked-card-cover liked-card-cover--fallback">♪</div>
|
||||
<% } %>
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
<% mostPopular.forEach((s) => { %>
|
||||
<a href="/songs/<%= s.slug %>" class="liked-card">
|
||||
<% if (s.coverPath) { %>
|
||||
<img src="/media/<%= s.coverPath %>" alt="" class="liked-card-cover">
|
||||
<img src="/media/<%= s.coverPath %>" alt="" class="liked-card-cover lb-trigger" data-lightbox>
|
||||
<% } else { %>
|
||||
<div class="liked-card-cover liked-card-cover--fallback">♪</div>
|
||||
<% } %>
|
||||
|
|
|
|||
Loading…
Reference in New Issue