mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-20 21:05:15 +02:00
add retry and delete buttons to torrents table
This commit is contained in:
238
web/src/lib/api/api.d.ts
vendored
238
web/src/lib/api/api.d.ts
vendored
@@ -248,6 +248,43 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/auth/oauth/authorize': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Oauth:Oauth2.Cookie.Authorize */
|
||||
get: operations['oauth_oauth2_cookie_authorize_api_v1_auth_oauth_authorize_get'];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/auth/oauth/callback': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Oauth:Oauth2.Cookie.Callback
|
||||
* @description The response varies based on the authentication backend used.
|
||||
*/
|
||||
get: operations['oauth_oauth2_cookie_callback_api_v1_auth_oauth_callback_get'];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/tv/shows': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -544,23 +581,6 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/torrent/{torrent_id}': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Get Torrent */
|
||||
get: operations['get_torrent_api_v1_torrent__torrent_id__get'];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/torrent': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -578,6 +598,41 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/torrent/{torrent_id}': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Get Torrent */
|
||||
get: operations['get_torrent_api_v1_torrent__torrent_id__get'];
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Delete Torrent */
|
||||
delete: operations['delete_torrent_api_v1_torrent__torrent_id__delete'];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/torrent/{torrent_id}/retry': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** Retry Torrent Download */
|
||||
post: operations['retry_torrent_download_api_v1_torrent__torrent_id__retry_post'];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
'/api/v1/movies': {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1221,6 +1276,11 @@ export interface components {
|
||||
*/
|
||||
timestamp?: string;
|
||||
};
|
||||
/** OAuth2AuthorizeResponse */
|
||||
OAuth2AuthorizeResponse: {
|
||||
/** Authorization Url */
|
||||
authorization_url: string;
|
||||
};
|
||||
/** PublicMovie */
|
||||
PublicMovie: {
|
||||
/**
|
||||
@@ -2275,6 +2335,80 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
oauth_oauth2_cookie_authorize_api_v1_auth_oauth_authorize_get: {
|
||||
parameters: {
|
||||
query?: {
|
||||
scopes?: string[];
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['OAuth2AuthorizeResponse'];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['HTTPValidationError'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
oauth_oauth2_cookie_callback_api_v1_auth_oauth_callback_get: {
|
||||
parameters: {
|
||||
query?: {
|
||||
code?: string | null;
|
||||
code_verifier?: string | null;
|
||||
state?: string | null;
|
||||
error?: string | null;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': unknown;
|
||||
};
|
||||
};
|
||||
/** @description Bad Request */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['ErrorModel'];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['HTTPValidationError'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
get_all_shows_api_v1_tv_shows_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2905,6 +3039,26 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
get_all_torrents_api_v1_torrent_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Torrent'][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
get_torrent_api_v1_torrent__torrent_id__get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2936,22 +3090,62 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
get_all_torrents_api_v1_torrent_get: {
|
||||
delete_torrent_api_v1_torrent__torrent_id__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
query?: {
|
||||
delete_files?: boolean;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
path: {
|
||||
torrent_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['Torrent'][];
|
||||
'application/json': components['schemas']['HTTPValidationError'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
retry_torrent_download_api_v1_torrent__torrent_id__retry_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
torrent_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
'application/json': components['schemas']['HTTPValidationError'];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
61
web/src/lib/components/delete-torrent-dialog.svelte
Normal file
61
web/src/lib/components/delete-torrent-dialog.svelte
Normal file
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button/index.js';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import * as Dialog from '$lib/components/ui/dialog/index.js';
|
||||
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-muted-foreground text-sm font-normal">
|
||||
(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>
|
||||
@@ -6,8 +6,43 @@
|
||||
} from '$lib/utils.js';
|
||||
import CheckmarkX from '$lib/components/checkmark-x.svelte';
|
||||
import * as Table from '$lib/components/ui/table/index.js';
|
||||
import type { components } from '$lib/api/api';
|
||||
import { getContext } from 'svelte';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import client from '$lib/api';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import DeleteTorrentDialog from '$lib/components/delete-torrent-dialog.svelte';
|
||||
|
||||
let { torrents, isShow = true } = $props();
|
||||
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...');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Table.Root>
|
||||
@@ -22,6 +57,9 @@
|
||||
<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>
|
||||
@@ -32,7 +70,9 @@
|
||||
</Table.Cell>
|
||||
{#if isShow}
|
||||
<Table.Cell>
|
||||
{convertTorrentSeasonRangeToIntegerRange(torrent)}
|
||||
{convertTorrentSeasonRangeToIntegerRange(
|
||||
(torrent as components['schemas']['RichSeasonTorrent']).seasons!
|
||||
)}
|
||||
</Table.Cell>
|
||||
{/if}
|
||||
<Table.Cell>
|
||||
@@ -47,6 +87,17 @@
|
||||
<Table.Cell>
|
||||
<CheckmarkX state={torrent.imported} />
|
||||
</Table.Cell>
|
||||
{#if user().is_superuser}
|
||||
<Table.Cell class="justify flex flex-col 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>
|
||||
</Table.Cell>
|
||||
{/if}
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
|
||||
Reference in New Issue
Block a user