예제 #1
0
        private async Task <MetadataResult <T> > GetMovieResult <T>(ItemLookupInfo info, CancellationToken cancellationToken)
            where T : BaseItem, new()
        {
            var result = new MetadataResult <T>
            {
                Item = new T()
            };

            var imdbId = info.GetProviderId(MetadataProviders.Imdb);

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false);
            }

            if (!string.IsNullOrEmpty(imdbId))
            {
                result.Item.SetProviderId(MetadataProviders.Imdb, imdbId);
                result.HasMetadata = true;

                await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
            }

            return(result);
        }
예제 #2
0
        private async Task <MetadataResult <T> > GetMovieResult <T>(ItemLookupInfo info, CancellationToken cancellationToken)
            where T : Video, new()
        {
            var result = new MetadataResult <T>
            {
                Item = new T()
            };

            var imdbId = info.GetProviderId(MetadataProviders.Imdb);

            var searchResult = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false);

            result.Item.Name = searchResult.Item3;

            if (string.IsNullOrEmpty(imdbId))
            {
                imdbId = searchResult.Item1;

                if (!string.IsNullOrEmpty(searchResult.Item2))
                {
                    result.Item.SetProviderId(MetadataProviders.Tmdb, searchResult.Item2);
                }
            }

            if (!string.IsNullOrEmpty(imdbId))
            {
                result.Item.SetProviderId(MetadataProviders.Imdb, imdbId);
                result.HasMetadata = true;

                await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, cancellationToken)
                .ConfigureAwait(false);
            }

            return(result);
        }
예제 #3
0
        public async Task <MetadataResult <T> > GetMetadata(ItemLookupInfo itemId, CancellationToken cancellationToken)
        {
            var tmdbId = itemId.GetProviderId(MetadataProviders.Tmdb);
            var imdbId = itemId.GetProviderId(MetadataProviders.Imdb);

            // Don't search for music video id's because it is very easy to misidentify.
            if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId) && typeof(T) != typeof(MusicVideo))
            {
                var searchResults = await new MovieDbSearch(_logger, _jsonSerializer, _libraryManager).GetMovieSearchResults(itemId, cancellationToken).ConfigureAwait(false);

                var searchResult = searchResults.FirstOrDefault();

                if (searchResult != null)
                {
                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                }
            }

            if (!string.IsNullOrEmpty(tmdbId) || !string.IsNullOrEmpty(imdbId))
            {
                cancellationToken.ThrowIfCancellationRequested();

                return(await FetchMovieData(tmdbId, imdbId, itemId.MetadataLanguage, itemId.MetadataCountryCode, cancellationToken).ConfigureAwait(false));
            }

            return(new MetadataResult <T>());
        }
예제 #4
0
        public Task <MetadataResult <T> > GetItemMetadata <T>(ItemLookupInfo id, CancellationToken cancellationToken)
            where T : BaseItem, new()
        {
            var movieDb = new GenericMovieDbInfo <T>(_logger, _jsonSerializer, _libraryManager, _fileSystem);

            return(movieDb.GetMetadata(id, cancellationToken));
        }
예제 #5
0
        private RemoteSearchResult ResultToMetadataResult(SearchResult result, ItemLookupInfo searchInfo, int?indexNumberEnd)
        {
            var item = new RemoteSearchResult
            {
                IndexNumber        = searchInfo.IndexNumber,
                Name               = result.Title,
                ParentIndexNumber  = searchInfo.ParentIndexNumber,
                SearchProviderName = Name,
                IndexNumberEnd     = indexNumberEnd
            };

            item.SetProviderId(MetadataProvider.Imdb, result.imdbID);

            if (OmdbProvider.TryParseYear(result.Year, out var parsedYear))
            {
                item.ProductionYear = parsedYear;
            }

            if (!string.IsNullOrEmpty(result.Released) &&
                DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var released))
            {
                item.PremiereDate = released;
            }

            if (!string.IsNullOrWhiteSpace(result.Poster))
            {
                item.ImageUrl = result.Poster;
            }

            return(item);
        }
예제 #6
0
        private async Task <MetadataResult <T> > GetResult <T>(ItemLookupInfo info, CancellationToken cancellationToken)
            where T : BaseItem, new()
        {
            var result = new MetadataResult <T>
            {
                Item        = new T(),
                QueriedById = true
            };

            var imdbId = info.GetProviderId(MetadataProvider.Imdb);

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                imdbId = await GetImdbId(info, cancellationToken).ConfigureAwait(false);

                result.QueriedById = false;
            }

            if (!string.IsNullOrEmpty(imdbId))
            {
                result.Item.SetProviderId(MetadataProvider.Imdb, imdbId);
                result.HasMetadata = true;

                await _omdbProvider.Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
            }

            return(result);
        }
