Fetch only new queue tracks from indexedDB
This commit is contained in:
parent
9f36c4b3a8
commit
f51007b807
|
@ -1,6 +1,6 @@
|
|||
import { createGlobalState, tryOnMounted, useIntervalFn, useRafFn, useStorage, useTimeoutFn, whenever } from '@vueuse/core'
|
||||
import { computed, nextTick, ref, watch, watchEffect, type Ref } from 'vue'
|
||||
import { useTracks } from '~/composables/audio/tracks'
|
||||
import { computed, ref, watch, watchEffect, type Ref } from 'vue'
|
||||
import { setGain } from './audio-api'
|
||||
|
||||
import { useQueue, currentIndex, currentTrack } from './queue'
|
||||
|
@ -43,6 +43,12 @@ export const usePlayer = createGlobalState(() => {
|
|||
sound.pause()
|
||||
})
|
||||
|
||||
const stop = async () => {
|
||||
isPlaying.value = false
|
||||
seekTo(0)
|
||||
return nextTick()
|
||||
}
|
||||
|
||||
// Create first track when we initalize the page
|
||||
// NOTE: We want to have it called only once, hence we're using createGlobalState
|
||||
const initializeFirstTrack = createGlobalState(() => tryOnMounted(() => {
|
||||
|
@ -195,13 +201,14 @@ export const usePlayer = createGlobalState(() => {
|
|||
return sound.isErrored.value
|
||||
})
|
||||
|
||||
const { start, stop } = useTimeoutFn(() => playNext(), 3000, { immediate: false })
|
||||
watch(currentIndex, stop)
|
||||
whenever(errored, start)
|
||||
const { start: startErrorTimeout, stop: stopErrorTimeout } = useTimeoutFn(() => playNext(), 3000, { immediate: false })
|
||||
watch(currentIndex, stopErrorTimeout)
|
||||
whenever(errored, startErrorTimeout)
|
||||
|
||||
return {
|
||||
initializeFirstTrack,
|
||||
isPlaying,
|
||||
stop,
|
||||
volume,
|
||||
mute,
|
||||
looping,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import type { Track, Upload } from '~/types'
|
||||
|
||||
import { computedAsync, createGlobalState, useNow, useStorage, useTimeAgo } from '@vueuse/core'
|
||||
import { shuffle as shuffleArray, sum, uniq } from 'lodash-es'
|
||||
import { createGlobalState, useNow, useStorage, useTimeAgo, whenever } from '@vueuse/core'
|
||||
import { shuffle as shuffleArray, sum } from 'lodash-es'
|
||||
import { computed, ref, shallowReactive, watchEffect } from 'vue'
|
||||
import { getMany, setMany } from 'idb-keyval'
|
||||
import { computed, watchEffect } from 'vue'
|
||||
import { useClamp } from '@vueuse/math'
|
||||
|
||||
import { looping, LoopingMode, isPlaying } from '~/composables/audio/player'
|
||||
import { looping, LoopingMode, isPlaying, usePlayer } from '~/composables/audio/player'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
@ -44,22 +44,45 @@ const shuffledIds = useStorage('queue:tracks:shuffled', [] as number[])
|
|||
|
||||
const isShuffled = computed(() => shuffledIds.value.length !== 0)
|
||||
|
||||
const tracksById = computedAsync(async () => {
|
||||
const trackObjects = await getMany(uniq(tracks.value))
|
||||
return trackObjects.reduce((acc, track) => {
|
||||
acc[track.id] = track
|
||||
return acc
|
||||
}, {}) as Record<number, QueueTrack>
|
||||
}, {})
|
||||
const tracksById = shallowReactive(new Map<number, QueueTrack>())
|
||||
const fetchingTracks = ref(false)
|
||||
watchEffect(async () => {
|
||||
if (fetchingTracks.value) return
|
||||
|
||||
const queue = computed(() => {
|
||||
const indexedTracks = tracksById.value
|
||||
const allTracks = new Set(tracks.value)
|
||||
const addedIds = new Set(allTracks)
|
||||
|
||||
if (isShuffled.value) {
|
||||
return shuffledIds.value.map(id => indexedTracks[id]).filter(i => i)
|
||||
for (const id of tracksById.keys()) {
|
||||
if (allTracks.has(id)) {
|
||||
// Track in queue, so remove it from the new ids set
|
||||
addedIds.delete(id)
|
||||
} else {
|
||||
// Track removed from queue, so remove it from the object
|
||||
tracksById.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
return tracks.value.map(id => indexedTracks[id]).filter(i => i)
|
||||
if (addedIds.size > 0) {
|
||||
fetchingTracks.value = true
|
||||
try {
|
||||
const trackInfos: QueueTrack[] = await getMany([...addedIds])
|
||||
for (const track of trackInfos) {
|
||||
tracksById.set(track.id, track)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
fetchingTracks.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const queue = computed<QueueTrack[]>(() => {
|
||||
const ids = isShuffled.value
|
||||
? shuffledIds.value
|
||||
: tracks.value
|
||||
|
||||
return ids.map(id => tracksById.get(id)).filter((i): i is QueueTrack => !!i)
|
||||
})
|
||||
|
||||
// Current Index
|
||||
|
@ -235,7 +258,11 @@ export const useQueue = createGlobalState(() => {
|
|||
}))
|
||||
|
||||
// Clear
|
||||
const clearRadio = ref(false)
|
||||
const clear = async () => {
|
||||
const { stop } = usePlayer()
|
||||
await stop()
|
||||
clearRadio.value = true
|
||||
tracks.value.length = 0
|
||||
}
|
||||
|
||||
|
@ -249,8 +276,9 @@ export const useQueue = createGlobalState(() => {
|
|||
}
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
if (tracks.value.length === 0) {
|
||||
whenever(clearRadio, () => {
|
||||
clearRadio.value = false
|
||||
if (store.state.radios.running) {
|
||||
return store.dispatch('radios/stop')
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import type { QueueTrack, QueueTrackSource } from '~/composables/audio/queue'
|
||||
import type { Sound } from '~/api/player'
|
||||
|
||||
import { soundImplementation } from '~/api/player'
|
||||
import { createGlobalState, syncRef } from '@vueuse/core'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { createGlobalState, syncRef, whenever } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useQueue } from '~/composables/audio/queue'
|
||||
import { connectAudioSource } from '~/composables/audio/audio-api'
|
||||
import { usePlayer } from '~/composables/audio/player'
|
||||
import { useQueue } from '~/composables/audio/queue'
|
||||
import { soundImplementation } from '~/api/player'
|
||||
|
||||
import useLRUCache from '~/composables/useLRUCache'
|
||||
import store from '~/store'
|
||||
|
@ -112,8 +112,9 @@ export const useTracks = createGlobalState(() => {
|
|||
|
||||
// NOTE: We want to have it called only once, hence we're using createGlobalState
|
||||
const initialize = createGlobalState(() => {
|
||||
const { currentTrack: track, currentIndex } = useQueue()
|
||||
watch(currentIndex, (index) => createTrack(index))
|
||||
const { currentIndex, currentTrack: track } = useQueue()
|
||||
|
||||
whenever(track, () => createTrack(currentIndex.value))
|
||||
syncRef(track, currentTrack, {
|
||||
direction: 'ltr'
|
||||
})
|
||||
|
|
|
@ -164,21 +164,25 @@ export default (props: PlayOptionsProps) => {
|
|||
const tracksToPlay = await getPlayableTracks()
|
||||
await addToQueue(...tracksToPlay)
|
||||
|
||||
const trackIndex = props.tracks?.findIndex(track => track.id === props.track?.id && track.position === props.track?.position) ?? 0
|
||||
await playTrack(trackIndex)
|
||||
if (props.track && props.tracks?.length) {
|
||||
const trackIndex = props.tracks?.findIndex(track => track.id === props.track?.id && track.position === props.track?.position) ?? 0
|
||||
await playTrack(trackIndex)
|
||||
isPlaying.value = true
|
||||
} else {
|
||||
await playTrack(0, true)
|
||||
isPlaying.value = true
|
||||
}
|
||||
|
||||
isPlaying.value = true
|
||||
playTrack(0, true)
|
||||
addMessage(tracksToPlay)
|
||||
}
|
||||
|
||||
const activateTrack = (track: Track, index: number) => {
|
||||
const activateTrack = async (track: Track, index: number) => {
|
||||
// TODO (wvffle): Check if position checking did not break anything
|
||||
if (track.id === currentTrack.value?.id && track.position === currentTrack.value?.position) {
|
||||
isPlaying.value = true
|
||||
}
|
||||
|
||||
replacePlay()
|
||||
return replacePlay()
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue