@episodehunter/thetvdb
Version:
Helper lib for thetvdb api
222 lines • 8.47 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ensureArray = exports.handelHttpError = exports.getHigestRating = exports.TheTvDb = void 0;
const node_fetch_1 = require("node-fetch");
const custom_erros_1 = require("./custom-erros");
const abort_controller_1 = require("abort-controller");
const noop = () => undefined;
const logWrapper = (log, msg) => (val) => {
log(msg);
return val;
};
class TheTvDb {
constructor(apikey, options) {
this.jwt = undefined;
this.apikey = apikey;
this.fetch = (options === null || options === void 0 ? void 0 : options.fetch) || node_fetch_1.default;
const defaultNextTimeout = (currentTimeout) => {
if (currentTimeout > 4000) {
return null;
}
return currentTimeout + 1000;
};
this.options = {
timeout: (options === null || options === void 0 ? void 0 : options.timeout) || 2000,
nextTimeout: (options === null || options === void 0 ? void 0 : options.nextTimeout) || defaultNextTimeout
};
}
get token() {
if (!this.jwt) {
this.jwt = this.fetchToken();
}
return this.jwt;
}
fetchShow(theTvDbId, log = noop) {
return this.get('https://api.thetvdb.com/series/' + theTvDbId, log)
.then(handelHttpError)
.then(res => res.json())
.then(logWrapper(log, `Done, getting back`))
.then(res => res.data);
}
async fetchShowEpisodes(theTvDbId, log = noop) {
var _a;
let episodes = [];
let nextPageToLoad = 1;
while (nextPageToLoad) {
const response = await this.fetchEpisodePage(theTvDbId, nextPageToLoad, log);
nextPageToLoad = (_a = response.links) === null || _a === void 0 ? void 0 : _a.next;
episodes = [...episodes, ...response.data];
}
return episodes;
}
/**
* Fetch the latest episodes.
* Will return somewhere between 0 and numberOfEpisodes + 99 episodes
*/
async fetchLatestShowEpisodes(theTvDbId, numberOfEpisodes, log = noop) {
var _a;
const response = await this.fetchEpisodePage(theTvDbId, 1, log);
const lastPage = ((_a = response.links) === null || _a === void 0 ? void 0 : _a.last) || 1;
if (lastPage === 1) {
return response.data;
}
else if (lastPage === 2) {
const result = await this.fetchEpisodePage(theTvDbId, 2, log);
return [...response.data, ...result.data];
}
let nextPageToLoad = lastPage;
let episodes = [];
while (episodes.length < numberOfEpisodes && nextPageToLoad) {
const result = await this.fetchEpisodePage(theTvDbId, nextPageToLoad, log);
episodes = [...result.data, ...episodes];
nextPageToLoad = result.links.prev;
}
return episodes;
}
fetchLastUpdateShowsList(lastUpdate, log = noop) {
return this.get('https://api.thetvdb.com/updated/query?fromTime=' + lastUpdate, log)
.then(handelHttpError)
.then(res => res.json())
.then(res => res.data)
.then(data => ensureArray(data));
}
fetchEpisodeImage(episodeId, log = noop) {
return this.get('https://api.thetvdb.com/episodes/' + episodeId, log)
.then(handelHttpError)
.then(res => res.json())
.then(res => res.data)
.then((episode) => episode.filename)
.then(rejectIfNot(new custom_erros_1.NotFound()))
.then(filename => this.fetchImage(filename, log));
}
fetchShowPoster(showId, log = noop) {
return this.get(`https://api.thetvdb.com/series/${showId}/images/query?keyType=poster`, log)
.then(handelHttpError)
.then(res => res.json())
.then(res => res.data)
.then(getHigestRating)
.then(rejectIfNot(new custom_erros_1.NotFound()))
.then(image => image.fileName)
.then(filename => this.fetchImage(filename, log));
}
fetchShowFanart(showId, log = noop) {
return this.get(`https://api.thetvdb.com/series/${showId}/images/query?keyType=fanart`, log)
.then(handelHttpError)
.then(res => res.json())
.then(res => res.data)
.then(getHigestRating)
.then(rejectIfNot(new custom_erros_1.NotFound()))
.then(image => image.fileName)
.then(filename => this.fetchImage(filename, log));
}
fetchEpisodePage(theTvDbId, page, log = noop) {
return this.get(`https://api.thetvdb.com/series/${theTvDbId}/episodes?page=${page}`, log)
.then(res => {
// The tv db API has a bug where the next page can give a 404
if (res.status === 404) {
return {
data: [],
links: {}
};
}
handelHttpError(res);
return res.json();
})
.then(res => {
return {
data: ensureArray(res.data),
links: res.links
};
})
.then(logWrapper(log, `Done, getting back`));
}
fetchImage(filename, log) {
log(`Making request to: 'https://www.thetvdb.com/banners/${filename}'`);
return this.fetch('https://www.thetvdb.com/banners/' + filename)
.then(handelHttpError)
.then(logWrapper(log, 'Parse the response as a buffer'))
.then(response => response.buffer())
.then(logWrapper(log, 'Done and done'));
}
async get(url, log, timeout = this.options.timeout) {
log('Making request to ' + url);
const token = await this.token;
const controller = new abort_controller_1.default();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const result = await this.fetch(url, {
method: 'GET',
headers: { Authorization: 'Bearer ' + token },
signal: controller.signal
}); // The current type to not accept signal
clearTimeout(timeoutId);
log('We got a result from ' + url);
return result;
}
catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
log(`Did not recive any reposne within ${timeout} ms. url: ` + url);
const nextTimeout = this.options.nextTimeout(timeout);
if (!nextTimeout) {
log(`Giving up. url: ` + url);
throw new custom_erros_1.Timeout(`Timeout after ${timeout} ms for url: ${url}`);
}
return this.get(url, log, nextTimeout);
}
if (error) {
log(`Could not get any respone. ${error.name} ${error.message}. url: ` +
url);
}
else {
log(`Could not get any respone. url: ` + url);
}
throw error;
}
}
fetchToken() {
return this.fetch('https://api.thetvdb.com/login', {
method: 'POST',
body: JSON.stringify({
apikey: this.apikey
}),
headers: { 'Content-Type': 'application/json' }
})
.then(handelHttpError)
.then(res => res.json())
.then(result => result.token);
}
}
exports.TheTvDb = TheTvDb;
function getHigestRating(images) {
return ensureArray(images).reduce((acc, image) => {
if (image.ratingsInfo.average > acc.ratingsInfo.average) {
return image;
}
else {
return acc;
}
}, images[0]);
}
exports.getHigestRating = getHigestRating;
function handelHttpError(res) {
if (res.status === 404) {
throw new custom_erros_1.NotFound();
}
if (!res.ok) {
throw new Error('Unable to make the http request: ' + res.statusText);
}
return res;
}
exports.handelHttpError = handelHttpError;
function ensureArray(data) {
if (Array.isArray(data)) {
return data;
}
return [];
}
exports.ensureArray = ensureArray;
function rejectIfNot(error) {
return (val) => val ? Promise.resolve(val) : Promise.reject(error);
}
//# sourceMappingURL=the-tv-db.js.map