예제 #7
0
        private async Task <MetadataResult <T> > GetMovieResult <T>(ItemLookupInfo info, CancellationToken cancellationToken)
            where T : BaseItem, new()
        {
            var result = new MetadataResult <T>
            {
                Item        = new T(),
                QueriedById = true
            };

            var imdbId = info.GetProviderId(MetadataProvider.Imdb);

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false);

                result.QueriedById = false;
            }

            if (!string.IsNullOrEmpty(imdbId))
            {
                result.Item.SetProviderId(MetadataProvider.Imdb, imdbId);
                result.HasMetadata = true;

                await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
            }

            return(result);
        }
예제 #8
0
        public Task <MetadataResult <T> > GetItemMetadata <T>(ItemLookupInfo id, CancellationToken cancellationToken)
            where T : Video, new()
        {
            var movieDb = new GenericMovieDbInfo <T>(_logger, _jsonSerializer);

            return(movieDb.GetMetadata(id, cancellationToken));
        }
예제 #9
0
        private async Task <string> GetMovieImdbId(ItemLookupInfo info, CancellationToken cancellationToken)
        {
            var results = await GetSearchResultsInternal(info, "movie", false, cancellationToken).ConfigureAwait(false);

            var first = results.FirstOrDefault();

            return(first == null ? null : first.GetProviderId(MetadataProvider.Imdb));
        }
        private EmbyItemData ToEmbyItemData <TEmbyItem>(ItemLookupInfo embyInfo, IMediaItemType <TEmbyItem> itemType,
                                                        IEnumerable <EmbyItemId> parentIds)
            where TEmbyItem : BaseItem
        {
            var existingIds = embyInfo.ProviderIds.Where(v => int.TryParse(v.Value, out _))
                              .ToDictionary(k => k.Key, v => int.Parse(v.Value));

            return(new EmbyItemData(itemType,
                                    new ItemIdentifier(embyInfo.IndexNumber.ToOption(), embyInfo.ParentIndexNumber.ToOption(),
                                                       embyInfo.Name), existingIds, embyInfo.MetadataLanguage, parentIds));
        }
예제 #11
0
        private async Task <Tuple <string, string, string> > GetMovieImdbId(ItemLookupInfo info, CancellationToken cancellationToken)
        {
            var result = await new GenericMovieDbInfo <Movie>(_logger, _jsonSerializer).GetMetadata(info, cancellationToken)
                         .ConfigureAwait(false);

            var imdb = result.HasMetadata ? result.Item.GetProviderId(MetadataProviders.Imdb) : null;
            var tmdb = result.HasMetadata ? result.Item.GetProviderId(MetadataProviders.Tmdb) : null;
            var name = result.HasMetadata ? result.Item.Name : null;

            return(new Tuple <string, string, string>(imdb, tmdb, name));
        }
예제 #12
0
        public async Task <IEnumerable <RemoteSearchResult> > GetMovieSearchResults(ItemLookupInfo searchInfo, CancellationToken cancellationToken)
        {
            var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb);

            if (!string.IsNullOrEmpty(tmdbId))
            {
                cancellationToken.ThrowIfCancellationRequested();

                var obj = await EnsureMovieInfo(tmdbId, searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken).ConfigureAwait(false);

                if (obj == null)
                {
                    return(new List <RemoteSearchResult>());
                }

                var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);

                var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original");

                var remoteResult = new RemoteSearchResult
                {
                    Name = obj.GetTitle(),
                    SearchProviderName = Name,
                    ImageUrl           = string.IsNullOrWhiteSpace(obj.poster_path) ? null : tmdbImageUrl + obj.poster_path
                };

                if (!string.IsNullOrWhiteSpace(obj.release_date))
                {
                    DateTimeOffset r;

                    // These dates are always in this exact format
                    if (DateTimeOffset.TryParse(obj.release_date, _usCulture, DateTimeStyles.None, out r))
                    {
                        remoteResult.PremiereDate   = r.ToUniversalTime();
                        remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year;
                    }
                }

                remoteResult.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_usCulture));

                if (!string.IsNullOrWhiteSpace(obj.imdb_id))
                {
                    remoteResult.SetProviderId(MetadataProviders.Imdb, obj.imdb_id);
                }

                return(new[] { remoteResult });
            }

            return(await new MovieDbSearch(_logger, _jsonSerializer, _libraryManager).GetMovieSearchResults(searchInfo, cancellationToken).ConfigureAwait(false));
        }
