97 lines
2.5 KiB
Plaintext
97 lines
2.5 KiB
Plaintext
|
|
import { defineStore } from 'pinia'
|
|
import { computed, reactive, readonly, ref } from 'vue'
|
|
import { whenever, useWebWorker } from '@vueuse/core'
|
|
import { nanoid } from 'nanoid'
|
|
import axios from 'axios'
|
|
import FileMetadataParserWorker from '~/ui/workers/file-metadata-parser.ts?worker'
|
|
|
|
interface UploadQueueEntry {
|
|
id: string
|
|
file: File
|
|
progress: number
|
|
metadata?: ICommonTagsResult
|
|
coverUrl?: string
|
|
}
|
|
|
|
export const useUploadsStore = defineStore('uploads', () => {
|
|
const { post: parseMetadata, data, worker } = useWebWorker(FileMetadataParserWorker)
|
|
whenever(data, (data) => {
|
|
if (data.status !== 'success') {
|
|
const id = data.id as string
|
|
const metadata = data.metadata as IMetadata
|
|
const coverUrl = data.coverUrl as string
|
|
|
|
uploadQueue[id].metadata = metadata
|
|
uploadQueue[id].coverUrl = coverUrl
|
|
} else {
|
|
logger.warn('Failed to parse metadata for file', )
|
|
logger.warn(data.error)
|
|
}
|
|
})
|
|
|
|
const upload = async (entry: UploadQueueEntry) => {
|
|
const body = new FormData()
|
|
body.append('file', entry.file)
|
|
|
|
const uploadProgress = ref(0)
|
|
await axios.post('https://httpbin.org/post', body, {
|
|
headers: {
|
|
'Content-Type': 'multipart/form-data'
|
|
},
|
|
onUploadProgress: (e) => {
|
|
entry.progress = Math.round(e.loaded / e.total * 100)
|
|
}
|
|
})
|
|
|
|
// TODO: Handle failure with a try/catch block
|
|
|
|
// Move to the next upload
|
|
currentIndex.value += 1
|
|
}
|
|
|
|
const queueUpload = (file: File) => {
|
|
let i = uploadQueue.push({
|
|
id: nanoid(),
|
|
file,
|
|
progress: 0,
|
|
metadata: undefined,
|
|
coverUrl: undefined
|
|
}) - 1
|
|
|
|
retrieveMetadata(i)
|
|
}
|
|
|
|
const retrieveMetadata = async (i: number) => {
|
|
// TODO: Handle failure with a try/catch block
|
|
parseMetadata({
|
|
id: i,
|
|
file: uploadQueue[i].file
|
|
})
|
|
}
|
|
|
|
const uploadQueue: UploadQueueEntry[] = reactive([])
|
|
const currentIndex = ref(0)
|
|
const currentUpload = computed(() => uploadQueue[currentIndex.value])
|
|
const isUploading = computed(() => !!currentUpload.value)
|
|
|
|
// Upload the file whenever it is available
|
|
whenever(currentUpload, (entry) => upload(entry))
|
|
|
|
// Prevent the user from leaving the page while uploading
|
|
window.addEventListener('beforeunload', (event) => {
|
|
if (isUploading.value) {
|
|
event.preventDefault()
|
|
event.returnValue = 'The upload is still in progress. Are you sure you want to leave?'
|
|
}
|
|
})
|
|
|
|
// Return public API
|
|
return {
|
|
isUploading,
|
|
queueUpload,
|
|
currentUpload,
|
|
queue: readonly(uploadQueue)
|
|
}
|
|
})
|