koel/resources/assets/js/services/uploadService.ts

164 lines
3.9 KiB
TypeScript
Raw Normal View History

2022-04-15 14:24:30 +00:00
import { without } from 'lodash'
2022-04-21 18:39:18 +00:00
import { reactive } from 'vue'
2022-04-15 14:24:30 +00:00
import { UploadFile, UploadStatus } from '@/config'
2022-04-24 08:50:45 +00:00
import { httpService } from '@/services'
2022-04-21 18:39:18 +00:00
import { albumStore, artistStore, songStore } from '@/stores'
2022-04-15 14:24:30 +00:00
import { eventBus } from '@/utils'
2022-04-24 08:50:45 +00:00
export const uploadService = {
2022-04-21 18:39:18 +00:00
state: reactive({
2022-04-15 14:24:30 +00:00
files: [] as UploadFile[]
2022-04-21 18:39:18 +00:00
}),
2022-04-15 14:24:30 +00:00
simultaneousUploads: 5,
2022-04-21 18:39:18 +00:00
queue (file: UploadFile | UploadFile[]) {
2022-04-15 14:24:30 +00:00
this.state.files = this.state.files.concat(file)
this.proceed()
},
2022-04-21 18:39:18 +00:00
remove (file: UploadFile) {
2022-04-15 14:24:30 +00:00
this.state.files = without(this.state.files, file)
this.proceed()
},
2022-04-21 18:39:18 +00:00
proceed () {
2022-04-15 14:24:30 +00:00
const remainingSlots = this.simultaneousUploads - this.getUploadingFiles().length
if (remainingSlots <= 0) {
return
}
for (let i = 0; i < remainingSlots; ++i) {
const file = this.getUploadCandidate()
if (file) {
this.upload(file)
}
}
},
2022-04-21 18:39:18 +00:00
getUploadingFiles () {
2022-04-15 14:24:30 +00:00
return this.state.files.filter(file => file.status === 'Uploading')
},
2022-04-21 18:39:18 +00:00
getUploadCandidate () {
2022-04-15 14:24:30 +00:00
return this.state.files.find(file => file.status === 'Ready')
},
2022-04-21 18:39:18 +00:00
async upload (file: UploadFile) {
2022-04-15 14:24:30 +00:00
if (file.status === 'Uploading') {
return
}
const formData = new FormData()
formData.append('file', file.file)
file.progress = 0
file.status = 'Uploading'
try {
2022-04-24 08:50:45 +00:00
const song = await httpService.post<SongUploadResult>('upload', formData, (progressEvent: ProgressEvent) => {
2022-04-15 14:24:30 +00:00
file.progress = progressEvent.loaded * 100 / progressEvent.total
})
file.status = 'Uploaded'
this.populateUploadResultIntoStores(song)
this.proceed() // upload the next file
2022-04-21 18:39:18 +00:00
window.setTimeout(() => this.remove(file), 1000)
2022-04-15 14:24:30 +00:00
eventBus.emit('SONG_UPLOADED')
2022-04-21 21:51:17 +00:00
} catch (error: any) {
2022-04-28 09:00:20 +00:00
console.error(error)
2022-04-21 18:39:18 +00:00
file.message = `Upload failed: ${error.response?.data?.message || 'Unknown error'}`
2022-04-15 14:24:30 +00:00
file.status = 'Errored'
this.proceed() // upload the next file
} finally {
this.checkUploadQueueStatus()
}
},
2022-04-21 18:39:18 +00:00
retry (file: UploadFile) {
2022-04-15 14:24:30 +00:00
// simply reset the status and wait for the next process
this.resetFile(file)
this.proceed()
},
2022-04-21 18:39:18 +00:00
retryAll () {
2022-04-15 14:24:30 +00:00
this.state.files.forEach(this.resetFile)
this.proceed()
},
2022-04-21 18:39:18 +00:00
resetFile: (file: UploadFile) => {
2022-04-15 14:24:30 +00:00
file.status = 'Ready'
file.progress = 0
},
2022-04-21 18:39:18 +00:00
clear () {
2022-04-15 14:24:30 +00:00
this.state.files = []
},
2022-04-21 18:39:18 +00:00
removeFailed () {
2022-04-15 14:24:30 +00:00
this.state.files = this.state.files.filter(file => file.status !== 'Errored')
},
2022-04-21 18:39:18 +00:00
checkUploadQueueStatus () {
2022-04-15 14:24:30 +00:00
const uploadingFiles = this.state.files.filter(file => file.status === 'Uploading')
if (uploadingFiles.length === 0) {
eventBus.emit('UPLOAD_QUEUE_FINISHED')
}
},
2022-04-21 18:39:18 +00:00
getFilesByStatus (status: UploadStatus) {
2022-04-15 14:24:30 +00:00
return this.state.files.filter(file => file.status === status)
},
2022-04-21 18:39:18 +00:00
populateUploadResultIntoStores (uploadResult: SongUploadResult) {
2022-04-15 14:24:30 +00:00
let artist = artistStore.byId(uploadResult.artist.id)!
let album = albumStore.byId(uploadResult.album.id)!
if (!artist) {
artist = Object.assign(uploadResult.artist, {
playCount: 0,
length: 0,
fmtLength: '',
info: null,
2022-04-28 09:00:20 +00:00
albums: [] as Album[],
songs: [] as Song[]
2022-04-15 14:24:30 +00:00
})
2022-04-28 09:00:20 +00:00
artistStore.prepend(artist)
2022-04-15 14:24:30 +00:00
}
if (!album) {
album = Object.assign(uploadResult.album, {
artist,
2022-04-28 09:00:20 +00:00
songs: [] as Song[],
2022-04-15 14:24:30 +00:00
playCount: 0,
length: 0,
fmtLength: '',
info: null
})
2022-04-28 09:00:20 +00:00
albumStore.prepend(album)
2022-04-15 14:24:30 +00:00
}
const song: Song = {
album,
artist,
id: uploadResult.id,
album_id: uploadResult.album.id,
artist_id: uploadResult.artist.id,
title: uploadResult.title,
length: uploadResult.length,
track: uploadResult.track,
disc: uploadResult.disc,
lyrics: '',
playCount: 0,
liked: false
}
songStore.setupSong(song)
songStore.all.unshift(song)
2022-04-15 14:24:30 +00:00
}
}