private async Task <Series> AutoDetectSeries( string seriesName, int?seriesYear, TvFileOrganizationOptions options, CancellationToken cancellationToken) { if (options.AutoDetectSeries) { RemoteSearchResult finalResult = null; // Perform remote search var seriesInfo = new SeriesInfo { Name = seriesName, Year = seriesYear }; var searchQuery = new RemoteSearchQuery <SeriesInfo> { SearchInfo = seriesInfo }; var searchResults = await _providerManager.GetRemoteSearchResults <Series, SeriesInfo>(searchQuery, cancellationToken).ConfigureAwait(false); // Group series by name and year (if 2 series with the exact same name, the same year ...) var groupedResult = searchResults.GroupBy( p => new { p.Name, p.ProductionYear }, p => p, (key, g) => new { Key = key, Result = g.ToList() }).ToList(); if (groupedResult.Count == 1) { finalResult = groupedResult.First().Result.First(); } else if (groupedResult.Count > 1) { var filtredResult = groupedResult .Select(i => new { Ref = i, Score = NameUtils.GetMatchScore(seriesName, seriesYear, i.Key.Name, i.Key.ProductionYear) }) .Where(i => i.Score > 0) .OrderByDescending(i => i.Score) .Select(i => i.Ref) .FirstOrDefault(); finalResult = filtredResult?.Result.First(); } if (finalResult != null) { // We are in the good position, we can create the item var organizationRequest = new EpisodeFileOrganizationRequest { NewSeriesName = finalResult.Name, NewSeriesProviderIds = finalResult.ProviderIds, NewSeriesYear = finalResult.ProductionYear, TargetFolder = options.DefaultSeriesLibraryPath }; return(await CreateNewSeries(organizationRequest, finalResult, options, cancellationToken).ConfigureAwait(false)); } } return(null); }
public async Task <IEnumerable <RemoteSearchResult> > GetRemoteSearchResults <TItemType, TLookupType>(RemoteSearchQuery <TLookupType> searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { // Give it a dummy path just so that it looks like a file system item var dummy = new TItemType { Path = "C:\\", // Dummy this up to fool the local trailer check Parent = new Folder() }; var options = GetMetadataOptions(dummy); var providers = GetMetadataProvidersInternal <TItemType>(dummy, options, searchInfo.IncludeDisabledProviders) .OfType <IRemoteSearchProvider <TLookupType> >(); if (!string.IsNullOrEmpty(searchInfo.SearchProviderName)) { providers = providers.Where(i => string.Equals(i.Name, searchInfo.SearchProviderName, StringComparison.OrdinalIgnoreCase)); } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage)) { searchInfo.SearchInfo.MetadataLanguage = ConfigurationManager.Configuration.PreferredMetadataLanguage; } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode)) { searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode; } foreach (var provider in providers) { var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false); var list = results.ToList(); if (list.Count > 0) { return(list.Take(10)); } } // Nothing found return(new List <RemoteSearchResult>()); }
private async Task <IEnumerable <RemoteSearchResult> > GetRemoteSearchResults <TItemType, TLookupType>(RemoteSearchQuery <TLookupType> searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { LibraryOptions libraryOptions; if (referenceItem == null) { // Give it a dummy path just so that it looks like a file system item var dummy = new TItemType { Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"), ParentId = Guid.NewGuid() }; dummy.SetParent(new Folder()); referenceItem = dummy; libraryOptions = new LibraryOptions(); } else { libraryOptions = _libraryManager.GetLibraryOptions(referenceItem); } var options = GetMetadataOptions(referenceItem); var providers = GetMetadataProvidersInternal <TItemType>(referenceItem, libraryOptions, options, searchInfo.IncludeDisabledProviders, false) .OfType <IRemoteSearchProvider <TLookupType> >(); if (!string.IsNullOrEmpty(searchInfo.SearchProviderName)) { providers = providers.Where(i => string.Equals(i.Name, searchInfo.SearchProviderName, StringComparison.OrdinalIgnoreCase)); } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage)) { searchInfo.SearchInfo.MetadataLanguage = _configurationManager.Configuration.PreferredMetadataLanguage; } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode)) { searchInfo.SearchInfo.MetadataCountryCode = _configurationManager.Configuration.MetadataCountryCode; } var resultList = new List <RemoteSearchResult>(); foreach (var provider in providers) { try { var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false); foreach (var result in results) { var existingMatch = resultList.FirstOrDefault(i => i.ProviderIds.Any(p => string.Equals(result.GetProviderId(p.Key), p.Value, StringComparison.OrdinalIgnoreCase))); if (existingMatch == null) { resultList.Add(result); } else { foreach (var providerId in result.ProviderIds) { if (!existingMatch.ProviderIds.ContainsKey(providerId.Key)) { existingMatch.ProviderIds.Add(providerId.Key, providerId.Value); } } if (string.IsNullOrWhiteSpace(existingMatch.ImageUrl)) { existingMatch.ImageUrl = result.ImageUrl; } } } } #pragma warning disable CA1031 // do not catch general exception types catch (Exception ex) #pragma warning restore CA1031 // do not catch general exception types { _logger.LogError(ex, "Provider {ProviderName} failed to retrieve search results", provider.Name); } } return(resultList); }
/// <inheritdoc/> public Task <IEnumerable <RemoteSearchResult> > GetRemoteSearchResults <TItemType, TLookupType>(RemoteSearchQuery <TLookupType> searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { BaseItem referenceItem = null; if (!searchInfo.ItemId.Equals(Guid.Empty)) { referenceItem = _libraryManager.GetItemById(searchInfo.ItemId); } return(GetRemoteSearchResults <TItemType, TLookupType>(searchInfo, referenceItem, cancellationToken)); }
public async Task <ActionResult <IEnumerable <RemoteSearchResult> > > GetMovieRemoteSearchResults([FromBody, Required] RemoteSearchQuery <MovieInfo> query) { var results = await _providerManager.GetRemoteSearchResults <Movie, MovieInfo>(query, CancellationToken.None) .ConfigureAwait(false); return(Ok(results)); }
public async Task <IEnumerable <RemoteSearchResult> > GetRemoteSearchResults <TItemType, TLookupType>(RemoteSearchQuery <TLookupType> searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { // Give it a dummy path just so that it looks like a file system item var dummy = new TItemType { Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"), ParentId = Guid.NewGuid() }; dummy.SetParent(new Folder()); var options = GetMetadataOptions(dummy); var providers = GetMetadataProvidersInternal <TItemType>(dummy, options, searchInfo.IncludeDisabledProviders, false, false) .OfType <IRemoteSearchProvider <TLookupType> >(); if (!string.IsNullOrEmpty(searchInfo.SearchProviderName)) { providers = providers.Where(i => string.Equals(i.Name, searchInfo.SearchProviderName, StringComparison.OrdinalIgnoreCase)); } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage)) { searchInfo.SearchInfo.MetadataLanguage = ConfigurationManager.Configuration.PreferredMetadataLanguage; } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode)) { searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode; } var resultList = new List <RemoteSearchResult>(); foreach (var provider in providers) { try { var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false); foreach (var result in results) { var existingMatch = resultList.FirstOrDefault(i => i.ProviderIds.Any(p => string.Equals(result.GetProviderId(p.Key), p.Value, StringComparison.OrdinalIgnoreCase))); if (existingMatch == null) { resultList.Add(result); } else { foreach (var providerId in result.ProviderIds) { if (!existingMatch.ProviderIds.ContainsKey(providerId.Key)) { existingMatch.ProviderIds.Add(providerId.Key, providerId.Value); } } if (string.IsNullOrWhiteSpace(existingMatch.ImageUrl)) { existingMatch.ImageUrl = result.ImageUrl; } } } } catch (Exception ex) { // Logged at lower levels } } //_logger.Debug("Returning search results {0}", _json.SerializeToString(resultList)); return(resultList); }
public async Task <IEnumerable <RemoteSearchResult> > GetRemoteSearchResults <TItemType, TLookupType>(RemoteSearchQuery <TLookupType> searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { const int maxResults = 10; // Give it a dummy path just so that it looks like a file system item var dummy = new TItemType { Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"), ParentId = Guid.NewGuid() }; dummy.SetParent(new Folder()); var options = GetMetadataOptions(dummy); var providers = GetMetadataProvidersInternal <TItemType>(dummy, options, searchInfo.IncludeDisabledProviders, false) .OfType <IRemoteSearchProvider <TLookupType> >(); if (!string.IsNullOrEmpty(searchInfo.SearchProviderName)) { providers = providers.Where(i => string.Equals(i.Name, searchInfo.SearchProviderName, StringComparison.OrdinalIgnoreCase)); } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage)) { searchInfo.SearchInfo.MetadataLanguage = ConfigurationManager.Configuration.PreferredMetadataLanguage; } if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode)) { searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode; } var resultList = new List <RemoteSearchResult>(); var foundProviderIds = new Dictionary <Tuple <string, string>, RemoteSearchResult>(); var foundTitleYearStrings = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var provider in providers) { try { var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false); foreach (var result in results) { var bFound = false; // This check prevents duplicate search results by comparing provider ids foreach (var providerId in result.ProviderIds) { var idTuple = new Tuple <string, string>(providerId.Key.ToLower(), providerId.Value.ToLower()); if (!foundProviderIds.ContainsKey(idTuple)) { foundProviderIds.Add(idTuple, result); } else { bFound = true; var existingResult = foundProviderIds[idTuple]; if (string.IsNullOrEmpty(existingResult.ImageUrl) && !string.IsNullOrEmpty(result.ImageUrl)) { existingResult.ImageUrl = result.ImageUrl; } } } if (!bFound && resultList.Count < maxResults) { resultList.Add(result); } } } catch (Exception ex) { // Logged at lower levels } } return(resultList); }