예제 #13
0
        public async Task <List <MediaRoot> > GetSearchResultsFromInfoAsync(ItemLookupInfo info, string format, CancellationToken cancellationToken)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }

            var results = new List <MediaRoot>();

            if (info.ProviderIds != null && info.ProviderIds.TryGetValue(Name, out var rawId) && int.TryParse(rawId, out var id))
            {
                _logger.LogCallerInfo($"Id: {id}");

                var media = await _api.GetFromIdAsync(id, cancellationToken).ConfigureAwait(false);

                if (media != null)
                {
                    results.Add(media);

                    return(results);
                }

                _logger.LogCallerWarning($"No Media with Id: {id} found");
            }
            else
            {
                _logger.LogCallerWarning($"No Id found for {nameof(info.Name)}: \"{info.Name}\"");
            }

            if (!string.IsNullOrEmpty(info.Name))
            {
                var searchResults = await _api.SearchAsync(info.Name, format, cancellationToken).ConfigureAwait(false);

                if (searchResults?.Count > 0)
                {
                    results.AddRange(searchResults);
                    return(results);
                }

                _logger.LogCallerWarning($"No Results found for {nameof(info.Name)}: \"{info.Name}\"");
            }
            else
            {
                _logger.LogCallerWarning($"No {nameof(info.Name)} found");
            }

            return(results);
        }
예제 #14
0
        public async Task<IEnumerable<RemoteSearchResult>> GetMovieSearchResults(ItemLookupInfo searchInfo, CancellationToken cancellationToken)
        {
            var tmdbId = searchInfo.GetProviderId(MetadataProvider.Tmdb);

            if (!string.IsNullOrEmpty(tmdbId))
            {
                cancellationToken.ThrowIfCancellationRequested();

                await EnsureMovieInfo(tmdbId, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);

                var dataFilePath = GetDataFilePath(tmdbId, searchInfo.MetadataLanguage);

                var obj = _jsonSerializer.DeserializeFromFile<MovieResult>(dataFilePath);

                var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);

                var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original");

                var remoteResult = new RemoteSearchResult
                {
                    Name = obj.GetTitle(),
                    SearchProviderName = Name,
                    ImageUrl = string.IsNullOrWhiteSpace(obj.Poster_Path) ? null : tmdbImageUrl + obj.Poster_Path
                };

                if (!string.IsNullOrWhiteSpace(obj.Release_Date))
                {
                    // These dates are always in this exact format
                    if (DateTime.TryParse(obj.Release_Date, _usCulture, DateTimeStyles.None, out var r))
                    {
                        remoteResult.PremiereDate = r.ToUniversalTime();
                        remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year;
                    }
                }

                remoteResult.SetProviderId(MetadataProvider.Tmdb, obj.Id.ToString(_usCulture));

                if (!string.IsNullOrWhiteSpace(obj.Imdb_Id))
                {
                    remoteResult.SetProviderId(MetadataProvider.Imdb, obj.Imdb_Id);
                }

                return new[] { remoteResult };
            }

            return await new TmdbSearch(_logger, _jsonSerializer, _libraryManager).GetMovieSearchResults(searchInfo, cancellationToken).ConfigureAwait(false);
        }
예제 #15
0
        private async Task <Show?> GetIdentifyShow(ItemLookupInfo lookupInfo, TvMazeClient tvMazeClient)
        {
            var searchResults = (await tvMazeClient.Search.ShowSearchAsync(lookupInfo.Name?.Trim()).ConfigureAwait(false)).ToList();

            if (searchResults.Count == 0)
            {
                // No search results.
                return(null);
            }

            if (lookupInfo.Year.HasValue)
            {
                return(searchResults.OrderBy(
                           s => DateTime.TryParse(s.Show.Premiered, out var premiereDate) ? Math.Abs(premiereDate.Year - lookupInfo.Year.Value) : 1)
                       .ThenByDescending(s => s.Score)
                       .FirstOrDefault()?.Show);
            }

            return(searchResults[0].Show);
        }
        public Task <Either <ProcessFailedResult, IMetadataFoundResult <TEmbyItem> > > GetResultAsync <TEmbyItem>(
            ItemLookupInfo embyInfo, IMediaItemType <TEmbyItem> itemType, IEnumerable <EmbyItemId> parentIds)
            where TEmbyItem : BaseItem
        {
            var embyItemData = this.ToEmbyItemData(embyInfo, itemType, parentIds);

            this.log.Debug($"Finding metadata for {embyItemData}");

            var mediaItem = this.mediaItemBuilder.Identify(embyItemData, itemType);

            var fullyRecognisedMediaItem = mediaItem.BindAsync(this.mediaItemBuilder.BuildMediaItem);

            return(fullyRecognisedMediaItem.BindAsync(
                       mi => itemType.CreateMetadataFoundResult(this.pluginConfiguration, mi, this.logManager))
                   .MapAsync(r =>
            {
                this.log.Debug(
                    $"Created metadata with provider Ids: {string.Join(", ", r.EmbyMetadataResult.Item.ProviderIds.Select(kvp => $"{kvp.Key}: {kvp.Value}"))}");
                return r;
            }));
        }
예제 #17
0
        private void ApplySearchResult(ItemLookupInfo lookupInfo, RemoteSearchResult result)
        {
            // Episode and Season do not support Identify, so the search results are the Series'
            switch (lookupInfo)
            {
            case EpisodeInfo episodeInfo:
                episodeInfo.SeriesProviderIds = result.ProviderIds;
                episodeInfo.ProviderIds.Clear();
                break;

            case SeasonInfo seasonInfo:
                seasonInfo.SeriesProviderIds = result.ProviderIds;
                seasonInfo.ProviderIds.Clear();
                break;

            default:
                lookupInfo.ProviderIds = result.ProviderIds;
                lookupInfo.Name        = result.Name;
                lookupInfo.Year        = result.ProductionYear;
                break;
            }
        }
        /// <summary>
        /// Finds the id from music brainz.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task{System.String}.</returns>
        private async Task <string> FindId(ItemLookupInfo item, CancellationToken cancellationToken)
        {
            // They seem to throw bad request failures on any term with a slash
            var nameToSearch = item.Name.Replace('/', ' ');

            var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));

            var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);

            var ns = new XmlNamespaceManager(doc.NameTable);

            ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
            var node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);

            if (node != null && node.Value != null)
            {
                return(node.Value);
            }

            if (HasDiacritics(item.Name))
            {
                // Try again using the search with accent characters url
                url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));

                doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);

                ns = new XmlNamespaceManager(doc.NameTable);
                ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
                node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);

                if (node != null && node.Value != null)
                {
                    return(node.Value);
                }
            }

            return(null);
        }
예제 #19
0
 public Task <IEnumerable <RemoteSearchResult> > GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken)
 {
     return(GetSearchResultsInternal(searchInfo, type, true, cancellationToken));
 }
예제 #20
0
        private async Task <IEnumerable <RemoteSearchResult> > GetSearchResultsInternal(ItemLookupInfo searchInfo, string type, bool enableMultipleResults, CancellationToken cancellationToken)
        {
            bool isSearch          = false;
            var  episodeSearchInfo = searchInfo as EpisodeInfo;

            var list = new List <RemoteSearchResult>();

            var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);

            var url = "http://www.omdbapi.com/?plot=full&r=json";

            if (type == "episode" && episodeSearchInfo != null)
            {
                episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out imdbId);
            }


            var name = searchInfo.Name;
            var year = searchInfo.Year;

            if (!string.IsNullOrWhiteSpace(name))
            {
                var parsedName = _libraryManager.ParseName(name);
                var yearInName = parsedName.Year;
                name = parsedName.Name;
                year = year ?? yearInName;
            }

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                if (year.HasValue)
                {
                    url += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture);
                }

                // &s means search and returns a list of results as opposed to t
                if (enableMultipleResults)
                {
                    url += "&s=" + WebUtility.UrlEncode(name);
                }
                else
                {
                    url += "&t=" + WebUtility.UrlEncode(name);
                }
                url     += "&type=" + type;
                isSearch = true;
            }
            else
            {
                url += "&i=" + imdbId;
            }

            if (type == "episode")
            {
                if (searchInfo.IndexNumber.HasValue)
                {
                    url += string.Format(CultureInfo.InvariantCulture, "&Episode={0}", searchInfo.IndexNumber);
                }
                if (searchInfo.ParentIndexNumber.HasValue)
                {
                    url += string.Format(CultureInfo.InvariantCulture, "&Season={0}", searchInfo.ParentIndexNumber);
                }
            }

            using (var stream = await _httpClient.Get(new HttpRequestOptions
            {
                Url = url,
                ResourcePool = OmdbProvider.ResourcePool,
                CancellationToken = cancellationToken
            }).ConfigureAwait(false))
            {
                var resultList = new List <SearchResult>();

                if (isSearch)
                {
                    var searchResultList = _jsonSerializer.DeserializeFromStream <SearchResultList>(stream);
                    if (searchResultList != null && searchResultList.Search != null)
                    {
                        resultList.AddRange(searchResultList.Search);
                    }
                }
                else
                {
                    var result = _jsonSerializer.DeserializeFromStream <SearchResult>(stream);
                    if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase))
                    {
                        resultList.Add(result);
                    }
                }

                foreach (var result in resultList)
                {
                    var item = new RemoteSearchResult
                    {
                        IndexNumber        = searchInfo.IndexNumber,
                        Name               = result.Title,
                        ParentIndexNumber  = searchInfo.ParentIndexNumber,
                        ProviderIds        = searchInfo.ProviderIds,
                        SearchProviderName = Name
                    };

                    if (episodeSearchInfo != null && episodeSearchInfo.IndexNumberEnd.HasValue)
                    {
                        item.IndexNumberEnd = episodeSearchInfo.IndexNumberEnd.Value;
                    }

                    item.SetProviderId(MetadataProviders.Imdb, result.imdbID);

                    int parsedYear;
                    if (result.Year.Length > 0 &&
                        int.TryParse(result.Year.Substring(0, Math.Min(result.Year.Length, 4)), NumberStyles.Any, CultureInfo.InvariantCulture, out parsedYear))
                    {
                        item.ProductionYear = parsedYear;
                    }

                    DateTime released;
                    if (!string.IsNullOrEmpty(result.Released) &&
                        DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out released))
                    {
                        item.PremiereDate = released;
                    }

                    if (!string.IsNullOrWhiteSpace(result.Poster) && !string.Equals(result.Poster, "N/A", StringComparison.OrdinalIgnoreCase))
                    {
                        item.ImageUrl = result.Poster;
                    }

                    list.Add(item);
                }
            }

            return(list);
        }
