This commit is contained in:
2022-01-03 18:03:53 +01:00
parent 559e32c059
commit 14775744b0
2 changed files with 151 additions and 122 deletions

View File

@@ -1,176 +1,205 @@
const fetch = require('node-fetch') const fetch = require("node-fetch");
const convertPlexToMovie = require('src/plex/convertPlexToMovie') const convertPlexToMovie = require("src/plex/convertPlexToMovie");
const convertPlexToShow = require('src/plex/convertPlexToShow') const convertPlexToShow = require("src/plex/convertPlexToShow");
const convertPlexToEpisode = require('src/plex/convertPlexToEpisode') const convertPlexToEpisode = require("src/plex/convertPlexToEpisode");
const { Movie, Show, Person } = require('src/tmdb/types') const { Movie, Show, Person } = require("src/tmdb/types");
const RedisCache = require('src/cache/redis') const RedisCache = require("src/cache/redis");
const redisCache = new RedisCache() const redisCache = new RedisCache();
const sanitize = (string) => string.toLowerCase().replace(/[^\w\s]/gi, '') const sanitize = string => string.toLowerCase().replace(/[^\w\s]/gi, "");
const matchingTitleAndYear = (plex, tmdb) => { const matchingTitleAndYear = (plex, tmdb) => {
let matchingTitle, matchingYear; let matchingTitle, matchingYear;
if (plex['title'] != null && tmdb['title'] != null) { if (plex["title"] != null && tmdb["title"] != null) {
const plexTitle = sanitize(plex.title) const plexTitle = sanitize(plex.title);
const tmdbTitle = sanitize(tmdb.title) const tmdbTitle = sanitize(tmdb.title);
matchingTitle = plexTitle == tmdbTitle; matchingTitle = plexTitle == tmdbTitle;
matchingTitle = matchingTitle ? matchingTitle : plexTitle.startsWith(tmdbTitle) matchingTitle = matchingTitle
} ? matchingTitle
else : plexTitle.startsWith(tmdbTitle);
matchingTitle = false; } else matchingTitle = false;
if (plex['year'] != null && tmdb['year'] != null) if (plex["year"] != null && tmdb["year"] != null)
matchingYear = plex.year == tmdb.year; matchingYear = plex.year == tmdb.year;
else else matchingYear = false;
matchingYear = false;
return matchingTitle && matchingYear return matchingTitle && matchingYear;
} };
const successfullResponse = (response) => { const successfullResponse = response => {
const { status, statusText } = response const { status, statusText } = response;
if (status === 200) { if (status === 200) {
return response.json() return response.json();
} else { } else {
throw { message: statusText, status: status } throw { message: statusText, status: status };
} }
} };
class Plex { class Plex {
constructor(ip, port=32400, cache=null) { constructor(ip, port = 32400, cache = null) {
this.plexIP = ip this.plexIP = ip;
this.plexPort = port this.plexPort = port;
this.cache = cache || redisCache; this.cache = cache || redisCache;
this.cacheTags = { this.cacheTags = {
machineInfo: 'plex/mi', machineInfo: "plex/mi",
search: 'plex/s' search: "plex/s"
} };
} }
fetchMachineIdentifier() { fetchMachineIdentifier() {
const cacheKey = `${this.cacheTags.machineInfo}` const cacheKey = `${this.cacheTags.machineInfo}`;
const url = `http://${this.plexIP}:${this.plexPort}/` const url = `http://${this.plexIP}:${this.plexPort}/`;
const options = { const options = {
timeout: 20000, timeout: 20000,
headers: { 'Accept': 'application/json' } headers: { Accept: "application/json" }
} };
return new Promise((resolve, reject) => this.cache.get(cacheKey) return new Promise((resolve, reject) =>
.then(machineInfo => resolve(machineInfo['machineIdentifier'])) this.cache
.catch(() => fetch(url, options)) .get(cacheKey)
.then(response => response.json()) .then(machineInfo => resolve(machineInfo["machineIdentifier"]))
.then(machineInfo => this.cache.set(cacheKey, machineInfo['MediaContainer'], 2628000)) .catch(() => fetch(url, options))
.then(machineInfo => resolve(machineInfo['machineIdentifier'])) .then(response => response.json())
.catch(error => { .then(machineInfo =>
if (error != undefined && error.type === 'request-timeout') { this.cache.set(cacheKey, machineInfo["MediaContainer"], 2628000)
reject({ message: 'Plex did not respond', status: 408, success: false }) )
} .then(machineInfo => resolve(machineInfo["machineIdentifier"]))
.catch(error => {
if (error != undefined && error.type === "request-timeout") {
reject({
message: "Plex did not respond",
status: 408,
success: false
});
}
reject(error) reject(error);
}) })
) );
} }
matchTmdbAndPlexMedia(plex, tmdb) { matchTmdbAndPlexMedia(plex, tmdb) {
let match; let match;
if (plex == null || tmdb == null) if (plex == null || tmdb == null) return false;
return false
if (plex instanceof Array) { if (plex instanceof Array) {
let possibleMatches = plex.map(plexItem => matchingTitleAndYear(plexItem, tmdb)) let possibleMatches = plex.map(plexItem =>
match = possibleMatches.includes(true) matchingTitleAndYear(plexItem, tmdb)
);
match = possibleMatches.includes(true);
} else { } else {
match = matchingTitleAndYear(plex, tmdb) match = matchingTitleAndYear(plex, tmdb);
} }
return match return match;
} }
async existsInPlex(tmdb) { async existsInPlex(tmdb) {
const plexMatch = await this.findPlexItemByTitleAndYear(tmdb.title, tmdb.year) const plexMatch = await this.findPlexItemByTitleAndYear(
return plexMatch ? true : false tmdb.title,
tmdb.year
);
return plexMatch ? true : false;
} }
findPlexItemByTitleAndYear(title, year) { findPlexItemByTitleAndYear(title, year) {
const query = { title, year } const query = { title, year };
return this.search(query.title) return this.search(query.title).then(plexSearchResults => {
.then(plexSearchResults => { const matchesInPlex = plexSearchResults.map(plex =>
const matchesInPlex = plexSearchResults.map(plex => this.matchTmdbAndPlexMedia(plex, query)) this.matchTmdbAndPlexMedia(plex, query)
);
if (matchesInPlex.includes(true) === false) if (matchesInPlex.includes(true) === false) return false;
return false;
const firstMatchIndex = matchesInPlex.indexOf(true) const firstMatchIndex = matchesInPlex.indexOf(true);
return plexSearchResults[firstMatchIndex][0] return plexSearchResults[firstMatchIndex][0];
}) });
} }
getDirectLinkByTitleAndYear(title, year) { getDirectLinkByTitleAndYear(title, year) {
const machineIdentifierPromise = this.fetchMachineIdentifier() const machineIdentifierPromise = this.fetchMachineIdentifier();
const matchingObjectInPlexPromise = this.findPlexItemByTitleAndYear(title, year) const matchingObjectInPlexPromise = this.findPlexItemByTitleAndYear(
title,
year
);
return Promise.all([machineIdentifierPromise, matchingObjectInPlexPromise]) return Promise.all([
.then(([machineIdentifier, matchingObjectInPlex]) => { machineIdentifierPromise,
if (matchingObjectInPlex == false || matchingObjectInPlex == null || matchingObjectInPlexPromise
matchingObjectInPlex['key'] == null || machineIdentifier == null) ]).then(([machineIdentifier, matchingObjectInPlex]) => {
return false if (
matchingObjectInPlex == false ||
matchingObjectInPlex == null ||
matchingObjectInPlex["key"] == null ||
machineIdentifier == null
)
return false;
const keyUriComponent = encodeURIComponent(matchingObjectInPlex.key) const keyUriComponent = encodeURIComponent(matchingObjectInPlex.key);
return `https://app.plex.tv/desktop#!/server/${machineIdentifier}/details?key=${keyUriComponent}` return `https://app.plex.tv/desktop#!/server/${machineIdentifier}/details?key=${keyUriComponent}`;
}) });
} }
search(query) { search(query) {
const cacheKey = `${this.cacheTags.search}:${query}` const cacheKey = `${this.cacheTags.search}:${query}`;
const url = `http://${this.plexIP}:${this.plexPort}/hubs/search?query=${encodeURIComponent(query)}` const url = `http://${this.plexIP}:${
this.plexPort
}/hubs/search?query=${encodeURIComponent(query)}`;
const options = { const options = {
timeout: 20000, timeout: 20000,
headers: { 'Accept': 'application/json' } headers: { Accept: "application/json" }
} };
return new Promise((resolve, reject) => this.cache.get(cacheKey) return new Promise((resolve, reject) =>
.catch(() => fetch(url, options)) // else fetch fresh data this.cache
.then(successfullResponse) .get(cacheKey)
.then(results => this.cache.set(cacheKey, results, 21600)) .catch(() => fetch(url, options)) // else fetch fresh data
.then(this.mapResults) .then(successfullResponse)
.then(resolve) .then(results => this.cache.set(cacheKey, results, 21600))
.catch(error => { .then(this.mapResults)
if (error != undefined && error.type === 'request-timeout') { .then(resolve)
reject({ message: 'Plex did not respond', status: 408, success: false }) .catch(error => {
} if (error != undefined && error.type === "request-timeout") {
reject({
message: "Plex did not respond",
status: 408,
success: false
});
}
reject(error) reject(error);
}) })
) );
} }
mapResults(response) { mapResults(response) {
if (response == null || response.MediaContainer == null || response.MediaContainer.Hub == null) { if (
return [] response == null ||
response.MediaContainer == null ||
response.MediaContainer.Hub == null
) {
return [];
} }
return response.MediaContainer.Hub return response.MediaContainer.Hub.filter(category => category.size > 0)
.filter(category => category.size > 0)
.map(category => { .map(category => {
if (category.type === 'movie') { if (category.type === "movie") {
return category.Metadata return category.Metadata;
} else if (category.type === 'show') { } else if (category.type === "show") {
return category.Metadata.map(convertPlexToShow) return category.Metadata.map(convertPlexToShow);
} else if (category.type === 'episode') { } else if (category.type === "episode") {
return category.Metadata.map(convertPlexToEpisode) return category.Metadata.map(convertPlexToEpisode);
} }
}) })
.filter(result => result !== undefined) .filter(result => result !== undefined);
} }
} }

