feat: improve sync

This commit is contained in:
2026-09-08 11:20:17 +02:00
parent 047a3a8b29
commit b11882c993
19 changed files with 160 additions and 55 deletions
+5
View File
@@ -4,4 +4,9 @@ import type {
declare global {
var MusicKit: MusicKitObject;
interface GlobalEventHandlersEventMap {
'musicplayer:playpause': CustomEvent<void>;
'musicplayer:playindex': CustomEvent<void>;
'musicplayer:seek': CustomEvent<void>;
}
}
+23 -5
View File
@@ -4,6 +4,8 @@ import {
queueIdx
} from '../player/state';
import {
onMounted,
onUnmounted,
ref,
watch
} from 'vue';
@@ -116,7 +118,8 @@ const sendStateData = () => {
request.post( `/room/${ room.value }/update/state`, JSON.stringify( {
'playing': isPlaying.value,
'index': queueIdx.value,
'start': new Date().getTime() - ( playbackPercentage.value * ( queue.value[ queueIdx.value ]?.duration ?? 0 ) ) - 100
'start': new Date().getTime() - 100,
'offset': playbackPercentage.value * ( queue.value[ queueIdx.value ]?.duration ?? 0 )
} ) );
setTimeout( () => {
@@ -128,10 +131,25 @@ const sendStateData = () => {
const useRoomWatchers = () => {
watch( queue, sendPlaylistData );
watch( [
isPlaying,
queueIdx
], sendStateData );
onMounted( () => {
document.addEventListener( 'musicplayer:playindex', sendStateData );
document.addEventListener( 'musicplayer:seek', sendStateData );
document.addEventListener( 'musicplayer:playpause', sendStateData );
} );
onUnmounted( () => {
try {
document.addEventListener( 'musicplayer:play', sendStateData );
} catch { /* empty */ }
try {
document.addEventListener( 'musicplayer:seek', sendStateData );
} catch { /* empty */ }
try {
document.addEventListener( 'musicplayer:playpause', sendStateData );
} catch { /* empty */ }
} );
if ( room.value ) connect();
};
+3 -3
View File
@@ -29,7 +29,6 @@ import type {
import {
load
} from './playlists/loader';
import messages from '../messages';
import {
playIndex
} from './playlists';
@@ -52,6 +51,7 @@ const play = () => {
sources[currentSource.value]?.play();
startTracking();
document.dispatchEvent( new CustomEvent( 'musicplayer:playpause' ) );
};
const pause = () => {
@@ -61,6 +61,7 @@ const pause = () => {
sources[currentSource.value]?.pause();
stopTracking();
document.dispatchEvent( new CustomEvent( 'musicplayer:playpause' ) );
};
/**
@@ -71,6 +72,7 @@ const seekTo = ( pos: number ) => {
if ( currentSource.value === '' ) return;
sources[currentSource.value]?.seekTo( pos );
document.dispatchEvent( new CustomEvent( 'musicplayer:seek' ) );
};
const skip10 = () => {
@@ -153,8 +155,6 @@ const addSongFromSource = async ( source: string, cb?: ( songs: Song[] ) => void
return true;
};
messages.useRoomWatchers();
export default {
play,
pause,
+3 -3
View File
@@ -16,8 +16,8 @@ import type {
Song
} from '@/ts/dtype/playlist';
import {
playlistIdx
} from '@/ts/userPlaylists/state';
setPlaylistIdx
} from '@/ts/userPlaylists';
export const addSongList = ( songs: Song[] ) => {
rawQueue.value = rawQueue.value.concat( songs );
@@ -25,7 +25,7 @@ export const addSongList = ( songs: Song[] ) => {
};
export const clearQueue = () => {
playlistIdx.value = -1;
setPlaylistIdx( 0 );
queue.value = [];
rawQueue.value = [];
sources[currentSource.value]?.stop();
+4 -1
View File
@@ -15,7 +15,7 @@ import {
* Play a song at the given index of the queue. Wraps to 0 and end if index below 0 or above end
* @param idx - The index in the queue to play at
*/
export const playIndex = async ( idx: number ) => {
export const playIndex = ( idx: number ) => {
if ( idx >= queue.value.length ) {
idx = repeat.value === 'all' ? 0 : -1;
} else if ( idx < 0 ) {
@@ -42,4 +42,7 @@ export const playIndex = async ( idx: number ) => {
startTracking();
isPlaying.value = true;
setTimeout( () => {
document.dispatchEvent( new CustomEvent( 'musicplayer:playindex', {} ) );
}, 500 );
};
+4
View File
@@ -6,6 +6,8 @@ import {
currentQueue,
currentQueueIdx,
isPlaying,
playbackOffset,
playbackTime,
startTime
} from './state';
import type {
@@ -40,6 +42,8 @@ const connect = (): Promise<void> => {
currentQueueIdx.value = data.state.index;
isPlaying.value = data.state.playing;
startTime.value = data.state.start;
playbackTime.value = data.state.offset;
playbackOffset.value = data.state.offset;
resolve();
};
+5
View File
@@ -2,6 +2,8 @@ import {
currentQueue,
currentQueueIdx,
isPlaying,
playbackOffset,
playbackTime,
startTime
} from './state';
import type {
@@ -17,6 +19,7 @@ export interface StateUpdate {
'playing': boolean;
'index': number;
'start': number;
'offset': number;
}
export const messageHandler = ( msg: string ) => {
@@ -36,6 +39,8 @@ export const messageHandler = ( msg: string ) => {
currentQueueIdx.value = state.index;
isPlaying.value = state.playing;
startTime.value = state.start;
playbackTime.value = state.offset;
playbackOffset.value = state.offset;
} else {
console.log( '[SSE] Received unknown data', data.type );
}
+6
View File
@@ -13,3 +13,9 @@ export const isPlaying = ref( false );
export const currentQueueIdx = ref( -1 );
export const startTime = ref( new Date().getTime() );
export const showArtworks = ref( false );
export const playbackTime = ref( 0 );
export const playbackOffset = ref( 0 );
+13
View File
@@ -1,7 +1,10 @@
import {
editingPlaylists,
playlistIdx,
playlists
} from './state';
import player from '../player';
export const addPlaylist = ( name: string ) => {
playlists.value.push( {
@@ -17,3 +20,13 @@ export const removePlaylist = ( idx: number ) => {
editingPlaylists.value.splice( idx, 1 );
}
};
export const selectPlaylist = ( idx: number ) => {
playlistIdx.value = idx;
player.clearQueue();
player.loadPlaylist( playlists.value[ idx ]!.songs );
};
export const setPlaylistIdx = ( idx: number ) => {
playlistIdx.value = idx;
};
+4 -2
View File
@@ -16,15 +16,17 @@ import {
useNotification
} from '@kyvg/vue3-notification';
export const savePlaylist = async () => {
export const savePlaylist = () => {
rawQueue.value = queue.value;
shuffle.value = false;
if ( playlistIdx.value ) {
if ( playlistIdx.value < 0 ) {
let name: null | string = '';
while ( !name || name.length === 0 ) {
name = prompt( 'You are trying to save a playlist that has not previously been created. Please enter a name for it' );
if ( !name ) return;
}
addPlaylist( name );