feat: basic player commands

This commit is contained in:
2026-08-30 19:58:08 +02:00
parent ce35371c06
commit 5b223875bd
11 changed files with 196 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
export type RepeatMode = 'off' | 'one' | 'all';
+103
View File
@@ -0,0 +1,103 @@
import {
currentSource,
queueIdx,
repeat,
shuffle,
sources
} from './state';
import {
startTracking,
stopTracking
} from './status-tracking';
import type {
RepeatMode
} from '../dtype/player';
import {
addSongList
} from './playlists/add';
import {
playIndex
} from './playlists';
const next = () => {
playIndex( queueIdx.value + 1 );
};
const prev = () => {
// TODO: Back to beginning if more than some seconds have passed?
playIndex( queueIdx.value - 1 );
};
const play = () => {
if ( currentSource.value === '' ) return;
sources[currentSource.value]?.play();
startTracking();
};
const pause = () => {
if ( currentSource.value === '' ) return;
sources[currentSource.value]?.pause();
stopTracking();
};
/**
* Seek to a specific point in the song
* @param pos - Percentage of song, value in [0, 1]
*/
const seekTo = ( pos: number ) => {
if ( currentSource.value === '' ) return;
sources[currentSource.value]?.seekTo( pos );
};
const skip10 = () => {
if ( currentSource.value === '' ) return;
const source = sources[currentSource.value];
const duration = source?.getDuration() ?? -1;
seekTo( ( ( ( source?.getPlaybackPos() ?? 0 ) * duration ) + 10 ) / duration );
};
const back10 = () => {
if ( currentSource.value === '' ) return;
const source = sources[currentSource.value];
const duration = source?.getDuration() ?? -1;
seekTo( ( ( ( source?.getPlaybackPos() ?? 0 ) * duration ) - 10 ) / duration );
};
const setShuffle = ( enabled: boolean ) => {
// TODO: Shuffle the order
shuffle.value = enabled;
};
const setRepeat = ( mode: RepeatMode ) => {
repeat.value = mode;
};
const getSources = (): string[] => {
return Object.keys( sources );
};
const addSongFromSource = async ( source: string ) => {
addSongList( await sources[source]!.addSongsFromThisSource() );
};
export default {
play,
pause,
seekTo,
skip10,
back10,
setShuffle,
setRepeat,
playIndex,
getSources,
addSongFromSource,
next,
prev
};
+14
View File
@@ -0,0 +1,14 @@
import type {
Song
} from '@/ts/dtype/playlist';
import {
queue
} from '../state';
export const addSongList = ( songs: Song[] ) => {
for ( const song of songs ) {
queue.value.push( song );
}
};
export const shuffleList = () => {};
+36
View File
@@ -0,0 +1,36 @@
import {
currentSource,
queue,
queueIdx,
repeat,
sources
} from '../state';
import {
startTracking,
stopTracking
} from '../status-tracking';
/**
* 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 ) => {
if ( idx >= queue.value.length ) {
idx = repeat.value === 'all' ? 0 : -1;
} else if ( idx < 0 ) {
idx = repeat.value === 'all' ? queue.value.length - 1 : -1;
}
if ( idx < 0 ) return false;
sources[currentSource.value]?.stop();
stopTracking();
const nextSong = queue.value[ idx ]!;
queueIdx.value = idx;
currentSource.value = nextSong.source;
sources[currentSource.value]?.playSong( nextSong.identifier );
startTracking();
};
@@ -1 +1,2 @@
// TODO: If local files contained, prompt user to select files, then associate based on file names
export const load = () => {};
+1 -1
View File
@@ -22,7 +22,7 @@ export interface PlayerSourcePlugin {
'login'?: () => Promise<boolean>;
/**
* Play a song by its ID
* Play a song by its ID. Should start playing it immediately
*/
'playSong': ( id: string ) => Promise<void>;
+13 -1
View File
@@ -2,9 +2,21 @@ import {
type Ref,
ref
} from 'vue';
import type {
PlayerSourcePlugin
} from './plugins/interface';
import type {
Playlist
} from '../dtype/playlist';
import type {
RepeatMode
} from '../dtype/player';
export const sources: {
[key: string]: PlayerSourcePlugin
} = {};
export const currentSource = ref( '' );
export const queueIdx = ref( 0 );
@@ -14,7 +26,7 @@ export const isPlaying = ref( false );
export const shuffle = ref( false );
export const repeat: Ref<'off' | 'one' | 'all'> = ref( 'off' );
export const repeat: Ref<RepeatMode> = ref( 'off' );
export const playbackPercentage = ref( 0 );
+4
View File
@@ -0,0 +1,4 @@
// Tracking of time and player status
export const startTracking = () => {};
export const stopTracking = () => {};
+23
View File
@@ -0,0 +1,23 @@
# Frontend
- [ ] Status tracking (position, etc)
- [ ] Change metadata association for automated association
- [ ] Move songs with D&D, or index assignment?
- [ ] Explain additional info
- [ ] Tour
- [ ] Get player working
- [ ] Save playlists locally or on backend
- [ ] SSE connection
- [ ] Anti-Tamper
- [ ] Remote showcase views
- [ ] Login
- [ ] About page
- [ ] Apple-Music signin
- [ ] Loading existing playlists with local music and association of that
# Backend
- [ ] Implement all endpoints
- [ ] Integrate with store and auth sdks
- [ ] Create FOSS solution for above (single user)
- [ ] Setup guide
- [ ] Docker containers
- [ ] CI