window.open('/movie/' + tmdbId, '_self')}
+ class="h-full w-full opacity-0 hover:opacity-100 transition-opacity flex flex-col justify-between cursor-pointer p-2 px-3 relative z-[1] peer"
+ style={progress > 0 ? 'padding-bottom: 0.6rem;' : ''}
>
-
-
window.open('/movie/' + tmdbMovie.id, '_self')}
- class="h-full w-full opacity-0 hover:opacity-100 transition-opacity flex flex-col justify-between cursor-pointer p-2 px-3 relative z-[1] peer"
- style={progress > 0 ? 'padding-bottom: 0.6rem;' : ''}
- >
-
-
{tmdbMovie.original_title}
-
- {formatGenres(tmdbMovie.genres)}
-
-
-
- {#if progressType === 'watched'}
-
- {progress
- ? formatMinutesToTime(tmdbMovie.runtime - tmdbMovie.runtime * (progress / 100)) +
- ' left'
- : formatMinutesToTime(tmdbMovie.runtime)}
-
- {:else if progressType === 'downloading'}
-
- {Math.floor(progress) + '% Downloaded'}
-
- {/if}
+
+
{title}
+
+ {genres.map((genre) => genre.charAt(0).toUpperCase() + genre.slice(1)).join(', ')}
-
-
+
+ {#if completionTime}
+
+ Downloaded in {formatMinutesToTime((new Date(completionTime).getTime() - Date.now()) / 1000 / 60)}
+
+ {:else}
+ {#if runtimeMinutes}
+
+
+
+ {progress
+ ? formatMinutesToTime(runtimeMinutes - runtimeMinutes * (progress / 100)) + ' left'
+ : formatMinutesToTime(runtimeMinutes)}
+
+
+ {/if}
+
+ {#if rating}
+
+
+
+ {rating.toFixed(1)}
+
+
+ {/if}
+ {/if}
+
-{/if}
+
+
+
diff --git a/src/routes/components/Card/CardProvider.svelte b/src/routes/components/Card/CardProvider.svelte
new file mode 100644
index 0000000..21a380b
--- /dev/null
+++ b/src/routes/components/Card/CardProvider.svelte
@@ -0,0 +1,38 @@
+
+
+{#await Promise.all([tmdbMoviePromise, jellyfinItemPromise, backdropUrlPromise])}
+
+{:then [tmdbMovie, jellyfinItem, backdropUrl]}
+
+{:catch err}
+ Error
+{/await}
diff --git a/src/routes/components/Card/card.ts b/src/routes/components/Card/card.ts
new file mode 100644
index 0000000..c88bf91
--- /dev/null
+++ b/src/routes/components/Card/card.ts
@@ -0,0 +1,42 @@
+import type { RadarrMovie } from '$lib/radarr/radarr';
+import { fetchTmdbMovieImages } from '$lib/tmdb-api';
+import type { TmdbMovie } from '$lib/tmdb-api';
+
+export interface CardProps {
+ tmdbId: string;
+ title: string;
+ genres: string[];
+ runtimeMinutes: number;
+ backdropUrl: string;
+ rating: number;
+}
+
+export const fetchCardProps = async (movie: RadarrMovie): Promise
=> {
+ const backdropUrl = fetchTmdbMovieImages(String(movie.tmdbId)).then(
+ (r) => r.backdrops.filter((b) => b.iso_639_1 === 'en')[0].file_path
+ );
+
+ return {
+ tmdbId: String(movie.tmdbId),
+ title: String(movie.title),
+ genres: movie.genres as string[],
+ runtimeMinutes: movie.runtime as any,
+ backdropUrl: await backdropUrl,
+ rating: movie.ratings?.tmdb?.value || movie.ratings?.imdb?.value || 0
+ };
+};
+
+export const fetchCardPropsTmdb = async (movie: TmdbMovie): Promise => {
+ const backdropUrl = fetchTmdbMovieImages(String(movie.id))
+ .then((r) => r.backdrops.filter((b) => b.iso_639_1 === 'en')[0]?.file_path)
+ .catch(console.error);
+
+ return {
+ tmdbId: String(movie.id),
+ title: String(movie.original_title),
+ genres: movie.genres.map((g) => g.name),
+ runtimeMinutes: movie.runtime,
+ backdropUrl: (await backdropUrl) || '',
+ rating: movie.vote_average || 0
+ };
+};
diff --git a/src/routes/discover/+page.server.ts b/src/routes/discover/+page.server.ts
new file mode 100644
index 0000000..2b1a87e
--- /dev/null
+++ b/src/routes/discover/+page.server.ts
@@ -0,0 +1,19 @@
+import type { PageServerLoad } from './$types';
+import { fetchTmdbMovie, fetchTmdbPopularMovies } from '$lib/tmdb-api';
+import { fetchCardPropsTmdb } from '../components/Card/card';
+
+export const load = (() => {
+ const popularMoviesPromise = fetchTmdbPopularMovies();
+
+ const popularMovies = popularMoviesPromise.then((movies) => {
+ return Promise.all(
+ movies.map(async (movie) => fetchCardPropsTmdb(await fetchTmdbMovie(String(movie.id))))
+ );
+ });
+
+ return {
+ streamed: {
+ popularMovies
+ }
+ };
+}) satisfies PageServerLoad;
diff --git a/src/routes/discover/+page.svelte b/src/routes/discover/+page.svelte
index 414d8ff..823666e 100644
--- a/src/routes/discover/+page.svelte
+++ b/src/routes/discover/+page.svelte
@@ -1,5 +1,4 @@
@@ -25,11 +20,11 @@
- {#await popularMovies}
+ {#await data.streamed.popularMovies}
{:then movies}
- {#each movies ? [...movies].reverse() : [] as movie (movie.id)}
-
+ {#each movies ? [...movies].reverse() : [] as movie (movie.tmdbId)}
+
{/each}
{/await}
@@ -37,11 +32,11 @@
- {#await popularMovies}
+ {#await data.streamed.popularMovies}
{:then movies}
- {#each movies || [] as movie (movie.id)}
-
+ {#each movies || [] as movie (movie.tmdbId)}
+
{/each}
{/await}
diff --git a/src/routes/library/+page.server.ts b/src/routes/library/+page.server.ts
index 636db49..0250887 100644
--- a/src/routes/library/+page.server.ts
+++ b/src/routes/library/+page.server.ts
@@ -1,5 +1,7 @@
import type { PageServerLoad } from './$types';
import { RadarrApi } from '$lib/radarr/radarr';
+import type { CardProps } from '../components/Card/card';
+import { fetchCardProps } from '../components/Card/card';
export const load = (() => {
const radarrMovies = RadarrApi.get('/api/v3/movie', {
@@ -14,42 +16,60 @@ export const load = (() => {
}
}).then((r) => r.data?.records?.filter((record) => record.movie));
- const downloading = downloadingRadarrMovies.then(async (movies) => {
- return movies?.map((m) => ({
- tmdbId: m.movie?.tmdbId,
- size: m.size,
- sizeleft: m.sizeleft
- }));
- });
-
- const unavailable = radarrMovies.then(async (movies) => {
- const downloadingMovies = await downloading;
- return movies?.filter(
- (m) =>
- (!m.movieFile || !m.hasFile || !m.isAvailable) &&
- !downloadingMovies?.find((d) => d.tmdbId === m.tmdbId)
+ const unavailable: Promise = radarrMovies.then(async (movies) => {
+ const downloadingMovies = await downloadingRadarrMovies;
+ return await Promise.all(
+ movies
+ ?.filter(
+ (m) =>
+ (!m.movieFile || !m.movieFile || !m.isAvailable) &&
+ !downloadingMovies?.find((d) => d.movie?.tmdbId === m.tmdbId)
+ )
+ .map(async (m) => fetchCardProps(m)) || []
);
});
- const available = radarrMovies.then(async (movies) => {
+ const available: Promise = radarrMovies.then(async (movies) => {
const downloadingMovies = await downloading;
const unavailableMovies = await unavailable;
if (!downloadingMovies || !movies) return [];
- return movies
- .filter((movie) => {
- return !downloadingMovies.find((downloadingMovie) => downloadingMovie.tmdbId === movie.id);
- })
- .filter(
- (movie) => !unavailableMovies?.find((unavailableMovie) => unavailableMovie.id === movie.id)
- );
+ return await Promise.all(
+ movies
+ .filter((movie) => {
+ return !downloadingMovies.find(
+ (downloadingMovie) => downloadingMovie.tmdbId === String(movie.tmdbId)
+ );
+ })
+ .filter(
+ (movie) =>
+ !unavailableMovies?.find(
+ (unavailableMovie) => unavailableMovie.tmdbId === String(movie.tmdbId)
+ )
+ )
+ .map(async (m) => fetchCardProps(m)) || []
+ );
});
+ const downloading: Promise = downloadingRadarrMovies.then(async (movies) => {
+ return Promise.all(
+ movies
+ ?.filter((m) => m?.movie?.tmdbId)
+ ?.map(async (m) => ({
+ ...(await fetchCardProps(m.movie as any)),
+ progress: m.sizeleft && m.size ? ((m.size - m.sizeleft) / m.size) * 100 : 0,
+ completionTime: m.estimatedCompletionTime
+ })) || []
+ );
+ });
+
+ // radarrMovies.then((d) => console.log(d.map((m) => m.ratings)));
+
return {
streamed: {
- available,
downloading,
+ available,
unavailable
}
};
diff --git a/src/routes/library/+page.svelte b/src/routes/library/+page.svelte
index 30f16b9..98b9a70 100644
--- a/src/routes/library/+page.svelte
+++ b/src/routes/library/+page.svelte
@@ -1,10 +1,9 @@