You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

152 lines
3.6 KiB

import Application from "@server/Application";
import TheMovieDb from "@lib/tmdb";
import { env, secret } from "@server/util";
import { readFile } from "fs/promises";
import TVDB from "tvdb-v4";
import { request, Agent } from "https";
import Service from "./Service";
import TvDb from "./TvDb";
import { IApiMovieDetails } from "@common/api_schema";
import { MovieTicket } from "@server/database/entities";
const CACHE_CLEAR_INTERVAL = 1000*10; // 60 seconds
export default class MovieSearch extends Service
{
protected tmdb!: TheMovieDb;
/**
* The instance of TVDB
*/
protected tvdb!: TvDb;
/**
* Hold a cache of recently fetch movie IMDB ids to speed up request times
*/
protected imdbCache: { [imdbId: string]: number };
/**
* Hold the clear cache interval reference
*/
private __clearCacheInterval: NodeJS.Timeout | null;
/**
* Create a new Movie Search service instance
*/
public constructor(app: Application) {
super("Movie Search", app);
this.imdbCache = {};
this.__clearCacheInterval = null;
}
/**
* Start the service
*/
public start() {
this.tvdb = this.app.service<TvDb>("TVDB");
}
/**
* Boot the service
*/
public async boot() {
let apiKey = await secret(env("TMDB_KEY_FILE"));
this.tmdb = new TheMovieDb(apiKey);
}
/**
* Shutdown the service
*/
public async shutdown() {
// no-op
}
/**
* Store an IMDb ID in cache
*/
protected cacheImdbId(id: string) {
this.imdbCache[id] = Date.now() + CACHE_CLEAR_INTERVAL;
if (this.__clearCacheInterval === null) {
this.__clearCacheInterval = setInterval(() => this.cleanImdbCache(), CACHE_CLEAR_INTERVAL);
}
}
/**
* Clean the IMDb cache
*/
protected cleanImdbCache() {
let now = Date.now();
let remaining = 0;
for (let key in this.imdbCache) {
if (now > this.imdbCache[key]) {
delete this.imdbCache[key];
} else {
remaining++;
}
}
if (remaining == 0) {
clearInterval(<NodeJS.Timeout>this.__clearCacheInterval);
this.__clearCacheInterval = null;
}
}
// Interface -----------------------------------------------------------------------------------
/**
* Verify the IMDb ID exists
*/
public verifyImdbId(id: string) {
return new Promise<boolean>((resolve, reject) => {
// If the ID is cached, no need to fetch it
if (id in this.imdbCache) {
resolve(true);
}
// Verify the movie exists on IMDb by checking for a 404
let req = request({ method: "HEAD", host: "www.imdb.com", path: `/title/${id}/` }, (response) => {
response.resume();
if (response.statusCode == undefined) {
reject();
return;
}
resolve(response.statusCode === 200);
response.destroy();
});
req.end();
});
}
/**
* Get the details of a movie
*/
public async details(id: number) {
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}));
}
return <IApiMovieDetails>{
backdrop_path: movie.backdrop_path,
imdb_id : movie.imdb_id,
overview : movie.overview,
poster_path : movie.poster_path,
release_date : movie.release_date,
runtime : movie.runtime,
title : movie.title,
is_requested : isRequested
};
}
/**
* Search for a movie
*/
public async search(query: string, year?: number) {
return await this.tmdb.searchMovie(query, year);
// let results = await this.tvdb.searchMovie(query, year);
// return results.map(movie => <any>{
// image : movie.image_url ? `/api/tvdb/artwork${new URL(movie.image_url).pathname}`: null,
// name : movie.name,
// year : movie.year
// });
}
}