diff --git a/CHANGELOG.md b/CHANGELOG.md index 64f6426..e8aab4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/package-lock.json b/package-lock.json index 4973341..8d409d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "webtools-ng", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 6f04c67..32838a1 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/modules/ExportTools/Export.vue b/src/components/modules/ExportTools/Export.vue index 4a5c46d..5319eb5 100644 --- a/src/components/modules/ExportTools/Export.vue +++ b/src/components/modules/ExportTools/Export.vue @@ -31,7 +31,6 @@ @change="selExpTypeMainChanged" name="selExpTypeMain"> - diff --git a/src/components/modules/ExportTools/defs/def-Fields.json b/src/components/modules/ExportTools/defs/def-Fields.json index 0dacd79..c4cb2cd 100644 --- a/src/components/modules/ExportTools/defs/def-Fields.json +++ b/src/components/modules/ExportTools/defs/def-Fields.json @@ -429,6 +429,19 @@ "call": 1, "type": "string" }, + "Episode Count (Cloud)": + { + "key": "$.title", + "call": 1, + "type": "int", + "postProcess": true + }, + "Episode Count (PMS)": { + "key": "$.leafCount", + "call": 1, + "type": "string", + "postProcess": true + }, "Export Art": { "key": "$.ratingKey", @@ -656,6 +669,13 @@ "call": 1, "type": "string" }, + "Link (Cloud)": + { + "key": "$.title", + "call": 1, + "type": "string", + "postProcess": true + }, "Location": { "key": "$.Location[*]", @@ -678,182 +698,165 @@ "call": 1, "type": "string" }, - "Media Aperture": - { + "Media Aperture": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.aperture" }, - "Media Aspect Ratio": - { + "Media Aspect Ratio": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.aspectRatio" }, - "Media Audio Channels": - { + "Media Audio Channels": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.audioChannels" }, - "Media Audio Codec": - { + "Media Audio Codec": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.audioCodec" }, - "Media Bitrate": - { + "Media Bitrate": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.bitrate" }, - "Media Container": - { + "Media Container": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.container" }, - "Media Exposure": - { + "Media Exposure": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.exposure" }, - "Media Duration": - { + "Media Duration": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "time", "subkey": "$.duration" }, - "Media Height": - { + "Media Height": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.height" }, - "Media Id": - { + "Media Id": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.id" }, - "Media Iso": - { + "Media Iso": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.iso" }, - "Media Make": - { + "Media Make": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.make" }, - "Media Model": - { + "Media Model": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.model" }, - "Media Title": - { + "Media Title": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.title" }, - "Media Video Codec": - { + "Media Video Codec": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.videoCodec" }, - "Media Video FrameRate": - { + "Media Video FrameRate": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.videoFrameRate" }, - "Media Video Profile": - { + "Media Video Profile": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.videoProfile" }, - "Media Video Resolution": - { + "Media Video Resolution": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.videoResolution" }, - "Media Width": - { + "Media Width": { "key": "$.Media[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.width" }, - "MetaData Language": - { + "MetaData Language": { "key": "$.guid", "call": 2, "type": "string", "postProcess": true }, - "MetaDB Link": - { + "MetaDB Link": { "key": "$.guid", "call": 2, "type": "string", "postProcess": true }, - "Mood": - { + "Missing": { + "key": "$.parentTitle", + "call": 1, + "type": "string", + "postProcess": true + }, + "Mood": { "key": "$.Mood[*]", "call": 1, "type": "array", "subtype": "string", "subkey": "$.tag" }, - "Optimized versions": - { + "Optimized versions": { "key": "$..target", "call": 1, "type": "array", @@ -861,15 +864,13 @@ "subkey": "$." }, - "Original Title": - { + "Original Title": { "key": "$..originalTitle", "call": 2, "type": "string", "postProcess": true }, - "Part Accessible": - { + "Part Accessible": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", @@ -877,16 +878,14 @@ "subkey": "$.accessible", "include": "checkFiles=1" }, - "Part Container": - { + "Part Container": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.container" }, - "Part Duration": - { + "Part Duration": { "key": "$..Media[*].Part[?(@.key.startsWith('/library/parts'))]", "call": 2, "type": "array", @@ -894,16 +893,14 @@ "subtype": "time", "subkey": "$.duration" }, - "Part Deep Analysis Version": - { + "Part Deep Analysis Version": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.deepAnalysisVersion" }, - "Part Exists": - { + "Part Exists": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", @@ -911,8 +908,7 @@ "subkey": "$.exists", "include": "checkFiles=1" }, - "Part File": - { + "Part File": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", @@ -920,16 +916,14 @@ "subtype": "string", "subkey": "$.file" }, - "Part File Combined": - { + "Part File Combined": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.file" }, - "Part File Path": - { + "Part File Path": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", @@ -937,48 +931,42 @@ "subtype": "string", "subkey": "$.file" }, - "Part has Thumbnail": - { + "Part has Thumbnail": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.hasThumbnail" }, - "Part Id": - { + "Part Id": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.id" }, - "Part Indexed": - { + "Part Indexed": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.indexes" }, - "Part Optimized for Streaming": - { + "Part Optimized for Streaming": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.optimizedForStreaming" }, - "Part Orientation": - { + "Part Orientation": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.orientation" }, - "Part Required Bandwidths": - { + "Part Required Bandwidths": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", @@ -986,8 +974,7 @@ "subkey": "$.requiredBandwidths", "include": "includeBandwidths=1" }, - "Part Size": - { + "Part Size": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", @@ -995,335 +982,288 @@ "subtype": "string", "subkey": "$.size" }, - "Part Size as Bytes": - { + "Part Size as Bytes": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.size" }, - "Part Video Profile": - { + "Part Video Profile": { "key": "$.Media[*].Part[*]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.videoProfile" }, - "Photo Album Name": - { + "Photo Album Name": { "key": "$.parentTitle", "call": 1, "type": "string" }, - "Photo Album Poster": - { + "Photo Album Poster": { "key": "$.parentThumb", "call": 1, "type": "string" }, - "Photo Top Album Art": - { + "Photo Top Album Art": { "key": "$.grandparentArt", "call": 1, "type": "string" }, - "Photo Top Album Name": - { + "Photo Top Album Name": { "key": "$.grandparentTitle", "call": 1, "type": "string" }, - "Photo Top Album Poster": - { + "Photo Top Album Poster": { "key": "$.grandparentThumb", "call": 1, "type": "string" }, - "Playlist Type": - { + "Playlist Type": { "key": "$.playlistType", "call": 1, "type": "string" }, - "PMS Media Path": - { + "PMS Media Path": { "key": "$.guid", "call": 1, "type": "string", "postProcess": true }, - "PMS Metadata Path": - { + "PMS Metadata Path": { "key": "$.guid", "call": 1, "type": "string", "postProcess": true }, - "Poster url": - { + "Poster url": { "key": "$.thumb", "call": 2, "type": "string" }, - "Rating": - { + "Rating": { "key": "$.rating", "call": 1, "type": "string", "postProcess": true }, - "Refreshing": - { + "Refreshing": { "key": "$.refreshing", "call": 1, "type": "string" }, - "Release Date": - { + "Release Date": { "key": "$..originallyAvailableAt", "call": 1, "type": "string" }, - "Roles": - { + "Roles": { "key": "$.Role[*]", "call": 1, "type": "array", "subtype": "string", "subkey": "$.tag" }, - "Scanned At": - { + "Scanned At": { "key": "$.scannedAt", "call": 1, "type": "datetime" }, - "Scanner": - { + "Scanner": { "key": "$.scanner", "call": 1, "type": "string" }, - "Season": - { + "Season": { "key": "$.parentIndex", "call": 1, "type": "string" }, - "Series Title": - { + "Season Count (Cloud)": { + "key": "$.title", + "call": 1, + "type": "int", + "postProcess": true + }, + "Season Count (PMS)": { + "key": "$.childCount", + "call": 1, + "type": "string", + "postProcess": true + }, + "Seasons (Cloud)": { + "key": "$.title", + "call": 1, + "type": "string", + "postProcess": true + }, + "Series Title": { "key": "$.grandparentTitle", "call": 1, "type": "string" }, - "Show Episode Count (PMS)": - { - "key": "$.leafCount", - "call": 1, - "type": "string", - "postProcess": true - }, - "Show Episode Count (TMDB)": - { - "key": "$.parentTitle", - "call": 1, - "type": "string", - "postProcess": true - }, - "Show Prefs Delete episodes after playing": - { + "Show Prefs Delete episodes after playing": { "key": "$..Preferences.Setting[?(@.id=='autoDeletionItemPolicyWatchedLibrary')].value", "call": 2, "type": "int", "include": "includePreferences=1", "postProcess": true }, - "Show Prefs Episode ordering": - { + "Show Prefs Episode ordering": { "key": "$..Preferences.Setting[?(@.id=='showOrdering')].value", "call": 2, "type": "string", "include": "includePreferences=1", "postProcess": true }, - "Show Prefs Episode sorting": - { + "Show Prefs Episode sorting": { "key": "$..Preferences.Setting[?(@.id=='episodeSort')].value", "call": 2, "type": "string", "include": "includePreferences=1", "postProcess": true }, - "Show Prefs Keep": - { + "Show Prefs Keep": { "key": "$..Preferences.Setting[?(@.id=='autoDeletionItemPolicyUnwatchedLibrary')].value", "call": 2, "type": "int", "include": "includePreferences=1", "postProcess": true }, - "Show Prefs Metadata language": - { + "Show Prefs Metadata language": { "key": "$..Preferences.Setting[?(@.id=='languageOverride')].value", "call": 2, "type": "int", "include": "includePreferences=1", "postProcess": true }, - "Show Prefs Seasons": - { + "Show Prefs Seasons": { "key": "$..Preferences.Setting[?(@.id=='flattenSeasons')].value", "call": 2, "type": "int", "include": "includePreferences=1", "postProcess": true }, - "Show Prefs Use original title": - { + "Show Prefs Use original title": { "key": "$..Preferences.Setting[?(@.id=='useOriginalTitle')].value", "call": 2, "type": "int", "include": "includePreferences=1", "postProcess": true }, - "Show Season Count (PMS)": - { - "key": "$.childCount", - "call": 1, - "type": "string", - "postProcess": true - }, - "Show Season Count (TMDB)": - { - "key": "$.parentTitle", - "call": 1, - "type": "string", - "postProcess": true - }, - "Missing": - { - "key": "$.parentTitle", - "call": 1, - "type": "string", - "postProcess": true - }, - "Show Title": - { + "Show Title": { "key": "$.parentTitle", "call": 1, "type": "string" }, - "Similar": - { + "Similar": { "key": "$.Similar[*]", "call": 1, "type": "array", "subtype": "string", "subkey": "$.tag" }, - "Smart": - { + "Smart": { "key": "$.smart", "call": 1, "type": "string" }, - "Sort title": - { + "Sort Season by": { + "key": "$.title", + "call": 1, + "type": "string", + "postProcess": true + }, + "Sort title": { "key": "$.titleSort", "call": 1, "type": "string", "postProcess": true }, - "Studio": - { + "Status (Cloud)": { + "key": "$.title", + "call": 1, + "type": "string", + "postProcess": true + }, + "Studio": { "key": "$.studio", "call": 1, "type": "string" }, - "Style": - { + "Style": { "key": "$.Style[*]", "call": 1, "type": "array", "subtype": "string", "subkey": "$.tag" }, - "Subtitle Stream Codec": - { + "Subtitle Stream Codec": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.codec" }, - "Subtitle Stream Codec ID": - { + "Subtitle Stream Codec ID": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "codecID" }, - "Subtitle Stream Default": - { + "Subtitle Stream Default": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.default" }, - "Subtitle Stream Forced": - { + "Subtitle Stream Forced": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.forced" }, - "Subtitle Stream Format": - { + "Subtitle Stream Format": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "format" }, - "Subtitle Stream Header Compression": - { + "Subtitle Stream Header Compression": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "headerCompression" }, - "Subtitle Stream Index": - { + "Subtitle Stream Index": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.index" }, - "Subtitle Stream Language": - { + "Subtitle Stream Language": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.language" }, - "Subtitle Stream Language Code": - { + "Subtitle Stream Language Code": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.languageCode" }, - "Subtitle Stream Required Bandwidths": - { + "Subtitle Stream Required Bandwidths": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", @@ -1331,68 +1271,58 @@ "subkey": "requiredBandwidths", "include": "includeBandwidths=1" }, - "Subtitle Stream Selected": - { + "Subtitle Stream Selected": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "selected" }, - "Subtitle Stream Title": - { + "Subtitle Stream Title": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==3)]", "call": 2, "type": "array", "subtype": "string", "subkey": "$.title" }, - "Suggested File Name": - { + "Suggested File Name": { "key": "$.title", "call": 1, "type": "string", "postProcess": true }, - "Suggested Folder Name": - { + "Suggested Folder Name": { "key": "$.title", "call": 1, "type": "string", "postProcess": true }, - "Summary": - { + "Summary": { "key": "$.summary", "call": 1, "type": "string" }, - "Tagline": - { + "Tagline": { "key": "tagline", "call": 1, "type": "string" }, - "Title": - { + "Title": { "key": "$.title", "call": 1, "type": "string" }, - "Track Counts": - { + "Track Counts": { "key": "$.leafCount", "call": 2, "type": "string" }, - "Type": - { + "Type": { "key": "$.type", "call": 1, "type": "string" }, - "TVDB ID": - { + "TVDB ID": { "key": "$.Guid[*]", "call": 1, "type": "array", @@ -1400,22 +1330,19 @@ "subkey": "$.id", "postProcess": true }, - "TVDB ID (Legacy)": - { + "TVDB ID (Legacy)": { "key": "$.guid", "call": 2, "type": "string", "postProcess": true }, - "TVDB Language (Legacy)": - { + "TVDB Language (Legacy)": { "key": "$.guid", "call": 2, "type": "string", "postProcess": true }, - "TMDB ID": - { + "TMDB ID": { "key": "$.Guid[*]", "call": 2, "type": "array", @@ -1423,8 +1350,7 @@ "subkey": "$.id", "postProcess": true }, - "TMDB Link": - { + "TMDB Link": { "key": "$.Guid[*]", "call": 2, "type": "array", @@ -1432,227 +1358,204 @@ "subkey": "$.id", "postProcess": true }, - "TMDB Status": - { + "TMDB Status": { "key": "$.title", "call": 1, "type": "string", "postProcess": true }, - "Updated": - { + "TVDB Status": { + "key": "$.title", + "call": 1, + "type": "string", + "postProcess": true + }, + "Updated": { "key": "$.updatedAt", "call": 1, "type": "datetime" }, - "User Rating": - { + "User Rating": { "key": "userRating", "call": 1, "type": "string" }, - "Video Stream Anamorphic": - { + "Video Stream Anamorphic": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "anamorphic" }, - "Video Stream Bit Depth": - { + "Video Stream Bit Depth": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "bitDepth" }, - "Video Stream Bitrate": - { + "Video Stream Bitrate": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "bitrate" }, - "Video Stream Cabac": - { + "Video Stream Cabac": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "cabac" }, - "Video Stream Chroma Sub Sampling": - { + "Video Stream Chroma Sub Sampling": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "chromaSubsampling" }, - "Video Stream Codec": - { + "Video Stream Codec": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "codec" }, - "Video Stream Codec ID": - { + "Video Stream Codec ID": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "codecID" }, - "Video Stream Color Primaries": - { + "Video Stream Color Primaries": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "colorPrimaries" }, - "Video Stream Color Range": - { + "Video Stream Color Range": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "colorRange" }, - "Video Stream Color Space": - { + "Video Stream Color Space": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "colorSpace" }, - "Video Stream Color Trc": - { + "Video Stream Color Trc": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "colorTrc" }, - "Video Stream Default": - { + "Video Stream Default": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "default" }, - "Video Stream Duration": - { + "Video Stream Duration": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "duration" }, - "Video Stream Frame Rate": - { + "Video Stream Frame Rate": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "frameRate" }, - "Video Stream Frame Rate Mode": - { + "Video Stream Frame Rate Mode": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "frameRateMode" }, - "Video Stream Has Scaling Matrix": - { + "Video Stream Has Scaling Matrix": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "hasScalingMatrix" }, - "Video Stream Height": - { + "Video Stream Height": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "height" }, - "Video Stream Index": - { + "Video Stream Index": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "index" }, - "Video Stream Language": - { + "Video Stream Language": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "language" }, - "Video Stream Language Code": - { + "Video Stream Language Code": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "languageCode" }, - "Video Stream Level": - { + "Video Stream Level": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "level" }, - "Video Stream Pixel Aspect Ratio": - { + "Video Stream Pixel Aspect Ratio": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "pixelAspectRatio" }, - "Video Stream Pixel Format": - { + "Video Stream Pixel Format": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "pixelFormat" }, - "Video Stream Profile": - { + "Video Stream Profile": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "profile" }, - "Video Stream Ref Frames": - { + "Video Stream Ref Frames": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "refFrames" }, - "Video Stream Required Bandwidths": - { + "Video Stream Required Bandwidths": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", @@ -1660,60 +1563,52 @@ "subkey": "requiredBandwidths", "include": "includeBandwidths=1" }, - "Video Stream Scan Type": - { + "Video Stream Scan Type": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "scanType" }, - "Video Stream Stream Identifier": - { + "Video Stream Stream Identifier": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "streamIdentifier" }, - "Video Stream Title": - { + "Video Stream Title": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "title" }, - "Video Stream Width": - { + "Video Stream Width": { "key": "$.Media[*].Part[*].Stream[?(@.streamType==1)]", "call": 2, "type": "array", "subtype": "string", "subkey": "width" }, - "View Count": - { + "View Count": { "key": "viewCount", "call": 1, "type": "string" }, - "Viewed Tracks": - { + "Viewed Tracks": { "key": "$.viewedLeafCount", "call": 1, "type": "string" }, - "Writers": - { + "Writers": { "key": "$.Writer[*]", "call": 1, "type": "array", "subtype": "string", "subkey": "$.tag" }, - "Year": - { + "Year": { "key": "$.year", "call": 1, "type": "string" diff --git a/src/components/modules/ExportTools/defs/def-Show.json b/src/components/modules/ExportTools/defs/def-Show.json index 4a0f4ab..94b55dc 100644 --- a/src/components/modules/ExportTools/defs/def-Show.json +++ b/src/components/modules/ExportTools/defs/def-Show.json @@ -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" ] } diff --git a/src/components/modules/ExportTools/scripts/ethelper.js b/src/components/modules/ExportTools/scripts/ethelper.js index 1691077..f8f6d4a 100644 --- a/src/components/modules/ExportTools/scripts/ethelper.js +++ b/src/components/modules/ExportTools/scripts/ethelper.js @@ -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); diff --git a/src/components/modules/General/tmdb.js b/src/components/modules/General/tmdb.js index 6b3696e..90c3a8d 100644 --- a/src/components/modules/General/tmdb.js +++ b/src/components/modules/General/tmdb.js @@ -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; } } diff --git a/src/components/modules/General/tvdb.js b/src/components/modules/General/tvdb.js new file mode 100644 index 0000000..a5fd9fa --- /dev/null +++ b/src/components/modules/General/tvdb.js @@ -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 }; \ No newline at end of file