funkwhale/front/src/components/library/FileUploadWidget.vue

109 lines
3.0 KiB
Vue

<script setup lang="ts">
import type { VueUploadItem } from 'vue-upload-component'
import type { components } from '~/generated/types'
import { useCookies } from '@vueuse/integrations/useCookies'
import { computed, ref, watch, getCurrentInstance } from 'vue'
import { useStore } from '~/store'
import FileUpload from 'vue-upload-component'
const props = defineProps<{
channel: components['schemas']['Channel']['uuid'];
}>()
const { get } = useCookies()
const instance = getCurrentInstance()
const attrs = instance?.attrs ?? {}
const store = useStore()
const headers = computed(() => {
const headers: Record<string, string> = typeof attrs.headers === 'object'
? { ...attrs.headers }
: {}
if (store.state.auth.oauth.accessToken) {
headers.Authorization ??= store.getters['auth/header']
}
const csrf = get('csrftoken')
if (csrf) headers['X-CSRFToken'] = csrf
return headers
})
const patchFileData = (file: VueUploadItem, data: Record<string, unknown> = {}) => {
let metadata = data.import_metadata as Record<string, unknown>
// @ts-expect-error Taken from 3.1.2
const filename: string = file.file.name || file.file.filename || file.name
data.source = `upload://${filename}`
if (metadata) {
metadata = { ...metadata }
if (!('title' in metadata)) {
metadata.title = filename.replace(/\.[^/.]+$/, '')
}
data.import_metadata = JSON.stringify(metadata)
}
data.channel = props.channel
return data
}
const uploadAction = async (file: VueUploadItem, self: any): Promise<VueUploadItem> => {
file.data = patchFileData(file, file.data)
// NOTE: We're only patching the file data. The rest of the process should remain the same:
// https://github.com/lian-yue/vue-upload-component/blob/1bd3be3a56e8ed2934dbe0beae151e9026ca51f9/src/FileUpload.vue#L973-L987
if (self.features.html5) {
if (self.shouldUseChunkUpload(file)) return self.uploadChunk(file)
if (file.putAction) return self.uploadPut(file)
if (file.postAction) return self.uploadHtml5(file)
}
if (file.postAction) return self.uploadHtml4(file)
return Promise.reject(new Error('No action configured'))
}
// NOTE: We need to expose the data and methods that we use
const upload = ref()
const active = ref(false)
watch(active, () => (upload.value.active = active.value))
const update = (file: VueUploadItem, data: Partial<VueUploadItem>) => upload.value.update(file, data)
const remove = (file: VueUploadItem) => upload.value.remove(file)
defineExpose({
active,
update,
remove
})
</script>
<script lang="ts">
// NOTE: We're disallowing overriding `custom-action` and `headers` props
export default { inheritAttrs: false }
</script>
<template>
<file-upload
ref="upload"
v-bind="$attrs"
:post-action="store.getters['instance/absoluteUrl']('/api/v2/uploads/')"
:multiple="true"
:thread="1"
:custom-action="uploadAction"
:headers="headers"
:extensions="store.state.ui.supportedExtensions"
:drop="true"
name="audio_file"
>
<slot />
</file-upload>
</template>