Răsfoiți Sursa

Improve cast and crew handling (#14370)

theguymadmax 2 zile în urmă
părinte
comite
7d18f3d6ed

+ 15 - 0
MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs

@@ -38,6 +38,21 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// </summary>
         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>

+ 30 - 4
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;

+ 44 - 14
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))
             {
@@ -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.Trim(),
+                        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?.Trim(),
-                        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);

+ 76 - 21
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs

@@ -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)
@@ -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.Trim(),
+                        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.Trim(),
+                        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?.Trim(),
-                        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);
                 }
             }
 

+ 60 - 23
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,47 +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))
                 {
-                    var member = cast[i];
-                    result.AddPerson(new PersonInfo
+                    if (string.IsNullOrWhiteSpace(actor.Name))
+                    {
+                        continue;
+                    }
+
+                    var personInfo = new PersonInfo
                     {
-                        Name = member.Name.Trim(),
-                        Role = member.Character.Trim(),
+                        Name = actor.Name.Trim(),
+                        Role = actor.Character?.Trim() ?? string.Empty,
                         Type = PersonKind.Actor,
-                        SortOrder = member.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?.Trim(),
-                        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;
         }
 

+ 45 - 17
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.Trim(),
+                        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?.Trim(),
-                        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;
                 }
             }
         }