remove public_ssr_api_url

This commit is contained in:
maxDorninger
2025-06-08 23:10:37 +02:00
parent ec2493afdb
commit 40a19edc56
26 changed files with 146 additions and 161 deletions

View File

@@ -2,20 +2,11 @@
## Environment Variables
### `PUBLIC_WEB_SSR`
Enables/disables Server-Side Rendering. (this is experimental). Default is `false`. Example: `true`.
### `PUBLIC_API_URL`
You (the browser) must reach the backend from this url. Default is `http://localhost:8000/api/v1`. Example:
`https://mediamanager.example.com/api/v1`.
### `PUBLIC_SSR_API_URL`
The frontend container must reach the backend from this url. Default is `http://localhost:8000/api/v1`. Example:
`http://backend:8000/api/v1`.
## Build Arguments (web/Dockerfile)
**TODO: expand on this section**
@@ -23,12 +14,12 @@ The frontend container must reach the backend from this url. Default is `http://
To configure a url base path for the frontend, you need to build the frontend docker container, this is because
unfortunately SvelteKit needs to know the base path at build time.
### `VERSION`
Sets the `PUBLIC_VERSION` environment variable at runtime in the frontend container. Passed during build. Example (in
build command): `docker build --build-arg VERSION=1.2.3 -f web/Dockerfile .`
### `BASE_URL`
Sets the base url path, it must begin with a slash and not end with one. Example (in build command):
`docker build --build-arg BASE_URL=/media -f web/Dockerfile .`
### `VERSION`
Sets the `PUBLIC_VERSION` environment variable at runtime in the frontend container. Passed during build. Example (in
build command): `docker build --build-arg VERSION=1.2.3 -f web/Dockerfile .`

View File

@@ -52,7 +52,6 @@ services:
- ./cache:/app/cache
environment:
- PUBLIC_API_URL=http://localhost:8000/api/v1
- PUBLIC_SSR_API_URL=http://backend:8000/api/v1
db:
image: postgres:latest
restart: unless-stopped

View File

@@ -6,10 +6,8 @@
import {goto} from '$app/navigation';
import {base} from '$app/paths';
import type {MetaDataProviderShowSearchResult} from '$lib/types.js';
import {toOptimizedURL} from 'sveltekit-image-optimize/components';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let loading = $state(false);
let errorMessage = $state(null);
let {result}: { result: MetaDataProviderShowSearchResult } = $props();
@@ -51,7 +49,7 @@
{#if result.poster_path != null}
<img
class="max-h-full max-w-full rounded-lg object-contain"
src={toOptimizedURL(result.poster_path)}
src={result.poster_path}
alt="{result.name}'s Poster Image"
/>
{:else}

View File

@@ -12,9 +12,8 @@
import * as Tabs from '$lib/components/ui/tabs/index.js';
import * as Select from '$lib/components/ui/select/index.js';
import * as Table from '$lib/components/ui/table/index.js';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let {show} = $props();
let dialogueState = $state(false);
let selectedSeasonNumber: number = $state(1);

View File

@@ -10,7 +10,7 @@
import LoadingBar from '$lib/components/loading-bar.svelte';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let {oauthProvider} = $props();
let oauthProviderName = $derived(oauthProvider.oauth_name);

View File

@@ -10,7 +10,7 @@
import {toast} from 'svelte-sonner';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let {show}: { show: PublicShow } = $props();
let dialogOpen = $state(false);

View File

@@ -9,9 +9,8 @@
import {toast} from 'svelte-sonner';
import {goto} from '$app/navigation';
import {base} from '$app/paths';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let {
requests,
filter = () => {

View File

@@ -0,0 +1,24 @@
<script>
import {getFullyQualifiedShowName} from "$lib/utils.js";
import logo from "$lib/images/svelte-logo.svg";
import {env} from "$env/dynamic/public";
const apiUrl = env.PUBLIC_API_URL;
let {show} = $props();
</script>
<picture>
<source
srcset="{apiUrl}/static/image/{show.id}.avif"
type="image/avif"
/>
<source
srcset="{apiUrl}/static/image/{show.id}.webp"
type="image/webp"
/>
<img
alt="{getFullyQualifiedShowName(show)}'s Poster Image"
class="aspect-9/16 center h-auto max-w-full rounded-lg object-cover"
src="{apiUrl}/static/image/{show.id}.jpeg"
/>
</picture>

View File

@@ -11,7 +11,7 @@
import {Input} from '$lib/components/ui/input/index.js';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let {users}: { users: User[] } = $props();
let sortedUsers = $derived(users.sort((a, b) => a.email.localeCompare(b.email)));
let selectedUser: User | null = $state(null);

View File

@@ -7,7 +7,7 @@
import {Input} from '$lib/components/ui/input/index.js';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let newPassword: string = $state('');
let newEmail: string = $state('');
let dialogOpen = $state(false);

View File

@@ -6,7 +6,7 @@ import {base} from '$app/paths';
import {toast} from 'svelte-sonner';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const qualityMap: { [key: number]: string } = {
1: '4K/UHD',

View File

@@ -1,10 +0,0 @@
import {env} from '$env/dynamic/public';
let ssrMode = false
if (env.PUBLIC_WEB_SSR == undefined) {
ssrMode = false;
} else {
ssrMode = env.PUBLIC_WEB_SSR.toLowerCase() == 'true';
}
console.log('SSR Mode:', ssrMode);
export const ssr = ssrMode;

View File

@@ -0,0 +1 @@
export const ssr = false;

View File

@@ -5,7 +5,7 @@ import {base} from '$app/paths';
import {browser} from "$app/environment";
import {goto} from '$app/navigation';
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: LayoutLoad = async ({fetch}) => {
const response = await fetch(apiUrl + '/users/me', {

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {PageLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: PageLoad = async ({fetch}) => {
const response = await fetch(apiUrl + '/tv/recommended', {

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {PageLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: PageLoad = async ({fetch}) => {
try {
const users = await fetch(apiUrl + '/users/all', {

View File

@@ -5,12 +5,12 @@
import {Separator} from '$lib/components/ui/separator/index.js';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js';
import {toOptimizedURL} from 'sveltekit-image-optimize/components';
import {getFullyQualifiedShowName} from '$lib/utils';
import logo from '$lib/images/svelte-logo.svg';
import LoadingBar from '$lib/components/loading-bar.svelte';
import ShowPicture from "$lib/components/show-picture.svelte";
const apiUrl = env.PUBLIC_SSR_API_URL
const apiUrl = env.PUBLIC_API_URL
let tvShowsPromise = page.data.tvShows;
</script>
@@ -63,14 +63,7 @@
<Card.Description class="truncate">{show.overview}</Card.Description>
</Card.Header>
<Card.Content>
<img
class="aspect-9/16 center h-auto max-w-full rounded-lg object-cover"
src={toOptimizedURL(`${apiUrl}/static/image/${show.id}.jpg`)}
alt="{getFullyQualifiedShowName(show)}'s Poster Image"
on:error={(e) => {
e.target.src = logo;
}}
/>
<ShowPicture show={show}/>
</Card.Content>
</Card.Root>
</a>

View File

@@ -1,8 +1,7 @@
import {env} from '$env/dynamic/public';
import type {PageLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: PageLoad = async ({fetch}) => {
const response = fetch(apiUrl + '/tv/shows', {

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {LayoutLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: LayoutLoad = async ({params, fetch}) => {
const showId = params.showId;

View File

@@ -1,126 +1,122 @@
<script lang="ts">
import {env} from '$env/dynamic/public';
import {Separator} from '$lib/components/ui/separator/index.js';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js';
import {goto} from '$app/navigation';
import {ImageOff} from 'lucide-svelte';
import * as Table from '$lib/components/ui/table/index.js';
import * as Table from '$lib/components/ui/table/index.js';
import {getContext} from 'svelte';
import type {RichShowTorrent, Show, User} from '$lib/types.js';
import {getFullyQualifiedShowName} from '$lib/utils';
import {toOptimizedURL} from 'sveltekit-image-optimize/components';
import DownloadSeasonDialog from '$lib/components/download-season-dialog.svelte';
import CheckmarkX from '$lib/components/checkmark-x.svelte';
import DownloadSeasonDialog from '$lib/components/download-season-dialog.svelte';
import CheckmarkX from '$lib/components/checkmark-x.svelte';
import {page} from '$app/state';
import TorrentTable from '$lib/components/torrent-table.svelte';
import RequestSeasonDialog from '$lib/components/request-season-dialog.svelte';
import {browser} from "$app/environment";
import TorrentTable from '$lib/components/torrent-table.svelte';
import RequestSeasonDialog from '$lib/components/request-season-dialog.svelte';
import {browser} from "$app/environment";
import ShowPicture from "$lib/components/show-picture.svelte";
const apiUrl = env.PUBLIC_SSR_API_URL;
let show: Show = getContext('show');
let user: User = getContext('user');
let torrents: RichShowTorrent = page.data.torrentsData;
const apiUrl = env.PUBLIC_API_URL
let show: Show = getContext('show');
let user: User = getContext('user');
let torrents: RichShowTorrent = page.data.torrentsData;
</script>
<header class="flex h-16 shrink-0 items-center gap-2">
<div class="flex items-center gap-2 px-4">
<div class="flex items-center gap-2 px-4">
<Sidebar.Trigger class="-ml-1"/>
<Separator class="mr-2 h-4" orientation="vertical"/>
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item class="hidden md:block">
<Breadcrumb.Link href="/dashboard">MediaManager</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item class="hidden md:block">
<Breadcrumb.Link href="/dashboard">MediaManager</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator class="hidden md:block"/>
<Breadcrumb.Item>
<Breadcrumb.Link href="/dashboard">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Item>
<Breadcrumb.Link href="/dashboard">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator class="hidden md:block"/>
<Breadcrumb.Item>
<Breadcrumb.Link href="/dashboard/tv">Shows</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Item>
<Breadcrumb.Link href="/dashboard/tv">Shows</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator class="hidden md:block"/>
<Breadcrumb.Item>
<Breadcrumb.Page>{getFullyQualifiedShowName(show())}</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
</div>
<Breadcrumb.Item>
<Breadcrumb.Page>{getFullyQualifiedShowName(show())}</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
</div>
</header>
<h1 class="scroll-m-20 text-center text-4xl font-extrabold tracking-tight lg:text-5xl">
{getFullyQualifiedShowName(show())}
{getFullyQualifiedShowName(show())}
</h1>
<div class="flex flex-1 flex-col gap-4 p-4">
<div class="flex items-center gap-2">
<div class="max-h-50% w-1/3 max-w-sm rounded-xl bg-muted/50">
{#if show().id}
<img
class="aspect-9/16 h-auto w-full rounded-lg object-cover"
src={toOptimizedURL(`${apiUrl}/static/image/${show().id}.jpg`)}
alt="{show().name}'s Poster Image"
/>
{:else}
<div
<div class="flex items-center gap-2">
<div class="max-h-50% w-1/3 max-w-sm rounded-xl bg-muted/50">
{#if show().id}
<ShowPicture show={show()}/>
{:else}
<div
class="aspect-9/16 flex h-auto w-full items-center justify-center rounded-lg bg-gray-200 text-gray-500"
>
>
<ImageOff size={48}/>
</div>
{/if}
</div>
<div class="h-full flex-auto rounded-xl bg-muted/50 p-4">
<p class="leading-7 [&:not(:first-child)]:mt-6">
{show().overview}
</p>
</div>
<div
</div>
{/if}
</div>
<div class="h-full flex-auto rounded-xl bg-muted/50 p-4">
<p class="leading-7 [&:not(:first-child)]:mt-6">
{show().overview}
</p>
</div>
<div
class="flex h-full flex-auto flex-col items-center justify-center gap-2 rounded-xl bg-muted/50 p-4"
>
{#if user().is_superuser}
>
{#if user().is_superuser}
<DownloadSeasonDialog show={show()}/>
{/if}
{/if}
<RequestSeasonDialog show={show()}/>
</div>
</div>
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 p-4 md:min-h-min">
<div class="w-full overflow-x-auto">
<Table.Root>
<Table.Caption>A list of all seasons.</Table.Caption>
<Table.Header>
<Table.Row>
<Table.Head>Number</Table.Head>
<Table.Head>Exists on file</Table.Head>
<Table.Head>Title</Table.Head>
<Table.Head>Overview</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#if show().seasons.length > 0}
{#each show().seasons as season (season.id)}
<Table.Row
</div>
</div>
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 p-4 md:min-h-min">
<div class="w-full overflow-x-auto">
<Table.Root>
<Table.Caption>A list of all seasons.</Table.Caption>
<Table.Header>
<Table.Row>
<Table.Head>Number</Table.Head>
<Table.Head>Exists on file</Table.Head>
<Table.Head>Title</Table.Head>
<Table.Head>Overview</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#if show().seasons.length > 0}
{#each show().seasons as season (season.id)}
<Table.Row
link={true}
onclick={() => goto('/dashboard/tv/' + show().id + '/' + season.id)}
>
<Table.Cell class="min-w-[10px] font-medium">{season.number}</Table.Cell>
<Table.Cell class="min-w-[10px] font-medium">
onclick={() => goto('/dashboard/tv/' + show().id + '/' + season.id)}
>
<Table.Cell class="min-w-[10px] font-medium">{season.number}</Table.Cell>
<Table.Cell class="min-w-[10px] font-medium">
<CheckmarkX state={season.downloaded}/>
</Table.Cell>
<Table.Cell class="min-w-[50px]">{season.name}</Table.Cell>
<Table.Cell class="max-w-[300px] truncate">{season.overview}</Table.Cell>
</Table.Row>
{/each}
{:else}
<Table.Row>
<Table.Cell colspan="3" class="text-center">No season data available.</Table.Cell>
</Table.Row>
{/if}
</Table.Body>
</Table.Root>
</div>
</div>
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 p-4 md:min-h-min">
<div class="w-full overflow-x-auto">
</Table.Cell>
<Table.Cell class="min-w-[50px]">{season.name}</Table.Cell>
<Table.Cell class="max-w-[300px] truncate">{season.overview}</Table.Cell>
</Table.Row>
{/each}
{:else}
<Table.Row>
<Table.Cell colspan="3" class="text-center">No season data available.</Table.Cell>
</Table.Row>
{/if}
</Table.Body>
</Table.Root>
</div>
</div>
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 p-4 md:min-h-min">
<div class="w-full overflow-x-auto">
<TorrentTable torrents={torrents.torrents}/>
</div>
</div>
</div>
</div>
</div>

View File

@@ -8,11 +8,11 @@
import type {PublicSeasonFile, Season, Show} from '$lib/types';
import CheckmarkX from '$lib/components/checkmark-x.svelte';
import {getFullyQualifiedShowName, getTorrentQualityString} from '$lib/utils';
import {toOptimizedURL} from "sveltekit-image-optimize/components";
import {env} from "$env/dynamic/public";
import {browser} from "$app/environment";
import ShowPicture from "$lib/components/show-picture.svelte";
const apiUrl = env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
const SeasonNumber = page.params.SeasonNumber;
let seasonFiles: PublicSeasonFile[] = $state(page.data.files);
let show: Show = getContext('show');
@@ -61,11 +61,7 @@
<div class="flex flex-1 flex-col gap-4 p-4">
<div class="flex items-center gap-2">
<div class="max-h-50% w-1/3 max-w-sm rounded-xl bg-muted/50">
<img
class="aspect-9/16 h-auto w-full rounded-lg object-cover"
alt="{show().name}'s Poster Image"
src={toOptimizedURL(`${apiUrl}/static/image/${show().id}.jpg`)}
/>
<ShowPicture show={show()}/>
</div>
<div class="h-full w-1/4 flex-auto rounded-xl bg-muted/50 p-4">
<p class="leading-7 [&:not(:first-child)]:mt-6">

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {PageLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: PageLoad = async ({fetch, params}) => {
const url = `${apiUrl}/tv/seasons/${params.SeasonId}/files`;

View File

@@ -14,7 +14,7 @@
import {toast} from 'svelte-sonner';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL
let searchTerm: string = $state('');
let metadataProvider: string = $state('tmdb');
let results: MetaDataProviderShowSearchResult[] | null = $state(null);

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {LayoutLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: LayoutLoad = async ({fetch}) => {
try {
const requests = await fetch(`${apiUrl}/tv/seasons/requests`, {

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {PageLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: PageLoad = async ({fetch}) => {
const response = await fetch(apiUrl + '/tv/shows/torrents', {

View File

@@ -2,7 +2,7 @@ import {env} from '$env/dynamic/public';
import type {PageLoad} from './$types';
import {browser} from "$app/environment";
const apiUrl = browser ? env.PUBLIC_API_URL : env.PUBLIC_SSR_API_URL;
const apiUrl = env.PUBLIC_API_URL;
export const load: PageLoad = async ({fetch}) => {
const response = await fetch(apiUrl + '/auth/metadata', {