fix: fix most linting errors
This commit is contained in:
parent
0507ddf756
commit
47ac13f8f5
|
@ -1,50 +0,0 @@
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
|
||||||
import { useUploadsStore } from '~/ui/stores/upload'
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
path: '/ui',
|
|
||||||
name: 'ui',
|
|
||||||
component: () => import('~/ui/layouts/constrained.vue'),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'upload',
|
|
||||||
name: 'upload',
|
|
||||||
component: () => import('~/ui/pages/upload.vue'),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
name: 'upload.index',
|
|
||||||
component: () => import('~/ui/pages/upload/index.vue')
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'running',
|
|
||||||
name: 'upload.running',
|
|
||||||
component: () => import('~/ui/pages/upload/running.vue'),
|
|
||||||
beforeEnter: (_to, _from, next) => {
|
|
||||||
const uploads = useUploadsStore()
|
|
||||||
if (uploads.uploadGroups.length === 0) {
|
|
||||||
next('/ui/upload')
|
|
||||||
} else {
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'history',
|
|
||||||
name: 'upload.history',
|
|
||||||
component: () => import('~/ui/pages/upload/history.vue')
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'all',
|
|
||||||
name: 'upload.all',
|
|
||||||
component: () => import('~/ui/pages/upload/all.vue')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
] as RouteRecordRaw[]
|
|
|
@ -44,14 +44,14 @@ const cancel = () => {
|
||||||
uploads.currentUploadGroup = undefined
|
uploads.currentUploadGroup = undefined
|
||||||
|
|
||||||
if (uploads.queue.length > 0) {
|
if (uploads.queue.length > 0) {
|
||||||
return router.push('/ui/upload/running')
|
return router.push('/upload/running')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const continueInBackground = () => {
|
const continueInBackground = () => {
|
||||||
libraryOpen.value = false
|
libraryOpen.value = false
|
||||||
uploads.currentUploadGroup = undefined
|
uploads.currentUploadGroup = undefined
|
||||||
return router.push('/ui/upload/running')
|
return router.push('/upload/running')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorting
|
// Sorting
|
||||||
|
|
|
@ -1,447 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { reactive, ref, computed } from 'vue'
|
|
||||||
import { UseTimeAgo } from '@vueuse/components'
|
|
||||||
import { Icon } from '@iconify/vue'
|
|
||||||
import { useUploadsStore } from '~/ui/stores/upload'
|
|
||||||
import { bytesToHumanSize } from '~/ui/composables/bytes'
|
|
||||||
|
|
||||||
const filesystemStats = reactive({
|
|
||||||
total: 10737418240,
|
|
||||||
used: 3e9
|
|
||||||
})
|
|
||||||
|
|
||||||
const filesystemProgress = computed(() => {
|
|
||||||
if (filesystemStats.used === 0) return 0
|
|
||||||
return filesystemStats.used / filesystemStats.total * 100
|
|
||||||
})
|
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{
|
|
||||||
label: 'Music library',
|
|
||||||
icon: 'headphones',
|
|
||||||
description: 'Host music you listen to.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Music channel',
|
|
||||||
icon: 'music-note-beamed',
|
|
||||||
description: 'Publish music you make.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Podcast channel',
|
|
||||||
icon: 'mic',
|
|
||||||
description: 'Publish podcast you make.'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const currentTab = ref(tabs[0].label)
|
|
||||||
|
|
||||||
// Modals
|
|
||||||
const libraryOpen = ref(false)
|
|
||||||
|
|
||||||
// Server import
|
|
||||||
const serverPath = ref('/srv/funkwhale/data/music')
|
|
||||||
|
|
||||||
// Upload
|
|
||||||
const combinedFileSize = computed(() => bytesToHumanSize(
|
|
||||||
uploads.queue.reduce((acc, { file }) => acc + file.size, 0)
|
|
||||||
))
|
|
||||||
|
|
||||||
const uploads = useUploadsStore()
|
|
||||||
const processFiles = (fileList: FileList) => {
|
|
||||||
console.log('processFiles', fileList)
|
|
||||||
for (const file of fileList) {
|
|
||||||
uploads.queueUpload(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancel = () => {
|
|
||||||
libraryOpen.value = false
|
|
||||||
uploads.cancelAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorting
|
|
||||||
const sortItems = reactive([
|
|
||||||
{ label: 'Upload time', value: 'upload-time' },
|
|
||||||
{ label: 'Upload time 2', value: 'upload-time-2' },
|
|
||||||
{ label: 'Upload time 3', value: 'upload-time-3' }
|
|
||||||
])
|
|
||||||
const currentSort = ref(sortItems[0])
|
|
||||||
|
|
||||||
// Filtering
|
|
||||||
const filterItems = reactive([
|
|
||||||
{ label: 'All', value: 'all' }
|
|
||||||
])
|
|
||||||
const currentFilter = ref(filterItems[0])
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<h1 class="mr-auto">
|
|
||||||
Upload
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div class="filesystem-stats">
|
|
||||||
<div
|
|
||||||
class="filesystem-stats--progress"
|
|
||||||
:style="`--progress: ${filesystemProgress}%`"
|
|
||||||
/>
|
|
||||||
<div class="flex items-center">
|
|
||||||
{{ bytesToHumanSize(filesystemStats.total) }} total
|
|
||||||
|
|
||||||
<div class="filesystem-stats--label full" />
|
|
||||||
{{ bytesToHumanSize(filesystemStats.used) }} used
|
|
||||||
|
|
||||||
<div class="filesystem-stats--label" />
|
|
||||||
{{ bytesToHumanSize(filesystemStats.total - filesystemStats.used) }} available
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p> Select a destination for your audio files: </p>
|
|
||||||
|
|
||||||
<div class="flex justify-between">
|
|
||||||
<FwCard
|
|
||||||
v-for="tab in tabs"
|
|
||||||
:key="tab.label"
|
|
||||||
:title="tab.label"
|
|
||||||
:class="currentTab === tab.label && 'active'"
|
|
||||||
@click="currentTab = tab.label"
|
|
||||||
>
|
|
||||||
<template #image>
|
|
||||||
<div class="image-icon">
|
|
||||||
<Icon :icon="'bi:' + tab.icon" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
{{ tab.description }}
|
|
||||||
<div class="radio-button" />
|
|
||||||
</FwCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<FwButton @click="libraryOpen = true">
|
|
||||||
Open library
|
|
||||||
</FwButton>
|
|
||||||
<FwModal
|
|
||||||
v-model="libraryOpen"
|
|
||||||
title="Upload music to library"
|
|
||||||
>
|
|
||||||
<template #alert="{ closeAlert }">
|
|
||||||
<FwAlert>
|
|
||||||
Before uploading, please ensure your files are tagged properly.
|
|
||||||
We recommend using Picard for that purpose.
|
|
||||||
|
|
||||||
<template #actions>
|
|
||||||
<FwButton @click="closeAlert">
|
|
||||||
Got it
|
|
||||||
</FwButton>
|
|
||||||
</template>
|
|
||||||
</FwAlert>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<FwFileInput
|
|
||||||
:accept="['.flac', '.ogg', '.opus', '.mp3', '.aac', '.aif', '.aiff', '.m4a']"
|
|
||||||
multiple
|
|
||||||
auto-reset
|
|
||||||
@files="processFiles"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Upload path -->
|
|
||||||
<div v-if="uploads.queue.length > 0">
|
|
||||||
<div class="list-header">
|
|
||||||
<div class="file-count">
|
|
||||||
{{ uploads.queue.length }} files, {{ combinedFileSize }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FwSelect
|
|
||||||
v-model="currentFilter"
|
|
||||||
icon="bi:filter"
|
|
||||||
:items="filterItems"
|
|
||||||
/>
|
|
||||||
<FwSelect
|
|
||||||
v-model="currentSort"
|
|
||||||
icon="bi:sort-down"
|
|
||||||
:items="sortItems"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="file-list">
|
|
||||||
<div
|
|
||||||
v-for="track in uploads.queue"
|
|
||||||
:key="track.id"
|
|
||||||
class="list-track"
|
|
||||||
>
|
|
||||||
<Transition mode="out-in">
|
|
||||||
<div
|
|
||||||
v-if="track.tags"
|
|
||||||
class="track-data"
|
|
||||||
>
|
|
||||||
<div class="track-title">
|
|
||||||
{{ track.tags.title }}
|
|
||||||
</div>
|
|
||||||
{{ track.tags.artist }} / {{ track.tags.album }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
class="track-title"
|
|
||||||
>
|
|
||||||
{{ track.file.name }}
|
|
||||||
</div>
|
|
||||||
</Transition>
|
|
||||||
<div class="upload-state">
|
|
||||||
<FwPill :color="track.failReason ? 'red' : track.importedAt ? 'blue' : 'secondary'">
|
|
||||||
{{
|
|
||||||
track.failReason
|
|
||||||
? 'failed'
|
|
||||||
: track.importedAt
|
|
||||||
? 'imported'
|
|
||||||
: track.progress === 100
|
|
||||||
? 'processing'
|
|
||||||
: 'uploading'
|
|
||||||
}}
|
|
||||||
</FwPill>
|
|
||||||
<div
|
|
||||||
v-if="track.importedAt"
|
|
||||||
class="track-progress"
|
|
||||||
>
|
|
||||||
<UseTimeAgo
|
|
||||||
v-slot="{ timeAgo }"
|
|
||||||
:time="track.importedAt"
|
|
||||||
>
|
|
||||||
{{ timeAgo }}
|
|
||||||
</UseTimeAgo>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
class="track-progress"
|
|
||||||
>
|
|
||||||
{{ bytesToHumanSize(track.file.size / 100 * track.progress) }}
|
|
||||||
/ {{ bytesToHumanSize(track.file.size) }}
|
|
||||||
⋅ {{ track.progress }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<FwButton
|
|
||||||
icon="bi:chevron-right"
|
|
||||||
variant="ghost"
|
|
||||||
color="secondary"
|
|
||||||
:is-loading="!track.importedAt"
|
|
||||||
:disabled="!track.importedAt"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Import path -->
|
|
||||||
<template v-else>
|
|
||||||
<label>Import from server directory</label>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<FwInput
|
|
||||||
v-model="serverPath"
|
|
||||||
class="w-full mr-4"
|
|
||||||
/>
|
|
||||||
<FwButton color="secondary">
|
|
||||||
Import
|
|
||||||
</FwButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #actions>
|
|
||||||
<FwButton
|
|
||||||
color="secondary"
|
|
||||||
@click="cancel"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</FwButton>
|
|
||||||
<FwButton @click="libraryOpen = false">
|
|
||||||
{{ uploads.queue.length ? 'Continue in background' : 'Save and close' }}
|
|
||||||
</FwButton>
|
|
||||||
</template>
|
|
||||||
</FwModal>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
h1 {
|
|
||||||
font-size: 36px;
|
|
||||||
font-weight: 900;
|
|
||||||
font-family: Lato, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex:not(.flex-col) {
|
|
||||||
.funkwhale.button {
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filesystem-stats {
|
|
||||||
color: var(--fw-gray-700);
|
|
||||||
> .flex {
|
|
||||||
padding: 1ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filesystem-stats--progress {
|
|
||||||
height: 20px;
|
|
||||||
border: 1px solid var(--fw-gray-600);
|
|
||||||
border-radius: 100vw;
|
|
||||||
padding: 4px 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filesystem-stats--label.full::after,
|
|
||||||
.filesystem-stats--progress::after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
background: var(--fw-gray-600);
|
|
||||||
border-radius: 100vw;
|
|
||||||
min-width: 4px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-width: var(--progress, 100);
|
|
||||||
transition: max-width 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filesystem-stats--label {
|
|
||||||
height: 14px;
|
|
||||||
border: 1px solid var(--fw-gray-600);
|
|
||||||
border-radius: 100vw;
|
|
||||||
padding: 2px 3px;
|
|
||||||
width: 2em;
|
|
||||||
margin: 0 1ch 0 3ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.funkwhale.card {
|
|
||||||
--fw-card-width: 12.5rem;
|
|
||||||
--fw-border-radius: 1rem;
|
|
||||||
padding: 1.3rem 2rem;
|
|
||||||
box-shadow: 0 2px 4px 2px rgba(#000, 0.1);
|
|
||||||
user-select: none;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
:deep(.card-content) {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-icon {
|
|
||||||
background: var(--fw-pastel-blue-1);
|
|
||||||
color: var(--fw-pastel-blue-3);
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.funkwhale.card {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
transition: margin-bottom 0.2s ease;
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
height: 1rem;
|
|
||||||
width: 1rem;
|
|
||||||
border: 1px solid var(--fw-gray-700);
|
|
||||||
border-radius: 1rem;
|
|
||||||
position: relative;
|
|
||||||
margin: 0.5rem auto 0;
|
|
||||||
transition: margin-bottom 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
background: var(--fw-blue-400);
|
|
||||||
border: inherit;
|
|
||||||
border-radius: inherit;
|
|
||||||
position: absolute;
|
|
||||||
inset: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
line-height: 1.2;
|
|
||||||
font-weight: 900;
|
|
||||||
margin: 2rem 0 0.75rem;
|
|
||||||
display: block;
|
|
||||||
color: var(--fw-gray-900);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 2rem 0 1rem;
|
|
||||||
|
|
||||||
> .file-count {
|
|
||||||
margin-right: auto;
|
|
||||||
color: var(--fw-gray-600);
|
|
||||||
font-weight: 900;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-track {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: .5rem 0;
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
border-top: 1px solid var(--fw-gray-200);
|
|
||||||
}
|
|
||||||
|
|
||||||
.track-data,
|
|
||||||
.track-title {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--fw-gray-960);
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&.v-enter-active,
|
|
||||||
&.v-leave-active {
|
|
||||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.v-enter-from {
|
|
||||||
transform: translateY(1rem);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.v-leave-to {
|
|
||||||
transform: translateY(-1rem);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.track-progress {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--fw-gray-600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-state {
|
|
||||||
margin-left: auto;
|
|
||||||
text-align: right;
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding-left: 1ch;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
|
|
||||||
:deep(.funkwhale.pill) {
|
|
||||||
margin-right: -0.5rem !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.funkwhale.button):not(:hover) {
|
|
||||||
background: transparent !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -66,7 +66,7 @@ const tabs = computed(() => [
|
||||||
<RouterLink
|
<RouterLink
|
||||||
v-for="tab in tabs"
|
v-for="tab in tabs"
|
||||||
:key="tab.key"
|
:key="tab.key"
|
||||||
:to="`/ui/upload/${tab.key}`"
|
:to="`/upload/${tab.key}`"
|
||||||
custom
|
custom
|
||||||
#="{ navigate, isExactActive }"
|
#="{ navigate, isExactActive }"
|
||||||
>
|
>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import auth from './auth'
|
||||||
import user from './user'
|
import user from './user'
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
import { requireLoggedIn } from '~/router/guards'
|
import { requireLoggedIn } from '~/router/guards'
|
||||||
|
import { useUploadsStore } from '~/ui/stores/upload'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
|
@ -49,7 +50,7 @@ export default [
|
||||||
beforeEnter: (_to, _from, next) => {
|
beforeEnter: (_to, _from, next) => {
|
||||||
const uploads = useUploadsStore()
|
const uploads = useUploadsStore()
|
||||||
if (uploads.uploadGroups.length === 0) {
|
if (uploads.uploadGroups.length === 0) {
|
||||||
next('/ui/upload')
|
next('/upload')
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
|
||||||
import { useUploadsStore } from '~/ui/stores/upload'
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
path: '/ui',
|
|
||||||
name: 'ui',
|
|
||||||
component: () => import('~/ui/layouts/constrained.vue'),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'upload',
|
|
||||||
name: 'upload',
|
|
||||||
component: () => import('~/ui/pages/upload.vue'),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
name: 'upload.index',
|
|
||||||
component: () => import('~/ui/pages/upload/index.vue')
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'running',
|
|
||||||
name: 'upload.running',
|
|
||||||
component: () => import('~/ui/pages/upload/running.vue'),
|
|
||||||
beforeEnter: (_to, _from, next) => {
|
|
||||||
const uploads = useUploadsStore()
|
|
||||||
if (uploads.uploadGroups.length === 0) {
|
|
||||||
next('/ui/upload')
|
|
||||||
} else {
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'history',
|
|
||||||
name: 'upload.history',
|
|
||||||
component: () => import('~/ui/pages/upload/history.vue')
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'all',
|
|
||||||
name: 'upload.all',
|
|
||||||
component: () => import('~/ui/pages/upload/all.vue')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
] as RouteRecordRaw[]
|
|
|
@ -8,6 +8,7 @@ import FileMetadataParserWorker from '~/ui/workers/file-metadata-parser.ts?worke
|
||||||
import type { MetadataParsingResult } from '~/ui/workers/file-metadata-parser'
|
import type { MetadataParsingResult } from '~/ui/workers/file-metadata-parser'
|
||||||
|
|
||||||
import type { Tags } from '~/ui/composables/metadata'
|
import type { Tags } from '~/ui/composables/metadata'
|
||||||
|
import useLogger from '~/composables/useLogger'
|
||||||
|
|
||||||
export type UploadGroupType = 'music-library' | 'music-channel' | 'podcast-channel'
|
export type UploadGroupType = 'music-library' | 'music-channel' | 'podcast-channel'
|
||||||
export type FailReason = 'missing-tags' | 'upload-failed' | 'upload-cancelled'
|
export type FailReason = 'missing-tags' | 'upload-failed' | 'upload-cancelled'
|
||||||
|
@ -34,6 +35,7 @@ export class UploadGroupEntry {
|
||||||
const body = new FormData()
|
const body = new FormData()
|
||||||
body.append('file', this.file)
|
body.append('file', this.file)
|
||||||
|
|
||||||
|
const logger = useLogger()
|
||||||
await axios.post(this.uploadGroup.uploadUrl, body, {
|
await axios.post(this.uploadGroup.uploadUrl, body, {
|
||||||
headers: { 'Content-Type': 'multipart/form-data' },
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
signal: this.abortController.signal,
|
signal: this.abortController.signal,
|
||||||
|
@ -43,12 +45,12 @@ export class UploadGroupEntry {
|
||||||
this.progress = Math.floor(e.loaded / (e.total ?? this.file.size) * 100)
|
this.progress = Math.floor(e.loaded / (e.total ?? this.file.size) * 100)
|
||||||
|
|
||||||
if (this.progress === 100) {
|
if (this.progress === 100) {
|
||||||
console.log(`[${this.id}] upload complete!`)
|
logger.info(`[${this.id}] upload complete!`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(`[${this.id}] import complete!`)
|
logger.info(`[${this.id}] import complete!`)
|
||||||
this.importedAt = new Date()
|
this.importedAt = new Date()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +115,8 @@ export class UploadGroup {
|
||||||
|
|
||||||
const { id, metadata } = entry
|
const { id, metadata } = entry
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
console.log('sending message to worker', id)
|
const logger = useLogger()
|
||||||
|
logger.log('sending message to worker', id)
|
||||||
retrieveMetadata({ id, file })
|
retrieveMetadata({ id, file })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +157,6 @@ const { post: retrieveMetadata, data: workerMetadata } = useWebWorker<MetadataPa
|
||||||
whenever(workerMetadata, (reactiveData) => {
|
whenever(workerMetadata, (reactiveData) => {
|
||||||
const data = toRaw(unref(reactiveData))
|
const data = toRaw(unref(reactiveData))
|
||||||
const entry = UploadGroup.entries[data.id]
|
const entry = UploadGroup.entries[data.id]
|
||||||
console.log(data, entry)
|
|
||||||
if (!entry) return
|
if (!entry) return
|
||||||
|
|
||||||
if (data.status === 'success') {
|
if (data.status === 'success') {
|
||||||
|
@ -164,11 +166,14 @@ whenever(workerMetadata, (reactiveData) => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entry.cancel('missing-tags', data.error)
|
entry.cancel('missing-tags', data.error)
|
||||||
console.warn(`Failed to parse metadata for file ${entry.file.name}:`, data.error)
|
const logger = useLogger()
|
||||||
|
logger.warn(`Failed to parse metadata for file ${entry.file.name}:`, data.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const useUploadsStore = defineStore('uploads', () => {
|
export const useUploadsStore = defineStore('uploads', () => {
|
||||||
|
const logger = useLogger()
|
||||||
|
|
||||||
const createUploadGroup = async (type: UploadGroupType) => {
|
const createUploadGroup = async (type: UploadGroupType) => {
|
||||||
// TODO: API call
|
// TODO: API call
|
||||||
const uploadGroup = new UploadGroup('guid:' + nanoid(), type, 'https://httpbin.org/post')
|
const uploadGroup = new UploadGroup('guid:' + nanoid(), type, 'https://httpbin.org/post')
|
||||||
|
@ -187,7 +192,7 @@ export const useUploadsStore = defineStore('uploads', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.fail('upload-failed', error)
|
entry.fail('upload-failed', error)
|
||||||
console.error(error)
|
logger.error(error)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
// Move to the next upload despite failing
|
// Move to the next upload despite failing
|
||||||
currentIndex.value += 1
|
currentIndex.value += 1
|
||||||
|
|
|
@ -19,9 +19,7 @@ export type MetadataParsingResult = MetadataParsingSuccess | MetadataParsingFail
|
||||||
|
|
||||||
const parse = async (id: string, file: File) => {
|
const parse = async (id: string, file: File) => {
|
||||||
try {
|
try {
|
||||||
console.log(`[${id}] parsing...`)
|
|
||||||
const tags = await getTags(file)
|
const tags = await getTags(file)
|
||||||
console.log(`[${id}] tags:`, tags)
|
|
||||||
const coverUrl = await getCoverUrl(tags)
|
const coverUrl = await getCoverUrl(tags)
|
||||||
|
|
||||||
postMessage({ id, status: 'success', tags, coverUrl })
|
postMessage({ id, status: 'success', tags, coverUrl })
|
||||||
|
|
Loading…
Reference in New Issue