This commit is contained in:
Tommy Mikkelsen 2022-09-15 22:36:37 +02:00
parent 39b04a47f5
commit 1af2a4bc9b
6 changed files with 473 additions and 387 deletions

View file

@ -9,6 +9,8 @@
**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:

File diff suppressed because it is too large Load diff

View file

@ -76,14 +76,13 @@
"Key",
"Title",
"Sort Season by",
"Link",
"Show Episode Count (PMS)",
"Show Season Count (PMS)",
"Show Episode Count (TMDB)",
"Show Season Count (TMDB)",
"Show Episode Count (TVDB)",
"Show Season Count (TVDB)",
"Status",
"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");
@ -309,7 +310,8 @@ const etHelper = new class ETHELPER {
SelectedMoviesID: null,
SelectedShowsID: wtconfig.get("ET.SelectedShowsID", "tmdb"),
showInfo: null,
SelectedLibShowOrdering: null
SelectedLibShowOrdering: null,
tvdbBearer: null
};
this.PMSHeader = wtutils.PMSHeader;
@ -546,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.showInfo['TMDBEPCount'] != this.Settings.showInfo['PMSEPCount']){
if ( this.Settings.showInfo['Episode Count (Cloud)'] != this.Settings.showInfo['PMSEPCount']){
retVal = "Episode mismatch"
}
if (!this.Settings.showInfo['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":
@ -723,10 +735,10 @@ const etHelper = new class ETHELPER {
retVal = retVal.split('?')[0];
}
break;
case "Link":
case "Link (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['link']){
retVal = this.Settings.showInfo['link'];
if ( this.Settings.showInfo['Link (Cloud)']){
retVal = this.Settings.showInfo['Link (Cloud)'];
}
break;
case "TVDB ID":
@ -844,20 +856,20 @@ 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.showInfo['PMSEPCount'] = parseInt(val);
retVal = val;
break;
case "Show Episode Count (TMDB)":
case "Season Count (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['TMDBEPCount']){
retVal = String(this.Settings.showInfo['TMDBEPCount']);
if ( this.Settings.showInfo['Season Count (Cloud)']){
retVal = this.Settings.showInfo['Season Count (Cloud)'];
}
break;
case "Show Episode Count (TVDB)":
case "Season Count (PMS)":
this.Settings.showInfo['PMSSCount'] = parseInt(val);
retVal = val;
break;
case "Seasons (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['TVDBEPCount']){
retVal = String(this.Settings.showInfo['TVDBEPCount']);
if ( this.Settings.showInfo['Seasons (Cloud)']){
retVal = JSON.stringify(this.Settings.showInfo['Seasons (Cloud)']);
}
break;
case "Sort Season by":
@ -983,26 +995,10 @@ const etHelper = new class ETHELPER {
break;
}
break;
case "Show Season Count (PMS)":
this.Settings.showInfo['PMSSCount'] = parseInt(val);
retVal = val;
break;
case "Show Season Count (TMDB)":
case "Status (Cloud)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['TMDBSCount']){
retVal = String(this.Settings.showInfo['TMDBSCount']);
}
break;
case "Show Season Count (TVDB)":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['TVDBSCount']){
retVal = String(this.Settings.showInfo['TVDBSCount']);
}
break;
case "Status":
retVal = wtconfig.get('ET.NotAvail');
if ( this.Settings.showInfo['Status']){
retVal = this.Settings.showInfo['Status'];
if ( this.Settings.showInfo['Status (Cloud)']){
retVal = this.Settings.showInfo['Status (Cloud)'];
}
break;
default:
@ -1018,6 +1014,7 @@ const etHelper = new class ETHELPER {
// 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}`);
@ -1039,6 +1036,7 @@ const etHelper = new class ETHELPER {
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;
@ -1050,20 +1048,17 @@ const etHelper = new class ETHELPER {
async addRowToTmp( { data }) {
if ( this.Settings.levelName == 'Find Missing Episodes'){
this.Settings.showInfo = {};
let id;
let id, attributename;
await this.getShowOrdering( { "ratingKey": data["ratingKey"] } );
console.log('Ged 33-3', this.Settings.showInfo["showOrdering"])
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"] = `https://www.themoviedb.org/tv/${id}`;
this.Settings.showInfo["Link (Cloud)"] = `https://www.themoviedb.org/tv/${id}`;
const TMDBInfo = await tmdb.getTMDBShowInfo(id);
for(var attributename in TMDBInfo){
console.log('Ged 87-3 ' + attributename + ": " + JSON.stringify(TMDBInfo[attributename]));
for( attributename in TMDBInfo){
this.Settings.showInfo[attributename] = TMDBInfo[attributename];
}
} else {
@ -1074,23 +1069,68 @@ const etHelper = new class ETHELPER {
this.Settings.showInfo["Status"] = this.Settings.showInfo["TMDBStatus"];
break;
case "aired":
this.Settings.showInfo["TVDBStatus"] = "Ged 1";
this.Settings.showInfo["TVDBEPCount"] = "Ged 2";
this.Settings.showInfo["TVDBSCount"] = "Ged 3";
// 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";
this.Settings.showInfo["Status"] = this.Settings.showInfo["TVDBStatus"];
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;
}
}
console.log('Ged 17-1-4-3', JSON.stringify(this.Settings.showInfo))
this.Settings.currentItem +=1;
status.updateStatusMsg( status.RevMsgType.Items, i18n.t('Common.Status.Msg.ProcessItem_0_1', {count: this.Settings.count, total: this.Settings.endItem}));
log.debug(`[ethelper.js] (addRowToTmp) Start addRowToTmp item ${this.Settings.currentItem} (Switch to Silly log to see contents)`)
@ -1115,12 +1155,9 @@ const etHelper = new class ETHELPER {
subType = fieldDef["subtype"];
subKey = fieldDef["subkey"];
doPostProc = fieldDef["postProcess"];
console.log('Ged 17-6')
switch(type) {
case "string":
console.log('Ged 17-7')
val = String(JSONPath({path: key, json: data})[0]);
console.log('Ged 17-8')
// Make N/A if not found
if (!val)
{

View file

@ -42,20 +42,16 @@ 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];
console.log('Ged 56-3', JSON.stringify(arrSeasons))
for (const season of arrSeasons) {
console.log('Ged 56-3-2', JSON.stringify(season))
const season_number = JSONPath({ path: "$.season_number", json: season })[0];
console.log('Ged 56-3-3', season_number)
console.log('Ged 56-3-4', JSONPath({ path: "$.episode_count", json: season })[0])
result['seasons'][season_number] = JSONPath({ path: "$.episode_count", json: season })[0];
} */
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) {

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 };