diff --git a/.github/workflows/build-push-backend.yml b/.github/workflows/build-push-backend.yml index f56fd6d..8a6ef51 100644 --- a/.github/workflows/build-push-backend.yml +++ b/.github/workflows/build-push-backend.yml @@ -70,6 +70,8 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v5 + with: + python-version: '3.13' - name: Install the project run: uv sync --locked --all-extras --dev diff --git a/Dockerfile b/Dockerfile index 4d75ba7..421393d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN npm ci && npm cache clean --force COPY web/ ./ RUN env PUBLIC_VERSION=${VERSION} PUBLIC_API_URL=${BASE_PATH} BASE_PATH=${BASE_PATH}/web npm run build -FROM ghcr.io/astral-sh/uv:debian-slim +FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim ARG VERSION ARG BASE_PATH="" LABEL author="github.com/maxdorninger" @@ -25,7 +25,7 @@ ENV PUBLIC_VERSION=${VERSION} \ WORKDIR /app RUN apt-get update && \ - apt-get install -y ca-certificates bash libtorrent21 gcc bc locales postgresql mime-support curl gzip unzip tar 7zip bzip2 unar && \ + apt-get install -y ca-certificates bash libtorrent21 gcc bc locales postgresql media-types mailcap curl gzip unzip tar 7zip bzip2 unar && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* diff --git a/web/eslint.config.js b/web/eslint.config.js index 7537f34..b478b21 100644 --- a/web/eslint.config.js +++ b/web/eslint.config.js @@ -48,7 +48,6 @@ export default ts.config( rules: { // Override or add rule settings here, such as: // 'svelte/rule-name': 'error' - 'svelte/no-navigation-without-resolve': 'off' } } ); diff --git a/web/src/lib/components/add-media-card.svelte b/web/src/lib/components/add-media-card.svelte index dc4ad51..fe3b6e4 100644 --- a/web/src/lib/components/add-media-card.svelte +++ b/web/src/lib/components/add-media-card.svelte @@ -3,7 +3,7 @@ import * as Card from '$lib/components/ui/card/index.js'; import { ImageOff } from 'lucide-svelte'; import { goto } from '$app/navigation'; - import { base } from '$app/paths'; + import { resolve } from '$app/paths'; import type { components } from '$lib/api/api'; import client from '$lib/api'; @@ -39,7 +39,11 @@ }); data = response.data; } - await goto(`${base}/dashboard/${isShow ? 'tv' : 'movies'}/` + data?.id); + if (isShow) { + await goto(resolve('/dashboard/tv/[showId]', { showId: data?.id ?? '' })); + } else { + await goto(resolve('/dashboard/movies/[movieId]', { movieId: data?.id ?? '' })); + } loading = false; } diff --git a/web/src/lib/components/app-sidebar.svelte b/web/src/lib/components/app-sidebar.svelte index 61bc10b..b51a0ce 100644 --- a/web/src/lib/components/app-sidebar.svelte +++ b/web/src/lib/components/app-sidebar.svelte @@ -9,7 +9,7 @@ Settings, TvIcon } from 'lucide-svelte'; - import { base } from '$app/paths'; + import { resolve } from '$app/paths'; import { PUBLIC_VERSION } from '$env/static/public'; @@ -17,47 +17,47 @@ navMain: [ { title: 'Dashboard', - url: base + '/dashboard', + url: resolve('/dashboard', {}), icon: Home, isActive: true }, { title: 'TV', - url: base + '/dashboard/tv', + url: resolve('/dashboard/tv', {}), icon: TvIcon, isActive: true, items: [ { title: 'Add a show', - url: base + '/dashboard/tv/add-show' + url: resolve('/dashboard/tv/add-show', {}) }, { title: 'Torrents', - url: base + '/dashboard/tv/torrents' + url: resolve('/dashboard/tv/torrents', {}) }, { title: 'Requests', - url: base + '/dashboard/tv/requests' + url: resolve('/dashboard/tv/requests', {}) } ] }, { title: 'Movies', - url: base + '/dashboard/movies', + url: resolve('/dashboard/movies', {}), icon: Clapperboard, isActive: true, items: [ { title: 'Add a movie', - url: base + '/dashboard/movies/add-movie' + url: resolve('/dashboard/movies/add-movie', {}) }, { title: 'Torrents', - url: base + '/dashboard/movies/torrents' + url: resolve('/dashboard/movies/torrents', {}) }, { title: 'Requests', - url: base + '/dashboard/movies/requests' + url: resolve('/dashboard/movies/requests', {}) } ] } @@ -65,12 +65,12 @@ navSecondary: [ { title: 'Notifications', - url: base + '/dashboard/notifications', + url: resolve('/dashboard/notifications', {}), icon: Bell }, { title: 'Settings', - url: base + '/dashboard/settings', + url: resolve('/dashboard/settings', {}), icon: Settings }, { @@ -85,7 +85,7 @@ }, { title: 'About', - url: base + '/dashboard/about', + url: resolve('/dashboard/about', {}), icon: Info } ] @@ -109,7 +109,7 @@ {#snippet child({ props })} - + Media Manager Logo
Media Manager diff --git a/web/src/lib/components/login-card.svelte b/web/src/lib/components/login-card.svelte index 3f50ec2..79add8a 100644 --- a/web/src/lib/components/login-card.svelte +++ b/web/src/lib/components/login-card.svelte @@ -11,6 +11,7 @@ import LoadingBar from '$lib/components/loading-bar.svelte'; import client from '$lib/api'; import { handleOauth } from '$lib/utils.ts'; + import { resolve } from '$app/paths'; let { oauthProviderNames @@ -46,7 +47,7 @@ console.log('Received User Data: ', response); errorMessage = 'Login successful! Redirecting...'; toast.success(errorMessage); - goto(base + '/dashboard'); + goto(resolve('/dashboard', {})); } else { toast.error('Login failed!'); errorMessage = `Login failed! Please check your credentials and try again.`; @@ -75,7 +76,10 @@
diff --git a/web/src/lib/components/nav-main.svelte b/web/src/lib/components/nav-main.svelte index 64c4f52..abf8d8b 100644 --- a/web/src/lib/components/nav-main.svelte +++ b/web/src/lib/components/nav-main.svelte @@ -2,6 +2,7 @@ import * as Collapsible from '$lib/components/ui/collapsible/index.js'; import * as Sidebar from '$lib/components/ui/sidebar/index.js'; import ChevronRight from '@lucide/svelte/icons/chevron-right'; + import { resolve } from '$app/paths'; let { items @@ -33,7 +34,7 @@ {mainItem.title} {/snippet} {#snippet child({ props })} - + {mainItem.title} diff --git a/web/src/lib/components/nav-projects.svelte b/web/src/lib/components/nav-projects.svelte index fa79d48..5a9f3f8 100644 --- a/web/src/lib/components/nav-projects.svelte +++ b/web/src/lib/components/nav-projects.svelte @@ -6,7 +6,7 @@ import Folder from '@lucide/svelte/icons/folder'; import Share from '@lucide/svelte/icons/share'; import Trash2 from '@lucide/svelte/icons/trash-2'; - + import { resolve } from '$app/paths'; let { projects }: { @@ -29,7 +29,7 @@ {#snippet child({ props })} - + {item.name} diff --git a/web/src/lib/components/nav-secondary.svelte b/web/src/lib/components/nav-secondary.svelte index 83f9a5a..5c3528e 100644 --- a/web/src/lib/components/nav-secondary.svelte +++ b/web/src/lib/components/nav-secondary.svelte @@ -3,7 +3,7 @@ import type { ComponentProps } from 'svelte'; import Sun from '@lucide/svelte/icons/sun'; import Moon from '@lucide/svelte/icons/moon'; - + import { resolve } from '$app/paths'; import { toggleMode } from 'mode-watcher'; let { @@ -41,7 +41,7 @@ {#snippet child({ props })} - + {item.title} diff --git a/web/src/lib/components/nav-user.svelte b/web/src/lib/components/nav-user.svelte index c7a3a04..6db0b03 100644 --- a/web/src/lib/components/nav-user.svelte +++ b/web/src/lib/components/nav-user.svelte @@ -1,7 +1,6 @@ @@ -57,7 +56,7 @@
- goto(base + '/dashboard/settings#me')}> + goto(resolve('/dashboard/settings#me', {}))}> My Account diff --git a/web/src/lib/components/season-requests-table.svelte b/web/src/lib/components/season-requests-table.svelte index 72e6ef0..bb3efde 100644 --- a/web/src/lib/components/season-requests-table.svelte +++ b/web/src/lib/components/season-requests-table.svelte @@ -8,7 +8,7 @@ import { Button } from '$lib/components/ui/button/index.js'; import { toast } from 'svelte-sonner'; import { goto } from '$app/navigation'; - import { base } from '$app/paths'; + import { resolve } from '$app/paths'; import client from '$lib/api'; let { @@ -28,7 +28,6 @@ isShow: boolean; } = $props(); const user: () => components['schemas']['UserRead'] = getContext('user'); - async function approveRequest(requestId: string, currentAuthorizedStatus: boolean) { let response; if (isShow) { @@ -183,9 +182,9 @@ variant="outline" onclick={() => goto( - base + - '/dashboard/tv/' + - (request as components['schemas']['RichSeasonRequest']).show.id + resolve('/dashboard/tv/[showId]', { + showId: (request as components['schemas']['RichSeasonRequest']).show.id! + }) )} > Download manually @@ -197,9 +196,9 @@ variant="outline" onclick={() => goto( - base + - '/dashboard/movies/' + - (request as components['schemas']['RichMovieRequest']).movie.id + resolve('/dashboard/movies/[movieId]', { + movieId: (request as components['schemas']['RichMovieRequest']).movie.id! + }) )} > Download manually diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 694667f..792be85 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -1,7 +1,7 @@ import { type ClassValue, clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; import { goto } from '$app/navigation'; -import { base } from '$app/paths'; +import { resolve } from '$app/paths'; import { toast } from 'svelte-sonner'; import client from '$lib/api'; @@ -60,7 +60,7 @@ export function convertTorrentSeasonRangeToIntegerRange(torrent: { export async function handleLogout() { await client.POST('/api/v1/auth/cookie/logout'); - await goto(base + '/login'); + await goto(resolve('/login', {})); } export async function handleOauth() { diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 1bd4674..8ecbeee 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -2,7 +2,7 @@ import '../app.css'; import { ModeWatcher } from 'mode-watcher'; import { Toaster } from '$lib/components/ui/sonner/index.js'; - import { base } from '$app/paths'; + import { resolve } from '$app/paths'; let { children } = $props(); @@ -10,7 +10,7 @@ MediaManager - + diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index 69f3b1c..0161db9 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,11 +1,11 @@ diff --git a/web/src/routes/dashboard/+layout.svelte b/web/src/routes/dashboard/+layout.svelte index a6d7aa7..68e24b6 100644 --- a/web/src/routes/dashboard/+layout.svelte +++ b/web/src/routes/dashboard/+layout.svelte @@ -4,14 +4,14 @@ import type { LayoutProps } from './$types'; import { setContext } from 'svelte'; import { goto } from '$app/navigation'; - import { base } from '$app/paths'; + import { resolve } from '$app/paths'; import { toast } from 'svelte-sonner'; let { data, children }: LayoutProps = $props(); console.log('Received User Data: ', data.user); if (!data.user?.is_verified) { toast.info('Your account requires verification. Redirecting...'); - goto(base + '/login/verify'); + goto(resolve('/login/verify', {})); } setContext('user', () => data.user); diff --git a/web/src/routes/dashboard/+layout.ts b/web/src/routes/dashboard/+layout.ts index 28a31ef..ac9dfbe 100644 --- a/web/src/routes/dashboard/+layout.ts +++ b/web/src/routes/dashboard/+layout.ts @@ -1,6 +1,6 @@ import type { LayoutLoad } from './$types'; import { redirect } from '@sveltejs/kit'; -import { base } from '$app/paths'; +import { resolve } from '$app/paths'; import { browser } from '$app/environment'; import { goto } from '$app/navigation'; import client from '$lib/api'; @@ -11,9 +11,9 @@ export const load: LayoutLoad = async ({ fetch }) => { if (!response.ok) { console.log('unauthorized, redirecting to login'); if (browser) { - await goto(base + '/login'); + await goto(resolve('/login', {})); } else { - throw redirect(303, base + '/login'); + throw redirect(303, resolve('/login', {})); } } return { user: data }; diff --git a/web/src/routes/dashboard/+page.svelte b/web/src/routes/dashboard/+page.svelte index 8ebfce5..d92cd85 100644 --- a/web/src/routes/dashboard/+page.svelte +++ b/web/src/routes/dashboard/+page.svelte @@ -3,7 +3,7 @@ import * as Sidebar from '$lib/components/ui/sidebar/index.js'; import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js'; import RecommendedMediaCarousel from '$lib/components/recommended-media-carousel.svelte'; - import { base } from '$app/paths'; + import { resolve } from '$app/paths'; import { onMount } from 'svelte'; import client from '$lib/api'; import type { components } from '$lib/api/api.d.ts'; @@ -41,7 +41,7 @@