Merge branch 'refs/heads/master' into fork/aasmoe/feat/multi-language-metadata

# Conflicts:
#	metadata_relay/app/tmdb.py
#	web/src/lib/api/api.d.ts
This commit is contained in:
maxid
2025-12-20 14:53:41 +01:00
17 changed files with 293 additions and 16 deletions

View File

@@ -0,0 +1,109 @@
<script lang="ts">
import type { components } from '$lib/api/api.ts';
import { toast } from 'svelte-sonner';
import client from '$lib/api/index.ts';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { getFullyQualifiedMediaName } from '$lib/utils.ts';
import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js';
import { Checkbox } from '$lib/components/ui/checkbox/index.js';
import { Label } from '$lib/components/ui/label/index.js';
import { buttonVariants } from '$lib/components/ui/button/index.js';
let {
media,
isShow
}: {
media: components['schemas']['PublicMovie'] | components['schemas']['PublicShow'];
isShow: boolean;
} = $props();
let deleteDialogOpen = $state(false);
let deleteFilesOnDisk = $state(false);
let deleteTorrents = $state(false);
async function delete_movie() {
if (!media.id) {
toast.error('Movie ID is missing');
return;
}
const { response } = await client.DELETE('/api/v1/movies/{movie_id}', {
params: {
path: { movie_id: media.id },
query: { delete_files_on_disk: deleteFilesOnDisk, delete_torrents: deleteTorrents }
}
});
if (!response.ok) {
const errorText = await response.text();
toast.error('Failed to delete movie: ' + errorText);
} else {
toast.success('Movie deleted successfully.');
deleteDialogOpen = false;
await goto(resolve('/dashboard/movies', {}), { invalidateAll: true });
}
}
async function delete_show() {
const { response } = await client.DELETE('/api/v1/tv/shows/{show_id}', {
params: {
path: { show_id: media.id! },
query: { delete_files_on_disk: deleteFilesOnDisk, delete_torrents: deleteTorrents }
}
});
if (!response.ok) {
const errorText = await response.text();
toast.error('Failed to delete show: ' + errorText);
} else {
toast.success('Show deleted successfully.');
deleteDialogOpen = false;
await goto(resolve('/dashboard/tv', {}), { invalidateAll: true });
}
}
</script>
<AlertDialog.Root bind:open={deleteDialogOpen}>
<AlertDialog.Trigger class={buttonVariants({ variant: 'destructive' })}>
Delete {isShow ? ' Show' : ' Movie'}
</AlertDialog.Trigger>
<AlertDialog.Content>
<AlertDialog.Header>
<AlertDialog.Title>Delete - {getFullyQualifiedMediaName(media)}?</AlertDialog.Title>
<AlertDialog.Description>
This action cannot be undone. This will permanently delete
<strong>{getFullyQualifiedMediaName(media)}</strong>.
</AlertDialog.Description>
</AlertDialog.Header>
<div class="flex flex-col gap-3 py-4">
<div class="flex items-center space-x-2">
<Checkbox bind:checked={deleteFilesOnDisk} id="delete-files" />
<Label
for="delete-files"
class="text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Also delete files on disk (this will only remove imported files, not downloads)
</Label>
</div>
<div class="flex items-center space-x-2">
<Checkbox bind:checked={deleteTorrents} id="delete-torrents" />
<Label
for="delete-torrents"
class="text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Also delete torrents (this will remove torrents from your download clients)
</Label>
</div>
</div>
<AlertDialog.Footer>
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
<AlertDialog.Action
onclick={() => {
if (isShow) {
delete_show();
} else delete_movie();
}}
class={buttonVariants({ variant: 'destructive' })}
>
Delete
</AlertDialog.Action>
</AlertDialog.Footer>
</AlertDialog.Content>
</AlertDialog.Root>

View File

@@ -22,6 +22,7 @@
let email = $state('');
let password = $state('');
let errorMessage = $state('');
let successMessage = $state('');
let isLoading = $state(false);
async function handleLogin(event: Event) {
@@ -29,6 +30,7 @@
isLoading = true;
errorMessage = '';
successMessage = '';
const { error, response } = await client.POST('/api/v1/auth/cookie/login', {
body: {
@@ -45,8 +47,8 @@
if (!error) {
console.log('Login successful!');
console.log('Received User Data: ', response);
errorMessage = 'Login successful! Redirecting...';
toast.success(errorMessage);
successMessage = 'Login successful! Redirecting...';
toast.success(successMessage);
goto(resolve('/dashboard', {}));
} else {
toast.error('Login failed!');
@@ -100,6 +102,13 @@
</Alert.Root>
{/if}
{#if successMessage}
<Alert.Root variant="default">
<Alert.Title>Success</Alert.Title>
<Alert.Description>{successMessage}</Alert.Description>
</Alert.Root>
{/if}
{#if isLoading}
<LoadingBar />
{/if}