Fix changing songs and add LRU cache
This commit is contained in:
		
							parent
							
								
									ccb905b004
								
							
						
					
					
						commit
						1be6701752
					
				| 
						 | 
				
			
			@ -84,7 +84,7 @@ ports:
 | 
			
		|||
 | 
			
		||||
vscode:
 | 
			
		||||
  extensions:
 | 
			
		||||
    - lukashass.volar
 | 
			
		||||
    - Vue.volar
 | 
			
		||||
    - ms-python.python
 | 
			
		||||
    - ms-toolsai.jupyter
 | 
			
		||||
    - ms-toolsai.jupyter-keymap
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
{
 | 
			
		||||
    "recommendations": [
 | 
			
		||||
        "Vue.volar"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +36,7 @@
 | 
			
		|||
    "idb-keyval": "^6.2.0",
 | 
			
		||||
    "js-logger": "1.6.1",
 | 
			
		||||
    "lodash-es": "4.17.21",
 | 
			
		||||
    "lru-cache": "^7.14.0",
 | 
			
		||||
    "moment": "2.29.4",
 | 
			
		||||
    "qs": "6.11.0",
 | 
			
		||||
    "showdown": "2.1.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,11 @@ import store from '~/store'
 | 
			
		|||
import axios from 'axios'
 | 
			
		||||
 | 
			
		||||
export const isPlaying = ref(false)
 | 
			
		||||
 | 
			
		||||
watch(isPlaying, (playing) => {
 | 
			
		||||
watchEffect(() => {
 | 
			
		||||
  const sound = currentSound.value
 | 
			
		||||
  if (!sound) return
 | 
			
		||||
 | 
			
		||||
  if (playing) {
 | 
			
		||||
  if (isPlaying.value) {
 | 
			
		||||
    sound.play()
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,12 +85,19 @@ const createQueueTrack = async (track: Track): Promise<QueueTrack> => {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Adding tracks
 | 
			
		||||
export const enqueue = async (...newTracks: Track[]) => {
 | 
			
		||||
export const enqueueAt = async (index: number, ...newTracks: Track[]) => {
 | 
			
		||||
  const queueTracks = await Promise.all(newTracks.map(createQueueTrack))
 | 
			
		||||
  await setMany(queueTracks.map(track => [track.id, track]))
 | 
			
		||||
 | 
			
		||||
  const ids = queueTracks.map(track => track.id)
 | 
			
		||||
 | 
			
		||||
  if (index >= tracks.value.length) {
 | 
			
		||||
    // we simply push to the end
 | 
			
		||||
    tracks.value.push(...ids)
 | 
			
		||||
  } else {
 | 
			
		||||
    // we insert the track at given position
 | 
			
		||||
    tracks.value.splice(index, 0, ...ids)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Shuffle new tracks
 | 
			
		||||
  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
 | 
			
		||||
export const dequeue = async (index: number) => {
 | 
			
		||||
  if (currentIndex.value === index) {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +142,6 @@ export const playTrack = async (trackIndex: number, force = false) => {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  currentIndex.value = trackIndex
 | 
			
		||||
  if (isPlaying.value) currentSound.value?.play()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Previous track
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +208,15 @@ export const shuffle = () => {
 | 
			
		|||
  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
 | 
			
		||||
const now = useNow()
 | 
			
		||||
export const endsIn = useTimeAgo(computed(() => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,20 @@ import type { QueueTrack, QueueTrackSource } from '~/composables/audio/queue'
 | 
			
		|||
import type { Sound } 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 { connectAudioSource } from '~/composables/audio/audio-api'
 | 
			
		||||
import { isPlaying } from '~/composables/audio/player'
 | 
			
		||||
 | 
			
		||||
import useLRUCache from '~/composables/useLRUCache'
 | 
			
		||||
import store from '~/store'
 | 
			
		||||
 | 
			
		||||
const ALLOWED_PLAY_TYPES: (CanPlayTypeResult | undefined)[] = ['maybe', 'probably']
 | 
			
		||||
const AUDIO_ELEMENT = document.createElement('audio')
 | 
			
		||||
 | 
			
		||||
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 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
 | 
			
		||||
      setTimeout(playNext, 0)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    soundCache.set(track.id, sound)
 | 
			
		||||
    soundPromises.delete(track.id)
 | 
			
		||||
    return sound
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +75,7 @@ export const createSound = async (track: QueueTrack): Promise<Sound> => {
 | 
			
		|||
// Create track from queue
 | 
			
		||||
export const createTrack = async (index: number) => {
 | 
			
		||||
  if (queue.value.length <= index || index === -1) return
 | 
			
		||||
  console.log('LOADING TRACK')
 | 
			
		||||
  console.log('LOADING TRACK', index)
 | 
			
		||||
 | 
			
		||||
  const track = queue.value[index]
 | 
			
		||||
  if (!soundPromises.has(track.id) && !soundCache.has(track.id)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +89,7 @@ export const createTrack = async (index: number) => {
 | 
			
		|||
  sound.audioNode.disconnect()
 | 
			
		||||
  connectAudioSource(sound.audioNode)
 | 
			
		||||
 | 
			
		||||
  if (isPlaying.value) {
 | 
			
		||||
  if (isPlaying.value && index === currentIndex.value) {
 | 
			
		||||
    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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import { useStore } from '~/store'
 | 
			
		|||
import axios from 'axios'
 | 
			
		||||
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'
 | 
			
		||||
 | 
			
		||||
export interface PlayOptionsProps {
 | 
			
		||||
| 
						 | 
				
			
			@ -143,11 +143,11 @@ export default (props: PlayOptionsProps) => {
 | 
			
		|||
 | 
			
		||||
    const tracks = await getPlayableTracks()
 | 
			
		||||
 | 
			
		||||
    const wasEmpty = store.state.queue.tracks.length === 0
 | 
			
		||||
    await store.dispatch('queue/appendMany', { tracks, index: store.state.queue.currentIndex + 1 })
 | 
			
		||||
    const wasEmpty = queue.value.length === 0
 | 
			
		||||
    await enqueueAt(currentIndex.value + 1, ...tracks)
 | 
			
		||||
 | 
			
		||||
    if (next && !wasEmpty) {
 | 
			
		||||
      await store.dispatch('queue/next')
 | 
			
		||||
      await playNext()
 | 
			
		||||
      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:
 | 
			
		||||
    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:
 | 
			
		||||
  version "0.25.9"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue