From f6f7fbe73df27bd58b4c3a17d2d2cb8342e17fd9 Mon Sep 17 00:00:00 2001 From: Aleksi Lassila Date: Thu, 13 Mar 2025 21:01:45 +0200 Subject: [PATCH] fix: tmdb series and movies not caching --- backend/src/metadata/metadata.entity.ts | 60 ++++++++++++++++--- backend/src/metadata/metadata.service.ts | 49 ++++++++++----- .../user-data/library/library.controller.ts | 2 +- .../src/user-data/library/library.service.ts | 7 ++- 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/backend/src/metadata/metadata.entity.ts b/backend/src/metadata/metadata.entity.ts index 7c72994..c2dfd3f 100644 --- a/backend/src/metadata/metadata.entity.ts +++ b/backend/src/metadata/metadata.entity.ts @@ -25,6 +25,36 @@ export class MovieMetadata { @ApiProperty({ type: 'string' }) @UpdateDateColumn() updatedAt: Date; + + /** + * Requires update before serving + */ + isOutdated() { + const releaseDate = this.tmdbMovie?.release_date; + + if (!this.tmdbMovie) return true; + if (!this.updatedAt) return true; + if ( + releaseDate && + new Date() > new Date(releaseDate) && + new Date(this.updatedAt) < new Date(releaseDate) + ) + return true; + + return false; + } + + /** + * Can be lazily updated after serving + */ + isStale() { + if (this.isOutdated()) return true; + + if (new Date().getTime() - this.updatedAt.getTime() > TMDB_CACHE_TTL) + return true; + + return false; + } } @Entity() @@ -45,19 +75,33 @@ export class SeriesMetadata { @UpdateDateColumn() updatedAt: Date; - isStale() { + /** + * Requires update before serving + */ + isOutdated() { + const nextAirDate = this.tmdbSeries?.next_episode_to_air?.air_date; + + if (!this.tmdbSeries) return true; if (!this.updatedAt) return true; + if ( + nextAirDate && + new Date() > new Date(nextAirDate) && + new Date(this.updatedAt) < new Date(nextAirDate) + ) + return true; + + return false; + } + + /** + * Can be lazily updated after serving + */ + isStale() { + if (this.isOutdated()) return true; if (new Date().getTime() - this.updatedAt.getTime() > TMDB_CACHE_TTL) return true; - if ( - this.tmdbSeries?.next_episode_to_air?.air_date && - new Date() > new Date(this.tmdbSeries.next_episode_to_air.air_date) - ) { - return true; - } - return false; } } diff --git a/backend/src/metadata/metadata.service.ts b/backend/src/metadata/metadata.service.ts index 842d6be..b2b13a4 100644 --- a/backend/src/metadata/metadata.service.ts +++ b/backend/src/metadata/metadata.service.ts @@ -37,17 +37,24 @@ export class MetadataService { movie.tmdbId = tmdbId; } - if ( - !movie.updatedAt || - new Date().getTime() - movie.updatedAt.getTime() > TMDB_CACHE_TTL - ) { - const tmdbMovie = await this.tmdbService.getFullMovie(Number(tmdbId)); - movie.tmdbMovie = tmdbMovie; - } + if (movie.isStale()) { + const updatedMovie = this.tmdbService + .getFullMovie(Number(tmdbId)) + .then(async (tmdbMovie) => { + if (tmdbMovie) { + movie.tmdbMovie = tmdbMovie; + movie.updatedAt = new Date(); + } - await this.movieRepository.upsert(movie, { - conflictPaths: ['tmdbId'], - }); + await this.movieRepository.upsert(movie, { + conflictPaths: ['tmdbId'], + }); + + return movie; + }); + + if (movie.isOutdated()) return updatedMovie; + } return movie; } @@ -66,13 +73,23 @@ export class MetadataService { if (series.isStale()) { this.logger.debug(`Caching series ${tmdbId}`); - const tmdbSeries = await this.tmdbService.getFullSeries(Number(tmdbId)); - if (tmdbSeries) series.tmdbSeries = tmdbSeries; - } + const updatedSeries = this.tmdbService + .getFullSeries(Number(tmdbId)) + .then(async (tmdbSeries) => { + if (tmdbSeries) { + series.tmdbSeries = tmdbSeries; + series.updatedAt = new Date(); + } - await this.seriesRepository.upsert(series, { - conflictPaths: ['tmdbId'], - }); + await this.seriesRepository.upsert(series, { + conflictPaths: ['tmdbId'], + }); + + return series; + }); + + if (series.isOutdated()) return updatedSeries; + } return series; } diff --git a/backend/src/user-data/library/library.controller.ts b/backend/src/user-data/library/library.controller.ts index 21194b4..71e4baa 100644 --- a/backend/src/user-data/library/library.controller.ts +++ b/backend/src/user-data/library/library.controller.ts @@ -20,7 +20,7 @@ import { PaginationParamsDto, SuccessResponseDto, } from 'src/common/common.dto'; -import { LibraryItemDto, LibraryItemDto2 } from './library.dto'; +import { LibraryItemDto2 } from './library.dto'; import { LibraryService } from './library.service'; @ApiTags('users') diff --git a/backend/src/user-data/library/library.service.ts b/backend/src/user-data/library/library.service.ts index 1c70e0d..8b414ef 100644 --- a/backend/src/user-data/library/library.service.ts +++ b/backend/src/user-data/library/library.service.ts @@ -1,9 +1,9 @@ import { Inject, Injectable } from '@nestjs/common'; -import { Repository } from 'typeorm'; -import { LibraryItem } from './library.entity'; import { MediaType, PaginationParamsDto } from 'src/common/common.dto'; -import { LibraryItemDto, LibraryItemDto2 } from './library.dto'; import { MetadataService } from 'src/metadata/metadata.service'; +import { Repository } from 'typeorm'; +import { LibraryItemDto2 } from './library.dto'; +import { LibraryItem } from './library.entity'; import { USER_LIBRARY_REPOSITORY } from './library.providers'; @Injectable() @@ -31,6 +31,7 @@ export class LibraryService { ? await this.metadataService.getMovieByTmdbId(item.tmdbId) : undefined; + return LibraryItemDto2.create({ libraryItem: item, seriesMetadata,