Files
frontend/app/pages/import.vue

113 lines
4.3 KiB
Vue

<script setup lang="ts">
import Outline from '@/components/ui/outline/Outline.vue';
import SidebarTrigger from '@/components/ui/sidebar/SidebarTrigger.vue';
import Empty from '@/components/ui/empty/Empty.vue';
import UploadEntry from '@/components/internal/import/uploadentry/UploadEntry.vue';
import EmptyHeader from '@/components/ui/empty/EmptyHeader.vue';
import EmptyMedia from '@/components/ui/empty/EmptyMedia.vue';
import EmptyTitle from '@/components/ui/empty/EmptyTitle.vue';
import EmptyDescription from '@/components/ui/empty/EmptyDescription.vue';
import { Download, MegaphoneOff, Play } from 'lucide-vue-next';
import type { EventSourceListener } from '~/composeables/api/event-source';
import type { StreamProgress200Item } from '~/composeables/api/models';
import { streamProgress } from '~/composeables/api/progress-sse-controller/progress-sse-controller';
import { useCurrentPlaylistStore } from '~/stores/use-current-playlist-store';
const currentPlaylistStore = useCurrentPlaylistStore();
const progressEntries = ref<Map<string, StreamProgress200Item>>(new Map());
let listener: EventSourceListener<StreamProgress200Item> | null = null;
const unwatch = watch(() => currentPlaylistStore.id, (newId, oldId) => {
if (newId !== -1 && newId !== oldId) {
listenImports();
} else if (newId === -1) {
stopImports();
}
}, { immediate: true });
const updateEntryFromProgress = (data: StreamProgress200Item) => {
if (!data.trackSourceId)
return;
progressEntries.value = new Map(progressEntries.value);
progressEntries.value.set(data.id!.toString(), data);
}
async function listenImports() {
if (listener) {
listener.close();
}
streamProgress(currentPlaylistStore.id).then(listener => {
listener.handle(data => {
updateEntryFromProgress(data);
})
}).catch(err => {
console.error(err);
})
}
function stopImports() {
if (listener) {
listener.close();
listener = null;
}
}
onUnmounted(() => {
stopImports();
unwatch();
});
</script>
<template>
<div class="flex-1">
<NuxtLayout name="default">
<template #header>
<Outline side="bottom" padding="dense" class="w-full">
<div class="flex gap-8 w-full items-center">
<SidebarTrigger :size="5" />
<h2 class="scroll-m-20 text-3xl font-semibold tracking-tight transition-colors first:mt-0">
Import tracks
</h2>
</div>
</Outline>
</template>
<div class="w-full flex flex-col p-8">
<Outline class="rounded-xl bg-muted flex flex-col items-center justify-center gap-1">
<Download />
<h4 class="scroll-m-20 text-xl font-semibold tracking-tight">
Drag and drop your audio files
</h4>
<p class="text-sm text-muted-foreground">
or
</p>
<Button variant="destructive">
<Play />
From Youtube
</Button>
</Outline>
<div>
<h3 class="scroll-m-20 text-2xl font-semibold tracking-tight">
Uploaded files
</h3>
<div class="space-y-2">
<UploadEntry v-for="entry in Array.from(progressEntries.values())" :key="entry.id"
:entry="entry" />
<Empty class="border border-dashed" v-if="progressEntries.size === 0">
<EmptyHeader>
<EmptyMedia variant="icon">
<MegaphoneOff />
</EmptyMedia>
<EmptyTitle>No imports found</EmptyTitle>
<EmptyDescription>
Upload any track to see their progress.
</EmptyDescription>
</EmptyHeader>
</Empty>
</div>
</div>
</div>
</NuxtLayout>
</div>
</template>