diff --git a/src/main.ts b/src/main.ts index e1a4dc7..3000f08 100644 --- a/src/main.ts +++ b/src/main.ts @@ -27,7 +27,7 @@ const authService = new AuthService() const api = new API(authService) const router = setupRouter(authService) const store = setupStore(authService, api) -setupAudio(store) +setupAudio(store, api) Vue.prototype.$auth = authService Vue.prototype.$api = api diff --git a/src/player/store.ts b/src/player/store.ts index 653c54b..8934cac 100644 --- a/src/player/store.ts +++ b/src/player/store.ts @@ -1,5 +1,6 @@ import { Store, Module } from 'vuex' import { shuffle, trackListEquals } from '@/shared/utils' +import { API } from '@/shared/api' const audio = new Audio() const storedQueue = JSON.parse(localStorage.getItem('queue') || '[]') @@ -12,6 +13,7 @@ const mediaSession: MediaSession | undefined = navigator.mediaSession interface State { queue: any[]; queueIndex: number; + scrobbled: boolean; isPlaying: boolean; duration: number; // duration of current track in seconds currentTime: number; // position of current track in seconds @@ -24,6 +26,7 @@ export const playerModule: Module = { state: { queue: storedQueue, queueIndex: storedQueueIndex, + scrobbled: false, isPlaying: false, duration: 0, currentTime: 0, @@ -65,6 +68,7 @@ export const playerModule: Module = { index = index < state.queue.length ? index : 0 state.queueIndex = index localStorage.setItem('queueIndex', index) + state.scrobbled = false const track = state.queue[index] audio.src = track.url if (mediaSession) { @@ -94,6 +98,9 @@ export const playerModule: Module = { setDuration(state, value: any) { state.duration = value }, + setScrobbled(state) { + state.scrobbled = true + }, }, actions: { @@ -194,20 +201,29 @@ export const playerModule: Module = { }, } -export function setupAudio(store: Store) { +export function setupAudio(store: Store, api: API) { audio.ontimeupdate = () => { store.commit('player/setCurrentTime', audio.currentTime) + + // Scrobble + if (store.state.player.scrobbled === false && + audio.duration > 30 && + audio.currentTime / audio.duration > 0.7) { + const id = store.getters['player/trackId'] + store.commit('player/setScrobbled') + api.scrobble(id) + } } audio.ondurationchange = () => { store.commit('player/setDuration', audio.duration) } - audio.onended = () => { - store.dispatch('player/next') - } audio.onerror = () => { store.commit('player/setPaused') store.commit('setError', audio.error) } + audio.onended = () => { + store.dispatch('player/next') + } if (mediaSession) { mediaSession.setActionHandler('play', () => { diff --git a/src/shared/api.ts b/src/shared/api.ts index 8c68e58..6be8993 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -312,6 +312,10 @@ export class API { return this.get('rest/startScan') } + async scrobble(id: string): Promise { + return this.get('rest/scrobble', { id }) + } + private normalizeRadioStation(item: any): Track & RadioStation { return { id: `radio-${item.id}`,