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,6 +307,14 @@ export default {
} }
}, },
async uploadItem(item) { async uploadItem(item) {
const CHUNK_SIZE = 50 * 1024 * 1024 // 50MB
let allFilesSuccessful = true
for (let fileIndex = 0; fileIndex < item.files.length; fileIndex++) {
const file = item.files[fileIndex]
if (file.size <= CHUNK_SIZE) {
// Legacy upload for small files
var form = new FormData() var form = new FormData()
form.set('title', item.title) form.set('title', item.title)
if (!this.selectedLibraryIsPodcast) { if (!this.selectedLibraryIsPodcast) {
@ -315,25 +323,17 @@ export default {
} }
form.set('library', this.selectedLibraryId) form.set('library', this.selectedLibraryId)
form.set('folder', this.selectedFolderId) form.set('folder', this.selectedFolderId)
form.set(`${fileIndex}`, file)
var index = 0
item.files.forEach((file) => {
form.set(`${index++}`, file)
})
const config = { const config = {
onUploadProgress: (progressEvent) => { onUploadProgress: (progressEvent) => {
if (progressEvent.lengthComputable) { if (progressEvent.lengthComputable) {
const progress = { this.updateItemCardProgress(item.index, { loaded: progressEvent.loaded, total: progressEvent.total })
loaded: progressEvent.loaded,
total: progressEvent.total
}
this.updateItemCardProgress(item.index, progress)
} }
} }
} }
return this.$axios const success = await this.$axios
.$post('/api/upload', form, config) .$post('/api/upload', form, config)
.then(() => true) .then(() => true)
.catch((error) => { .catch((error) => {
@ -341,6 +341,43 @@ export default {
this.$toast.error(error.response?.data || 'Oops, something went wrong...') this.$toast.error(error.response?.data || 'Oops, something went wrong...')
return false 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
}
}
}
}
return allFilesSuccessful
}, },
validateItems() { validateItems() {
var itemData = [] var itemData = []