diff --git a/src/lib/apis/tmdb/tmdbApi.ts b/src/lib/apis/tmdb/tmdbApi.ts index 1f2808d..f4a6028 100644 --- a/src/lib/apis/tmdb/tmdbApi.ts +++ b/src/lib/apis/tmdb/tmdbApi.ts @@ -65,6 +65,16 @@ export const getTmdbSeries = async (tmdbId: number): Promise res.data as SeriesDetailsFull | undefined); +export const getTmdbSeriesSeason = async (tmdbId: number, season: number) => + TmdbApiOpen.get('/3/tv/{series_id}/season/{season_number}', { + params: { + path: { + series_id: tmdbId, + season_number: season + } + } + }).then((res) => res.data); + export const getTmdbSeriesImages = async (tmdbId: number) => TmdbApiOpen.get('/3/tv/{series_id}/images', { params: { diff --git a/src/lib/components/Card/Card.svelte b/src/lib/components/Card/Card.svelte index 457793b..1c8b517 100644 --- a/src/lib/components/Card/Card.svelte +++ b/src/lib/components/Card/Card.svelte @@ -16,7 +16,7 @@ export let available = true; export let progress = 0; - export let size: 'dynamic' | 'normal' | 'large' = 'normal'; + export let size: 'dynamic' | 'md' | 'large' = 'md'; export let randomProgress = false; if (randomProgress) { progress = Math.random() > 0.3 ? Math.random() * 100 : 0; @@ -25,7 +25,7 @@
- + - +
(scrollX = carousel.scrollLeft)} + on:scroll={() => (scrollX = carousel?.scrollLeft || scrollX)} >
- {#if scrollX > 0} + {#if scrollX > 50}
{/if} -
+ {#if carousel && scrollX < carousel?.scrollWidth - carousel?.clientWidth - 50} +
+ {/if}
diff --git a/src/lib/components/Carousel/CarouselPlaceholderItems.svelte b/src/lib/components/Carousel/CarouselPlaceholderItems.svelte index d84a4f5..3a11c67 100644 --- a/src/lib/components/Carousel/CarouselPlaceholderItems.svelte +++ b/src/lib/components/Carousel/CarouselPlaceholderItems.svelte @@ -1,6 +1,6 @@ {#each Array(10) as _, i (i)} diff --git a/src/lib/components/Carousel/UICarousel.svelte b/src/lib/components/Carousel/UICarousel.svelte new file mode 100644 index 0000000..6d52a6e --- /dev/null +++ b/src/lib/components/Carousel/UICarousel.svelte @@ -0,0 +1,7 @@ + + +
+ +
diff --git a/src/lib/components/EpisodeCard/EpisodeCard.svelte b/src/lib/components/EpisodeCard/EpisodeCard.svelte new file mode 100644 index 0000000..42c6b6a --- /dev/null +++ b/src/lib/components/EpisodeCard/EpisodeCard.svelte @@ -0,0 +1,55 @@ + + +
+
+
+
+ + {episodeTag} + +
+
+ {runtime} min +
+
+
+
{subtitle}
+
+ {title} +
+
+
+
+
+ + + +
+
+
diff --git a/src/lib/components/Navbar/TitleSearchModal.svelte b/src/lib/components/Navbar/TitleSearchModal.svelte index f24c4a3..1cde9d8 100644 --- a/src/lib/components/Navbar/TitleSearchModal.svelte +++ b/src/lib/components/Navbar/TitleSearchModal.svelte @@ -70,7 +70,7 @@ {#each results.filter((m) => m).slice(0, 5) as result}
(window.location.href = '/movie/' + result.id)} >
toggleShowDetails(release.guid)} >
diff --git a/src/lib/components/ResourceDetails/ResourceDetails.svelte b/src/lib/components/ResourceDetails/ResourceDetails.svelte index ccc88ea..ddbe64e 100644 --- a/src/lib/components/ResourceDetails/ResourceDetails.svelte +++ b/src/lib/components/ResourceDetails/ResourceDetails.svelte @@ -6,12 +6,14 @@ import { formatMinutesToTime } from '$lib/utils'; import classNames from 'classnames'; import { ChevronDown, Clock, Play, TriangleRight } from 'radix-icons-svelte'; - import { getContext } from 'svelte'; + import { getContext, type ComponentProps } from 'svelte'; import { fade, fly } from 'svelte/transition'; import HeightHider from '../HeightHider.svelte'; import type { PlayerState } from '../VideoPlayer/VideoPlayer'; import LibraryDetails from './LibraryDetails.svelte'; import IconButton from '../IconButton.svelte'; + import SeasonsDetails from './SeasonsDetails.svelte'; + import EpisodeCard from '../EpisodeCard/EpisodeCard.svelte'; export let tmdbId: number; export let type: 'movie' | 'tv'; @@ -30,9 +32,7 @@ export let tmdbRating: number; export let starring: CastMember[]; - export let lastEpisode: - | { backdropPath: string; name: string; episodeTag: string; runtime: number } - | undefined = undefined; + export let lastEpisode: ComponentProps | undefined = undefined; export let videos: Video[]; export let showDetails = false; @@ -54,20 +54,6 @@ // Transitions const duration = 200; - const monthNames = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December' - ]; const { playerState, close, streamJellyfinId } = getContext('player'); function openTrailer() { @@ -157,7 +143,7 @@ />
{monthNames[releaseDate.getMonth()]}{releaseDate.toLocaleString('en', { month: 'long' })} {releaseDate.getFullYear()} {/if} @@ -243,7 +229,7 @@ class="flex flex-col gap-6 justify-between 2xl:w-96 xl:w-80 lg:w-64 w-52 row-span-full" style={opacityStyle} > -
+

Details

@@ -303,39 +289,8 @@ {/if}
{#if lastEpisode} -
-
-
-
- {lastEpisode.episodeTag} -
-
- {lastEpisode.runtime} min -
-
-
-
- Next Episode -
-
- {lastEpisode.name} -
-
-
-
-
- - - -
-
+
+
{/if}
@@ -346,6 +301,11 @@
+ {#key tmdbId} + {#if type === 'tv' && seasons > 0} + + {/if} + {/key}
{#key tmdbId} + import { getTmdbSeriesSeason } from '$lib/apis/tmdb/tmdbApi'; + import classNames from 'classnames'; + import EpisodeCard from '../EpisodeCard/EpisodeCard.svelte'; + import Carousel from '../Carousel/Carousel.svelte'; + import CarouselPlaceholderItems from '../Carousel/CarouselPlaceholderItems.svelte'; + import { Star, StarFilled } from 'radix-icons-svelte'; + import UiCarousel from '../Carousel/UICarousel.svelte'; + + export let tmdbId: number; + export let totalSeasons: number; + let visibleSeason = 1; + + async function fetchSeasons(seasons: number) { + const promises = [...Array(seasons).keys()].map((i) => getTmdbSeriesSeason(tmdbId, i + 1)); + + console.log(promises); + + return Promise.all(promises); + } + + +
+ {#await fetchSeasons(totalSeasons)} + +
+ {#each [...Array(3).keys()] as season} +
+ Season 1 +
+ {/each} +
+ +
+ {:then seasons} +
+
+ {#each seasons as season} +
+ + + {#each seasons as season} + + {/each} + + {#each season?.episodes || [] as episode} + {@const upcoming = + new Date(episode.air_date || Date.now()) > new Date() || episode.runtime === null} +
+ +
+ {#if upcoming} + {@const date = new Date(episode.air_date || Date.now())} + + {:else} + {episode.vote_average?.toFixed(1)} + + {/if} +
+
+
+ {/each} +
+
+ {/each} +
+
+ {/await} +
diff --git a/src/lib/components/SetupRequired/SetupRequired.svelte b/src/lib/components/SetupRequired/SetupRequired.svelte index 4a4c560..d3af0e8 100644 --- a/src/lib/components/SetupRequired/SetupRequired.svelte +++ b/src/lib/components/SetupRequired/SetupRequired.svelte @@ -10,7 +10,7 @@

    {#each Object.keys(missingEnvironmentVariables).filter((k) => missingEnvironmentVariables[k]) as variableName} - {variableName} + {variableName} {/each}
diff --git a/src/routes/series/[id]/+page.svelte b/src/routes/series/[id]/+page.svelte index 9582be9..a60a542 100644 --- a/src/routes/series/[id]/+page.svelte +++ b/src/routes/series/[id]/+page.svelte @@ -29,7 +29,8 @@ lastEpisode={lastEpisode?.still_path && lastEpisode?.name ? { backdropPath: lastEpisode.still_path, - name: lastEpisode.name, + title: lastEpisode.name, + subtitle: 'Latest Episode', runtime: lastEpisode.runtime || 0, episodeTag: (lastEpisode.season_number ? `S${lastEpisode.season_number}` : '') + diff --git a/tailwind.config.js b/tailwind.config.js index c8013fb..4f235ff 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -9,7 +9,7 @@ export default { }, colors: { darken: '#07050199', - 'highlight-dim': '#fde68a20' + lighten: '#fde68a20' } } },