diff --git a/src/lib/apis/tmdb/tmdbApi.ts b/src/lib/apis/tmdb/tmdbApi.ts index 9d95161..1f2808d 100644 --- a/src/lib/apis/tmdb/tmdbApi.ts +++ b/src/lib/apis/tmdb/tmdbApi.ts @@ -1,9 +1,20 @@ import axios from 'axios'; import { PUBLIC_TMDB_API_KEY } from '$env/static/public'; import { request } from '$lib/utils'; -import type { paths } from './tmdb.generated'; +import type { operations, paths } from './tmdb.generated'; import createClient from 'openapi-fetch'; +export type SeriesDetails = + operations['tv-series-details']['responses']['200']['content']['application/json']; +export interface SeriesDetailsFull extends SeriesDetails { + videos: { + results: Video[]; + }; + credits: { + cast: CastMember[]; + }; +} + export const TmdbApiOpen = createClient({ baseUrl: 'https://api.themoviedb.org', headers: { @@ -16,9 +27,12 @@ export const getTmdbMovie = async (tmdbId: number) => params: { path: { movie_id: tmdbId + }, + query: { + append_to_response: 'videos,credits' } } - }).then((res) => res.data); + }).then((res) => res.data as TmdbMovieFull | undefined); export const getTmdbPopularMovies = () => TmdbApiOpen.get('/3/movie/popular', { @@ -39,6 +53,18 @@ export const getTmdbIdFromTvdbId = async (tvdbId: number) => .then((res) => res.data?.tv_results?.[0]) .then((res: any) => res?.id as number | undefined); +export const getTmdbSeries = async (tmdbId: number): Promise => + await TmdbApiOpen.get('/3/tv/{series_id}', { + params: { + path: { + series_id: tmdbId + }, + query: { + append_to_response: 'videos,credits' + } + } + }).then((res) => res.data as SeriesDetailsFull | undefined); + export const getTmdbSeriesImages = async (tmdbId: number) => TmdbApiOpen.get('/3/tv/{series_id}/images', { params: { @@ -75,13 +101,17 @@ export const fetchTmdbPopularMovies = () => export const requestTmdbPopularMovies = () => request(fetchTmdbPopularMovies, null); export interface TmdbMovieFull extends TmdbMovie { - videos: Video[]; - images: { - backdrops: Backdrop[]; - logos: Logo[]; - posters: Poster[]; + videos: { + results: Video[]; + }; + // images: { + // backdrops: Backdrop[]; + // logos: Logo[]; + // posters: Poster[]; + // }; + credits: { + cast: CastMember[]; }; - credits: CastMember[]; } export type MovieDetailsResponse = TmdbMovie; diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button.svelte index 812bc83..ba97989 100644 --- a/src/lib/components/Button.svelte +++ b/src/lib/components/Button.svelte @@ -11,7 +11,7 @@ export let href: string | undefined = undefined; export let target: string | undefined = undefined; - let buttonStyle; + let buttonStyle: string; $: buttonStyle = classNames( 'border-2 border-white transition-all uppercase tracking-widest text-xs whitespace-nowrap', { @@ -27,9 +27,9 @@ } ); - const handleClick = (event) => { + const handleClick = (event: MouseEvent) => { if (href) { - if (target === '_blank') window.open(href, target).focus(); + if (target === '_blank') window.open(href, target)?.focus(); else window.open(href, target as string); } else { dispatch('click', event); @@ -37,6 +37,7 @@ }; + diff --git a/src/lib/components/ResourceDetails/LibraryDetails.svelte b/src/lib/components/ResourceDetails/LibraryDetails.svelte index 8d3e163..1b669ad 100644 --- a/src/lib/components/ResourceDetails/LibraryDetails.svelte +++ b/src/lib/components/ResourceDetails/LibraryDetails.svelte @@ -9,7 +9,7 @@ import { log } from '$lib/utils.js'; let isRequestModalVisible = false; - export let tmdbId: string; + export let tmdbId: number; export let jellyfinStreamDisabled: boolean; export let openJellyfinStream: () => void; diff --git a/src/lib/components/ResourceDetails/ResourceDetails.svelte b/src/lib/components/ResourceDetails/ResourceDetails.svelte index b23b397..ccc88ea 100644 --- a/src/lib/components/ResourceDetails/ResourceDetails.svelte +++ b/src/lib/components/ResourceDetails/ResourceDetails.svelte @@ -1,20 +1,40 @@ -{#if movies[index]} - {#await Promise.all(movies)} -
- {:then awaitedMovies} - - - - {:catch err} - Error occurred {JSON.stringify(err)} - {/await} -{:else} +{#await moviesPromise}
-{/if} +{:then movies} + {@const movie = movies[index]} + g.name || '') || []} + runtime={movie?.runtime || 0} + tmdbRating={movie?.vote_average || 0} + starring={movie?.credits?.cast?.slice(0, 5)} + videos={movie.videos?.results || []} + backdropPath={movie?.backdrop_path || ''} + > + + +{:catch err} + Error occurred {JSON.stringify(err)} +{/await} {#await $library then libraryData} {#if libraryData.movies.filter((movie) => movie.continueWatching).length} diff --git a/src/routes/movie/[id]/+page.server.ts b/src/routes/movie/[id]/+page.server.ts index 71ba400..079482e 100644 --- a/src/routes/movie/[id]/+page.server.ts +++ b/src/routes/movie/[id]/+page.server.ts @@ -3,6 +3,6 @@ import type { PageServerLoad } from './$types'; export const load = (async ({ params }) => { return { - movie: await getTmdbMovie(params.id) + movie: await getTmdbMovie(Number(params.id)) }; }) satisfies PageServerLoad; diff --git a/src/routes/movie/[id]/+page.svelte b/src/routes/movie/[id]/+page.svelte index a2bf230..fff5931 100644 --- a/src/routes/movie/[id]/+page.svelte +++ b/src/routes/movie/[id]/+page.svelte @@ -1,9 +1,24 @@ {#if data.movie} - + {@const movie = data.movie} + g.name || '') || []} + runtime={movie?.runtime || 0} + tmdbRating={movie?.vote_average || 0} + starring={movie?.credits?.cast?.slice(0, 5)} + videos={movie.videos?.results || []} + backdropPath={movie?.backdrop_path || ''} + showDetails={true} + /> {/if} diff --git a/src/routes/series/[id]/+page.svelte b/src/routes/series/[id]/+page.svelte new file mode 100644 index 0000000..9582be9 --- /dev/null +++ b/src/routes/series/[id]/+page.svelte @@ -0,0 +1,40 @@ + + +{#if data.series} + {@const series = data.series} + {@const lastEpisode = series.last_episode_to_air} + g.name || '') || []} + runtime={series.episode_run_time?.[0] || 0} + tmdbRating={series.vote_average || 0} + starring={series.credits?.cast || []} + videos={series.videos?.results || []} + showDetails={true} + lastEpisode={lastEpisode?.still_path && lastEpisode?.name + ? { + backdropPath: lastEpisode.still_path, + name: lastEpisode.name, + runtime: lastEpisode.runtime || 0, + episodeTag: + (lastEpisode.season_number ? `S${lastEpisode.season_number}` : '') + + (lastEpisode.episode_number ? `E${lastEpisode.episode_number}` : '') + } + : undefined} + /> +{/if} diff --git a/src/routes/series/[id]/+page.ts b/src/routes/series/[id]/+page.ts new file mode 100644 index 0000000..9df4ade --- /dev/null +++ b/src/routes/series/[id]/+page.ts @@ -0,0 +1,8 @@ +import { getTmdbSeries } from '$lib/apis/tmdb/tmdbApi'; +import type { PageLoad } from './$types'; + +export const load = (async ({ params }) => { + return { + series: await getTmdbSeries(Number(params.id)) + }; +}) satisfies PageLoad; diff --git a/src/routes/show/[id]/+page.svelte b/src/routes/show/[id]/+page.svelte deleted file mode 100644 index 1dacaf2..0000000 --- a/src/routes/show/[id]/+page.svelte +++ /dev/null @@ -1,6 +0,0 @@ - - -
TV Show of {data.tmdbId}
diff --git a/src/routes/show/[id]/+page.ts b/src/routes/show/[id]/+page.ts deleted file mode 100644 index 1d56513..0000000 --- a/src/routes/show/[id]/+page.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { PageLoad } from './$types'; - -export const load = (({ params }) => ({ tmdbId: params.id })) satisfies PageLoad; diff --git a/svelte.config.js b/svelte.config.js index caa0677..bb44c60 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -17,7 +17,7 @@ const config = { vitePlugin: { experimental: { inspector: { - toggleKeyCombo: 'meta', + // toggleKeyCombo: 'meta', holdMode: true } }