Fix changing songs and add LRU cache
This commit is contained in:
parent
ccb905b004
commit
1be6701752
|
@ -84,7 +84,7 @@ ports:
|
||||||
|
|
||||||
vscode:
|
vscode:
|
||||||
extensions:
|
extensions:
|
||||||
- lukashass.volar
|
- Vue.volar
|
||||||
- ms-python.python
|
- ms-python.python
|
||||||
- ms-toolsai.jupyter
|
- ms-toolsai.jupyter
|
||||||
- ms-toolsai.jupyter-keymap
|
- ms-toolsai.jupyter-keymap
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"Vue.volar"
|
||||||
|
]
|
||||||
|
}
|
|
@ -36,6 +36,7 @@
|
||||||
"idb-keyval": "^6.2.0",
|
"idb-keyval": "^6.2.0",
|
||||||
"js-logger": "1.6.1",
|
"js-logger": "1.6.1",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
|
"lru-cache": "^7.14.0",
|
||||||
"moment": "2.29.4",
|
"moment": "2.29.4",
|
||||||
"qs": "6.11.0",
|
"qs": "6.11.0",
|
||||||
"showdown": "2.1.0",
|
"showdown": "2.1.0",
|
||||||
|
|
|
@ -8,12 +8,11 @@ import store from '~/store'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export const isPlaying = ref(false)
|
export const isPlaying = ref(false)
|
||||||
|
watchEffect(() => {
|
||||||
watch(isPlaying, (playing) => {
|
|
||||||
const sound = currentSound.value
|
const sound = currentSound.value
|
||||||
if (!sound) return
|
if (!sound) return
|
||||||
|
|
||||||
if (playing) {
|
if (isPlaying.value) {
|
||||||
sound.play()
|
sound.play()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,12 +85,19 @@ const createQueueTrack = async (track: Track): Promise<QueueTrack> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding tracks
|
// Adding tracks
|
||||||
export const enqueue = async (...newTracks: Track[]) => {
|
export const enqueueAt = async (index: number, ...newTracks: Track[]) => {
|
||||||
const queueTracks = await Promise.all(newTracks.map(createQueueTrack))
|
const queueTracks = await Promise.all(newTracks.map(createQueueTrack))
|
||||||
await setMany(queueTracks.map(track => [track.id, track]))
|
await setMany(queueTracks.map(track => [track.id, track]))
|
||||||
|
|
||||||
const ids = queueTracks.map(track => track.id)
|
const ids = queueTracks.map(track => track.id)
|
||||||
|
|
||||||
|
if (index >= tracks.value.length) {
|
||||||
|
// we simply push to the end
|
||||||
tracks.value.push(...ids)
|
tracks.value.push(...ids)
|
||||||
|
} else {
|
||||||
|
// we insert the track at given position
|
||||||
|
tracks.value.splice(index, 0, ...ids)
|
||||||
|
}
|
||||||
|
|
||||||
// Shuffle new tracks
|
// Shuffle new tracks
|
||||||
if (isShuffled.value) {
|
if (isShuffled.value) {
|
||||||
|
@ -98,6 +105,10 @@ export const enqueue = async (...newTracks: Track[]) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enqueue = async (...newTracks: Track[]) => {
|
||||||
|
return enqueueAt(tracks.value.length, ...newTracks)
|
||||||
|
}
|
||||||
|
|
||||||
// Removing tracks
|
// Removing tracks
|
||||||
export const dequeue = async (index: number) => {
|
export const dequeue = async (index: number) => {
|
||||||
if (currentIndex.value === index) {
|
if (currentIndex.value === index) {
|
||||||
|
@ -131,7 +142,6 @@ export const playTrack = async (trackIndex: number, force = false) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
currentIndex.value = trackIndex
|
currentIndex.value = trackIndex
|
||||||
if (isPlaying.value) currentSound.value?.play()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Previous track
|
// Previous track
|
||||||
|
@ -198,6 +208,15 @@ export const shuffle = () => {
|
||||||
shuffledIds.value = shuffleArray(tracks.value)
|
shuffledIds.value = shuffleArray(tracks.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const reshuffleUpcomingTracks = () => {
|
||||||
|
// TODO: Test if needed to add 1 to currentIndex
|
||||||
|
const listenedTracks = shuffledIds.value.slice(0, currentIndex.value)
|
||||||
|
const upcomingTracks = shuffledIds.value.slice(currentIndex.value)
|
||||||
|
|
||||||
|
listenedTracks.push(...shuffleArray(upcomingTracks))
|
||||||
|
shuffledIds.value = listenedTracks
|
||||||
|
}
|
||||||
|
|
||||||
// Ends in
|
// Ends in
|
||||||
const now = useNow()
|
const now = useNow()
|
||||||
export const endsIn = useTimeAgo(computed(() => {
|
export const endsIn = useTimeAgo(computed(() => {
|
||||||
|
|
|
@ -2,18 +2,20 @@ import type { QueueTrack, QueueTrackSource } from '~/composables/audio/queue'
|
||||||
import type { Sound } from '~/api/player'
|
import type { Sound } from '~/api/player'
|
||||||
|
|
||||||
import { soundImplementation } from '~/api/player'
|
import { soundImplementation } from '~/api/player'
|
||||||
import { computed, shallowReactive } from 'vue'
|
import { computed, watchEffect } from 'vue'
|
||||||
|
|
||||||
import { playNext, queue, currentTrack, currentIndex } from '~/composables/audio/queue'
|
import { playNext, queue, currentTrack, currentIndex } from '~/composables/audio/queue'
|
||||||
import { connectAudioSource } from '~/composables/audio/audio-api'
|
import { connectAudioSource } from '~/composables/audio/audio-api'
|
||||||
import { isPlaying } from '~/composables/audio/player'
|
import { isPlaying } from '~/composables/audio/player'
|
||||||
|
|
||||||
|
import useLRUCache from '~/composables/useLRUCache'
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
|
|
||||||
const ALLOWED_PLAY_TYPES: (CanPlayTypeResult | undefined)[] = ['maybe', 'probably']
|
const ALLOWED_PLAY_TYPES: (CanPlayTypeResult | undefined)[] = ['maybe', 'probably']
|
||||||
const AUDIO_ELEMENT = document.createElement('audio')
|
const AUDIO_ELEMENT = document.createElement('audio')
|
||||||
|
|
||||||
const soundPromises = new Map<number, Promise<Sound>>()
|
const soundPromises = new Map<number, Promise<Sound>>()
|
||||||
const soundCache = shallowReactive(new Map<number, Sound>())
|
const soundCache = useLRUCache<number, Sound>({ max: 10 })
|
||||||
|
|
||||||
const getTrackSources = (track: QueueTrack): QueueTrackSource[] => {
|
const getTrackSources = (track: QueueTrack): QueueTrackSource[] => {
|
||||||
const sources: QueueTrackSource[] = track.sources
|
const sources: QueueTrackSource[] = track.sources
|
||||||
|
@ -60,7 +62,6 @@ export const createSound = async (track: QueueTrack): Promise<Sound> => {
|
||||||
// NOTE: We push it to the end of the job queue
|
// NOTE: We push it to the end of the job queue
|
||||||
setTimeout(playNext, 0)
|
setTimeout(playNext, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
soundCache.set(track.id, sound)
|
soundCache.set(track.id, sound)
|
||||||
soundPromises.delete(track.id)
|
soundPromises.delete(track.id)
|
||||||
return sound
|
return sound
|
||||||
|
@ -74,7 +75,7 @@ export const createSound = async (track: QueueTrack): Promise<Sound> => {
|
||||||
// Create track from queue
|
// Create track from queue
|
||||||
export const createTrack = async (index: number) => {
|
export const createTrack = async (index: number) => {
|
||||||
if (queue.value.length <= index || index === -1) return
|
if (queue.value.length <= index || index === -1) return
|
||||||
console.log('LOADING TRACK')
|
console.log('LOADING TRACK', index)
|
||||||
|
|
||||||
const track = queue.value[index]
|
const track = queue.value[index]
|
||||||
if (!soundPromises.has(track.id) && !soundCache.has(track.id)) {
|
if (!soundPromises.has(track.id) && !soundCache.has(track.id)) {
|
||||||
|
@ -88,7 +89,7 @@ export const createTrack = async (index: number) => {
|
||||||
sound.audioNode.disconnect()
|
sound.audioNode.disconnect()
|
||||||
connectAudioSource(sound.audioNode)
|
connectAudioSource(sound.audioNode)
|
||||||
|
|
||||||
if (isPlaying.value) {
|
if (isPlaying.value && index === currentIndex.value) {
|
||||||
await sound.play()
|
await sound.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,4 +102,6 @@ export const createTrack = async (index: number) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watchEffect(async () => createTrack(currentIndex.value))
|
||||||
|
|
||||||
export const currentSound = computed(() => soundCache.get(currentTrack.value?.id ?? -1))
|
export const currentSound = computed(() => soundCache.get(currentTrack.value?.id ?? -1))
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { useStore } from '~/store'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import jQuery from 'jquery'
|
import jQuery from 'jquery'
|
||||||
|
|
||||||
import { enqueue as addToQueue, currentTrack } from '~/composables/audio/queue'
|
import { enqueue as addToQueue, currentTrack, playNext, currentIndex, enqueueAt, queue } from '~/composables/audio/queue'
|
||||||
import { isPlaying } from '~/composables/audio/player'
|
import { isPlaying } from '~/composables/audio/player'
|
||||||
|
|
||||||
export interface PlayOptionsProps {
|
export interface PlayOptionsProps {
|
||||||
|
@ -143,11 +143,11 @@ export default (props: PlayOptionsProps) => {
|
||||||
|
|
||||||
const tracks = await getPlayableTracks()
|
const tracks = await getPlayableTracks()
|
||||||
|
|
||||||
const wasEmpty = store.state.queue.tracks.length === 0
|
const wasEmpty = queue.value.length === 0
|
||||||
await store.dispatch('queue/appendMany', { tracks, index: store.state.queue.currentIndex + 1 })
|
await enqueueAt(currentIndex.value + 1, ...tracks)
|
||||||
|
|
||||||
if (next && !wasEmpty) {
|
if (next && !wasEmpty) {
|
||||||
await store.dispatch('queue/next')
|
await playNext()
|
||||||
isPlaying.value = true
|
isPlaying.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import LRU from 'lru-cache'
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
|
export default <T, K>(options: LRU.Options<T, K>) => {
|
||||||
|
const cache = new LRU(options)
|
||||||
|
|
||||||
|
// @ts-expect-error keyMap is used internally so it is not defined in the types
|
||||||
|
cache.keyMap = reactive(cache.keyMap)
|
||||||
|
|
||||||
|
return cache
|
||||||
|
}
|
|
@ -4120,6 +4120,11 @@ lru-cache@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
|
lru-cache@^7.14.0:
|
||||||
|
version "7.14.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.0.tgz#21be64954a4680e303a09e9468f880b98a0b3c7f"
|
||||||
|
integrity sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ==
|
||||||
|
|
||||||
magic-string@^0.25.0, magic-string@^0.25.7:
|
magic-string@^0.25.0, magic-string@^0.25.7:
|
||||||
version "0.25.9"
|
version "0.25.9"
|
||||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
|
||||||
|
|
Loading…
Reference in New Issue