예제 #21
0
        private async Task <IEnumerable <RemoteSearchResult> > GetSearchResultsInternal(ItemLookupInfo searchInfo, bool isSearch, CancellationToken cancellationToken)
        {
            var type = searchInfo switch
            {
                EpisodeInfo => "episode",
                SeriesInfo => "series",
                _ => "movie"
            };

            // This is a bit hacky?
            var episodeSearchInfo = searchInfo as EpisodeInfo;
            var indexNumberEnd    = episodeSearchInfo?.IndexNumberEnd;

            var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb);

            var urlQuery = new StringBuilder("plot=full&r=json");

            if (episodeSearchInfo != null)
            {
                episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out imdbId);
                if (searchInfo.IndexNumber.HasValue)
                {
                    urlQuery.Append("&Episode=").Append(searchInfo.IndexNumber.Value);
                }

                if (searchInfo.ParentIndexNumber.HasValue)
                {
                    urlQuery.Append("&Season=").Append(searchInfo.ParentIndexNumber.Value);
                }
            }

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                var name = searchInfo.Name;
                var year = searchInfo.Year;
                if (!string.IsNullOrWhiteSpace(name))
                {
                    var parsedName = _libraryManager.ParseName(name);
                    var yearInName = parsedName.Year;
                    name = parsedName.Name;
                    year ??= yearInName;
                }

                if (year.HasValue)
                {
                    urlQuery.Append("&y=").Append(year);
                }

                // &s means search and returns a list of results as opposed to t
                urlQuery.Append(isSearch ? "&s=" : "&t=");
                urlQuery.Append(WebUtility.UrlEncode(name));
                urlQuery.Append("&type=")
                .Append(type);
            }
            else
            {
                urlQuery.Append("&i=")
                .Append(imdbId);
                isSearch = false;
            }

            var url = OmdbProvider.GetOmdbUrl(urlQuery.ToString());

            using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);

            await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);

            if (isSearch)
            {
                var searchResultList = await JsonSerializer.DeserializeAsync <SearchResultList>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);

                if (searchResultList?.Search != null)
                {
                    var resultCount = searchResultList.Search.Count;
                    var result      = new RemoteSearchResult[resultCount];
                    for (var i = 0; i < resultCount; i++)
                    {
                        result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
                    }

                    return(result);
                }
            }
            else
            {
                var result = await JsonSerializer.DeserializeAsync <SearchResult>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);

                if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
                {
                    return(new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) });
                }
            }

            return(Enumerable.Empty <RemoteSearchResult>());
        }
