mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-21 16:25:36 +02:00
format files
This commit is contained in:
19
web/src/ambient.d.ts
vendored
Normal file
19
web/src/ambient.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Ambient module declarations for SvelteKit environment variables and enhanced images
|
||||
|
||||
declare module '$env/dynamic/public' {
|
||||
export const env: {
|
||||
PUBLIC_API_URL: string;
|
||||
[key: string]: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
declare module '$env/static/public' {
|
||||
export const PUBLIC_VERSION: string;
|
||||
export const PUBLIC_API_URL: string;
|
||||
}
|
||||
|
||||
// Enhanced image module declarations
|
||||
declare module '*?enhanced' {
|
||||
const value: unknown;
|
||||
export default value;
|
||||
}
|
||||
19
web/src/app.d.ts
vendored
19
web/src/app.d.ts
vendored
@@ -10,4 +10,23 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
// Environment variables declarations
|
||||
declare module '$env/dynamic/public' {
|
||||
export const env: {
|
||||
PUBLIC_API_URL: string;
|
||||
[key: string]: string | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
declare module '$env/static/public' {
|
||||
export const PUBLIC_VERSION: string;
|
||||
export const PUBLIC_API_URL: string;
|
||||
}
|
||||
|
||||
// Enhanced image module declarations
|
||||
declare module '*?enhanced' {
|
||||
const value: unknown;
|
||||
export default value;
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -33,7 +33,7 @@ export function getTorrentStatusString(value: number): string {
|
||||
return torrentStatusMap[value] || 'unknown';
|
||||
}
|
||||
|
||||
export function getFullyQualifiedMediaName(media: { name: string; year: number }): string {
|
||||
export function getFullyQualifiedMediaName(media: { name: string; year: number | null }): string {
|
||||
let name = media.name;
|
||||
if (media.year != null) {
|
||||
name += ' (' + media.year + ')';
|
||||
@@ -45,13 +45,16 @@ export function convertTorrentSeasonRangeToIntegerRange(torrent: {
|
||||
season?: number[];
|
||||
seasons?: number[];
|
||||
}): string {
|
||||
if (torrent?.season?.length === 1) return torrent.season[0]?.toString();
|
||||
if (torrent?.season?.length >= 2)
|
||||
return torrent.season[0]?.toString() + '-' + torrent.season.at(-1).toString();
|
||||
if (torrent?.seasons?.length === 1) return torrent.seasons[0]?.toString();
|
||||
if (torrent?.seasons?.length >= 2)
|
||||
return torrent.seasons[0]?.toString() + '-' + torrent.seasons.at(-1).toString();
|
||||
else {
|
||||
if (torrent?.season?.length === 1) return torrent.season[0]?.toString() || '';
|
||||
if (torrent?.season?.length && torrent.season.length >= 2) {
|
||||
const lastSeason = torrent.season.at(-1);
|
||||
return torrent.season[0]?.toString() + '-' + (lastSeason?.toString() || '');
|
||||
}
|
||||
if (torrent?.seasons?.length === 1) return torrent.seasons[0]?.toString() || '';
|
||||
if (torrent?.seasons?.length && torrent.seasons.length >= 2) {
|
||||
const lastSeason = torrent.seasons.at(-1);
|
||||
return torrent.seasons[0]?.toString() + '-' + (lastSeason?.toString() || '');
|
||||
} else {
|
||||
console.log('Error parsing season range: ' + torrent?.seasons + torrent?.season);
|
||||
return 'Error parsing season range: ' + torrent?.seasons + torrent?.season;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { base } from '$app/paths';
|
||||
import { onMount } from 'svelte';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { MetaDataProviderSearchResult } from '$lib/types';
|
||||
import type { MetaDataProviderSearchResult } from '$lib/types';
|
||||
|
||||
const apiUrl = env.PUBLIC_API_URL;
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||
import type { PublicMovie } from '$lib/types';
|
||||
|
||||
const apiUrl = env.PUBLIC_API_URL;
|
||||
let movies;
|
||||
let movies: PublicMovie[] = [];
|
||||
let loading = false;
|
||||
onMount(async () => {
|
||||
loading = true;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
import type { PageLoad } from './$types';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export const load: LayoutLoad = async ({ params, fetch }) => {
|
||||
export const load: PageLoad = async ({ params, fetch }) => {
|
||||
const res = await fetch(`${env.PUBLIC_API_URL}/movies/${params.movieId}`, {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
@@ -43,5 +43,5 @@
|
||||
<h1 class="scroll-m-20 text-center text-4xl font-extrabold tracking-tight lg:text-5xl">
|
||||
Movie Requests
|
||||
</h1>
|
||||
<RequestsTable bind:requests isShow={false} />
|
||||
<RequestsTable {requests} isShow={false} />
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js';
|
||||
import { base } from '$app/paths';
|
||||
import type { User } from '$lib/types';
|
||||
|
||||
let currentUser = getContext('user');
|
||||
let users = page.data.users;
|
||||
let currentUser: () => User = getContext('user');
|
||||
let users = $state(page.data.users);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -56,7 +57,7 @@
|
||||
<Card.Description>Edit or delete users</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<UserTable bind:users />
|
||||
<UserTable {users} />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{/if}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
const showData = $derived(data.showData);
|
||||
setContext('show', () => showData);
|
||||
const fetchError = $derived(data.error);
|
||||
const fetchError = $derived((data as { error?: string }).error || null);
|
||||
</script>
|
||||
|
||||
{#if fetchError}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { ImageOff } from 'lucide-svelte';
|
||||
import * as Table from '$lib/components/ui/table/index.js';
|
||||
import { getContext } from 'svelte';
|
||||
import type { RichShowTorrent, Show, User } from '$lib/types.js';
|
||||
import type { PublicShow, RichShowTorrent, Show, User } from '$lib/types.js';
|
||||
import { getFullyQualifiedMediaName } from '$lib/utils';
|
||||
import DownloadSeasonDialog from '$lib/components/download-season-dialog.svelte';
|
||||
import CheckmarkX from '$lib/components/checkmark-x.svelte';
|
||||
@@ -48,10 +48,10 @@
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{getFullyQualifiedMediaName(show)} - MediaManager</title>
|
||||
<title>{getFullyQualifiedMediaName(show())} - MediaManager</title>
|
||||
<meta
|
||||
content="View details and manage downloads for {getFullyQualifiedMediaName(
|
||||
show
|
||||
show()
|
||||
)} in MediaManager"
|
||||
name="description"
|
||||
/>
|
||||
@@ -122,7 +122,7 @@
|
||||
{/if}
|
||||
<DownloadSeasonDialog show={show()} />
|
||||
{/if}
|
||||
<RequestSeasonDialog show={show()} />
|
||||
<RequestSeasonDialog show={show() as PublicShow} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 rounded-xl bg-muted/50 p-4">
|
||||
@@ -146,7 +146,7 @@
|
||||
>
|
||||
<Table.Cell class="min-w-[10px] font-medium">{season.number}</Table.Cell>
|
||||
<Table.Cell class="min-w-[10px] font-medium">
|
||||
<CheckmarkX state={season.downloaded} />
|
||||
<CheckmarkX state={false} />
|
||||
</Table.Cell>
|
||||
<Table.Cell class="min-w-[50px]">{season.name}</Table.Cell>
|
||||
<Table.Cell class="max-w-[300px] truncate">{season.overview}</Table.Cell>
|
||||
@@ -154,7 +154,7 @@
|
||||
{/each}
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan="3" class="text-center">No season data available.</Table.Cell>
|
||||
<Table.Cell colspan={3} class="text-center">No season data available.</Table.Cell>
|
||||
</Table.Row>
|
||||
{/if}
|
||||
</Table.Body>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
let seasonFiles: PublicSeasonFile[] = $state(page.data.files);
|
||||
let season: Season = $state(page.data.season);
|
||||
let show: ()=> Show = getContext('show');
|
||||
let show: () => Show = getContext('show');
|
||||
|
||||
console.log('loaded files', seasonFiles);
|
||||
</script>
|
||||
|
||||
@@ -39,7 +39,7 @@ export const load: PageLoad = async ({ fetch, params }) => {
|
||||
} catch (error) {
|
||||
console.error('An error occurred while fetching TV show files:', error);
|
||||
return {
|
||||
error: `An unexpected error occurred: ${error.message || 'Unknown error'}`,
|
||||
error: `An unexpected error occurred: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
files: [],
|
||||
season: null
|
||||
};
|
||||
|
||||
@@ -44,5 +44,5 @@
|
||||
<h1 class="scroll-m-20 text-center text-4xl font-extrabold tracking-tight lg:text-5xl">
|
||||
Season Requests
|
||||
</h1>
|
||||
<RequestsTable bind:requests isShow={true} />
|
||||
<RequestsTable {requests} isShow={true} />
|
||||
</div>
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
bind:value={newPassword}
|
||||
disabled={isLoading}
|
||||
required
|
||||
minlength="1"
|
||||
minlength={1}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
@@ -120,7 +120,7 @@
|
||||
bind:value={confirmPassword}
|
||||
disabled={isLoading}
|
||||
required
|
||||
minlength="1"
|
||||
minlength={1}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user