|
|
@ -19,6 +19,7 @@ import { uniqWith } from 'lodash';
|
|
|
|
const imdbRegex = new RegExp(/imdb:\/\/(tt[0-9]+)/);
|
|
|
|
const imdbRegex = new RegExp(/imdb:\/\/(tt[0-9]+)/);
|
|
|
|
const tmdbRegex = new RegExp(/tmdb:\/\/([0-9]+)/);
|
|
|
|
const tmdbRegex = new RegExp(/tmdb:\/\/([0-9]+)/);
|
|
|
|
const tvdbRegex = new RegExp(/tvdb:\/\/([0-9]+)/);
|
|
|
|
const tvdbRegex = new RegExp(/tvdb:\/\/([0-9]+)/);
|
|
|
|
|
|
|
|
const mbRegex = new RegExp(/mbid:\/\/([0-9a-f-]+)/);
|
|
|
|
const tmdbShowRegex = new RegExp(/themoviedb:\/\/([0-9]+)/);
|
|
|
|
const tmdbShowRegex = new RegExp(/themoviedb:\/\/([0-9]+)/);
|
|
|
|
const plexRegex = new RegExp(/plex:\/\//);
|
|
|
|
const plexRegex = new RegExp(/plex:\/\//);
|
|
|
|
// Hama agent uses ASS naming, see details here:
|
|
|
|
// Hama agent uses ASS naming, see details here:
|
|
|
@ -209,6 +210,8 @@ class PlexScanner
|
|
|
|
plexitem.type === 'season'
|
|
|
|
plexitem.type === 'season'
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
await this.processPlexShow(plexitem);
|
|
|
|
await this.processPlexShow(plexitem);
|
|
|
|
|
|
|
|
} else if (plexitem.type === 'artist') {
|
|
|
|
|
|
|
|
await this.processPlexArtist(plexitem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
this.log('Failed to process Plex media', 'error', {
|
|
|
|
this.log('Failed to process Plex media', 'error', {
|
|
|
@ -224,13 +227,18 @@ class PlexScanner
|
|
|
|
const has4k = plexitem.Media.some(
|
|
|
|
const has4k = plexitem.Media.some(
|
|
|
|
(media) => media.videoResolution === '4k'
|
|
|
|
(media) => media.videoResolution === '4k'
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
if (mediaIds.tmdbId) {
|
|
|
|
await this.processMovie(mediaIds.tmdbId, {
|
|
|
|
await this.processMovie(mediaIds.tmdbId, {
|
|
|
|
is4k: has4k && this.enable4kMovie,
|
|
|
|
is4k: has4k && this.enable4kMovie,
|
|
|
|
mediaAddedAt: new Date(plexitem.addedAt * 1000),
|
|
|
|
mediaAddedAt: new Date(plexitem.addedAt * 1000),
|
|
|
|
ratingKey: plexitem.ratingKey,
|
|
|
|
ratingKey: plexitem.ratingKey,
|
|
|
|
title: plexitem.title,
|
|
|
|
title: plexitem.title,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.log('No TMDB ID found for movie', 'warn', {
|
|
|
|
|
|
|
|
title: plexitem.title,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async processPlexMovieByTmdbId(
|
|
|
|
private async processPlexMovieByTmdbId(
|
|
|
@ -273,7 +281,9 @@ class PlexScanner
|
|
|
|
await this.processHamaSpecials(metadata, mediaIds.tvdbId);
|
|
|
|
await this.processHamaSpecials(metadata, mediaIds.tvdbId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const tvShow = await this.tmdb.getTvShow({ tvId: mediaIds.tmdbId });
|
|
|
|
const tvShow = await this.tmdb.getTvShow({
|
|
|
|
|
|
|
|
tvId: mediaIds.tmdbId as number,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const seasons = tvShow.seasons;
|
|
|
|
const seasons = tvShow.seasons;
|
|
|
|
const processableSeasons: ProcessableSeason[] = [];
|
|
|
|
const processableSeasons: ProcessableSeason[] = [];
|
|
|
@ -322,7 +332,7 @@ class PlexScanner
|
|
|
|
|
|
|
|
|
|
|
|
if (mediaIds.tvdbId) {
|
|
|
|
if (mediaIds.tvdbId) {
|
|
|
|
await this.processShow(
|
|
|
|
await this.processShow(
|
|
|
|
mediaIds.tmdbId,
|
|
|
|
mediaIds.tmdbId as number,
|
|
|
|
mediaIds.tvdbId ?? tvShow.external_ids.tvdb_id,
|
|
|
|
mediaIds.tvdbId ?? tvShow.external_ids.tvdb_id,
|
|
|
|
processableSeasons,
|
|
|
|
processableSeasons,
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -334,6 +344,21 @@ class PlexScanner
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async processPlexArtist(plexitem: PlexLibraryItem) {
|
|
|
|
|
|
|
|
const mediaIds = await this.getMediaIds(plexitem);
|
|
|
|
|
|
|
|
if (mediaIds.mbId) {
|
|
|
|
|
|
|
|
await this.processArtist(mediaIds.mbId, {
|
|
|
|
|
|
|
|
mediaAddedAt: new Date(plexitem.addedAt * 1000),
|
|
|
|
|
|
|
|
ratingKey: plexitem.ratingKey,
|
|
|
|
|
|
|
|
title: plexitem.title,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.log('No MusicBrainz ID found for artist', 'warn', {
|
|
|
|
|
|
|
|
title: plexitem.title,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async getMediaIds(plexitem: PlexLibraryItem): Promise<MediaIds> {
|
|
|
|
private async getMediaIds(plexitem: PlexLibraryItem): Promise<MediaIds> {
|
|
|
|
let mediaIds: Partial<MediaIds> = {};
|
|
|
|
let mediaIds: Partial<MediaIds> = {};
|
|
|
|
// Check if item is using new plex movie/tv agent
|
|
|
|
// Check if item is using new plex movie/tv agent
|
|
|
@ -372,6 +397,8 @@ class PlexScanner
|
|
|
|
} else if (ref.id.match(tvdbRegex)) {
|
|
|
|
} else if (ref.id.match(tvdbRegex)) {
|
|
|
|
const tvdbMatch = ref.id.match(tvdbRegex)?.[1];
|
|
|
|
const tvdbMatch = ref.id.match(tvdbRegex)?.[1];
|
|
|
|
mediaIds.tvdbId = Number(tvdbMatch);
|
|
|
|
mediaIds.tvdbId = Number(tvdbMatch);
|
|
|
|
|
|
|
|
} else if (ref.id.match(mbRegex)) {
|
|
|
|
|
|
|
|
mediaIds.mbId = ref.id.match(mbRegex)?.[1] ?? undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
@ -487,10 +514,16 @@ class PlexScanner
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for MusicBrainz
|
|
|
|
|
|
|
|
} else if (plexitem.guid.match(mbRegex)) {
|
|
|
|
|
|
|
|
const mbMatch = plexitem.guid.match(mbRegex);
|
|
|
|
|
|
|
|
if (mbMatch) {
|
|
|
|
|
|
|
|
mediaIds.mbId = mbMatch[1];
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!mediaIds.tmdbId) {
|
|
|
|
if (!mediaIds.tmdbId && !mediaIds.mbId) {
|
|
|
|
throw new Error('Unable to find TMDB ID');
|
|
|
|
throw new Error('Unable to find either a TMDB ID or a MB ID');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// We check above if we have the TMDB ID, so we can safely assert the type below
|
|
|
|
// We check above if we have the TMDB ID, so we can safely assert the type below
|
|
|
|