mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-21 00:05:36 +02:00
format files
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
const apiUrl = env.PUBLIC_API_URL;
|
||||
let loading = $state(false);
|
||||
let errorMessage = $state(null);
|
||||
let errorMessage = $state<string | null>(null);
|
||||
let { result, isShow = true }: { result: MetaDataProviderSearchResult; isShow: boolean } =
|
||||
$props();
|
||||
console.log('Add Show Card Result: ', result);
|
||||
@@ -28,7 +28,7 @@
|
||||
if (response.ok) {
|
||||
await goto(`${base}/dashboard/${isShow ? 'tv' : 'movies'}/` + responseData.id);
|
||||
} else {
|
||||
errorMessage = 'Error occurred: ' + responseData;
|
||||
errorMessage = 'Error occurred: ' + JSON.stringify(responseData);
|
||||
}
|
||||
loading = false;
|
||||
}
|
||||
@@ -63,7 +63,7 @@
|
||||
<Button
|
||||
class="w-full font-semibold"
|
||||
disabled={result.added || loading}
|
||||
onclick={() => addMedia(result)}
|
||||
onclick={() => addMedia()}
|
||||
>
|
||||
{#if loading}
|
||||
<span class="animate-pulse">Loading...</span>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils'; // Assuming you have the cn utility from shadcn-svelte
|
||||
|
||||
type Variant = 'default' | 'secondary' | 'outline' | 'destructive';
|
||||
type Size = 'default' | 'sm' | 'lg';
|
||||
|
||||
let {
|
||||
label,
|
||||
variant = 'default',
|
||||
@@ -9,8 +12,8 @@
|
||||
class: className = ''
|
||||
} = $props<{
|
||||
label: string;
|
||||
variant?: 'default' | 'secondary' | 'outline' | 'destructive';
|
||||
size?: 'default' | 'sm' | 'lg';
|
||||
variant?: Variant;
|
||||
size?: Size;
|
||||
onClose?: () => void;
|
||||
class?: string;
|
||||
}>();
|
||||
@@ -20,7 +23,7 @@
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50';
|
||||
|
||||
// Variant styles
|
||||
const variantStyles = {
|
||||
const variantStyles: Record<Variant, string> = {
|
||||
default:
|
||||
'border bg-background text-foreground shadow-sm hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
||||
@@ -30,7 +33,7 @@
|
||||
};
|
||||
|
||||
// Size styles
|
||||
const sizeStyles = {
|
||||
const sizeStyles: Record<Size, string> = {
|
||||
default: 'h-9 px-3 py-0.5', // Adjusted height for New York style
|
||||
sm: 'h-7 px-2 py-0.5 text-xs', // Adjusted height for New York style
|
||||
lg: 'h-10 px-4 py-0.5' // Adjusted height for New York style
|
||||
@@ -41,7 +44,7 @@
|
||||
'ml-1 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full';
|
||||
</script>
|
||||
|
||||
<div class={cn(baseStyles, variantStyles[variant], sizeStyles[size], className)}>
|
||||
<div class={cn(baseStyles, variantStyles[variant as Variant], sizeStyles[size as Size], className)}>
|
||||
{label}
|
||||
{#if onClose}
|
||||
<button
|
||||
|
||||
@@ -120,7 +120,10 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#snippet saveDirectoryPreview(movie, filePathSuffix)}
|
||||
{#snippet saveDirectoryPreview(
|
||||
movie: { name: string; metadata_provider: string; external_id: number; year: number | null },
|
||||
filePathSuffix: string
|
||||
)}
|
||||
/{getFullyQualifiedMediaName(movie)} [{movie.metadata_provider}id-{movie.external_id}
|
||||
]/{movie.name}{filePathSuffix === '' ? '' : ' - ' + filePathSuffix}.mkv
|
||||
{/snippet}
|
||||
@@ -142,7 +145,7 @@
|
||||
<Tabs.Content value="basic">
|
||||
<div class="grid w-full items-center gap-1.5">
|
||||
<Label for="file-suffix">Filepath suffix</Label>
|
||||
<Select.Root bind:value={filePathSuffix} id="file-suffix" type="single">
|
||||
<Select.Root bind:value={filePathSuffix} type="single">
|
||||
<Select.Trigger class="w-[180px]">{filePathSuffix}</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="">None</Select.Item>
|
||||
|
||||
@@ -129,7 +129,10 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#snippet saveDirectoryPreview(show, filePathSuffix)}
|
||||
{#snippet saveDirectoryPreview(
|
||||
show: { name: string; metadata_provider: string; external_id: number; year: number | null },
|
||||
filePathSuffix: string
|
||||
)}
|
||||
/{getFullyQualifiedMediaName(show)} [{show.metadata_provider}id-{show.external_id}]/ Season XX/{show.name}
|
||||
SXXEXX {filePathSuffix === '' ? '' : ' - ' + filePathSuffix}.mkv
|
||||
{/snippet}
|
||||
@@ -167,7 +170,7 @@
|
||||
listed in the "Seasons" cell will be imported!
|
||||
</p>
|
||||
<Label for="file-suffix">Filepath suffix</Label>
|
||||
<Select.Root type="single" bind:value={filePathSuffix} id="file-suffix">
|
||||
<Select.Root type="single" bind:value={filePathSuffix}>
|
||||
<Select.Trigger class="w-[180px]">{filePathSuffix}</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="">None</Select.Item>
|
||||
@@ -284,7 +287,6 @@
|
||||
{/each}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{torrent.seasons}
|
||||
{convertTorrentSeasonRangeToIntegerRange(torrent)}
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-right">
|
||||
|
||||
@@ -12,16 +12,18 @@
|
||||
const apiUrl = env.PUBLIC_API_URL;
|
||||
let { movie }: { movie: PublicMovie } = $props();
|
||||
let dialogOpen = $state(false);
|
||||
let minQuality = $state<Quality | undefined>(undefined);
|
||||
let wantedQuality = $state<Quality | undefined>(undefined);
|
||||
let minQuality = $state<string | undefined>(undefined);
|
||||
let wantedQuality = $state<string | undefined>(undefined);
|
||||
let isSubmittingRequest = $state(false);
|
||||
let submitRequestError = $state<string | null>(null);
|
||||
|
||||
const qualityValues: Quality[] = [1, 2, 3, 4];
|
||||
let qualityOptions = $derived(
|
||||
qualityValues.map((q) => ({ value: q, label: getTorrentQualityString(q) }))
|
||||
qualityValues.map((q) => ({ value: q.toString(), label: getTorrentQualityString(q) }))
|
||||
);
|
||||
let isFormInvalid = $derived(
|
||||
!minQuality || !wantedQuality || parseInt(wantedQuality) > parseInt(minQuality)
|
||||
);
|
||||
let isFormInvalid = $derived(!minQuality || !wantedQuality || wantedQuality > minQuality);
|
||||
|
||||
async function handleRequestMovie() {
|
||||
isSubmittingRequest = true;
|
||||
@@ -36,8 +38,8 @@
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
movie_id: movie.id,
|
||||
min_quality: minQuality,
|
||||
wanted_quality: wantedQuality
|
||||
min_quality: parseInt(minQuality!),
|
||||
wanted_quality: parseInt(wantedQuality!)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -65,7 +67,7 @@
|
||||
<Dialog.Root bind:open={dialogOpen}>
|
||||
<Dialog.Trigger
|
||||
class={buttonVariants({ variant: 'default' })}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
dialogOpen = true;
|
||||
}}
|
||||
>
|
||||
@@ -82,7 +84,7 @@
|
||||
<Label class="text-right" for="min-quality">Min Quality</Label>
|
||||
<Select.Root bind:value={minQuality} type="single">
|
||||
<Select.Trigger class="w-full" id="min-quality">
|
||||
{minQuality ? getTorrentQualityString(minQuality) : 'Select Minimum Quality'}
|
||||
{minQuality ? getTorrentQualityString(parseInt(minQuality)) : 'Select Minimum Quality'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each qualityOptions as option (option.value)}
|
||||
@@ -97,7 +99,9 @@
|
||||
<Label class="text-right" for="wanted-quality">Wanted Quality</Label>
|
||||
<Select.Root bind:value={wantedQuality} type="single">
|
||||
<Select.Trigger class="w-full" id="wanted-quality">
|
||||
{wantedQuality ? getTorrentQualityString(wantedQuality) : 'Select Wanted Quality'}
|
||||
{wantedQuality
|
||||
? getTorrentQualityString(parseInt(wantedQuality))
|
||||
: 'Select Wanted Quality'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each qualityOptions as option (option.value)}
|
||||
|
||||
@@ -14,31 +14,31 @@
|
||||
|
||||
let dialogOpen = $state(false);
|
||||
let selectedSeasonsIds = $state<string[]>([]);
|
||||
let minQuality = $state<Quality | undefined>(undefined);
|
||||
let wantedQuality = $state<Quality | undefined>(undefined);
|
||||
let minQuality = $state<string | undefined>(undefined);
|
||||
let wantedQuality = $state<string | undefined>(undefined);
|
||||
let isSubmittingRequest = $state(false);
|
||||
let submitRequestError = $state<string | null>(null);
|
||||
|
||||
const qualityValues: Quality[] = [1, 2, 3, 4];
|
||||
let qualityOptions = $derived(
|
||||
qualityValues.map((q) => ({ value: q, label: getTorrentQualityString(q) }))
|
||||
qualityValues.map((q) => ({ value: q.toString(), label: getTorrentQualityString(q) }))
|
||||
);
|
||||
let isFormInvalid = $derived(
|
||||
!selectedSeasonsIds ||
|
||||
selectedSeasonsIds.length === 0 ||
|
||||
!minQuality ||
|
||||
!wantedQuality ||
|
||||
wantedQuality > minQuality
|
||||
parseInt(wantedQuality) > parseInt(minQuality)
|
||||
);
|
||||
|
||||
async function handleRequestSeason() {
|
||||
isSubmittingRequest = true;
|
||||
submitRequestError = null;
|
||||
|
||||
const payloads: CreateSeasonRequest = selectedSeasonsIds.map((seasonId) => ({
|
||||
const payloads: CreateSeasonRequest[] = selectedSeasonsIds.map((seasonId) => ({
|
||||
season_id: seasonId,
|
||||
min_quality: minQuality,
|
||||
wanted_quality: wantedQuality
|
||||
min_quality: parseInt(minQuality!) as Quality,
|
||||
wanted_quality: parseInt(wantedQuality!) as Quality
|
||||
}));
|
||||
for (const payload of payloads) {
|
||||
try {
|
||||
@@ -51,35 +51,38 @@
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (response.status === 204) {
|
||||
// Success, no content
|
||||
dialogOpen = false; // Close the dialog
|
||||
// Reset form fields
|
||||
selectedSeasonsIds = undefined;
|
||||
minQuality = undefined;
|
||||
wantedQuality = undefined;
|
||||
toast.success('Season request submitted successfully!');
|
||||
} else {
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: response.statusText }));
|
||||
submitRequestError = `Failed to submit request: ${errorData.message || response.statusText}`;
|
||||
toast.error(submitRequestError);
|
||||
console.error('Failed to submit request', response.statusText, errorData);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
submitRequestError = `Error submitting request: ${error instanceof Error ? error.message : String(error)}`;
|
||||
toast.error(submitRequestError);
|
||||
console.error('Error submitting request:', error);
|
||||
} finally {
|
||||
isSubmittingRequest = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!submitRequestError) {
|
||||
dialogOpen = false;
|
||||
// Reset form fields
|
||||
selectedSeasonsIds = [];
|
||||
minQuality = undefined;
|
||||
wantedQuality = undefined;
|
||||
toast.success('Season request(s) submitted successfully!');
|
||||
}
|
||||
|
||||
isSubmittingRequest = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open={dialogOpen}>
|
||||
<Dialog.Trigger
|
||||
class={buttonVariants({ variant: 'default' })}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
dialogOpen = true;
|
||||
}}
|
||||
>
|
||||
@@ -96,11 +99,11 @@
|
||||
<!-- Season Select -->
|
||||
<div class="grid grid-cols-[1fr,3fr] items-center gap-4 md:grid-cols-[100px,1fr]">
|
||||
<Label class="text-right" for="season">Season</Label>
|
||||
<Select.Root bind:value={selectedSeasonsIds}>
|
||||
<Select.Root bind:value={selectedSeasonsIds} type="multiple">
|
||||
<Select.Trigger class="w-full" id="season">
|
||||
{#each selectedSeasonsIds as seasonId (seasonId)}
|
||||
{#if show.seasons.find((season) => season.id === seasonId)}
|
||||
{show.seasons.find((season) => season.id === seasonId).number},
|
||||
Season {show.seasons.find((season) => season.id === seasonId)?.number},
|
||||
{/if}
|
||||
{:else}
|
||||
Select one or more seasons
|
||||
@@ -108,7 +111,7 @@
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each show.seasons as season (season.id)}
|
||||
<Select.Item value={season.id}>
|
||||
<Select.Item value={season.id || ''}>
|
||||
Season {season.number}{season.name ? `: ${season.name}` : ''}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
@@ -121,7 +124,7 @@
|
||||
<Label class="text-right" for="min-quality">Min Quality</Label>
|
||||
<Select.Root bind:value={minQuality} type="single">
|
||||
<Select.Trigger class="w-full" id="min-quality">
|
||||
{minQuality ? getTorrentQualityString(minQuality) : 'Select Minimum Quality'}
|
||||
{minQuality ? getTorrentQualityString(parseInt(minQuality)) : 'Select Minimum Quality'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each qualityOptions as option (option.value)}
|
||||
@@ -136,7 +139,9 @@
|
||||
<Label class="text-right" for="wanted-quality">Wanted Quality</Label>
|
||||
<Select.Root bind:value={wantedQuality} type="single">
|
||||
<Select.Trigger class="w-full" id="wanted-quality">
|
||||
{wantedQuality ? getTorrentQualityString(wantedQuality) : 'Select Wanted Quality'}
|
||||
{wantedQuality
|
||||
? getTorrentQualityString(parseInt(wantedQuality))
|
||||
: 'Select Wanted Quality'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each qualityOptions as option (option.value)}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
isShow = true
|
||||
}: {
|
||||
requests: SeasonRequest[];
|
||||
filter: (request: SeasonRequest) => boolean;
|
||||
filter?: (request: SeasonRequest) => boolean;
|
||||
isShow: boolean;
|
||||
} = $props();
|
||||
const user: () => User = getContext('user');
|
||||
@@ -42,7 +42,7 @@
|
||||
if (requestIndex !== -1) {
|
||||
let newAuthorizedStatus = !currentAuthorizedStatus;
|
||||
requests[requestIndex].authorized = newAuthorizedStatus;
|
||||
requests[requestIndex].authorized_by = newAuthorizedStatus ? user() : null;
|
||||
requests[requestIndex].authorized_by = newAuthorizedStatus ? user() : undefined;
|
||||
}
|
||||
toast.success(
|
||||
`Request ${!currentAuthorizedStatus ? 'approved' : 'unapproved'} successfully.`
|
||||
@@ -116,7 +116,7 @@
|
||||
{#if isShow}
|
||||
{getFullyQualifiedMediaName(request.show)}
|
||||
{:else}
|
||||
{getFullyQualifiedMediaName(request.movie)}
|
||||
{getFullyQualifiedMediaName(request.show)}
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
{#if isShow}
|
||||
@@ -163,7 +163,7 @@
|
||||
class=""
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onclick={() => goto(base + '/dashboard/movies/' + request.movie.id)}
|
||||
onclick={() => goto(base + '/dashboard/tv/' + request.show.id)}
|
||||
>
|
||||
Download manually
|
||||
</Button>
|
||||
@@ -179,7 +179,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan="8" class="text-center">There are currently no requests.</Table.Cell>
|
||||
<Table.Cell colspan={8} class="text-center">There are currently no requests.</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
toast.success(`User ${selectedUser.email} updated successfully.`);
|
||||
dialogOpen = false;
|
||||
|
||||
const idx = sortedUsers.findIndex((u) => u.id === selectedUser.id);
|
||||
const idx = sortedUsers.findIndex((u) => u.id === selectedUser!.id);
|
||||
if (idx !== -1) {
|
||||
sortedUsers[idx] = selectedUser;
|
||||
sortedUsers[idx] = selectedUser!;
|
||||
}
|
||||
|
||||
selectedUser = null;
|
||||
|
||||
Reference in New Issue
Block a user