mirror of
https://github.com/jellyfin/jellyfin-vue.git
synced 2026-09-03 05:10:26 +03:00
refactor: metadata file upload code cleanup
This commit is contained in:
committed by
Fernando Fernández
parent
c7364638a0
commit
a4195d3a1b
@@ -503,14 +503,14 @@ function openUploadImgeEditor(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle upload image editor opening
|
||||
* Handle upload image editor closing
|
||||
*/
|
||||
function closeUploadImgeEditor(): void {
|
||||
isImageDialogVisible.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle upload image editor opening
|
||||
* Handle image upload
|
||||
*/
|
||||
async function onImageUpload(): Promise<void> {
|
||||
await getData();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<VDialog
|
||||
max-width="60%"
|
||||
:model-value="isImageDialogVisible"
|
||||
@update:model-value="emit('close')">
|
||||
@update:model-value="closeDialog">
|
||||
<VCard class="px-6">
|
||||
<VCardTitle>{{ t('addImage') }}</VCardTitle>
|
||||
<VDivider class="uno-mb-6" />
|
||||
@@ -35,7 +35,7 @@
|
||||
variant="flat"
|
||||
width="8em"
|
||||
class="mr-1"
|
||||
@click="emit('close')">
|
||||
@click="closeDialog">
|
||||
{{ t('cancel') }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
@@ -88,17 +88,28 @@ const imageTypes = computed(() => [
|
||||
]);
|
||||
|
||||
/**
|
||||
* Handles the file upload.
|
||||
* Handle dialog closing.
|
||||
*/
|
||||
function closeDialog(): void {
|
||||
selectedFile.value = undefined;
|
||||
imageType.value = undefined;
|
||||
emit('close');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the file upload.
|
||||
*/
|
||||
async function onSave(): Promise<void> {
|
||||
if (!selectedFile.value || !imageType.value) {
|
||||
useSnackbar(t('failedToReadImage'), 'red');
|
||||
emit('close');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const base64FileContent = await ReadFileContent(selectedFile.value);
|
||||
// According to the TypeScript typings, the SDK expects the body to be a File.
|
||||
// However, sending a File causes the backend to return a 500 error due to a base64 parsing exception.
|
||||
// When the File is converted to a base64 string, the backend works as expected.
|
||||
const base64FileContent = await readFileContent(selectedFile.value);
|
||||
|
||||
const payload: ImageApiSetItemImageRequest = {
|
||||
itemId,
|
||||
@@ -119,16 +130,16 @@ async function onSave(): Promise<void> {
|
||||
imageType.value = undefined;
|
||||
|
||||
emit('upload-image');
|
||||
useSnackbar(t('imageUploadedSuccesfully'), 'green');
|
||||
useSnackbar(t('imageUploadedSuccessfully'), 'green');
|
||||
} catch {
|
||||
useSnackbar(t('imageUploadFailed'), 'red');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the file content in base64 format.
|
||||
* Read the file content in base64 format.
|
||||
*/
|
||||
async function ReadFileContent(file: File): Promise<string> {
|
||||
async function readFileContent(file: File): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
"identifyInstructResult": "You can click on one of these cards to apply the result",
|
||||
"imageSearchResult": "Image search result",
|
||||
"imageType": "Image type",
|
||||
"imageUploadedSuccesfully": "Image uploaded succesfully",
|
||||
"imageUploadedSuccessfully": "Image uploaded successfully",
|
||||
"imageUploadFailed": "Image upload failed",
|
||||
"imageVotes": "{{votes}} votes",
|
||||
"images": "Images",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
:disabled="disabled"
|
||||
@change="onInputChange">
|
||||
<div
|
||||
tabindex="0"
|
||||
:class="[
|
||||
'uno-min-h-84 uno-flex uno-flex-col items-center justify-center',
|
||||
'uno-border-2 uno-border-dashed uno-rounded-xl uno-p-8 uno-text-center uno-bg-transparent',
|
||||
@@ -35,7 +34,7 @@
|
||||
block
|
||||
size="large"
|
||||
color="primary"
|
||||
@click="onDropZoneClick">
|
||||
@click="onBrowseButtonClick">
|
||||
{{ t('browseFiles') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
@@ -55,7 +54,7 @@
|
||||
v-if="preview"
|
||||
:src="preview"
|
||||
class="uno-w-12 uno-h-12 uno-object-cover uno-rounded-md uno-border uno-border-gray-200 dark:uno-border-gray-700">
|
||||
<div class="flex flex-col">
|
||||
<div>
|
||||
<div class="uno-font-medium uno-text-gray-900 dark:uno-text-gray-100 uno-break-all">
|
||||
{{ file.name }}
|
||||
</div>
|
||||
@@ -76,7 +75,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTranslation } from 'i18next-vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import JIcon from './JIcon.vue';
|
||||
|
||||
const { accept, disabled } = defineProps<{
|
||||
@@ -119,7 +118,7 @@ const acceptedFileRules = computed(() => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles the file update and validation.
|
||||
* Handle the file update and validation.
|
||||
*/
|
||||
function updateFile(value: File | undefined): void {
|
||||
errorMessage.value = undefined;
|
||||
@@ -149,7 +148,7 @@ function updateFile(value: File | undefined): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the file input change.
|
||||
* Handle the file input change.
|
||||
*/
|
||||
function onInputChange(event: Event): void {
|
||||
const target = event.target as HTMLInputElement;
|
||||
@@ -159,33 +158,43 @@ function onInputChange(event: Event): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the file drop.
|
||||
* Handle the file drop.
|
||||
*/
|
||||
function onDrop(e: DragEvent): void {
|
||||
e.preventDefault();
|
||||
dragging.value = false;
|
||||
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateFile(e.dataTransfer?.files[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the file drag over.
|
||||
* Handle the file drag over.
|
||||
*/
|
||||
function onDragOver(e: DragEvent): void {
|
||||
e.preventDefault();
|
||||
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
dragging.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the file drag leave.
|
||||
* Handle the file drag leave.
|
||||
*/
|
||||
function onDragLeave(): void {
|
||||
dragging.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the drop zone click.
|
||||
* Handle the drop zone click.
|
||||
*/
|
||||
function onDropZoneClick(): void {
|
||||
function onBrowseButtonClick(): void {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
@@ -194,20 +203,34 @@ function onDropZoneClick(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the image clear icon click.
|
||||
* Handle the image clear icon click.
|
||||
*/
|
||||
function onClearButtonClick(): void {
|
||||
file.value = undefined;
|
||||
errorMessage.value = undefined;
|
||||
}
|
||||
|
||||
watch(file, (newFile) => {
|
||||
if (preview.value) {
|
||||
URL.revokeObjectURL(preview.value);
|
||||
preview.value = undefined;
|
||||
}
|
||||
|
||||
if (!newFile) {
|
||||
preview.value = undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
preview.value = newFile.type.startsWith('image/') ? URL.createObjectURL(newFile) : undefined;
|
||||
if (newFile.type.startsWith('image/')) {
|
||||
preview.value = URL.createObjectURL(newFile);
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (preview.value) {
|
||||
URL.revokeObjectURL(preview.value);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user