예제 #22
0
        private async Task <IEnumerable <RemoteSearchResult> > GetSearchResults(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken)
        {
            var name = idInfo.Name;
            var year = idInfo.Year;

            if (string.IsNullOrWhiteSpace(name))
            {
                return(new List <RemoteSearchResult>());
            }

            var tmdbSettings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);

            var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original");

            // TODO: Investigate: Does this mean we are reparsing already parsed ItemLookupInfo?
            var parsedName = _libraryManager.ParseName(name);
            var yearInName = parsedName.Year;

            name = parsedName.Name;
            year ??= yearInName;

            _logger.LogInformation("TmdbSearch: Finding id for item: {0} ({1})", name, year);
            var language = idInfo.MetadataLanguage.ToLowerInvariant();

            // Replace sequences of non-word characters with space
            // TMDB expects a space separated list of words make sure that is the case
            name = _cleanNonWord.Replace(name, " ").Trim();

            var results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);

            if (results.Count == 0)
            {
                //try in english if wasn't before
                if (!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                {
                    results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                }
            }

            // TODO: retrying alternatives should be done outside the search
            // provider so that the retry logic can be common for all search
            // providers
            if (results.Count == 0)
            {
                var name2 = parsedName.Name;

                // Remove things enclosed in []{}() etc
                name2 = _cleanEnclosed.Replace(name2, string.Empty);

                // Replace sequences of non-word characters with space
                name2 = _cleanNonWord.Replace(name2, " ");

                // Clean based on common stop words / tokens
                name2 = _cleanStopWords.Replace(name2, string.Empty);

                // Trim whitespace
                name2 = name2.Trim();

                // Search again if the new name is different
                if (!string.Equals(name2, name) && !string.IsNullOrWhiteSpace(name2))
                {
                    _logger.LogInformation("TmdbSearch: Finding id for item: {0} ({1})", name2, year);
                    results = await GetSearchResults(name2, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);

                    if (results.Count == 0 && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                    {
                        //one more time, in english
                        results = await GetSearchResults(name2, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                    }
                }
            }

            return(results.Where(i =>
            {
                if (year.HasValue && i.ProductionYear.HasValue)
                {
                    // Allow one year tolerance
                    return Math.Abs(year.Value - i.ProductionYear.Value) <= 1;
                }

                return true;
            }));
        }
예제 #23
0
 public Task <IEnumerable <RemoteSearchResult> > GetMovieSearchResults(ItemLookupInfo idInfo, CancellationToken cancellationToken)
 {
     return(GetSearchResults(idInfo, "movie", cancellationToken));
 }
예제 #24
0
 private void ApplySearchResult(ItemLookupInfo lookupInfo, RemoteSearchResult result)
 {
     lookupInfo.ProviderIds = result.ProviderIds;
     lookupInfo.Name        = result.Name;
     lookupInfo.Year        = result.ProductionYear;
 }
예제 #25
0
        private void FillLookupData(ItemLookupInfo lookupInfo, IHasMetadata item, MetadataRawTable table)
        {
            var propInfos = GetItemProperties(lookupInfo.GetType());

            var name = lookupInfo.Name;

            if (lookupInfo.Year.HasValue)
            {
                name = string.Format("{0} ({1})", name, lookupInfo.Year.Value);
            }

            table.LookupData.Add(new KeyValuePair <string, object>("Name", name));

            foreach (var propInfo in propInfos)
            {
                switch (propInfo.Name)
                {
                case "ProviderIds":
                    table.LookupData.Add(new KeyValuePair <string, object>(propInfo.Name, FlattenProviderIds(lookupInfo.ProviderIds, item, ", ")));
                    break;

                case "SeriesProviderIds":
                    var seasonInfo = lookupInfo as SeasonInfo;
                    if (seasonInfo != null)
                    {
                        table.LookupData.Add(new KeyValuePair <string, object>(propInfo.Name, FlattenProviderIds(seasonInfo.SeriesProviderIds, new Series(), ", ")));
                    }

                    var episodeInfo = lookupInfo as EpisodeInfo;
                    if (episodeInfo != null)
                    {
                        table.LookupData.Add(new KeyValuePair <string, object>(propInfo.Name, FlattenProviderIds(episodeInfo.SeriesProviderIds, new Series(), ", ")));
                    }

                    break;

                case "Name":
                case "Year":
                case "IsAutomated":
                case "MetadataCountryCode":
                    break;

                default:
                    var value = propInfo.GetValue(lookupInfo);
                    if (value != null)
                    {
                        if (propInfo.PropertyType == typeof(DateTime?))
                        {
                            DateTime?dateValue = (DateTime?)value;
                            table.LookupData.Add(new KeyValuePair <string, object>(propInfo.Name, dateValue.Value.ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern)));
                        }
                        else
                        {
                            table.LookupData.Add(new KeyValuePair <string, object>(propInfo.Name, value));
                        }
                    }

                    break;
                }
            }
        }
예제 #26
0
        public async Task <IEnumerable <RemoteSearchResult> > GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken)
        {
            var list = new List <RemoteSearchResult>();

            var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);

            var url = "http://www.omdbapi.com/?plot=short&r=json";

            var name = searchInfo.Name;
            var year = searchInfo.Year;

            if (!string.IsNullOrWhiteSpace(name))
            {
                var parsedName = _libraryManager.ParseName(name);
                var yearInName = parsedName.Year;
                name = parsedName.Name;
                year = year ?? yearInName;
            }

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                if (year.HasValue)
                {
                    url += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture);
                }

                url += "&t=" + WebUtility.UrlEncode(name);
                url += "&type=" + type;
            }
            else
            {
                url += "&i=" + imdbId;
            }

            using (var stream = await _httpClient.Get(new HttpRequestOptions
            {
                Url = url,
                ResourcePool = OmdbProvider.ResourcePool,
                CancellationToken = cancellationToken,
                CacheMode = CacheMode.Unconditional,
                CacheLength = TimeSpan.FromDays(2)
            }).ConfigureAwait(false))
            {
                var result = _jsonSerializer.DeserializeFromStream <SearchResult>(stream);

                if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase))
                {
                    var item = new RemoteSearchResult();

                    item.SearchProviderName = Name;
                    item.Name = result.Title;
                    item.SetProviderId(MetadataProviders.Imdb, result.imdbID);

                    int parsedYear;
                    if (int.TryParse(result.Year, NumberStyles.Any, CultureInfo.InvariantCulture, out parsedYear))
                    {
                        item.ProductionYear = parsedYear;
                    }

                    if (!string.IsNullOrWhiteSpace(result.Poster) && !string.Equals(result.Poster, "N/A", StringComparison.OrdinalIgnoreCase))
                    {
                        item.ImageUrl = result.Poster;
                    }

                    list.Add(item);
                }
            }

            return(list);
        }
