aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/Plugins')
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalUrlProvider.cs31
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs7
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs9
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs32
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs13
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalUrlProvider.cs28
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalUrlProvider.cs28
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs32
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs24
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalUrlProvider.cs28
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackExternalUrlProvider.cs28
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs4
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs15
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html34
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs60
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs107
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs82
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs62
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs98
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs2
37 files changed, 628 insertions, 151 deletions
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
index 138cfef19..622bb1dba 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
@@ -19,9 +19,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => null;
/// <inheritdoc />
- public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicAlbum;
}
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalUrlProvider.cs
new file mode 100644
index 000000000..01d284105
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalUrlProvider.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.AudioDb;
+
+/// <summary>
+/// External artist URLs for AudioDb.
+/// </summary>
+public class AudioDbAlbumExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "TheAudioDb Album";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item.TryGetProviderId(MetadataProvider.AudioDbAlbum, out var externalId))
+ {
+ var baseUrl = "https://www.theaudiodb.com/";
+ switch (item)
+ {
+ case MusicAlbum:
+ yield return baseUrl + $"album/{externalId}";
+ break;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs
index 8a516e1ce..d2eeb7f07 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
@@ -50,9 +49,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
/// <inheritdoc />
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
{
- var id = item.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
-
- if (!string.IsNullOrWhiteSpace(id))
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out var id))
{
await AudioDbAlbumProvider.Current.EnsureInfo(id, cancellationToken).ConfigureAwait(false);
@@ -70,7 +67,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
}
}
- return Enumerable.Empty<RemoteImageInfo>();
+ return [];
}
private List<RemoteImageInfo> GetImages(AudioDbAlbumProvider.Album item)
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
index ff30af879..49ece22a9 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
@@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
if (!string.IsNullOrWhiteSpace(result.strArtist))
{
- item.AlbumArtists = new string[] { result.strArtist };
+ item.AlbumArtists = [result.strArtist];
}
if (!string.IsNullOrEmpty(result.intYearReleased))
@@ -104,7 +104,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
if (!string.IsNullOrEmpty(result.strGenre))
{
- item.Genres = new[] { result.strGenre };
+ item.Genres = [result.strGenre];
}
item.SetProviderId(MetadataProvider.AudioDbArtist, result.idArtist);
@@ -170,6 +170,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
var url = AudioDbArtistProvider.BaseUrl + "/album-mb.php?i=" + musicBrainzReleaseGroupId;
var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
+ var fileInfo = _fileSystem.GetFileSystemInfo(path);
+ if (fileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
+ {
+ return;
+ }
Directory.CreateDirectory(Path.GetDirectoryName(path));
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
index 8aceb48c0..3b5955b5b 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
@@ -19,9 +19,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
/// <inheritdoc />
- public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicArtist;
}
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs
new file mode 100644
index 000000000..56b0d9bcb
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.AudioDb;
+
+/// <summary>
+/// External artist URLs for AudioDb.
+/// </summary>
+public class AudioDbArtistExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "TheAudioDb Artist";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item.TryGetProviderId(MetadataProvider.AudioDbArtist, out var externalId))
+ {
+ var baseUrl = "https://www.theaudiodb.com/";
+ switch (item)
+ {
+ case MusicAlbum:
+ case Person:
+ yield return baseUrl + $"artist/{externalId}";
+ break;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs
index 4e7757cd2..88730f34d 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
@@ -43,21 +42,19 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
/// <inheritdoc />
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
{
- return new ImageType[]
- {
+ return
+ [
ImageType.Primary,
ImageType.Logo,
ImageType.Banner,
ImageType.Backdrop
- };
+ ];
}
/// <inheritdoc />
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
{
- var id = item.GetProviderId(MetadataProvider.MusicBrainzArtist);
-
- if (!string.IsNullOrWhiteSpace(id))
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var id))
{
await AudioDbArtistProvider.Current.EnsureArtistInfo(id, cancellationToken).ConfigureAwait(false);
@@ -75,7 +72,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
}
}
- return Enumerable.Empty<RemoteImageInfo>();
+ return [];
}
private List<RemoteImageInfo> GetImages(AudioDbArtistProvider.Artist item)
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
index 014481da2..fdfd330cd 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
@@ -19,9 +19,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
/// <inheritdoc />
- public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio;
}
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
index 787539104..5a39ec1cd 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
@@ -19,9 +19,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
/// <inheritdoc />
- public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
}
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
index 825fe32fa..f1fc4a137 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
@@ -20,8 +20,5 @@ public class MusicBrainzAlbumArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.AlbumArtist;
/// <inheritdoc />
- public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio;
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalUrlProvider.cs
new file mode 100644
index 000000000..f4b3f4f8c
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalUrlProvider.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External album artist URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzAlbumArtistExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "MusicBrainz Album Artist";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item is MusicAlbum)
+ {
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out var externalId))
+ {
+ yield return Plugin.Instance!.Configuration.Server + $"/artist/{externalId}";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
index b7d53984c..48784e0ec 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
@@ -20,8 +20,5 @@ public class MusicBrainzAlbumExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
/// <inheritdoc />
- public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalUrlProvider.cs
new file mode 100644
index 000000000..b9d3b4835
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalUrlProvider.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External album URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzAlbumExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "MusicBrainz Album";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item is MusicAlbum)
+ {
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out var externalId))
+ {
+ yield return Plugin.Instance!.Configuration.Server + $"/release/{externalId}";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
index b3f001618..bd5d67ed1 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
@@ -20,8 +20,5 @@ public class MusicBrainzArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
/// <inheritdoc />
- public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicArtist;
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs
new file mode 100644
index 000000000..ee5a597c6
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External artist URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzArtistExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "MusicBrainz Artist";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var externalId))
+ {
+ switch (item)
+ {
+ case MusicAlbum:
+ case Person:
+ yield return Plugin.Instance!.Configuration.Server + $"/artist/{externalId}";
+
+ break;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
index a0a922293..470cdad66 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
@@ -20,8 +20,5 @@ public class MusicBrainzOtherArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
/// <inheritdoc />
- public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs
new file mode 100644
index 000000000..89d8b9b99
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs
@@ -0,0 +1,24 @@
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// MusicBrainz recording id.
+/// </summary>
+public class MusicBrainzRecordingId : IExternalId
+{
+ /// <inheritdoc />
+ public string ProviderName => "MusicBrainz";
+
+ /// <inheritdoc />
+ public string Key => MetadataProvider.MusicBrainzRecording.ToString();
+
+ /// <inheritdoc />
+ public ExternalIdMediaType? Type => ExternalIdMediaType.Recording;
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is Audio;
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
index 47b6d6963..c19b62abf 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
@@ -20,8 +20,5 @@ public class MusicBrainzReleaseGroupExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.ReleaseGroup;
/// <inheritdoc />
- public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release-group/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalUrlProvider.cs
new file mode 100644
index 000000000..dd0a939f7
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalUrlProvider.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External release group URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzReleaseGroupExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "MusicBrainz Release Group";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item is MusicAlbum)
+ {
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out var externalId))
+ {
+ yield return Plugin.Instance!.Configuration.Server + $"/release-group/{externalId}";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackExternalUrlProvider.cs
new file mode 100644
index 000000000..59e6f42b1
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackExternalUrlProvider.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External track URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzTrackExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "MusicBrainz Track";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ if (item is Audio)
+ {
+ if (item.TryGetProviderId(MetadataProvider.MusicBrainzTrack, out var externalId))
+ {
+ yield return Plugin.Instance!.Configuration.Server + $"/track/{externalId}";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
index cb4345660..6a7b6f541 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
@@ -20,8 +20,5 @@ public class MusicBrainzTrackId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Track;
/// <inheritdoc />
- public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/track/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio;
}
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs
index d8b33a799..ccff31eba 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs
@@ -55,13 +55,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb
if (info.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string? seriesImdbId)
&& !string.IsNullOrEmpty(seriesImdbId)
- && info.IndexNumber.HasValue
- && info.ParentIndexNumber.HasValue)
+ && info.IndexNumber.HasValue)
{
result.HasMetadata = await _omdbProvider.FetchEpisodeData(
result,
info.IndexNumber.Value,
- info.ParentIndexNumber.Value,
+ info.ParentIndexNumber ?? 1,
info.GetProviderId(MetadataProvider.Imdb),
seriesImdbId,
info.MetadataLanguage,
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
index de0da7f7b..ad9edb031 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
@@ -421,7 +421,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{
var person = new PersonInfo
{
- Name = result.Director,
+ Name = result.Director.Trim(),
Type = PersonKind.Director
};
@@ -432,7 +432,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{
var person = new PersonInfo
{
- Name = result.Writer,
+ Name = result.Writer.Trim(),
Type = PersonKind.Writer
};
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
index d453a4ff4..2076589d3 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
@@ -21,9 +21,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
return item is Movie || item is MusicVideo || item is Trailer;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
index 99b759ae2..f11b1d95a 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
@@ -39,6 +39,21 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
public int MaxCastMembers { get; set; } = 15;
/// <summary>
+ /// Gets or sets a value indicating the maximum number of crew members to fetch for an item.
+ /// </summary>
+ public int MaxCrewMembers { get; set; } = 15;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to hide cast members without profile images.
+ /// </summary>
+ public bool HideMissingCastMembers { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to hide crew members without profile images.
+ /// </summary>
+ public bool HideMissingCrewMembers { get; set; }
+
+ /// <summary>
/// Gets or sets a value indicating the poster image size to fetch.
/// </summary>
public string? PosterSize { get; set; }
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
index f3c24e7b4..89d380ec1 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
@@ -25,9 +25,24 @@
<input is="emby-checkbox" type="checkbox" id="importSeasonName" />
<span>Import season name from metadata fetched for series.</span>
</label>
- <div class="inputContainer">
- <input is="emby-input" type="number" id="maxCastMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Cast Members" />
- <div class="fieldDescription">The maximum number of cast members to fetch for an item.</div>
+ <div class="verticalSection">
+ <h2>Cast & Crew Settings</h2>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="maxCastMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Cast Members" />
+ <div class="fieldDescription">The maximum number of cast members to fetch for an item.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="maxCrewMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Crew Members" />
+ <div class="fieldDescription">The maximum number of crew members to fetch for an item.</div>
+ </div>
+ <label class="checkboxContainer">
+ <input is="emby-checkbox" type="checkbox" id="hideMissingCastMembers" />
+ <span>Hide cast members without profile images.</span>
+ </label>
+ <label class="checkboxContainer">
+ <input is="emby-checkbox" type="checkbox" id="hideMissingCrewMembers" />
+ <span>Hide crew members without profile images.</span>
+ </label>
</div>
<div class="verticalSection verticalSection-extrabottompadding">
<h2>Image Scaling</h2>
@@ -129,6 +144,8 @@
document.querySelector('#excludeTagsSeries').checked = config.ExcludeTagsSeries;
document.querySelector('#excludeTagsMovies').checked = config.ExcludeTagsMovies;
document.querySelector('#importSeasonName').checked = config.ImportSeasonName;
+ document.querySelector('#hideMissingCastMembers').checked = config.HideMissingCastMembers;
+ document.querySelector('#hideMissingCrewMembers').checked = config.HideMissingCrewMembers;
var maxCastMembers = document.querySelector('#maxCastMembers');
maxCastMembers.value = config.MaxCastMembers;
@@ -137,12 +154,18 @@
cancelable: false
}));
+ var maxCrewMembers = document.querySelector('#maxCrewMembers');
+ maxCrewMembers.value = config.MaxCrewMembers;
+ maxCrewMembers.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
pluginConfig = config;
configureImageScaling();
});
});
-
document.querySelector('.configForm')
.addEventListener('submit', function (e) {
Dashboard.showLoadingMsg();
@@ -153,6 +176,9 @@
config.ExcludeTagsMovies = document.querySelector('#excludeTagsMovies').checked;
config.ImportSeasonName = document.querySelector('#importSeasonName').checked;
config.MaxCastMembers = document.querySelector('#maxCastMembers').value;
+ config.MaxCrewMembers = document.querySelector('#maxCrewMembers').value;
+ config.HideMissingCastMembers = document.querySelector('#hideMissingCastMembers').checked;
+ config.HideMissingCrewMembers = document.querySelector('#hideMissingCrewMembers').checked;
config.PosterSize = document.querySelector('#selectPosterSize').value;
config.BackdropSize = document.querySelector('#selectBackdropSize').value;
config.LogoSize = document.querySelector('#selectLogoSize').value;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
index 6d6032e8f..9a1d872ec 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
@@ -21,9 +21,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
public ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
// Supports images for tv movies
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
index eef08b251..2f8cb68ef 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
@@ -144,6 +144,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
{
var tmdbId = info.GetProviderId(MetadataProvider.Tmdb);
var imdbId = info.GetProviderId(MetadataProvider.Imdb);
+ var config = Plugin.Instance.Configuration;
if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId))
{
@@ -234,7 +235,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
var genres = movieResult.Genres;
- foreach (var genre in genres.Select(g => g.Name))
+ foreach (var genre in genres.Select(g => g.Name).Trimmed())
{
movie.AddGenre(genre);
}
@@ -249,12 +250,26 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
if (movieResult.Credits?.Cast is not null)
{
- foreach (var actor in movieResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ var castQuery = movieResult.Credits.Cast.AsEnumerable();
+
+ if (config.HideMissingCastMembers)
{
+ castQuery = castQuery.Where(a => !string.IsNullOrEmpty(a.ProfilePath));
+ }
+
+ castQuery = castQuery.OrderBy(a => a.Order).Take(config.MaxCastMembers);
+
+ foreach (var actor in castQuery)
+ {
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
SortOrder = actor.Order
};
@@ -275,32 +290,47 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
if (movieResult.Credits?.Crew is not null)
{
- foreach (var person in movieResult.Credits.Crew)
+ var crewQuery = movieResult.Credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
+ {
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
+
+ crewQuery = crewQuery.Take(config.MaxCrewMembers);
+
+ foreach (var entry in crewQuery)
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ var crewMember = entry.CrewMember;
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType
};
- if (!string.IsNullOrWhiteSpace(person.ProfilePath))
+ if (!string.IsNullOrWhiteSpace(crewMember.ProfilePath))
{
- personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(person.ProfilePath);
+ personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath);
}
- if (person.Id > 0)
+ if (crewMember.Id > 0)
{
- personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture));
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
}
metadataResult.AddPerson(personInfo);
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
index d26a70028..2c0787b15 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
@@ -20,9 +20,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
return item is Person;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
index d1fec7cb1..7de0e430f 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
@@ -63,10 +63,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
return Enumerable.Empty<RemoteImageInfo>();
}
- var seasonNumber = episode.ParentIndexNumber;
+ var seasonNumber = episode.ParentIndexNumber ?? 1;
var episodeNumber = episode.IndexNumber;
- if (!seasonNumber.HasValue || !episodeNumber.HasValue)
+ if (!episodeNumber.HasValue)
{
return Enumerable.Empty<RemoteImageInfo>();
}
@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
// TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
var episodeResult = await _tmdbClientManager
- .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken)
+ .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken)
.ConfigureAwait(false);
var stills = episodeResult?.Images?.Stills;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
index e628abde5..7d0900cfd 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
// The search query must either provide an episode number or date
- if (!searchInfo.IndexNumber.HasValue || !searchInfo.ParentIndexNumber.HasValue)
+ if (!searchInfo.IndexNumber.HasValue)
{
return Enumerable.Empty<RemoteSearchResult>();
}
@@ -81,6 +81,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
{
var metadataResult = new MetadataResult<Episode>();
+ var config = Plugin.Instance.Configuration;
// Allowing this will dramatically increase scan times
if (info.IsMissingEpisode)
@@ -96,10 +97,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
return metadataResult;
}
- var seasonNumber = info.ParentIndexNumber;
+ var seasonNumber = info.ParentIndexNumber ?? 1;
var episodeNumber = info.IndexNumber;
- if (!seasonNumber.HasValue || !episodeNumber.HasValue)
+ if (!episodeNumber.HasValue)
{
return metadataResult;
}
@@ -112,7 +113,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
List<TvEpisode>? result = null;
for (int? episode = startindex; episode <= endindex; episode++)
{
- var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false);
+ var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false);
if (episodeInfo is not null)
{
(result ??= new List<TvEpisode>()).Add(episodeInfo);
@@ -156,7 +157,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
else
{
episodeResult = await _tmdbClientManager
- .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+ .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
.ConfigureAwait(false);
}
@@ -206,52 +207,106 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
if (credits?.Cast is not null)
{
- foreach (var actor in credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ var castQuery = config.HideMissingCastMembers
+ ? credits.Cast.Where(a => !string.IsNullOrEmpty(a.ProfilePath)).OrderBy(a => a.Order)
+ : credits.Cast.OrderBy(a => a.Order);
+
+ foreach (var actor in castQuery.Take(config.MaxCastMembers))
{
- metadataResult.AddPerson(new PersonInfo
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
+ var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
- SortOrder = actor.Order
- });
+ SortOrder = actor.Order,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath)
+ };
+
+ if (actor.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ metadataResult.AddPerson(personInfo);
}
}
if (credits?.GuestStars is not null)
{
- foreach (var guest in credits.GuestStars.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ var guestQuery = config.HideMissingCastMembers
+ ? credits.GuestStars.Where(a => !string.IsNullOrEmpty(a.ProfilePath)).OrderBy(a => a.Order)
+ : credits.GuestStars.OrderBy(a => a.Order);
+
+ foreach (var guest in guestQuery.Take(config.MaxCastMembers))
{
- metadataResult.AddPerson(new PersonInfo
+ if (string.IsNullOrWhiteSpace(guest.Name))
+ {
+ continue;
+ }
+
+ var personInfo = new PersonInfo
{
Name = guest.Name.Trim(),
- Role = guest.Character,
+ Role = guest.Character?.Trim() ?? string.Empty,
Type = PersonKind.GuestStar,
- SortOrder = guest.Order
- });
+ SortOrder = guest.Order,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(guest.ProfilePath)
+ };
+
+ if (guest.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, guest.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ metadataResult.AddPerson(personInfo);
}
}
- // and the rest from crew
if (credits?.Crew is not null)
{
- foreach (var person in credits.Crew)
+ var crewQuery = credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
+ {
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
+
+ foreach (var entry in crewQuery.Take(config.MaxCrewMembers))
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ var crewMember = entry.CrewMember;
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
- metadataResult.AddPerson(new PersonInfo
+ var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
- });
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath)
+ };
+
+ if (crewMember.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ metadataResult.AddPerson(personInfo);
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
index 3f208b599..cfef0d656 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public async Task<MetadataResult<Season>> GetMetadata(SeasonInfo info, CancellationToken cancellationToken)
{
var result = new MetadataResult<Season>();
+ var config = Plugin.Instance.Configuration;
info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string? seriesTmdbId);
@@ -65,10 +66,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
result.Item = new Season
{
IndexNumber = seasonNumber,
- Overview = seasonResult.Overview
+ Overview = seasonResult.Overview,
+ PremiereDate = seasonResult.AirDate,
+ ProductionYear = seasonResult.AirDate?.Year
};
- if (Plugin.Instance.Configuration.ImportSeasonName)
+ if (config.ImportSeasonName)
{
result.Item.Name = seasonResult.Name;
}
@@ -77,46 +80,81 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
// TODO why was this disabled?
var credits = seasonResult.Credits;
+
if (credits?.Cast is not null)
{
- var cast = credits.Cast.OrderBy(c => c.Order).Take(Plugin.Instance.Configuration.MaxCastMembers).ToList();
- for (var i = 0; i < cast.Count; i++)
+ var castQuery = config.HideMissingCastMembers
+ ? credits.Cast.Where(a => !string.IsNullOrEmpty(a.ProfilePath)).OrderBy(a => a.Order)
+ : credits.Cast.OrderBy(a => a.Order);
+
+ foreach (var actor in castQuery.Take(config.MaxCastMembers))
{
- result.AddPerson(new PersonInfo
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
+ var personInfo = new PersonInfo
{
- Name = cast[i].Name.Trim(),
- Role = cast[i].Character,
+ Name = actor.Name.Trim(),
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
- SortOrder = cast[i].Order
- });
+ SortOrder = actor.Order,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath)
+ };
+
+ if (actor.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ result.AddPerson(personInfo);
}
}
if (credits?.Crew is not null)
{
- foreach (var person in credits.Crew)
+ var crewQuery = credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ foreach (var entry in crewQuery.Take(config.MaxCrewMembers))
+ {
+ var crewMember = entry.CrewMember;
+
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
- result.AddPerson(new PersonInfo
+ var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
- });
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath)
+ };
+
+ if (crewMember.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ result.AddPerson(personInfo);
}
}
- result.Item.PremiereDate = seasonResult.AirDate;
- result.Item.ProductionYear = seasonResult.AirDate?.Year;
-
return result;
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
index 5f2d7909a..840cec984 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
@@ -20,9 +20,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public ExternalIdMediaType? Type => ExternalIdMediaType.Series;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
return item is Series;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
index e4062740f..8791712c7 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
@@ -323,17 +323,31 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
private IEnumerable<PersonInfo> GetPersons(TvShow seriesResult)
{
+ var config = Plugin.Instance.Configuration;
+
if (seriesResult.Credits?.Cast is not null)
{
- foreach (var actor in seriesResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ IEnumerable<Cast> castQuery = seriesResult.Credits.Cast.OrderBy(a => a.Order);
+
+ if (config.HideMissingCastMembers)
+ {
+ castQuery = castQuery.Where(a => !string.IsNullOrEmpty(a.ProfilePath));
+ }
+
+ foreach (var actor in castQuery.Take(config.MaxCastMembers))
{
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
SortOrder = actor.Order,
- ImageUrl = _tmdbClientManager.GetPosterUrl(actor.ProfilePath)
+ ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath)
};
if (actor.Id > 0)
@@ -347,30 +361,44 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
if (seriesResult.Credits?.Crew is not null)
{
- var keepTypes = new[]
+ var crewQuery = seriesResult.Credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
{
- PersonType.Director,
- PersonType.Writer,
- PersonType.Producer
- };
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
- foreach (var person in seriesResult.Credits.Crew)
+ foreach (var entry in crewQuery.Take(config.MaxCrewMembers))
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ var crewMember = entry.CrewMember;
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
- yield return new PersonInfo
+ var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath)
};
+
+ if (crewMember.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ yield return personInfo;
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 4916a95d9..767004c9e 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -374,7 +374,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// <returns>The TMDb tv show information.</returns>
public async Task<IReadOnlyList<SearchTv>> SearchSeriesAsync(string name, string language, int year = 0, CancellationToken cancellationToken = default)
{
- var key = $"searchseries-{name}-{language}";
+ var key = $"searchseries-{name}-{year.ToString(CultureInfo.InvariantCulture)}-{language}";
if (_memoryCache.TryGetValue(key, out SearchContainer<SearchTv>? series) && series is not null)
{
return series.Results;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs
new file mode 100644
index 000000000..8d9ec10c1
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using TMDbLib.Objects.TvShows;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb;
+
+/// <summary>
+/// External URLs for TMDb.
+/// </summary>
+public class TmdbExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "TMDB";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ switch (item)
+ {
+ case Series:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out var externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{externalId}";
+ }
+
+ break;
+ case Season season:
+ if (season.Series?.TryGetProviderId(MetadataProvider.Tmdb, out var seriesExternalId) == true)
+ {
+ var orderString = season.Series.DisplayOrder;
+ var seasonNumber = season.IndexNumber;
+ if (string.IsNullOrEmpty(orderString) && seasonNumber is not null)
+ {
+ // Default order is airdate
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}";
+ }
+
+ if (Enum.TryParse<TvGroupType>(season.Series.DisplayOrder, out var order))
+ {
+ if (order.Equals(TvGroupType.OriginalAirDate) && seasonNumber is not null)
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}";
+ }
+ }
+ }
+
+ break;
+ case Episode episode:
+ if (episode.Series?.TryGetProviderId(MetadataProvider.Tmdb, out seriesExternalId) == true)
+ {
+ var orderString = episode.Series.DisplayOrder;
+ var seasonNumber = episode.Season?.IndexNumber;
+ var episodeNumber = episode.IndexNumber;
+ if (string.IsNullOrEmpty(orderString) && seasonNumber is not null && episodeNumber is not null)
+ {
+ // Default order is airdate
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}/episode/{episodeNumber}";
+ }
+
+ if (Enum.TryParse<TvGroupType>(orderString, out var order))
+ {
+ if (order.Equals(TvGroupType.OriginalAirDate) && seasonNumber is not null && episodeNumber is not null)
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}/episode/{episodeNumber}";
+ }
+ }
+ }
+
+ break;
+ case Movie:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"movie/{externalId}";
+ }
+
+ break;
+ case Person:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"person/{externalId}";
+ }
+
+ break;
+ case BoxSet:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"collection/{externalId}";
+ }
+
+ break;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
index a7c93ac4c..afbada3b3 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
@@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
PersonKind.Producer
};
- [GeneratedRegex(@"[\W_]+")]
+ [GeneratedRegex(@"[\W_-[ยท]]+")]
private static partial Regex NonWordRegex();
/// <summary>