Implement local track upload
This commit is contained in:
@ -16,13 +16,15 @@ import { useCurrentPlaylistStore } from '~/stores/use-current-playlist-store';
|
||||
import FileUpload from '@/components/ui/file-upload/FileUpload.vue';
|
||||
import FileUploadGrid from '@/components/ui/file-upload/FileUploadGrid.vue';
|
||||
import Button from '@/components/ui/button/Button.vue';
|
||||
import { addLocalTrack } from '~/composeables/api/track-controller/track-controller';
|
||||
|
||||
const files = ref<File[]>([]);
|
||||
|
||||
const currentPlaylistStore = useCurrentPlaylistStore();
|
||||
const progressEntries = ref<Map<string, StreamProgress200Item>>(new Map());
|
||||
let listener: EventSourceListener<StreamProgress200Item> | null = null;
|
||||
|
||||
const ongoingUploads = ref<Map<string, { file: File; progress: number }>>(new Map());
|
||||
|
||||
const sortedProgressEntries = computed(() => {
|
||||
return Array.from(progressEntries.value.values())
|
||||
.sort((a, b) => {
|
||||
@ -60,6 +62,69 @@ async function listenImports() {
|
||||
})
|
||||
}
|
||||
|
||||
async function handleFileUpload(uploadedFiles: File[]) {
|
||||
if (!currentPlaylistStore.id || currentPlaylistStore.id === -1) {
|
||||
console.error('No playlist selected');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const file of uploadedFiles) {
|
||||
const uploadId = generateUploadId(file);
|
||||
|
||||
ongoingUploads.value.set(uploadId, { file, progress: 0 });
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('source', file);
|
||||
|
||||
await addLocalTrack(
|
||||
currentPlaylistStore.id,
|
||||
{ source: file },
|
||||
{
|
||||
onUploadProgress: (progressEvent) => {
|
||||
if (progressEvent.total) {
|
||||
const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
|
||||
ongoingUploads.value.set(uploadId, {
|
||||
file,
|
||||
progress: Math.min(progress, 100)
|
||||
});
|
||||
|
||||
ongoingUploads.value = new Map(ongoingUploads.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ongoingUploads.value.delete(uploadId);
|
||||
ongoingUploads.value = new Map(ongoingUploads.value);
|
||||
|
||||
const index = files.value.findIndex(f =>
|
||||
f.name === file.name &&
|
||||
f.size === file.size &&
|
||||
f.lastModified === file.lastModified
|
||||
);
|
||||
if (index !== -1) {
|
||||
files.value.splice(index, 1);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Upload failed:', error);
|
||||
ongoingUploads.value.delete(uploadId);
|
||||
ongoingUploads.value = new Map(ongoingUploads.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateUploadId(file: File): string {
|
||||
return `${file.name}-${file.size}-${file.lastModified}-${Date.now()}`;
|
||||
}
|
||||
|
||||
function handleFileChange(changedFiles: File[]) {
|
||||
files.value = changedFiles;
|
||||
|
||||
handleFileUpload(changedFiles);
|
||||
}
|
||||
|
||||
function onYoutubeClick(e: MouseEvent) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
@ -91,7 +156,8 @@ onUnmounted(() => {
|
||||
</Outline>
|
||||
</template>
|
||||
<div class="w-full flex flex-col p-8">
|
||||
<FileUpload v-model="files" class="rounded-lg border border-dashed border-muted" @onChange="">
|
||||
<FileUpload v-model="files" class="rounded-lg border border-dashed border-muted"
|
||||
@onChange="handleFileChange" :ongoing-uploads="ongoingUploads">
|
||||
<template #default>
|
||||
<FileUploadGrid />
|
||||
</template>
|
||||
@ -113,8 +179,12 @@ onUnmounted(() => {
|
||||
Uploaded files
|
||||
</h3>
|
||||
<div class="space-y-2">
|
||||
|
||||
|
||||
<UploadEntry v-for="entry in sortedProgressEntries" :key="entry.id" :entry="entry" />
|
||||
<Empty class="border border-dashed" v-if="progressEntries.size === 0">
|
||||
|
||||
<Empty class="border border-dashed"
|
||||
v-if="progressEntries.size === 0 && ongoingUploads.size === 0">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<MegaphoneOff />
|
||||
|
||||
Reference in New Issue
Block a user