|
@ -3,11 +3,11 @@ import TheMovieDb from "@lib/tmdb"; |
|
|
import { env, secret } from "@server/util"; |
|
|
import { env, secret } from "@server/util"; |
|
|
import { readFile } from "fs/promises"; |
|
|
import { readFile } from "fs/promises"; |
|
|
import TVDB from "tvdb-v4"; |
|
|
import TVDB from "tvdb-v4"; |
|
|
import { request, Agent } from "https"; |
|
|
|
|
|
|
|
|
import { request } from "https"; |
|
|
import Service from "./Service"; |
|
|
import Service from "./Service"; |
|
|
import TvDb from "./TvDb"; |
|
|
import TvDb from "./TvDb"; |
|
|
import { IApiMovieDetails } from "@common/api_schema"; |
|
|
import { IApiMovieDetails } from "@common/api_schema"; |
|
|
import { MovieTicket } from "@server/database/entities"; |
|
|
|
|
|
|
|
|
import { MovieInfo, MovieTicket } from "@server/database/entities"; |
|
|
|
|
|
|
|
|
const CACHE_CLEAR_INTERVAL = 1000*10; // 60 seconds
|
|
|
const CACHE_CLEAR_INTERVAL = 1000*10; // 60 seconds
|
|
|
|
|
|
|
|
@ -21,9 +21,9 @@ export default class MovieSearch extends Service |
|
|
protected tvdb!: TvDb; |
|
|
protected tvdb!: TvDb; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Hold a cache of recently fetch movie IMDB ids to speed up request times |
|
|
|
|
|
|
|
|
* Hold a cache of recently fetched movies to speed up request times |
|
|
*/ |
|
|
*/ |
|
|
protected imdbCache: { [imdbId: string]: number }; |
|
|
|
|
|
|
|
|
protected movieCache: { [tmdbId: number]: { timestamp: number, movie: IApiMovieDetails } }; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Hold the clear cache interval reference |
|
|
* Hold the clear cache interval reference |
|
@ -35,7 +35,7 @@ export default class MovieSearch extends Service |
|
|
*/ |
|
|
*/ |
|
|
public constructor(app: Application) { |
|
|
public constructor(app: Application) { |
|
|
super("Movie Search", app); |
|
|
super("Movie Search", app); |
|
|
this.imdbCache = {}; |
|
|
|
|
|
|
|
|
this.movieCache = {}; |
|
|
this.__clearCacheInterval = null; |
|
|
this.__clearCacheInterval = null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -64,22 +64,23 @@ export default class MovieSearch extends Service |
|
|
/** |
|
|
/** |
|
|
* Store an IMDb ID in cache |
|
|
* Store an IMDb ID in cache |
|
|
*/ |
|
|
*/ |
|
|
protected cacheImdbId(id: string) { |
|
|
|
|
|
this.imdbCache[id] = Date.now() + CACHE_CLEAR_INTERVAL; |
|
|
|
|
|
|
|
|
protected cacheMovie(tmdbId: number, movie: IApiMovieDetails) { |
|
|
|
|
|
this.movieCache[tmdbId] = { movie, timestamp: Date.now() + CACHE_CLEAR_INTERVAL }; |
|
|
if (this.__clearCacheInterval === null) { |
|
|
if (this.__clearCacheInterval === null) { |
|
|
this.__clearCacheInterval = setInterval(() => this.cleanImdbCache(), CACHE_CLEAR_INTERVAL); |
|
|
|
|
|
|
|
|
this.__clearCacheInterval = setInterval(() => this.cleanMovieCache(), CACHE_CLEAR_INTERVAL); |
|
|
} |
|
|
} |
|
|
|
|
|
return this.movieCache[tmdbId]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Clean the IMDb cache |
|
|
* Clean the IMDb cache |
|
|
*/ |
|
|
*/ |
|
|
protected cleanImdbCache() { |
|
|
|
|
|
|
|
|
protected cleanMovieCache() { |
|
|
let now = Date.now(); |
|
|
let now = Date.now(); |
|
|
let remaining = 0; |
|
|
let remaining = 0; |
|
|
for (let key in this.imdbCache) { |
|
|
|
|
|
if (now > this.imdbCache[key]) { |
|
|
|
|
|
delete this.imdbCache[key]; |
|
|
|
|
|
|
|
|
for (let key in this.movieCache) { |
|
|
|
|
|
if (now > this.movieCache[key].timestamp) { |
|
|
|
|
|
delete this.movieCache[key]; |
|
|
} else { |
|
|
} else { |
|
|
remaining++; |
|
|
remaining++; |
|
|
} |
|
|
} |
|
@ -98,9 +99,9 @@ export default class MovieSearch extends Service |
|
|
public verifyImdbId(id: string) { |
|
|
public verifyImdbId(id: string) { |
|
|
return new Promise<boolean>((resolve, reject) => { |
|
|
return new Promise<boolean>((resolve, reject) => { |
|
|
// If the ID is cached, no need to fetch it
|
|
|
// If the ID is cached, no need to fetch it
|
|
|
if (id in this.imdbCache) { |
|
|
|
|
|
resolve(true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// if (id in this.imdbCache) {
|
|
|
|
|
|
// resolve(true);
|
|
|
|
|
|
// }
|
|
|
// Verify the movie exists on IMDb by checking for a 404
|
|
|
// Verify the movie exists on IMDb by checking for a 404
|
|
|
let req = request({ method: "HEAD", host: "www.imdb.com", path: `/title/${id}/` }, (response) => { |
|
|
let req = request({ method: "HEAD", host: "www.imdb.com", path: `/title/${id}/` }, (response) => { |
|
|
response.resume(); |
|
|
response.resume(); |
|
@ -120,12 +121,15 @@ export default class MovieSearch extends Service |
|
|
*/ |
|
|
*/ |
|
|
public async details(id: number) { |
|
|
public async details(id: number) { |
|
|
let isRequested = false; |
|
|
let isRequested = false; |
|
|
let movie = await this.tmdb.movie(id); |
|
|
|
|
|
if (movie.imdb_id != null) { |
|
|
|
|
|
this.cacheImdbId(movie.imdb_id); |
|
|
|
|
|
isRequested = Boolean(await MovieTicket.findOne({imdbId: movie.imdb_id})); |
|
|
|
|
|
|
|
|
if (id in this.movieCache) { |
|
|
|
|
|
if (!this.movieCache[id].movie.is_requested) { |
|
|
|
|
|
isRequested = await MovieInfo.count({tmdbId: id}) > 0; |
|
|
|
|
|
this.movieCache[id].movie.is_requested = isRequested; |
|
|
|
|
|
} |
|
|
|
|
|
return this.movieCache[id].movie; |
|
|
} |
|
|
} |
|
|
return <IApiMovieDetails>{ |
|
|
|
|
|
|
|
|
let movie = await this.tmdb.movie(id); |
|
|
|
|
|
let result: IApiMovieDetails = { |
|
|
backdrop_path: movie.backdrop_path, |
|
|
backdrop_path: movie.backdrop_path, |
|
|
imdb_id : movie.imdb_id, |
|
|
imdb_id : movie.imdb_id, |
|
|
overview : movie.overview, |
|
|
overview : movie.overview, |
|
@ -135,6 +139,7 @@ export default class MovieSearch extends Service |
|
|
title : movie.title, |
|
|
title : movie.title, |
|
|
is_requested : isRequested |
|
|
is_requested : isRequested |
|
|
}; |
|
|
}; |
|
|
|
|
|
return this.cacheMovie(id, result).movie; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|