Merge pull request #590 from WebTools-NG/#573-Add-tvdb-to-find-missing-episodes

#573 add tvdb to find missing episodes
This commit is contained in:
Tommy Mikkelsen 2022-09-15 22:37:51 +02:00 committed by GitHub
commit 5cc3facaae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 586 additions and 352 deletions

View file

@ -1,5 +1,16 @@
# ![Logo](https://github.com/WebTools-NG/WebTools-NG/blob/master/src/assets/WebTools-48x48.png) WebTools-ng Change log
## V1.1.1 ( Not released yet )
**Note**: In this version, the following is disabled:
* Export to xlsx format ([See #331](https://github.com/WebTools-NG/WebTools-NG/issues/331))
* Photo export
**Changes**:
* [#573 Add tvdb to find missing episodes](https://github.com/WebTools-NG/WebTools-NG/issues/573) (Enhancement)
## V1.1.0 ( 20220913 )
**Note**: In this version, the following is disabled:

2
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "webtools-ng",
"version": "1.1.0",
"version": "1.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {

View file

@ -1,7 +1,7 @@
{
"name": "webtools-ng",
"productName": "WebTools-NG",
"version": "1.1.0",
"version": "1.1.1",
"description": "WebTools Next Generation 4 Plex",
"author": "dane22 & CPSO",
"license": "MPL-2.0",

View file

@ -31,7 +31,6 @@
@change="selExpTypeMainChanged"
name="selExpTypeMain">
</b-form-select>
<WTNGtt tt="Modules.ET.optExpType.ttExpType" size="20px"></WTNGtt>
</b-form-group>
</div>
</b-col>

File diff suppressed because it is too large Load diff

View file

@ -75,12 +75,14 @@
"findmissingEp": [
"Key",
"Title",
"TMDB Link",
"Show Episode Count (PMS)",
"Show Episode Count (TMDB)",
"Show Season Count (PMS)",
"Show Season Count (TMDB)",
"TMDB Status",
"Sort Season by",
"Link (Cloud)",
"Status (Cloud)",
"Episode Count (PMS)",
"Season Count (PMS)",
"Episode Count (Cloud)",
"Season Count (Cloud)",
"Seasons (Cloud)",
"Missing"
]
}

View file

@ -10,6 +10,7 @@ import Excel from 'exceljs';
import { status } from '../../General/status';
import { time } from '../../General/time';
import { tmdb } from '../../General/tmdb';
import { tvdb } from '../../General/tvdb';
var path = require("path");
var sanitize = require("sanitize-filename");
@ -308,7 +309,9 @@ const etHelper = new class ETHELPER {
element: null,
SelectedMoviesID: null,
SelectedShowsID: wtconfig.get("ET.SelectedShowsID", "tmdb"),
tmdbShowInfo: null
showInfo: null,
SelectedLibShowOrdering: null,
tvdbBearer: null
};
this.PMSHeader = wtutils.PMSHeader;
@ -428,6 +431,8 @@ const etHelper = new class ETHELPER {
this.Settings.fields = null;
this.Settings.currentItem = 0;
this.Settings.totalItems = null;
this.Settings.SelectedLibShowOrdering = null;
this.Settings.showInfo = null;
}
isEmpty( {val} )
@ -543,13 +548,23 @@ const etHelper = new class ETHELPER {
case "Audience Rating":
retVal = val.substring(0, 3);
break;
case "Episode Count (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['Episode Count (Cloud)']){
retVal = this.Settings.showInfo['Episode Count (Cloud)'];
}
break;
case "Episode Count (PMS)":
this.Settings.showInfo['PMSEPCount'] = parseInt(val);
retVal = val;
break;
case "Missing":
retVal = i18n.t('Common.Ok');
if ( this.Settings.tmdbShowInfo['TMDBEPCount'] != this.Settings.tmdbShowInfo['PMSEPCount']){
if ( this.Settings.showInfo['Episode Count (Cloud)'] != this.Settings.showInfo['PMSEPCount']){
retVal = "Episode mismatch"
}
if (!this.Settings.tmdbShowInfo['TMDBEPCount']){
retVal = "No tmdb Guid found"
if (!this.Settings.showInfo['Episode Count (Cloud)']){
retVal = "No Guid found, please refresh metadata, or sort order not avail at cloud provider"
}
break;
case "Rating":
@ -720,6 +735,12 @@ const etHelper = new class ETHELPER {
retVal = retVal.split('?')[0];
}
break;
case "Link (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['Link (Cloud)']){
retVal = this.Settings.showInfo['Link (Cloud)'];
}
break;
case "TVDB ID":
retVal = wtconfig.get('ET.NotAvail');
guidArr = val.split(wtconfig.get('ET.ArraySep'));
@ -797,12 +818,6 @@ const etHelper = new class ETHELPER {
}
}
break;
case "TMDB Status":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.tmdbShowInfo['TMDBStatus']){
retVal = this.Settings.tmdbShowInfo['TMDBStatus'];
}
break;
case "PMS Media Path":
retVal = wtconfig.get('ET.NotAvail');
var hashes = await this.getHash(data);
@ -841,16 +856,25 @@ const etHelper = new class ETHELPER {
//var path = require('path');
retVal = path.join('Metadata', libTypeName, sha1[0], sha1.slice(1) + '.bundle');
break;
case "Show Episode Count (PMS)":
this.Settings.tmdbShowInfo['PMSEPCount'] = parseInt(val);
case "Season Count (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['Season Count (Cloud)']){
retVal = this.Settings.showInfo['Season Count (Cloud)'];
}
break;
case "Season Count (PMS)":
this.Settings.showInfo['PMSSCount'] = parseInt(val);
retVal = val;
break;
case "Show Episode Count (TMDB)":
case "Seasons (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.tmdbShowInfo['TMDBEPCount']){
retVal = String(this.Settings.tmdbShowInfo['TMDBEPCount']);
if ( this.Settings.showInfo['Seasons (Cloud)']){
retVal = JSON.stringify(this.Settings.showInfo['Seasons (Cloud)']);
}
break;
case "Sort Season by":
retVal = this.Settings.showInfo['showOrdering'];
break;
case "Show Prefs Episode sorting":
switch (val){
case "-1":
@ -971,14 +995,10 @@ const etHelper = new class ETHELPER {
break;
}
break;
case "Show Season Count (PMS)":
this.Settings.tmdbShowInfo['PMSSCount'] = parseInt(val);
retVal = val;
break;
case "Show Season Count (TMDB)":
case "Status (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.tmdbShowInfo['TMDBSCount']){
retVal = String(this.Settings.tmdbShowInfo['TMDBSCount']);
if ( this.Settings.showInfo['Status (Cloud)']){
retVal = this.Settings.showInfo['Status (Cloud)'];
}
break;
default:
@ -992,17 +1012,123 @@ const etHelper = new class ETHELPER {
return await retVal;
}
// Get library default show ordering
async SelectedLibShowOrdering(){
console.log('Ged 44-3', this.Settings.SelectedLibShowOrdering)
if (!this.Settings.SelectedLibShowOrdering){
// We need to get the default for this library
log.info(`[ethelper.js] (SelectedLibShowOrdering) - Getting default show ordering for library ${this.Settings.LibName}`);
let url = `${this.Settings.baseURL}/library/sections/all?includePreferences=1`;
this.PMSHeader["X-Plex-Token"] = this.Settings.accessToken;
log.verbose(`[ethelper.js] (SelectedLibShowOrdering) Calling url: ${url}`);
let response = await fetch(url, { method: 'GET', headers: this.PMSHeader});
let resp = await response.json();
this.Settings.SelectedLibShowOrdering = JSONPath({path: `$..Directory[?(@.key==${this.Settings.selLibKey})].Preferences.Setting[?(@.id=="showOrdering")].value`, json: resp})[0];
log.info(`[ethelper.js] (SelectedLibShowOrdering) - Default show ordering for library is: ${this.Settings.SelectedLibShowOrdering}`);
}
return this.Settings.SelectedLibShowOrdering
}
// Get specific show ordering
async getShowOrdering( { ratingKey } ){
let url = `${this.Settings.baseURL}/library/metadata/${ratingKey}?includeGuids=0&includePreferences=1&checkFiles=0&includeRelated=0&includeExtras=0&includeBandwidths=0&includeChapters=0&excludeElements=Actor,Collection,Country,Director,Genre,Label,Mood,Producer,Similar,Writer,Role&excludeFields=summary,tagline`;
this.PMSHeader["X-Plex-Token"] = this.Settings.accessToken;
log.verbose(`[ethelper.js] (getShowOrdering) Calling url: ${url}`);
let response = await fetch(url, { method: 'GET', headers: this.PMSHeader});
let resp = await response.json();
console.log('Ged 54-3', this.Settings.SelectedLibShowOrdering)
var showOrder = JSONPath({path: `$..Preferences.Setting[?(@.id=="showOrdering")].value`, json: resp})[0];
if (showOrder != ""){
this.Settings.showInfo['showOrdering'] = showOrder;
} else {
this.Settings.showInfo['showOrdering'] = await this.SelectedLibShowOrdering();
}
}
async addRowToTmp( { data }) {
if ( this.Settings.levelName == 'Find Missing Episodes'){
// Special level, so we need to get info from tmdb
log.info(`[ethelper.js] (addRowToTmp) - Level "Find Missing Episodes" selected, so we must contact tmdb`);
this.Settings.tmdbShowInfo = {};
const tmdbId = String(JSONPath({ path: "$.Guid[?(@.id.startsWith('tmdb'))].id", json: data })).substring(7,);
if ( tmdbId){
this.Settings.tmdbShowInfo = await tmdb.getTMDBShowInfo(tmdbId);
} else {
const title = JSONPath({ path: "$.title", json: data });
log.error(`[ethelper.js] (addRowToTmp) - No tmdb guid found for ${title}`);
this.Settings.showInfo = {};
let id, attributename;
await this.getShowOrdering( { "ratingKey": data["ratingKey"] } );
switch ( this.Settings.showInfo["showOrdering"] ) {
case "tmdbAiring":
// Special level, so we need to get info from tmdb
log.info(`[ethelper.js] (addRowToTmp) - Level "Find Missing Episodes" selected, so we must contact tmdb`);
id = String(JSONPath({ path: "$.Guid[?(@.id.startsWith('tmdb'))].id", json: data })).substring(7,);
if ( id ){
this.Settings.showInfo["Link (Cloud)"] = `https://www.themoviedb.org/tv/${id}`;
const TMDBInfo = await tmdb.getTMDBShowInfo(id);
for( attributename in TMDBInfo){
this.Settings.showInfo[attributename] = TMDBInfo[attributename];
}
} else {
const title = JSONPath({ path: "$.title", json: data });
log.error(`[ethelper.js] (addRowToTmp) - No tmdb guid found for ${title}`);
}
this.Settings.showInfo["showOrdering"] = "TMDB Airing";
this.Settings.showInfo["Status"] = this.Settings.showInfo["TMDBStatus"];
break;
case "aired":
// Special level, so we need to get info from tvdb
log.info(`[ethelper.js] (addRowToTmp) - Level "Find Missing Episodes" selected, so we must contact tvdb`);
id = String(JSONPath({ path: "$.Guid[?(@.id.startsWith('tvdb'))].id", json: data })).substring(7,);
// Get TVDB Access Token
if (!this.Settings.tvdbBearer){
this.Settings.tvdbBearer = await tvdb.login();
}
if ( id ){
const showInfo = await tvdb.getTVDBShowAired( {tvdbId: id, bearer: this.Settings.tvdbBearer} );
for( attributename in showInfo){
this.Settings.showInfo[attributename] = showInfo[attributename];
}
} else {
const title = JSONPath({ path: "$.title", json: data });
log.error(`[ethelper.js] (addRowToTmp) - No tmdb guid found for ${title}`);
}
this.Settings.showInfo["showOrdering"] = "TVDB Airing";
break;
case "dvd":
// Special level, so we need to get info from tvdb
log.info(`[ethelper.js] (addRowToTmp) - Level "Find Missing Episodes" selected, so we must contact tvdb for DVD order`);
id = String(JSONPath({ path: "$.Guid[?(@.id.startsWith('tvdb'))].id", json: data })).substring(7,);
// Get TVDB Access Token
if (!this.Settings.tvdbBearer){
this.Settings.tvdbBearer = await tvdb.login();
}
if ( id ){
const showInfo = await tvdb.getTVDBShowDVD( {tvdbId: id, bearer: this.Settings.tvdbBearer} );
for( attributename in showInfo){
this.Settings.showInfo[attributename] = showInfo[attributename];
}
} else {
const title = JSONPath({ path: "$.title", json: data });
log.error(`[ethelper.js] (addRowToTmp) - No tmdb guid found for ${title}`);
}
this.Settings.showInfo["showOrdering"] = "TVDB DVD";
this.Settings.showInfo["Status"] = this.Settings.showInfo["TVDBStatus"];
break;
case "absolute":
// Special level, so we need to get info from tvdb
log.info(`[ethelper.js] (addRowToTmp) - Level "Find Missing Episodes" selected, so we must contact tvdb`);
id = String(JSONPath({ path: "$.Guid[?(@.id.startsWith('tvdb'))].id", json: data })).substring(7,);
// Get TVDB Access Token
if (!this.Settings.tvdbBearer){
this.Settings.tvdbBearer = await tvdb.login();
}
if ( id ){
const showInfo = await tvdb.getTVDBShowAbsolute( {tvdbId: id, bearer: this.Settings.tvdbBearer} );
for( attributename in showInfo){
this.Settings.showInfo[attributename] = showInfo[attributename];
}
} else {
const title = JSONPath({ path: "$.title", json: data });
log.error(`[ethelper.js] (addRowToTmp) - No tmdb guid found for ${title}`);
}
this.Settings.showInfo["showOrdering"] = "TVDB Absolute";
this.Settings.showInfo["Status"] = this.Settings.showInfo["TVDBStatus"];
break;
}
}
this.Settings.currentItem +=1;
@ -1132,8 +1258,8 @@ const etHelper = new class ETHELPER {
}
catch (error)
{
log.error(`We had an exception in ethelper addRowToTmp as ${error}`);
log.error(`Fields are name: ${name}, key: ${key}, type: ${type}, subType: ${subType}, subKey: ${subKey}`);
log.error(`[ethelper.js] (addRowToTmp) - We had an exception as ${error}`);
log.error(`[ethelper.js] (addRowToTmp) - Fields are name: ${name}, key: ${key}, type: ${type}, subType: ${subType}, subKey: ${subKey}`);
}
// Remove last internal separator
str = str.substring(0,str.length-etHelper.intSep.length);

View file

@ -42,26 +42,28 @@ const tmdb = new class TMDB {
})
.then((response) => {
log.debug('[tmdb.js] (getTMDBShowInfo) - Response from getTMDBShowInfo recieved');
result['TMDBStatus'] = JSONPath({ path: "$.status", json: response.data })[0];
result['TMDBEPCount'] = JSONPath({ path: "$.number_of_episodes", json: response.data })[0];
result['TMDBSCount'] = JSONPath({ path: "$.number_of_seasons", json: response.data })[0];
result['seasons'] = {};
const arrSeasons = JSONPath({ path: "$.seasons", json: response.data })[0];
for (const season of arrSeasons) {
const season_number = JSONPath({ path: "$.season_number", json: season })[0];
result['seasons'][season_number] = JSONPath({ path: "$.episode_count", json: season });
result['Status (Cloud)'] = JSONPath({ path: "$.status", json: response.data })[0];
result['Episode Count (Cloud)'] = JSONPath({ path: "$.number_of_episodes", json: response.data })[0];
result['Season Count (Cloud)'] = JSONPath({ path: "$.number_of_seasons", json: response.data })[0];
// Now get season/episode
const seasons = JSONPath({ path: "$..seasons[*]", json: response.data })
let Seasons_Cloud = {};
for ( var idx in seasons ){
Seasons_Cloud[JSONPath({ path: "$..season_number", json: seasons[idx]})] = JSONPath({ path: "$..episode_count", json: seasons[idx]})[0];
}
result['Seasons (Cloud)'] = Seasons_Cloud;
})
.catch(function (error) {
if (error.response) {
log.error('getTMDBShowInfo: ' + error.response.data);
log.error(`[tmdb.js] (getTMDBShowInfo) - Response error: ${error.response.data}`);
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
} else if (error.request) {
log.error('getTMDBShowInfo: ' + error.request);
log.error(`[tmdb.js] (getTMDBShowInfo) - Request Error: ${error.request}`);
} else {
log.error('getTMDBShowInfo: ' + error.message);
log.error(`[tmdb.js] (getTMDBShowInfo) - ${error.message}`);
}
})
log.silly(`[tmdb.js] (getTMDBShowInfo) - Returning: ${JSON.stringify(result)}`)
return result;
}
}

View file

@ -0,0 +1,199 @@
// TVDB stuff used
//import store from '../../../store';
//import { wtconfig } from './wtutils';
import axios from 'axios';
import { wtutils } from './wtutils';
const log = require('electron-log');
const {JSONPath} = require('jsonpath-plus');
const tvdb = new class TVDB {
constructor() {
this.baseUrl = 'https://thetvdb.com/';
this.baseAPIUrl = 'https://api4.thetvdb.com/v4/';
this.headers = {
"Accept": "application/json"
}
}
async login(){
log.info(`[tvdb.js] (login) - Logging in to theTVDB`);
const apiKey = wtutils.envVarLocal( 'Key_tvdb' );
let payload = { apikey: apiKey };
let url = `${this.baseAPIUrl}login`;
let bearer;
await axios.post( url, payload, {headers: this.headers})
.then((response) => {
log.debug('[tvdb.js] (login) - Response recieved');
bearer = JSONPath({ path: "$..token", json: response })[0];
})
.catch(function (error) {
if (error.response) {
log.error(`[tvdb.js] (login) - Response error: ${error.response.data}`);
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
} else if (error.request) {
log.error(`[tvdb.js] (login) - Request Error: ${error.request}`);
} else {
log.error(`[tvdb.js] (login) - ${error.message}`);
}
})
return bearer;
}
async getTVDBShowAired( {tvdbId: tvdbId, bearer: bearer} ){
log.info(`[tvdb.js] (getTVDBShowAired) - Getting tmdb aired info for ${tvdbId}`);
let url = `${this.baseAPIUrl}series/${tvdbId}/episodes/official?page=0`;
let headers = this.headers;
let seasons = {};
headers["Authorization"] = `Bearer ${bearer}`;
let result = {};
await axios({
method: 'get',
url: url,
headers: headers
})
.then((response) => {
log.debug('[tvdb.js] (getTVDBShowAired) - Response from getTVDBShowAired recieved');
result['Link (Cloud)'] = `https://thetvdb.com/series/${JSONPath({ path: "$..slug", json: response.data })[0]}`;
result['Status (Cloud)'] = JSONPath({ path: "$..status.name", json: response.data })[0];
// Sadly, the tvdb doesn't have a count field for seasons and episodes, so we need to count each :-(
let episodes = JSONPath({ path: "$..episodes[*]", json: response.data });
// Gather season/episode info
for ( var idx in episodes ){
const season = JSONPath({ path: "$..seasonNumber", json: episodes[idx] })[0];
if( Object.prototype.hasOwnProperty.call(seasons, season) ){
seasons[season] = seasons[season] + 1;
} else {
seasons[season] = 1;
}
}
// Get Season Count
result['Season Count (Cloud)'] = Object.keys(seasons).length;
// Get episode count
let episodeCount = 0;
Object.entries(seasons).forEach(([key, value]) => {
episodeCount = episodeCount + parseInt(value);
key;
})
result['Episode Count (Cloud)'] = episodeCount;
result['Seasons (Cloud)'] = seasons;
})
.catch(function (error) {
if (error.response) {
log.error(`[tvdb.js] (getTVDBShowAired) - Response error: ${error.response.data}`);
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
} else if (error.request) {
log.error(`[tvdb.js] (getTVDBShowAired) - Request Error: ${error.request}`);
} else {
log.error(`[tvdb.js] (getTVDBShowAired) - ${error.message}`);
}
})
return result;
}
async getTVDBShowDVD( {tvdbId: tvdbId, bearer: bearer} ){
log.info(`[tvdb.js] (getTVDBShowDVD) - Getting tmdb DVD info for ${tvdbId}`);
let url = `${this.baseAPIUrl}series/${tvdbId}/episodes/dvd?page=0`;
let headers = this.headers;
let seasons = {};
headers["Authorization"] = `Bearer ${bearer}`;
let result = {};
await axios({
method: 'get',
url: url,
headers: headers
})
.then((response) => {
log.debug('[tvdb.js] (getTVDBShowDVD) - Response from getTVDBShowDVD recieved');
result['Link (Cloud)'] = `https://thetvdb.com/series/${JSONPath({ path: "$..slug", json: response.data })[0]}`;
result['Status (Cloud)'] = JSONPath({ path: "$..status.name", json: response.data })[0];
// Sadly, the tvdb doesn't have a count field for seasons and episodes, so we need to count each :-(
let episodes = JSONPath({ path: "$..episodes[*]", json: response.data });
// Gather season/episode info
for ( var idx in episodes ){
const season = JSONPath({ path: "$..seasonNumber", json: episodes[idx] })[0];
if( Object.prototype.hasOwnProperty.call(seasons, season) ){
seasons[season] = seasons[season] + 1;
} else {
seasons[season] = 1;
}
}
// Get Season Count
result['Season Count (Cloud)'] = Object.keys(seasons).length;
// Get episode count
let episodeCount = 0;
Object.entries(seasons).forEach(([key, value]) => {
episodeCount = episodeCount + parseInt(value);
key;
})
result['Episode Count (Cloud)'] = episodeCount;
result['Seasons (Cloud)'] = seasons;
})
.catch(function (error) {
if (error.response) {
log.error(`[tvdb.js] (getTVDBShowDVD) - Response error: ${error.response.data}`);
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
} else if (error.request) {
log.error(`[tvdb.js] (getTVDBShowDVD) - Request Error: ${error.request}`);
} else {
log.error(`[tvdb.js] (getTVDBShowDVD) - ${error.message}`);
}
})
return result;
}
async getTVDBShowAbsolute( {tvdbId: tvdbId, bearer: bearer} ){
log.info(`[tvdb.js] (getTVDBShowAbsolute) - Getting tmdb Absolute info for ${tvdbId}`);
let url = `${this.baseAPIUrl}series/${tvdbId}/episodes/absolute?page=0`;
let headers = this.headers;
let seasons = {};
headers["Authorization"] = `Bearer ${bearer}`;
let result = {};
await axios({
method: 'get',
url: url,
headers: headers
})
.then((response) => {
log.debug('[tvdb.js] (getTVDBShowAbsolute) - Response from getTVDBShowAbsolute recieved');
result['Link (Cloud)'] = `https://thetvdb.com/series/${JSONPath({ path: "$..slug", json: response.data })[0]}`;
result['Status (Cloud)'] = JSONPath({ path: "$..status.name", json: response.data })[0];
// Sadly, the tvdb doesn't have a count field for seasons and episodes, so we need to count each :-(
let episodes = JSONPath({ path: "$..episodes[*]", json: response.data });
// Gather season/episode info
for ( var idx in episodes ){
const season = JSONPath({ path: "$..seasonNumber", json: episodes[idx] })[0];
if( Object.prototype.hasOwnProperty.call(seasons, season) ){
seasons[season] = seasons[season] + 1;
} else {
seasons[season] = 1;
}
}
// Get Season Count
result['Season Count (Cloud)'] = Object.keys(seasons).length;
// Get episode count
let episodeCount = 0;
Object.entries(seasons).forEach(([key, value]) => {
episodeCount = episodeCount + parseInt(value);
key;
})
result['Episode Count (Cloud)'] = episodeCount;
result['Seasons (Cloud)'] = seasons;
})
.catch(function (error) {
if (error.response) {
log.error(`[tvdb.js] (getTVDBShowAbsolute) - Response error: ${error.response.data}`);
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
} else if (error.request) {
log.error(`[tvdb.js] (getTVDBShowAbsolute) - Request Error: ${error.request}`);
} else {
log.error(`[tvdb.js] (getTVDBShowAbsolute) - ${error.message}`);
}
})
return result;
}
}
export { tvdb };