feat: Add recommendations, cast and more info to movie page

This commit is contained in:
Aleksi Lassila
2024-05-31 01:36:48 +03:00
parent 4c3dde4464
commit 8f561bfa7f
2 changed files with 191 additions and 103 deletions

View File

@@ -194,22 +194,37 @@ export class TmdbApi implements Api<paths> {
.then((res) => res.data);
getPopularSeries = () =>
TmdbApiOpen.GET('/3/tv/popular', {
this.getClient()
.GET('/3/tv/popular', {
params: {
query: {
language: get(settings)?.language
}
}
}).then((res) => res.data?.results || []);
})
.then((res) => res.data?.results || []);
getSeriesRecommendations = (tmdbId: number) =>
TmdbApiOpen.GET('/3/tv/{series_id}/recommendations', {
this.getClient()
.GET('/3/tv/{series_id}/recommendations', {
params: {
path: {
series_id: tmdbId
}
}
}).then((res) => res.data?.results || []);
})
.then((res) => res.data?.results || []);
getMovieRecommendations = (tmdbId: number) =>
this.getClient()
.GET('/3/movie/{movie_id}/recommendations', {
params: {
path: {
movie_id: tmdbId
}
}
})
.then((res) => res.data?.results || []);
getEpisode = (
seriesId: number,

View File

@@ -12,10 +12,15 @@
import DetachedPage from '../components/DetachedPage/DetachedPage.svelte';
import { openMovieMediaManager } from '../components/Modal/modal.store';
import { playerState } from '../components/VideoPlayer/VideoPlayer';
import { scrollIntoView } from '../selectable';
import Carousel from '../components/Carousel/Carousel.svelte';
import TmdbPersonCard from '../components/PersonCard/TmdbPersonCard.svelte';
import TmdbCard from '../components/Card/TmdbCard.svelte';
export let id: string;
const { promise: movieDataP } = useRequest(tmdbApi.getTmdbMovie, Number(id));
$: recommendations = tmdbApi.getMovieRecommendations(Number(id));
const { promise: jellyfinItemP } = useRequest(
(id: string) => jellyfinApi.getLibraryItemFromTmdbId(id),
id
@@ -32,7 +37,11 @@
</script>
<DetachedPage let:handleGoBack let:registrar>
<div class="min-h-screen flex flex-col py-12 px-20 relative">
<div class="relative">
<Container
class="h-[calc(100vh-4rem)] flex flex-col py-16 px-32"
on:enter={scrollIntoView({ top: 999 })}
>
<HeroCarousel
urls={$movieDataP.then(
(movie) =>
@@ -83,7 +92,7 @@
class="flex mt-8"
focusOnMount
on:back={handleGoBack}
{registrar}
on:mount={registrar}
>
{#if jellyfinItem}
<Button
@@ -128,5 +137,69 @@
{/await}
</div>
</HeroCarousel>
</Container>
<Container on:enter={scrollIntoView({ top: 0 })} class="">
{#await $movieDataP then movie}
<Carousel scrollClass="px-32" class="mb-8">
<div slot="header">Show Cast</div>
{#each movie?.credits?.cast?.slice(0, 15) || [] as credit}
<TmdbPersonCard on:enter={scrollIntoView({ horizontal: 128 })} tmdbCredit={credit} />
{/each}
</Carousel>
{/await}
{#await recommendations then recommendations}
<Carousel scrollClass="px-32" class="mb-8">
<div slot="header">Recommendations</div>
{#each recommendations || [] as recommendation}
<TmdbCard item={recommendation} on:enter={scrollIntoView({ horizontal: 128 })} />
{/each}
</Carousel>
{/await}
</Container>
{#await $movieDataP then movie}
<Container class="flex-1 bg-secondary-950 pt-8 px-32" on:enter={scrollIntoView({ top: 0 })}>
<h1 class="font-medium tracking-wide text-2xl text-zinc-300 mb-8">More Information</h1>
<div class="text-zinc-300 font-medium text-lg flex flex-wrap">
<div class="flex-1">
<div class="mb-8">
<h2 class="uppercase text-sm font-semibold text-zinc-500 mb-0.5">Directed By</h2>
<div>
{movie?.credits.crew
?.filter((c) => c.job === 'Director')
?.map((c) => c.name)
.join(', ')}
</div>
</div>
<div class="mb-8">
<h2 class="uppercase text-sm font-semibold text-zinc-500 mb-0.5">Written By</h2>
<div>
{movie?.credits.crew
?.filter((c) => c.job === 'Writer')
?.map((c) => c.name)
.join(', ')}
</div>
</div>
</div>
<div class="flex-1">
<div class="mb-8">
<h2 class="uppercase text-sm font-semibold text-zinc-500 mb-0.5">Languages</h2>
<div>
{movie?.spoken_languages?.map((language) => language.name).join(', ')}
</div>
</div>
<div class="mb-8">
<h2 class="uppercase text-sm font-semibold text-zinc-500 mb-0.5">Release Date</h2>
<div>
{new Date(movie?.release_date || 0).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
})}
</div>
</div>
</div>
</div>
</Container>
{/await}
</div>
</DetachedPage>