Commit 3: Frontend Chunking Logic

This commit is contained in:
Josh Roskos 2026-05-16 21:10:31 -05:00
parent 7bc04e5e16
commit 2ab36b42df

View file

@ -307,40 +307,77 @@ export default {
} }
}, },
async uploadItem(item) { async uploadItem(item) {
var form = new FormData() const CHUNK_SIZE = 50 * 1024 * 1024 // 50MB
form.set('title', item.title) let allFilesSuccessful = true
if (!this.selectedLibraryIsPodcast) {
form.set('author', item.author || '')
form.set('series', item.series || '')
}
form.set('library', this.selectedLibraryId)
form.set('folder', this.selectedFolderId)
var index = 0 for (let fileIndex = 0; fileIndex < item.files.length; fileIndex++) {
item.files.forEach((file) => { const file = item.files[fileIndex]
form.set(`${index++}`, file)
})
const config = { if (file.size <= CHUNK_SIZE) {
onUploadProgress: (progressEvent) => { // Legacy upload for small files
if (progressEvent.lengthComputable) { var form = new FormData()
const progress = { form.set('title', item.title)
loaded: progressEvent.loaded, if (!this.selectedLibraryIsPodcast) {
total: progressEvent.total form.set('author', item.author || '')
form.set('series', item.series || '')
}
form.set('library', this.selectedLibraryId)
form.set('folder', this.selectedFolderId)
form.set(`${fileIndex}`, file)
const config = {
onUploadProgress: (progressEvent) => {
if (progressEvent.lengthComputable) {
this.updateItemCardProgress(item.index, { loaded: progressEvent.loaded, total: progressEvent.total })
}
}
}
const success = await this.$axios
.$post('/api/upload', form, config)
.then(() => true)
.catch((error) => {
console.error('Failed to upload item', error)
this.$toast.error(error.response?.data || 'Oops, something went wrong...')
return false
})
if (!success) allFilesSuccessful = false
} else {
// Chunked upload
const fileId = crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).substring(2) + Date.now().toString(36)
const totalChunks = Math.ceil(file.size / CHUNK_SIZE)
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
const start = chunkIndex * CHUNK_SIZE
const end = Math.min(start + CHUNK_SIZE, file.size)
const chunk = file.slice(start, end)
var chunkForm = new FormData()
chunkForm.set('fileId', fileId)
chunkForm.set('chunkIndex', chunkIndex)
chunkForm.set('totalChunks', totalChunks)
chunkForm.set('filename', file.name)
chunkForm.set('title', item.title)
if (!this.selectedLibraryIsPodcast) {
chunkForm.set('author', item.author || '')
chunkForm.set('series', item.series || '')
}
chunkForm.set('library', this.selectedLibraryId)
chunkForm.set('folder', this.selectedFolderId)
chunkForm.set('chunk', chunk)
try {
// Await each chunk sequentially
await this.$axios.$post('/api/upload/chunk', chunkForm)
} catch (error) {
console.error(`Failed to upload chunk ${chunkIndex} for ${file.name}`, error)
allFilesSuccessful = false
break // Stop uploading chunks if one fails
} }
this.updateItemCardProgress(item.index, progress)
} }
} }
} }
return allFilesSuccessful
return this.$axios
.$post('/api/upload', form, config)
.then(() => true)
.catch((error) => {
console.error('Failed to upload item', error)
this.$toast.error(error.response?.data || 'Oops, something went wrong...')
return false
})
}, },
validateItems() { validateItems() {
var itemData = [] var itemData = []