View File

@@ -1,11 +1,11 @@
/* /*
* @Author: KevinMidboe * @Author: KevinMidboe
* @Date: 2017-10-21 09:54:31 * @Date: 2017-10-21 09:54:31
* @Last Modified by: KevinMidboe * @Last Modified by: KevinMidboe
* @Last Modified time: 2018-02-26 19:56:32 * @Last Modified time: 2018-02-26 19:56:32
*/ */
const PirateRepository = require('src/pirate/pirateRepository'); const PirateRepository = require("src/pirate/pirateRepository");
// const pirateRepository = new PirateRepository(); // const pirateRepository = new PirateRepository();
/** /**
@@ -15,15 +15,15 @@ const PirateRepository = require('src/pirate/pirateRepository');
* @returns {Callback} * @returns {Callback}
*/ */
function updateRequested(req, res) { function updateRequested(req, res) {
const { query, page, type } = req.query; const { query, page, type } = req.query;
PirateRepository.SearchPiratebay(query, page, type) PirateRepository.SearchPiratebay(query, page, type)
.then((result) => { .then(result => {
res.send({ success: true, results: result }); res.send({ success: true, results: result });
}) })
.catch(error => { .catch(error => {
res.status(401).send({ success: false, message: error.message }); res.status(401).send({ success: false, message: error.message });
}); });
} }
module.exports = updateRequested; module.exports = updateRequested;