예제 #27
0
        private async Task <IEnumerable <RemoteSearchResult> > GetSearchResultsInternal(ItemLookupInfo searchInfo, string type, bool isSearch, CancellationToken cancellationToken)
        {
            var episodeSearchInfo = searchInfo as EpisodeInfo;

            var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb);

            var urlQuery = "plot=full&r=json";

            if (type == "episode" && episodeSearchInfo != null)
            {
                episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out imdbId);
            }

            var name = searchInfo.Name;
            var year = searchInfo.Year;

            if (!string.IsNullOrWhiteSpace(name))
            {
                var parsedName = _libraryManager.ParseName(name);
                var yearInName = parsedName.Year;
                name = parsedName.Name;
                year ??= yearInName;
            }

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                if (year.HasValue)
                {
                    urlQuery += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture);
                }

                // &s means search and returns a list of results as opposed to t
                if (isSearch)
                {
                    urlQuery += "&s=" + WebUtility.UrlEncode(name);
                }
                else
                {
                    urlQuery += "&t=" + WebUtility.UrlEncode(name);
                }

                urlQuery += "&type=" + type;
            }
            else
            {
                urlQuery += "&i=" + imdbId;
                isSearch  = false;
            }

            if (type == "episode")
            {
                if (searchInfo.IndexNumber.HasValue)
                {
                    urlQuery += string.Format(CultureInfo.InvariantCulture, "&Episode={0}", searchInfo.IndexNumber);
                }

                if (searchInfo.ParentIndexNumber.HasValue)
                {
                    urlQuery += string.Format(CultureInfo.InvariantCulture, "&Season={0}", searchInfo.ParentIndexNumber);
                }
            }

            var url = OmdbProvider.GetOmdbUrl(urlQuery);

            using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false);

            await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

            var resultList = new List <SearchResult>();

            if (isSearch)
            {
                var searchResultList = await _jsonSerializer.DeserializeFromStreamAsync <SearchResultList>(stream).ConfigureAwait(false);

                if (searchResultList != null && searchResultList.Search != null)
                {
                    resultList.AddRange(searchResultList.Search);
                }
            }
            else
            {
                var result = await _jsonSerializer.DeserializeFromStreamAsync <SearchResult>(stream).ConfigureAwait(false);

                if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase))
                {
                    resultList.Add(result);
                }
            }

            return(resultList.Select(result =>
            {
                var item = new RemoteSearchResult
                {
                    IndexNumber = searchInfo.IndexNumber,
                    Name = result.Title,
                    ParentIndexNumber = searchInfo.ParentIndexNumber,
                    SearchProviderName = Name
                };

                if (episodeSearchInfo != null && episodeSearchInfo.IndexNumberEnd.HasValue)
                {
                    item.IndexNumberEnd = episodeSearchInfo.IndexNumberEnd.Value;
                }

                item.SetProviderId(MetadataProvider.Imdb, result.imdbID);

                if (result.Year.Length > 0 &&
                    int.TryParse(result.Year.AsSpan().Slice(0, Math.Min(result.Year.Length, 4)), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear))
                {
                    item.ProductionYear = parsedYear;
                }

                if (!string.IsNullOrEmpty(result.Released) &&
                    DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var released))
                {
                    item.PremiereDate = released;
                }

                if (!string.IsNullOrWhiteSpace(result.Poster) && !string.Equals(result.Poster, "N/A", StringComparison.OrdinalIgnoreCase))
                {
                    item.ImageUrl = result.Poster;
                }

                return item;
            }));
        }
