< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Plugins.Tmdb.Movies.TmdbMovieProvider
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
Line coverage
57%
Covered lines: 4
Uncovered lines: 3
Coverable lines: 7
Total lines: 340
Line coverage: 57.1%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Order()100%210%
get_Name()100%210%
GetImageResponse(...)100%210%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Globalization;
 4using System.Linq;
 5using System.Net.Http;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using Jellyfin.Data.Enums;
 9using Jellyfin.Extensions;
 10using MediaBrowser.Common.Net;
 11using MediaBrowser.Controller.Entities;
 12using MediaBrowser.Controller.Entities.Movies;
 13using MediaBrowser.Controller.Library;
 14using MediaBrowser.Controller.Providers;
 15using MediaBrowser.Model.Entities;
 16using MediaBrowser.Model.Providers;
 17using TMDbLib.Objects.Find;
 18using TMDbLib.Objects.Search;
 19
 20namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
 21{
 22    /// <summary>
 23    /// Movie provider powered by TMDb.
 24    /// </summary>
 25    public class TmdbMovieProvider : IRemoteMetadataProvider<Movie, MovieInfo>, IHasOrder
 26    {
 27        private readonly IHttpClientFactory _httpClientFactory;
 28        private readonly ILibraryManager _libraryManager;
 29        private readonly TmdbClientManager _tmdbClientManager;
 30
 31        /// <summary>
 32        /// Initializes a new instance of the <see cref="TmdbMovieProvider"/> class.
 33        /// </summary>
 34        /// <param name="libraryManager">The <see cref="ILibraryManager"/>.</param>
 35        /// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/>.</param>
 36        /// <param name="tmdbClientManager">The <see cref="TmdbClientManager"/>.</param>
 37        public TmdbMovieProvider(
 38            ILibraryManager libraryManager,
 39            TmdbClientManager tmdbClientManager,
 40            IHttpClientFactory httpClientFactory)
 41        {
 2242            _libraryManager = libraryManager;
 2243            _tmdbClientManager = tmdbClientManager;
 2244            _httpClientFactory = httpClientFactory;
 2245        }
 46
 47        /// <inheritdoc />
 048        public int Order => 1;
 49
 50        /// <inheritdoc />
 051        public string Name => TmdbUtils.ProviderName;
 52
 53        /// <inheritdoc />
 54        public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(MovieInfo searchInfo, CancellationToken canc
 55        {
 56            if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var id))
 57            {
 58                var movie = await _tmdbClientManager
 59                    .GetMovieAsync(
 60                        int.Parse(id, CultureInfo.InvariantCulture),
 61                        searchInfo.MetadataLanguage,
 62                        TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
 63                        cancellationToken)
 64                    .ConfigureAwait(false);
 65
 66                if (movie is not null)
 67                {
 68                    var remoteResult = new RemoteSearchResult
 69                    {
 70                        Name = movie.Title ?? movie.OriginalTitle,
 71                        SearchProviderName = Name,
 72                        ImageUrl = _tmdbClientManager.GetPosterUrl(movie.PosterPath),
 73                        Overview = movie.Overview
 74                    };
 75
 76                    if (movie.ReleaseDate is not null)
 77                    {
 78                        var releaseDate = movie.ReleaseDate.Value.ToUniversalTime();
 79                        remoteResult.PremiereDate = releaseDate;
 80                        remoteResult.ProductionYear = releaseDate.Year;
 81                    }
 82
 83                    remoteResult.SetProviderId(MetadataProvider.Tmdb, movie.Id.ToString(CultureInfo.InvariantCulture));
 84                    remoteResult.TrySetProviderId(MetadataProvider.Imdb, movie.ImdbId);
 85
 86                    return new[] { remoteResult };
 87                }
 88            }
 89
 90            IReadOnlyList<SearchMovie>? movieResults = null;
 91            if (searchInfo.TryGetProviderId(MetadataProvider.Imdb, out id))
 92            {
 93                var result = await _tmdbClientManager.FindByExternalIdAsync(
 94                    id,
 95                    FindExternalSource.Imdb,
 96                    TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
 97                    cancellationToken).ConfigureAwait(false);
 98                movieResults = result?.MovieResults;
 99            }
 100
 101            if (movieResults is null && searchInfo.TryGetProviderId(MetadataProvider.Tvdb, out id))
 102            {
 103                var result = await _tmdbClientManager.FindByExternalIdAsync(
 104                    id,
 105                    FindExternalSource.TvDb,
 106                    TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
 107                    cancellationToken).ConfigureAwait(false);
 108                movieResults = result?.MovieResults;
 109            }
 110
 111            if (movieResults is null)
 112            {
 113                movieResults = await _tmdbClientManager
 114                    .SearchMovieAsync(searchInfo.Name, searchInfo.Year ?? 0, searchInfo.MetadataLanguage, cancellationTo
 115                    .ConfigureAwait(false);
 116            }
 117
 118            var len = movieResults.Count;
 119            var remoteSearchResults = new RemoteSearchResult[len];
 120            for (var i = 0; i < len; i++)
 121            {
 122                var movieResult = movieResults[i];
 123                var remoteSearchResult = new RemoteSearchResult
 124                {
 125                    Name = movieResult.Title ?? movieResult.OriginalTitle,
 126                    ImageUrl = _tmdbClientManager.GetPosterUrl(movieResult.PosterPath),
 127                    Overview = movieResult.Overview,
 128                    SearchProviderName = Name
 129                };
 130
 131                var releaseDate = movieResult.ReleaseDate?.ToUniversalTime();
 132                remoteSearchResult.PremiereDate = releaseDate;
 133                remoteSearchResult.ProductionYear = releaseDate?.Year;
 134
 135                remoteSearchResult.SetProviderId(MetadataProvider.Tmdb, movieResult.Id.ToString(CultureInfo.InvariantCul
 136                remoteSearchResults[i] = remoteSearchResult;
 137            }
 138
 139            return remoteSearchResults;
 140        }
 141
 142        /// <inheritdoc />
 143        public async Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
 144        {
 145            var tmdbId = info.GetProviderId(MetadataProvider.Tmdb);
 146            var imdbId = info.GetProviderId(MetadataProvider.Imdb);
 147
 148            if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId))
 149            {
 150                // ParseName is required here.
 151                // Caller provides the filename with extension stripped and NOT the parsed filename
 152                var parsedName = _libraryManager.ParseName(info.Name);
 153                var cleanedName = TmdbUtils.CleanName(parsedName.Name);
 154                var searchResults = await _tmdbClientManager.SearchMovieAsync(cleanedName, info.Year ?? parsedName.Year 
 155
 156                if (searchResults.Count > 0)
 157                {
 158                    tmdbId = searchResults[0].Id.ToString(CultureInfo.InvariantCulture);
 159                }
 160            }
 161
 162            if (string.IsNullOrEmpty(tmdbId) && !string.IsNullOrEmpty(imdbId))
 163            {
 164                var movieResultFromImdbId = await _tmdbClientManager.FindByExternalIdAsync(imdbId, FindExternalSource.Im
 165                if (movieResultFromImdbId?.MovieResults.Count > 0)
 166                {
 167                    tmdbId = movieResultFromImdbId.MovieResults[0].Id.ToString(CultureInfo.InvariantCulture);
 168                }
 169            }
 170
 171            if (string.IsNullOrEmpty(tmdbId))
 172            {
 173                return new MetadataResult<Movie>();
 174            }
 175
 176            var movieResult = await _tmdbClientManager
 177                .GetMovieAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), info.MetadataLanguage, TmdbUtils.G
 178                .ConfigureAwait(false);
 179
 180            if (movieResult is null)
 181            {
 182                return new MetadataResult<Movie>();
 183            }
 184
 185            var movie = new Movie
 186            {
 187                Name = movieResult.Title ?? movieResult.OriginalTitle,
 188                OriginalTitle = movieResult.OriginalTitle,
 189                Overview = movieResult.Overview?.Replace("\n\n", "\n", StringComparison.InvariantCulture),
 190                Tagline = movieResult.Tagline,
 191                ProductionLocations = movieResult.ProductionCountries.Select(pc => pc.Name).ToArray()
 192            };
 193            var metadataResult = new MetadataResult<Movie>
 194            {
 195                HasMetadata = true,
 196                ResultLanguage = info.MetadataLanguage,
 197                Item = movie
 198            };
 199
 200            movie.SetProviderId(MetadataProvider.Tmdb, tmdbId);
 201            movie.SetProviderId(MetadataProvider.Imdb, movieResult.ImdbId);
 202            if (movieResult.BelongsToCollection is not null)
 203            {
 204                movie.SetProviderId(MetadataProvider.TmdbCollection, movieResult.BelongsToCollection.Id.ToString(Culture
 205                movie.CollectionName = movieResult.BelongsToCollection.Name;
 206            }
 207
 208            movie.CommunityRating = Convert.ToSingle(movieResult.VoteAverage);
 209
 210            if (movieResult.Releases?.Countries is not null)
 211            {
 212                var releases = movieResult.Releases.Countries.Where(i => !string.IsNullOrWhiteSpace(i.Certification)).To
 213
 214                var ourRelease = releases.FirstOrDefault(c => string.Equals(c.Iso_3166_1, info.MetadataCountryCode, Stri
 215                var usRelease = releases.FirstOrDefault(c => string.Equals(c.Iso_3166_1, "US", StringComparison.OrdinalI
 216
 217                if (ourRelease is not null)
 218                {
 219                    movie.OfficialRating = TmdbUtils.BuildParentalRating(ourRelease.Iso_3166_1, ourRelease.Certification
 220                }
 221                else if (usRelease is not null)
 222                {
 223                    movie.OfficialRating = usRelease.Certification;
 224                }
 225            }
 226
 227            movie.PremiereDate = movieResult.ReleaseDate;
 228            movie.ProductionYear = movieResult.ReleaseDate?.Year;
 229
 230            if (movieResult.ProductionCompanies is not null)
 231            {
 232                movie.SetStudios(movieResult.ProductionCompanies.Select(c => c.Name));
 233            }
 234
 235            var genres = movieResult.Genres;
 236
 237            foreach (var genre in genres.Select(g => g.Name))
 238            {
 239                movie.AddGenre(genre);
 240            }
 241
 242            if (movieResult.Keywords?.Keywords is not null)
 243            {
 244                for (var i = 0; i < movieResult.Keywords.Keywords.Count; i++)
 245                {
 246                    movie.AddTag(movieResult.Keywords.Keywords[i].Name);
 247                }
 248            }
 249
 250            if (movieResult.Credits?.Cast is not null)
 251            {
 252                foreach (var actor in movieResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.
 253                {
 254                    var personInfo = new PersonInfo
 255                    {
 256                        Name = actor.Name.Trim(),
 257                        Role = actor.Character,
 258                        Type = PersonKind.Actor,
 259                        SortOrder = actor.Order
 260                    };
 261
 262                    if (!string.IsNullOrWhiteSpace(actor.ProfilePath))
 263                    {
 264                        personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath);
 265                    }
 266
 267                    if (actor.Id > 0)
 268                    {
 269                        personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture))
 270                    }
 271
 272                    metadataResult.AddPerson(personInfo);
 273                }
 274            }
 275
 276            if (movieResult.Credits?.Crew is not null)
 277            {
 278                foreach (var person in movieResult.Credits.Crew)
 279                {
 280                    // Normalize this
 281                    var type = TmdbUtils.MapCrewToPersonType(person);
 282
 283                    if (!TmdbUtils.WantedCrewKinds.Contains(type)
 284                        && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnor
 285                    {
 286                        continue;
 287                    }
 288
 289                    var personInfo = new PersonInfo
 290                    {
 291                        Name = person.Name.Trim(),
 292                        Role = person.Job,
 293                        Type = type
 294                    };
 295
 296                    if (!string.IsNullOrWhiteSpace(person.ProfilePath))
 297                    {
 298                        personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(person.ProfilePath);
 299                    }
 300
 301                    if (person.Id > 0)
 302                    {
 303                        personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture)
 304                    }
 305
 306                    metadataResult.AddPerson(personInfo);
 307                }
 308            }
 309
 310            if (movieResult.Videos?.Results is not null)
 311            {
 312                var trailers = new List<MediaUrl>();
 313                for (var i = 0; i < movieResult.Videos.Results.Count; i++)
 314                {
 315                    var video = movieResult.Videos.Results[i];
 316                    if (!TmdbUtils.IsTrailerType(video))
 317                    {
 318                        continue;
 319                    }
 320
 321                    trailers.Add(new MediaUrl
 322                    {
 323                        Url = string.Format(CultureInfo.InvariantCulture, "https://www.youtube.com/watch?v={0}", video.K
 324                        Name = video.Name
 325                    });
 326                }
 327
 328                movie.RemoteTrailers = trailers;
 329            }
 330
 331            return metadataResult;
 332        }
 333
 334        /// <inheritdoc />
 335        public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
 336        {
 0337            return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
 338        }
 339    }
 340}