diff --git a/front/src/composables/audio/player.ts b/front/src/composables/audio/player.ts index e9291b3f7..e4555e8df 100644 --- a/front/src/composables/audio/player.ts +++ b/front/src/composables/audio/player.ts @@ -43,7 +43,7 @@ export const isPlaying = ref(false) // Use Player export const usePlayer = createGlobalState(() => { const { currentSound } = useTracks() - const { playNext } = useQueue() + const { playNext, playPrevious } = useQueue() const pauseReason = ref(PauseReason.UserInput) @@ -228,6 +228,56 @@ export const usePlayer = createGlobalState(() => { watch(currentIndex, stopErrorTimeout) whenever(errored, startErrorTimeout) + // Mobile controls and lockscreen cover art + const updateMediaSession = () => { + if ('mediaSession' in navigator && currentTrack.value) { + // Check if the cover is large enough for higher res + const isHighRes = currentTrack.value.coverUrl.includes('large') || currentTrack.value.coverUrl.includes('original') + + navigator.mediaSession.metadata = new MediaMetadata({ + title: currentTrack.value.title, + artist: currentTrack.value.artistCredit?.map(ac => ac.credit).join(', ') || 'Unknown Artist', + album: currentTrack.value.albumTitle || 'Unknown Album', + artwork: [ + { src: currentTrack.value.coverUrl, sizes: isHighRes ? "1200x1200" : "1024x1024", type: 'image/jpeg' } + ] + }) + + navigator.mediaSession.setActionHandler('play', () => { + isPlaying.value = true; + }) + + navigator.mediaSession.setActionHandler('pause', () => { + isPlaying.value = false; + }) + + navigator.mediaSession.setActionHandler('previoustrack', () => { + playPrevious() + }) + + navigator.mediaSession.setActionHandler('nexttrack', () => { + playNext() + }) + + navigator.mediaSession.setActionHandler('seekbackward', (details) => { + seekBy(details.seekOffset || -10) + }) + + navigator.mediaSession.setActionHandler('seekforward', (details) => { + seekBy(details.seekOffset || 10) + }) + } + } + + watch(currentTrack, () => { + updateMediaSession(); + }) + + watch(isPlaying, () => { + navigator.mediaSession.playbackState = isPlaying.value ? 'playing' : 'paused'; + }) + + return { initializeFirstTrack, isPlaying, diff --git a/front/src/composables/audio/queue.ts b/front/src/composables/audio/queue.ts index 8fde87bf8..0ea1797d1 100644 --- a/front/src/composables/audio/queue.ts +++ b/front/src/composables/audio/queue.ts @@ -123,11 +123,11 @@ export const useQueue = createGlobalState(() => { artistId: (track.artist_credit && track.artist_credit[0] && track.artist_credit[0].artist.id) ?? -1, albumId: track.album?.id ?? -1, coverUrl: ( - (track.cover?.urls) - || (track.album?.cover?.urls) - || ((track.artist_credit && track.artist_credit[0] && track.artist_credit[0].artist && track.artist_credit[0].artist.attachment_cover?.urls)) - || {} - )?.original ?? new URL('../../assets/audio/default-cover.png', import.meta.url).href, + track.cover?.urls.original || + track.album.cover?.urls.original || + track.artist_credit[0].artist.attachment_cover?.urls.original || + new URL('../../assets/audio/default-cover.png', import.meta.url).href + ).toString(), sources: track.uploads.map(upload => ({ uuid: upload.uuid, duration: upload.duration,