From 77e920672d5ce842f7e393d83fd0ea09f932b364 Mon Sep 17 00:00:00 2001 From: Kasper Seweryn Date: Tue, 31 Jan 2023 22:31:38 +0100 Subject: [PATCH] feat: optimize CPU and memory usage Part-of: --- front/package.json | 3 +- front/src/api/player.ts | 21 +- front/src/components/Queue.vue | 47 +- front/src/components/audio/Player.vue | 1 - front/src/components/audio/track/Row.vue | 7 +- front/src/components/audio/track/Table.vue | 13 - front/src/components/vui/list/VirtualList.vue | 36 +- front/src/composables/audio/player.ts | 9 - front/src/composables/audio/queue.ts | 7 +- front/src/composables/audio/tracks.ts | 2 +- front/src/locales/en_US.json | 3 +- front/src/main.ts | 7 + front/src/style/components/_queue.scss | 12 + front/vite.config.ts | 8 +- front/yarn.lock | 928 +++++++++++++++++- 15 files changed, 999 insertions(+), 105 deletions(-) diff --git a/front/package.json b/front/package.json index b3fda3f52..022d6f0ea 100644 --- a/front/package.json +++ b/front/package.json @@ -58,7 +58,7 @@ }, "devDependencies": { "@intlify/eslint-plugin-vue-i18n": "2.0.0", - "@intlify/vite-plugin-vue-i18n": "6.0.3", + "@intlify/unplugin-vue-i18n": "^0.8.1", "@types/diff": "5.0.2", "@types/dompurify": "2.4.0", "@types/howler": "2.2.7", @@ -73,6 +73,7 @@ "@vitejs/plugin-vue": "4.0.0", "@vitest/coverage-c8": "0.25.8", "@vue/compiler-sfc": "3.2.45", + "@vue/devtools": "^6.5.0", "@vue/eslint-config-standard": "8.0.1", "@vue/eslint-config-typescript": "11.0.2", "@vue/test-utils": "2.2.7", diff --git a/front/src/api/player.ts b/front/src/api/player.ts index bac347f53..abfb37663 100644 --- a/front/src/api/player.ts +++ b/front/src/api/player.ts @@ -11,8 +11,8 @@ export interface SoundSource { } export interface Sound { - preload(): void | Promise - dispose(): void + preload(): Promise + dispose(): Promise readonly audioNode: IAudioNode readonly isErrored: Ref @@ -23,11 +23,11 @@ export interface Sound { readonly buffered: number looping: boolean - pause(): void | Promise - play(): void | Promise + pause(): Promise + play(): Promise - seekTo(seconds: number): void | Promise - seekBy(seconds: number): void | Promise + seekTo(seconds: number): Promise + seekBy(seconds: number): Promise onSoundLoop: EventHookOn onSoundEnd: EventHookOn @@ -95,19 +95,22 @@ export class HTMLSound implements Sound { this.isLoaded.value = this.#audio.readyState >= 2 }) - useEventListener(this.#audio, 'error', () => { + useEventListener(this.#audio, 'error', (err) => { + console.error('>> AUDIO ERRORED', err, this.__track?.title) this.isErrored.value = true this.isLoaded.value = true }) } - preload () { + async preload () { + this.isErrored.value = false console.log('CALLING PRELOAD ON', this.__track?.title) this.#audio.load() } - dispose () { + async dispose () { this.audioNode.disconnect() + this.#audio.pause() // Cancel any request downloading the source this.#audio.src = '' diff --git a/front/src/components/Queue.vue b/front/src/components/Queue.vue index 0fa7379ec..2d2428137 100644 --- a/front/src/components/Queue.vue +++ b/front/src/components/Queue.vue @@ -2,7 +2,7 @@ import type { QueueItemSource } from '~/types' import { whenever, watchDebounced, useCurrentElement, useScrollLock, useFullscreen, useIdle, refAutoReset, useStorage } from '@vueuse/core' -import { nextTick, ref, computed, watchEffect, onMounted } from 'vue' +import { nextTick, ref, computed, watchEffect, watch, defineAsyncComponent } from 'vue' import { useFocusTrap } from '@vueuse/integrations/useFocusTrap' import { useRouter } from 'vue-router' import { useI18n } from 'vue-i18n' @@ -17,11 +17,12 @@ import time from '~/utils/time' import TrackFavoriteIcon from '~/components/favorites/TrackFavoriteIcon.vue' import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue' import PlayerControls from '~/components/audio/PlayerControls.vue' -import MilkDrop from '~/components/audio/visualizer/MilkDrop.vue' import VirtualList from '~/components/vui/list/VirtualList.vue' import QueueItem from '~/components/QueueItem.vue' +const MilkDrop = defineAsyncComponent(() => import('~/components/audio/visualizer/MilkDrop.vue')) + const { isPlaying, currentTime, @@ -41,7 +42,7 @@ const { dequeue, playTrack, reorder, - endsIn: timeLeft, + endsIn, clear } = useQueue() @@ -92,16 +93,6 @@ const scrollToCurrent = (behavior: ScrollBehavior = 'smooth') => { watchDebounced(currentTrack, () => scrollToCurrent(), { debounce: 100 }) -const scrollLoop = () => { - const visible = [...(list.value?.scroller.$_views.values() ?? [])].map(item => item.nr.index) - if (!visible.includes(currentIndex.value)) { - list.value?.scrollToIndex(currentIndex.value) - requestAnimationFrame(scrollLoop) - } -} - -onMounted(scrollLoop) - whenever( () => queue.value.length === 0, () => store.commit('ui/queueFocused', null), @@ -117,6 +108,13 @@ const touchProgress = (event: MouseEvent) => { seekTo(time) } +const animated = ref(false) +watch(currentTrack, async track => { + animated.value = false + await nextTick() + animated.value = true +}) + const play = async (index: number) => { isPlaying.value = true return playTrack(index) @@ -357,8 +355,13 @@ const coverType = useStorage('queue:cover-type', CoverType.COVER_ART) :style="{ 'transform': `translateX(${bufferProgress - 100}%)` }" />
@@ -415,12 +418,11 @@ const coverType = useStorage('queue:cover-type', CoverType.COVER_ART)
{{ $t('components.Queue.meta.queuePosition', {index: currentIndex +1, length: queue.length}) }} - + + {{ $t('components.Queue.meta.end') }} + + {{ endsIn }} +
@@ -433,8 +435,7 @@ const coverType = useStorage('queue:cover-type', CoverType.COVER_ART) :component="QueueItem" :size="50" @reorder="reorderTracks" - @visible="scrollToCurrent('auto')" - @hidden="scrollLoop" + @visible="list.scrollToIndex(currentIndex, 'center')" >