예제 #28
0
        private async Task <IEnumerable <RemoteSearchResult> > GetSearchResults(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken)
        {
            var name = idInfo.Name;
            var year = idInfo.Year;

            if (string.IsNullOrWhiteSpace(name))
            {
                return(new List <RemoteSearchResult>());
            }

            var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);

            var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original");

            if (!string.IsNullOrWhiteSpace(name))
            {
                var parsedName = _libraryManager.ParseName(name);
                var yearInName = parsedName.Year;
                name = parsedName.Name;
                year = year ?? yearInName;
            }

            _logger.Info("MovieDbProvider: Finding id for item: " + name);
            var language = idInfo.MetadataLanguage.ToLower();

            //nope - search for it
            //var searchType = item is BoxSet ? "collection" : "movie";

            var results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);

            if (results.Count == 0)
            {
                //try in english if wasn't before
                if (!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                {
                    results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                }
            }

            if (results.Count == 0)
            {
                // try with dot and _ turned to space
                var originalName = name;

                name = name.Replace(",", " ");
                name = name.Replace(".", " ");
                name = name.Replace("_", " ");
                name = name.Replace("-", " ");
                name = name.Replace("!", " ");
                name = name.Replace("?", " ");

                var parenthIndex = name.IndexOf('(');
                if (parenthIndex != -1)
                {
                    name = name.Substring(0, parenthIndex);
                }

                name = name.Trim();

                // Search again if the new name is different
                if (!string.Equals(name, originalName))
                {
                    results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);

                    if (results.Count == 0 && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                    {
                        //one more time, in english
                        results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                    }
                }
            }

            return(results.Where(i =>
            {
                if (year.HasValue && i.ProductionYear.HasValue)
                {
                    // Allow one year tolerance
                    return Math.Abs(year.Value - i.ProductionYear.Value) <= 1;
                }

                return true;
            }));
        }
예제 #29
0
        private async Task <IEnumerable <RemoteSearchResult> > GetSearchResults(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken)
        {
            var name       = idInfo.Name;
            var year       = idInfo.Year;
            int?yearInName = null;

            var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);

            var tmdbImageUrl = tmdbSettings.images.base_url + "original";

            NameParser.ParseName(name, out name, out yearInName);

            year = year ?? yearInName;

            _logger.Info("MovieDbProvider: Finding id for item: " + name);
            var language = idInfo.MetadataLanguage.ToLower();

            //nope - search for it
            //var searchType = item is BoxSet ? "collection" : "movie";

            var results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);

            if (results.Count == 0)
            {
                //try in english if wasn't before
                if (!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                {
                    results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                }
            }

            if (results.Count == 0)
            {
                // try with dot and _ turned to space
                var originalName = name;

                name = name.Replace(",", " ");
                name = name.Replace(".", " ");
                name = name.Replace("_", " ");
                name = name.Replace("-", " ");
                name = name.Replace("!", " ");
                name = name.Replace("?", " ");

                name = name.Trim();

                // Search again if the new name is different
                if (!string.Equals(name, originalName))
                {
                    results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);

                    if (results.Count == 0 && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                    {
                        //one more time, in english
                        results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                    }
                }
            }

            return(results.Where(i =>
            {
                if (year.HasValue && i.ProductionYear.HasValue)
                {
                    return year.Value == i.ProductionYear.Value;
                }

                return true;
            }));
        }