feat: Personalized tmdb recommendations
This commit is contained in:
@@ -34,6 +34,14 @@ export class JellyfinSettings {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export class TmdbSettings {
|
||||
@ApiProperty({ required: true })
|
||||
sessionId: string;
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export class Settings {
|
||||
@ApiProperty({ required: true })
|
||||
autoplayTrailers: boolean;
|
||||
@@ -52,6 +60,8 @@ export class Settings {
|
||||
radarr: RadarrSettings;
|
||||
@ApiProperty({ required: true, type: JellyfinSettings })
|
||||
jellyfin: JellyfinSettings;
|
||||
@ApiProperty({ required: true, type: TmdbSettings })
|
||||
tmdb: TmdbSettings;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: Settings = {
|
||||
@@ -81,6 +91,10 @@ const DEFAULT_SETTINGS: Settings = {
|
||||
baseUrl: '',
|
||||
userId: '',
|
||||
},
|
||||
tmdb: {
|
||||
sessionId: '',
|
||||
userId: '',
|
||||
},
|
||||
};
|
||||
|
||||
@Entity()
|
||||
|
||||
5
src/lib/apis/reiverr/reiverr.generated.d.ts
vendored
5
src/lib/apis/reiverr/reiverr.generated.d.ts
vendored
@@ -42,6 +42,10 @@ export interface components {
|
||||
baseUrl: string;
|
||||
userId: string;
|
||||
};
|
||||
TmdbSettings: {
|
||||
sessionId: string;
|
||||
userId: string;
|
||||
};
|
||||
Settings: {
|
||||
autoplayTrailers: boolean;
|
||||
language: string;
|
||||
@@ -49,6 +53,7 @@ export interface components {
|
||||
sonarr: components["schemas"]["SonarrSettings"];
|
||||
radarr: components["schemas"]["RadarrSettings"];
|
||||
jellyfin: components["schemas"]["JellyfinSettings"];
|
||||
tmdb: components["schemas"]["TmdbSettings"];
|
||||
};
|
||||
UserDto: {
|
||||
id: string;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { TMDB_API_KEY, TMDB_BACKDROP_SMALL } from '../../constants';
|
||||
import { settings } from '../../stores/settings.store';
|
||||
import type { TitleType } from '../../types';
|
||||
import type { Api } from '../api.interface';
|
||||
import { appState } from '../../stores/app-state.store';
|
||||
|
||||
const CACHE_ONE_DAY = 'max-age=86400';
|
||||
const CACHE_FOUR_DAYS = 'max-age=345600';
|
||||
@@ -59,6 +60,14 @@ export class TmdbApi implements Api<paths> {
|
||||
return TmdbApi.getClient();
|
||||
}
|
||||
|
||||
getSessionId() {
|
||||
return get(appState)?.user?.settings.tmdb.sessionId;
|
||||
}
|
||||
|
||||
getUserId() {
|
||||
return get(appState)?.user?.settings.tmdb.userId;
|
||||
}
|
||||
|
||||
// MOVIES
|
||||
|
||||
getTmdbMovie = async (tmdbId: number) => {
|
||||
@@ -203,6 +212,46 @@ export class TmdbApi implements Api<paths> {
|
||||
.then((res) => res.data);
|
||||
|
||||
// OTHER
|
||||
|
||||
// USER
|
||||
|
||||
getRecommendedMovies = async (): Promise<TmdbMovie2[]> => {
|
||||
const userId = this.getUserId();
|
||||
if (!userId) return [];
|
||||
|
||||
return (
|
||||
this.getClient()
|
||||
// @ts-ignore
|
||||
?.GET('/4/account/{account_object_id}/movie/recommendations', {
|
||||
params: {
|
||||
path: {
|
||||
account_object_id: userId
|
||||
}
|
||||
}
|
||||
})
|
||||
.then((res: any) => res.data?.results || [])
|
||||
);
|
||||
};
|
||||
|
||||
getRecommendedSeries = async (): Promise<TmdbSeries2[]> => {
|
||||
const userId = this.getUserId();
|
||||
console.log('userId recommended series', userId);
|
||||
|
||||
if (!userId) return [];
|
||||
|
||||
return (
|
||||
this.getClient()
|
||||
// @ts-ignore
|
||||
?.GET('/4/account/{account_object_id}/tv/recommendations', {
|
||||
params: {
|
||||
path: {
|
||||
account_object_id: userId
|
||||
}
|
||||
}
|
||||
})
|
||||
.then((res: any) => res.data?.results || [])
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const tmdbApi = new TmdbApi();
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
const newDigitalReleases = getDigitalReleases();
|
||||
const upcomingMovies = getUpcomingMovies();
|
||||
const recommendedMovies = tmdbApi.getRecommendedMovies();
|
||||
recommendedMovies.then((res) => console.log('Recommended Movies', res));
|
||||
|
||||
function getUpcomingMovies() {
|
||||
return TmdbApi.getClient()
|
||||
@@ -89,6 +91,17 @@
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#await recommendedMovies then recommendedMovies}
|
||||
{#if recommendedMovies?.length}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Recommended Movies</span>
|
||||
{#each recommendedMovies as item}
|
||||
<TmdbCard on:enter={scrollIntoView({ horizontal: 128 })} size="lg" {item} />
|
||||
{/each}
|
||||
</Carousel>
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#await newDigitalReleases then nowStreaming}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">New Digital Releases</span>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
const nowStreaming = getNowStreaming();
|
||||
const upcomingSeries = fetchUpcomingSeries();
|
||||
const recommendedSeries = tmdbApi.getRecommendedSeries();
|
||||
|
||||
function getNowStreaming() {
|
||||
return TmdbApi.getClient()
|
||||
@@ -83,6 +84,17 @@
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#await recommendedSeries then recommendedSeries}
|
||||
{#if recommendedSeries?.length}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Recommended</span>
|
||||
{#each recommendedSeries as item}
|
||||
<TmdbCard on:enter={scrollIntoView({ horizontal: 128 })} size="lg" {item} />
|
||||
{/each}
|
||||
</Carousel>
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#await nowStreaming then nowStreaming}
|
||||
<Carousel scrollClass="px-32" on:enter={scrollIntoView({ vertical: 128 })}>
|
||||
<span slot="header">Now Streaming</span>
|
||||
|
||||
Reference in New Issue
Block a user