mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-23 01:05:13 +02:00
feat: show recently played from library on front pages
This commit is contained in:
@@ -166,13 +166,21 @@ export interface PaginatedResponseDto {
|
||||
export interface MovieDto {
|
||||
id?: string;
|
||||
tmdbId: string;
|
||||
tmdbMovie?: object;
|
||||
}
|
||||
|
||||
export interface Series {
|
||||
id?: string;
|
||||
tmdbId: string;
|
||||
tmdbSeries?: object;
|
||||
}
|
||||
|
||||
export interface LibraryItemDto {
|
||||
tmdbId: string;
|
||||
mediaType: 'Movie' | 'Series' | 'Episode';
|
||||
playStates?: PlayStateDto[];
|
||||
metadata?: MovieDto;
|
||||
movieMetadata?: MovieDto;
|
||||
seriesMetadata?: Series;
|
||||
}
|
||||
|
||||
export interface SuccessResponseDto {
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
{:then items} -->
|
||||
{#each items as item}
|
||||
<TmdbCard
|
||||
item={'tmdbMovie' in item ? item.tmdbMovie : item.tmdbSeries}
|
||||
item={item.metadata}
|
||||
progress={item.playStates?.[0]?.progress || 0}
|
||||
on:enter={scrollIntoView({ all: 64 })}
|
||||
size="dynamic"
|
||||
|
||||
@@ -1,19 +1,39 @@
|
||||
<script lang="ts">
|
||||
import Container from '$components/Container.svelte';
|
||||
import HeroShowcase from '../components/HeroShowcase/HeroShowcase.svelte';
|
||||
import { TMDB_MOVIE_GENRES, TmdbApi, tmdbApi } from '../apis/tmdb/tmdb-api';
|
||||
import { getShowcasePropsFromTmdbMovie } from '../components/HeroShowcase/HeroShowcase';
|
||||
import Carousel from '../components/Carousel/Carousel.svelte';
|
||||
import { scrollIntoView } from '../selectable';
|
||||
import { libraryItemsDataStore } from '$lib/stores/data.store';
|
||||
import { derived } from 'svelte/store';
|
||||
import { jellyfinApi } from '../apis/jellyfin/jellyfin-api';
|
||||
import JellyfinCard from '../components/Card/JellyfinCard.svelte';
|
||||
import { formatDateToYearMonthDay } from '../utils';
|
||||
import { TMDB_MOVIE_GENRES, TmdbApi, tmdbApi } from '../apis/tmdb/tmdb-api';
|
||||
import TmdbCard from '../components/Card/TmdbCard.svelte';
|
||||
import { navigate } from '../components/StackRouter/StackRouter';
|
||||
import Carousel from '../components/Carousel/Carousel.svelte';
|
||||
import DetachedPage from '../components/DetachedPage/DetachedPage.svelte';
|
||||
import { getShowcasePropsFromTmdbMovie } from '../components/HeroShowcase/HeroShowcase';
|
||||
import HeroShowcase from '../components/HeroShowcase/HeroShowcase.svelte';
|
||||
import { navigate } from '../components/StackRouter/StackRouter';
|
||||
import { scrollIntoView } from '../selectable';
|
||||
import { formatDateToYearMonthDay } from '../utils';
|
||||
|
||||
const continueWatching = jellyfinApi.getContinueWatching('movie');
|
||||
const recentlyAdded = jellyfinApi.getRecentlyAdded('movie');
|
||||
const { ...libraryData } = libraryItemsDataStore.getRequest();
|
||||
const libraryContinueWatching = derived(libraryData, (libraryData) => {
|
||||
if (!libraryData) return [];
|
||||
|
||||
const movies = libraryData.filter((i) => i.mediaType === 'Movie' && i.playStates?.length);
|
||||
|
||||
movies.sort((a, b) => {
|
||||
const aMax = Math.max(
|
||||
...(a.playStates?.map((p) => new Date(p.lastPlayedAt).getTime()) || [0])
|
||||
);
|
||||
const bMax = Math.max(
|
||||
...(b.playStates?.map((p) => new Date(p.lastPlayedAt).getTime()) || [0])
|
||||
);
|
||||
|
||||
return bMax - aMax;
|
||||
});
|
||||
|
||||
return movies.map((i) => i.metadata);
|
||||
});
|
||||
|
||||
// const continueWatching = jellyfinApi.getContinueWatching('movie');
|
||||
// const recentlyAdded = jellyfinApi.getRecentlyAdded('movie');
|
||||
|
||||
const popularMovies = tmdbApi.getPopularMovies();
|
||||
|
||||
@@ -69,7 +89,16 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="my-16 space-y-8 relative z-10">
|
||||
{#await continueWatching then continueWatching}
|
||||
{#if $libraryContinueWatching.length}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Continue Watching</span>
|
||||
{#each $libraryContinueWatching as item}
|
||||
<TmdbCard on:enter={scrollIntoView({ horizontal: 128 })} size="lg" {item} />
|
||||
{/each}
|
||||
</Carousel>
|
||||
{/if}
|
||||
|
||||
<!-- {#await continueWatching then continueWatching}
|
||||
{#if continueWatching?.length}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Continue Watching</span>
|
||||
@@ -89,7 +118,7 @@
|
||||
{/if}
|
||||
{/await}
|
||||
{/if}
|
||||
{/await}
|
||||
{/await} -->
|
||||
|
||||
{#await popularMovies then popularMovies}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
|
||||
@@ -12,9 +12,31 @@
|
||||
import { navigate } from '../components/StackRouter/StackRouter';
|
||||
import { TMDB_SERIES_GENRES } from '../apis/tmdb/tmdb-api.js';
|
||||
import DetachedPage from '../components/DetachedPage/DetachedPage.svelte';
|
||||
import { libraryItemsDataStore } from '$lib/stores/data.store';
|
||||
import { derived } from 'svelte/store';
|
||||
|
||||
const continueWatching = jellyfinApi.getContinueWatchingSeries();
|
||||
const recentlyAdded = jellyfinApi.getRecentlyAdded('series');
|
||||
const { ...libraryData } = libraryItemsDataStore.getRequest();
|
||||
const libraryContinueWatching = derived(libraryData, (libraryData) => {
|
||||
if (!libraryData) return [];
|
||||
|
||||
const series = libraryData.filter((i) => i.mediaType === 'Series' && i.playStates?.length);
|
||||
|
||||
series.sort((a, b) => {
|
||||
const aMax = Math.max(
|
||||
...(a.playStates?.map((p) => new Date(p.lastPlayedAt).getTime()) || [0])
|
||||
);
|
||||
const bMax = Math.max(
|
||||
...(b.playStates?.map((p) => new Date(p.lastPlayedAt).getTime()) || [0])
|
||||
);
|
||||
|
||||
return bMax - aMax;
|
||||
});
|
||||
|
||||
return series.map((i) => i.metadata);
|
||||
});
|
||||
|
||||
// const continueWatching = jellyfinApi.getContinueWatchingSeries();
|
||||
// const recentlyAdded = jellyfinApi.getRecentlyAdded('series');
|
||||
|
||||
const nowStreaming = getNowStreaming();
|
||||
const upcomingSeries = fetchUpcomingSeries();
|
||||
@@ -62,7 +84,16 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="my-16 space-y-8 relative z-10">
|
||||
{#await continueWatching then continueWatching}
|
||||
{#if $libraryContinueWatching.length}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Continue Watching</span>
|
||||
{#each $libraryContinueWatching as item}
|
||||
<TmdbCard on:enter={scrollIntoView({ horizontal: 128 })} size="lg" {item} />
|
||||
{/each}
|
||||
</Carousel>
|
||||
{/if}
|
||||
|
||||
<!-- {#await continueWatching then continueWatching}
|
||||
{#if continueWatching?.length}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Continue Watching</span>
|
||||
@@ -82,7 +113,7 @@
|
||||
{/if}
|
||||
{/await}
|
||||
{/if}
|
||||
{/await}
|
||||
{/await} -->
|
||||
|
||||
{#await popular then popular}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { derived, get, type Readable, writable } from 'svelte/store';
|
||||
import { jellyfinApi } from '../apis/jellyfin/jellyfin-api';
|
||||
import { tmdbApi, type TmdbMovieFull2, type TmdbSeries2 } from '../apis/tmdb/tmdb-api';
|
||||
import {
|
||||
tmdbApi,
|
||||
type TmdbMovieFull2,
|
||||
type TmdbSeries2,
|
||||
type TmdbSeriesFull2
|
||||
} from '../apis/tmdb/tmdb-api';
|
||||
import { awaitAppInitialization, reiverrApiNew, user } from './user.store';
|
||||
|
||||
type AwaitableStoreValue<R, T = { data?: R }> = {
|
||||
@@ -236,16 +241,12 @@ export const libraryItemsDataStore = useRequestsStore(() =>
|
||||
reiverrApiNew.users
|
||||
.getLibraryItems(get(user)?.id as string)
|
||||
.then((r) =>
|
||||
Promise.all(
|
||||
r.data.items.map((i) =>
|
||||
i.mediaType === 'Movie'
|
||||
? tmdbApi
|
||||
.getTmdbMovie(Number(i.tmdbId))
|
||||
.then((movie) => ({ tmdbMovie: movie!, playStates: i.playStates }))
|
||||
: tmdbApi
|
||||
.getTmdbSeries(Number(i.tmdbId))
|
||||
.then((series) => ({ tmdbSeries: series!, playStates: i.playStates }))
|
||||
)
|
||||
).then((i) => i.filter((i) => ('tmdbMovie' in i ? !!i.tmdbMovie : !!i.tmdbSeries)))
|
||||
r.data.items.map((i) => ({
|
||||
...i,
|
||||
metadata:
|
||||
(i.movieMetadata?.tmdbMovie as TmdbMovieFull2) ||
|
||||
(i.seriesMetadata?.tmdbSeries as TmdbSeriesFull2)
|
||||
}))
|
||||
)
|
||||
.then((i) => i.filter((i) => !!i.metadata))
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user