< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Plugins.Omdb.OmdbItemProvider
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
Line coverage
20%
Covered lines: 7
Uncovered lines: 27
Coverable lines: 34
Total lines: 312
Line coverage: 20.5%
Branch coverage
0%
Covered branches: 0
Total branches: 8
Branch coverage: 0%
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_Name()100%210%
get_Order()100%210%
GetSearchResults(...)100%210%
GetSearchResults(...)100%210%
GetSearchResults(...)100%210%
GetSearchResults(...)100%210%
GetMetadata(...)100%210%
GetMetadata(...)100%210%
GetMetadata(...)100%210%
ResultToMetadataResult(...)0%7280%
GetImageResponse(...)100%210%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591, SA1300
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Globalization;
 8using System.Linq;
 9using System.Net;
 10using System.Net.Http;
 11using System.Net.Http.Json;
 12using System.Text;
 13using System.Text.Json;
 14using System.Threading;
 15using System.Threading.Tasks;
 16using Jellyfin.Extensions.Json;
 17using MediaBrowser.Common.Net;
 18using MediaBrowser.Controller.Configuration;
 19using MediaBrowser.Controller.Entities;
 20using MediaBrowser.Controller.Entities.Movies;
 21using MediaBrowser.Controller.Entities.TV;
 22using MediaBrowser.Controller.Library;
 23using MediaBrowser.Controller.Providers;
 24using MediaBrowser.Model.Entities;
 25using MediaBrowser.Model.IO;
 26using MediaBrowser.Model.Providers;
 27
 28namespace MediaBrowser.Providers.Plugins.Omdb
 29{
 30    public class OmdbItemProvider : IRemoteMetadataProvider<Series, SeriesInfo>,
 31        IRemoteMetadataProvider<Movie, MovieInfo>, IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder
 32    {
 33        private readonly IHttpClientFactory _httpClientFactory;
 34        private readonly ILibraryManager _libraryManager;
 35        private readonly JsonSerializerOptions _jsonOptions;
 36        private readonly OmdbProvider _omdbProvider;
 37
 38        public OmdbItemProvider(
 39            IHttpClientFactory httpClientFactory,
 40            ILibraryManager libraryManager,
 41            IFileSystem fileSystem,
 42            IServerConfigurationManager configurationManager)
 43        {
 4444            _httpClientFactory = httpClientFactory;
 4445            _libraryManager = libraryManager;
 4446            _omdbProvider = new OmdbProvider(_httpClientFactory, fileSystem, configurationManager);
 47
 4448            _jsonOptions = new JsonSerializerOptions(JsonDefaults.Options);
 4449            _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter());
 4450            _jsonOptions.Converters.Add(new JsonOmdbNotAvailableInt32Converter());
 4451        }
 52
 053        public string Name => "The Open Movie Database";
 54
 55        // After primary option
 056        public int Order => 2;
 57
 58        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancella
 59        {
 060            return GetSearchResultsInternal(searchInfo, true, cancellationToken);
 61        }
 62
 63        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellat
 64        {
 065            return GetSearchResultsInternal(searchInfo, true, cancellationToken);
 66        }
 67
 68        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellati
 69        {
 070            return GetSearchResultsInternal(searchInfo, true, cancellationToken);
 71        }
 72
 73        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancella
 74        {
 075            return GetSearchResultsInternal(searchInfo, true, cancellationToken);
 76        }
 77
 78        private async Task<IEnumerable<RemoteSearchResult>> GetSearchResultsInternal(ItemLookupInfo searchInfo, bool isS
 79        {
 80            var type = searchInfo switch
 81            {
 82                EpisodeInfo => "episode",
 83                SeriesInfo => "series",
 84                _ => "movie"
 85            };
 86
 87            // This is a bit hacky?
 88            var episodeSearchInfo = searchInfo as EpisodeInfo;
 89            var indexNumberEnd = episodeSearchInfo?.IndexNumberEnd;
 90
 91            var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb);
 92
 93            var urlQuery = new StringBuilder("plot=full&r=json");
 94            if (episodeSearchInfo is not null)
 95            {
 96                episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out imdbId);
 97                if (searchInfo.IndexNumber.HasValue)
 98                {
 99                    urlQuery.Append("&Episode=").Append(searchInfo.IndexNumber.Value);
 100                }
 101
 102                if (searchInfo.ParentIndexNumber.HasValue)
 103                {
 104                    urlQuery.Append("&Season=").Append(searchInfo.ParentIndexNumber.Value);
 105                }
 106            }
 107
 108            if (string.IsNullOrWhiteSpace(imdbId))
 109            {
 110                var name = searchInfo.Name;
 111                var year = searchInfo.Year;
 112                if (!string.IsNullOrWhiteSpace(name))
 113                {
 114                    var parsedName = _libraryManager.ParseName(name);
 115                    var yearInName = parsedName.Year;
 116                    name = parsedName.Name;
 117                    year ??= yearInName;
 118                }
 119
 120                if (year.HasValue)
 121                {
 122                    urlQuery.Append("&y=").Append(year);
 123                }
 124
 125                // &s means search and returns a list of results as opposed to t
 126                urlQuery.Append(isSearch ? "&s=" : "&t=");
 127                urlQuery.Append(WebUtility.UrlEncode(name));
 128                urlQuery.Append("&type=")
 129                    .Append(type);
 130            }
 131            else
 132            {
 133                urlQuery.Append("&i=")
 134                    .Append(imdbId);
 135                isSearch = false;
 136            }
 137
 138            var url = OmdbProvider.GetOmdbUrl(urlQuery.ToString());
 139
 140            using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationTo
 141            if (isSearch)
 142            {
 143                var searchResultList = await response.Content.ReadFromJsonAsync<SearchResultList>(_jsonOptions, cancella
 144                if (searchResultList?.Search is not null)
 145                {
 146                    var resultCount = searchResultList.Search.Count;
 147                    var result = new RemoteSearchResult[resultCount];
 148                    for (var i = 0; i < resultCount; i++)
 149                    {
 150                        result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
 151                    }
 152
 153                    return result;
 154                }
 155            }
 156            else
 157            {
 158                var result = await response.Content.ReadFromJsonAsync<SearchResult>(_jsonOptions, cancellationToken).Con
 159                if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
 160                {
 161                    return new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) };
 162                }
 163            }
 164
 165            return Enumerable.Empty<RemoteSearchResult>();
 166        }
 167
 168        public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken)
 169        {
 0170            return GetResult<Trailer>(info, cancellationToken);
 171        }
 172
 173        public Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
 174        {
 0175            return GetResult<Series>(info, cancellationToken);
 176        }
 177
 178        public Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
 179        {
 0180            return GetResult<Movie>(info, cancellationToken);
 181        }
 182
 183        private RemoteSearchResult ResultToMetadataResult(SearchResult result, ItemLookupInfo searchInfo, int? indexNumb
 184        {
 0185            var item = new RemoteSearchResult
 0186            {
 0187                IndexNumber = searchInfo.IndexNumber,
 0188                Name = result.Title,
 0189                ParentIndexNumber = searchInfo.ParentIndexNumber,
 0190                SearchProviderName = Name,
 0191                IndexNumberEnd = indexNumberEnd
 0192            };
 193
 0194            item.SetProviderId(MetadataProvider.Imdb, result.imdbID);
 195
 0196            if (OmdbProvider.TryParseYear(result.Year, out var parsedYear))
 197            {
 0198                item.ProductionYear = parsedYear;
 199            }
 200
 0201            if (!string.IsNullOrEmpty(result.Released)
 0202                && DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out
 203            {
 0204                item.PremiereDate = released;
 205            }
 206
 0207            if (!string.IsNullOrWhiteSpace(result.Poster))
 208            {
 0209                item.ImageUrl = result.Poster;
 210            }
 211
 0212            return item;
 213        }
 214
 215        private async Task<MetadataResult<T>> GetResult<T>(ItemLookupInfo info, CancellationToken cancellationToken)
 216            where T : BaseItem, new()
 217        {
 218            var result = new MetadataResult<T>
 219            {
 220                Item = new T(),
 221                QueriedById = true
 222            };
 223
 224            var imdbId = info.GetProviderId(MetadataProvider.Imdb);
 225            if (string.IsNullOrWhiteSpace(imdbId))
 226            {
 227                imdbId = await GetImdbId(info, cancellationToken).ConfigureAwait(false);
 228                result.QueriedById = false;
 229            }
 230
 231            if (!string.IsNullOrEmpty(imdbId))
 232            {
 233                result.Item.SetProviderId(MetadataProvider.Imdb, imdbId);
 234                result.HasMetadata = true;
 235
 236                await _omdbProvider.Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationT
 237            }
 238
 239            return result;
 240        }
 241
 242        private async Task<string> GetImdbId(ItemLookupInfo info, CancellationToken cancellationToken)
 243        {
 244            var results = await GetSearchResultsInternal(info, false, cancellationToken).ConfigureAwait(false);
 245            var first = results.FirstOrDefault();
 246            return first?.GetProviderId(MetadataProvider.Imdb);
 247        }
 248
 249        public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
 250        {
 0251            return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
 252        }
 253
 254        private class SearchResult
 255        {
 256            public string Title { get; set; }
 257
 258            public string Year { get; set; }
 259
 260            public string Rated { get; set; }
 261
 262            public string Released { get; set; }
 263
 264            public string Season { get; set; }
 265
 266            public string Episode { get; set; }
 267
 268            public string Runtime { get; set; }
 269
 270            public string Genre { get; set; }
 271
 272            public string Director { get; set; }
 273
 274            public string Writer { get; set; }
 275
 276            public string Actors { get; set; }
 277
 278            public string Plot { get; set; }
 279
 280            public string Language { get; set; }
 281
 282            public string Country { get; set; }
 283
 284            public string Awards { get; set; }
 285
 286            public string Poster { get; set; }
 287
 288            public string Metascore { get; set; }
 289
 290            public string imdbRating { get; set; }
 291
 292            public string imdbVotes { get; set; }
 293
 294            public string imdbID { get; set; }
 295
 296            public string seriesID { get; set; }
 297
 298            public string Type { get; set; }
 299
 300            public string Response { get; set; }
 301        }
 302
 303        private class SearchResultList
 304        {
 305            /// <summary>
 306            /// Gets or sets the results.
 307            /// </summary>
 308            /// <value>The results.</value>
 309            public List<SearchResult> Search { get; set; }
 310        }
 311    }
 312}