create torrent components folder

This commit is contained in:
maxid
2026-01-03 12:10:24 +01:00
parent fc79563be3
commit bd7e9090b2
7 changed files with 12 additions and 12 deletions

View File

@@ -0,0 +1,61 @@
<script lang="ts">
import { Button, buttonVariants } from '$lib/components/ui/button';
import { Label } from '$lib/components/ui/label';
import { toast } from 'svelte-sonner';
import * as Dialog from '$lib/components/ui/dialog';
import client from '$lib/api';
import { Checkbox } from '$lib/components/ui/checkbox';
import { invalidateAll } from '$app/navigation';
let { torrentId, torrentName }: { torrentId: string; torrentName: string } = $props();
let dialogueState = $state(false);
let deleteFiles = $state(false);
async function deleteTorrent() {
const { error } = await client.DELETE(`/api/v1/torrent/{torrent_id}`, {
params: {
path: {
torrent_id: torrentId
},
query: {
delete_files: deleteFiles
}
}
});
if (error) {
toast.error(`Failed to delete torrent: ${error}`);
} else {
toast.success('Torrent deleted successfully!');
dialogueState = false;
}
await invalidateAll();
}
</script>
<Dialog.Root bind:open={dialogueState}>
<Dialog.Trigger class={buttonVariants({ variant: 'destructive' })}>Delete Torrent</Dialog.Trigger>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Delete a Torrent</Dialog.Title>
<Dialog.Description>
Delete Torrent "{torrentName}". This action cannot be undone!
</Dialog.Description>
</Dialog.Header>
<div class="flex w-full max-w-sm items-center space-x-2">
<Checkbox bind:checked={deleteFiles} id="delete-files" />
<div class="flex flex-col">
<Label for="delete-files">
Delete associated files as well.
<p class="text-sm font-normal text-muted-foreground">
(Only files in the download location will be deleted)
</p>
</Label>
</div>
</div>
<Dialog.Footer>
<Button onclick={() => (dialogueState = false)}>Cancel</Button>
<Button onclick={() => deleteTorrent()} variant="destructive">Delete Torrent</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>

View File

@@ -0,0 +1,62 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
import * as Dialog from '$lib/components/ui/dialog';
import type { components } from '$lib/api/api';
import { Switch } from '$lib/components/ui/switch';
import { Label } from '$lib/components/ui/label';
import client from '$lib/api';
import { toast } from 'svelte-sonner';
import { invalidateAll } from '$app/navigation';
let {
torrent
}: {
torrent: components['schemas']['MovieTorrent'] | components['schemas']['RichSeasonTorrent'];
} = $props();
let dialogOpen = $state(false);
let importedState = $derived(torrent.imported);
async function closeDialog() {
dialogOpen = false;
}
async function saveTorrent() {
const { error } = await client.PATCH('/api/v1/torrent/{torrent_id}/status', {
params: {
path: {
torrent_id: torrent.torrent_id!
},
query: {
imported: importedState
}
}
});
if (error) {
toast.error('Failed to update torrent.');
return;
}
await invalidateAll();
await closeDialog();
}
</script>
<Dialog.Root bind:open={dialogOpen}>
<Dialog.Trigger>
<Button class="w-full" onclick={() => (dialogOpen = true)}>Edit Torrent</Button>
</Dialog.Trigger>
<Dialog.Content class="w-full max-w-[600px] rounded-lg p-6 shadow-lg">
<Dialog.Header>
<Dialog.Title class="mb-1 text-xl font-semibold">Edit Torrent</Dialog.Title>
<Dialog.Description class="mb-4 text-sm">
Edit torrent "{torrent.torrent_title}".
</Dialog.Description>
</Dialog.Header>
<div class="flex gap-2">
<Label for="imported-state">Torrent {importedState ? 'is' : 'is not'} imported.</Label>
<Switch bind:checked={importedState} id="imported-state" />
</div>
<Dialog.Footer class="mt-8 flex justify-between gap-2">
<Button onclick={() => closeDialog()} variant="secondary">Cancel</Button>
<Button onclick={() => saveTorrent()}>Save Torrent</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>

View File

@@ -0,0 +1,107 @@
<script lang="ts">
import {
convertTorrentSeasonRangeToIntegerRange,
getTorrentQualityString,
getTorrentStatusString
} from '$lib/utils.js';
import CheckmarkX from '$lib/components/checkmark-x.svelte';
import * as Table from '$lib/components/ui/table';
import type { components } from '$lib/api/api';
import { getContext } from 'svelte';
import { Button } from '$lib/components/ui/button';
import client from '$lib/api';
import { toast } from 'svelte-sonner';
import DeleteTorrentDialog from '$lib/components/torrents/delete-torrent-dialog.svelte';
import EditTorrentDialog from '$lib/components/torrents/edit-torrent-dialog.svelte';
import { invalidateAll } from '$app/navigation';
let {
torrents,
isShow = true
}: {
torrents:
| components['schemas']['MovieTorrent'][]
| components['schemas']['RichSeasonTorrent'][];
isShow: boolean;
} = $props();
let user: () => components['schemas']['UserRead'] = getContext('user');
async function retryTorrentDownload(
torrent: components['schemas']['MovieTorrent'] | components['schemas']['RichSeasonTorrent']
) {
console.log(`Retrying download for torrent ${torrent.torrent_title}`);
const { error } = await client.POST('/api/v1/torrent/{torrent_id}/retry', {
params: {
path: {
torrent_id: torrent.torrent_id!
}
}
});
if (error) {
toast.error(`Failed on retrying download: ${error}`);
} else {
console.log(`Successfully retried download for torrent ${torrent.torrent_title}`);
toast.success('Trying to download torrent...');
}
await invalidateAll();
}
</script>
<Table.Root>
<Table.Caption>A list of all torrents.</Table.Caption>
<Table.Header>
<Table.Row>
<Table.Head>Name</Table.Head>
{#if isShow}
<Table.Head>Seasons</Table.Head>
{/if}
<Table.Head>Download Status</Table.Head>
<Table.Head>Quality</Table.Head>
<Table.Head>File Path Suffix</Table.Head>
<Table.Head>Imported</Table.Head>
{#if user().is_superuser}
<Table.Head>Actions</Table.Head>
{/if}
</Table.Row>
</Table.Header>
<Table.Body>
{#each torrents as torrent (torrent.torrent_id)}
<Table.Row>
<Table.Cell class="font-medium">
{torrent.torrent_title}
</Table.Cell>
{#if isShow}
<Table.Cell>
{convertTorrentSeasonRangeToIntegerRange(
(torrent as components['schemas']['RichSeasonTorrent']).seasons!
)}
</Table.Cell>
{/if}
<Table.Cell>
{getTorrentStatusString(torrent.status)}
</Table.Cell>
<Table.Cell class="font-medium">
{getTorrentQualityString(torrent.quality)}
</Table.Cell>
<Table.Cell>
{torrent.file_path_suffix}
</Table.Cell>
<Table.Cell>
<CheckmarkX state={torrent.imported} />
</Table.Cell>
{#if user().is_superuser}
<Table.Cell class="flex flex-col justify-center gap-2 xl:flex-row">
{#if 'finished' !== getTorrentStatusString(torrent.status)}
<Button variant="secondary" onclick={() => retryTorrentDownload(torrent)}>
Retry Download
</Button>
{/if}
<DeleteTorrentDialog torrentName={torrent.torrent_title} torrentId={torrent.torrent_id!}
></DeleteTorrentDialog>
<EditTorrentDialog {torrent} />
</Table.Cell>
{/if}
</Table.Row>
{/each}
</Table.Body>
</Table.Root>