diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-03-01 17:34:27 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-03-01 17:34:27 -0500 |
| commit | 6c5cf81752c4189e9a7a8c79ea84d802cc979eea (patch) | |
| tree | ef98da95463b2f6f535a3b9785ba64f4ddde7e46 | |
| parent | d537826d818bcff1da3b766b35dbacd7fa9a3184 (diff) | |
a start to the lookup feature
| -rw-r--r-- | MediaBrowser.Api/ItemLookupService.cs | 252 | ||||
| -rw-r--r-- | MediaBrowser.Api/Library/LibraryService.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.Api/MediaBrowser.Api.csproj | 1 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Providers/IProviderManager.cs | 12 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs | 11 | ||||
| -rw-r--r-- | MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs | 73 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/ProviderManager.cs | 23 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Movies/MovieDbProvider.cs | 7 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Movies/MovieDbSearch.cs | 96 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs | 14 | ||||
| -rw-r--r-- | MediaBrowser.Providers/People/MovieDbPersonProvider.cs | 15 | ||||
| -rw-r--r-- | MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs | 15 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs | 28 |
14 files changed, 484 insertions, 94 deletions
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs new file mode 100644 index 000000000..25782f8c1 --- /dev/null +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -0,0 +1,252 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Providers; +using ServiceStack; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Api +{ + [Route("/Items/{Id}/ExternalIdInfos", "GET")] + [Api(Description = "Gets external id infos for an item")] + public class GetExternalIdInfos : IReturn<List<ExternalIdInfo>> + { + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + + [Route("/Items/RemoteSearch/Movie", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetMovieRemoteSearchResults : RemoteSearchQuery<MovieInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/Trailer", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetTrailerRemoteSearchResults : RemoteSearchQuery<TrailerInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/AdultVideo", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetAdultVideoRemoteSearchResults : RemoteSearchQuery<ItemLookupInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/Series", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetSeriesRemoteSearchResults : RemoteSearchQuery<SeriesInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/Game", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetGameRemoteSearchResults : RemoteSearchQuery<GameInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/BoxSet", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetBoxSetRemoteSearchResults : RemoteSearchQuery<BoxSetInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/Person", "POST")] + [Api(Description = "Gets external id infos for an item")] + public class GetPersonRemoteSearchResults : RemoteSearchQuery<PersonLookupInfo>, IReturn<List<RemoteSearchResult>> + { + } + + [Route("/Items/RemoteSearch/Image", "GET")] + [Api(Description = "Gets a remote image")] + public class GetRemoteSearchImage + { + [ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ImageUrl { get; set; } + + [ApiMember(Name = "ProviderName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ProviderName { get; set; } + } + + public class ItemLookupService : BaseApiService + { + private readonly IDtoService _dtoService; + private readonly IProviderManager _providerManager; + private readonly IServerApplicationPaths _appPaths; + private readonly IFileSystem _fileSystem; + + public ItemLookupService(IDtoService dtoService, IProviderManager providerManager, IServerApplicationPaths appPaths, IFileSystem fileSystem) + { + _dtoService = dtoService; + _providerManager = providerManager; + _appPaths = appPaths; + _fileSystem = fileSystem; + } + + public object Get(GetExternalIdInfos request) + { + var item = _dtoService.GetItemByDtoId(request.Id); + + var infos = _providerManager.GetExternalIdInfos(item).ToList(); + + return ToOptimizedResult(infos); + } + + public object Post(GetMovieRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Post(GetAdultVideoRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<AdultVideo, ItemLookupInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Post(GetSeriesRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Post(GetGameRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Post(GetBoxSetRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Post(GetPersonRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Post(GetTrailerRemoteSearchResults request) + { + var result = _providerManager.GetRemoteSearchResults<Trailer, TrailerInfo>(request, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + + public object Get(GetRemoteSearchImage request) + { + var result = GetRemoteImage(request).Result; + + return result; + } + + /// <summary> + /// Gets the remote image. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>Task{System.Object}.</returns> + private async Task<object> GetRemoteImage(GetRemoteSearchImage request) + { + var urlHash = request.ImageUrl.GetMD5(); + var pointerCachePath = GetFullCachePath(urlHash.ToString()); + + string contentPath; + + try + { + using (var reader = new StreamReader(pointerCachePath)) + { + contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); + } + + if (File.Exists(contentPath)) + { + return ToStaticFileResult(contentPath); + } + } + catch (DirectoryNotFoundException) + { + // Means the file isn't cached yet + } + catch (FileNotFoundException) + { + // Means the file isn't cached yet + } + + await DownloadImage(request.ProviderName, request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false); + + // Read the pointer file again + using (var reader = new StreamReader(pointerCachePath)) + { + contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); + } + + return ToStaticFileResult(contentPath); + } + + /// <summary> + /// Downloads the image. + /// </summary> + /// <param name="providerName">Name of the provider.</param> + /// <param name="url">The URL.</param> + /// <param name="urlHash">The URL hash.</param> + /// <param name="pointerCachePath">The pointer cache path.</param> + /// <returns>Task.</returns> + private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath) + { + var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false); + + var ext = result.ContentType.Split('/').Last(); + + var fullCachePath = GetFullCachePath(urlHash + "." + ext); + + Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath)); + using (var stream = result.Content) + { + using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) + { + await stream.CopyToAsync(filestream).ConfigureAwait(false); + } + } + + Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + using (var writer = new StreamWriter(pointerCachePath)) + { + await writer.WriteAsync(fullCachePath).ConfigureAwait(false); + } + } + + /// <summary> + /// Gets the full cache path. + /// </summary> + /// <param name="filename">The filename.</param> + /// <returns>System.String.</returns> + private string GetFullCachePath(string filename) + { + return Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename); + } + + } +} diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 4cb20273f..c3fdbb9a0 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -6,10 +6,8 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; using ServiceStack; using System; @@ -50,18 +48,6 @@ namespace MediaBrowser.Api.Library public int Index { get; set; } } - [Route("/Items/{Id}/ExternalIdInfos", "GET")] - [Api(Description = "Gets external id infos for an item")] - public class GetExternalIdInfos : IReturn<List<ExternalIdInfo>> - { - /// <summary> - /// Gets or sets the id. - /// </summary> - /// <value>The id.</value> - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - } - /// <summary> /// Class GetCriticReviews /// </summary> @@ -256,29 +242,18 @@ namespace MediaBrowser.Api.Library private readonly IUserDataManager _userDataManager; private readonly IDtoService _dtoService; - private readonly IProviderManager _providerManager; /// <summary> /// Initializes a new instance of the <see cref="LibraryService" /> class. /// </summary> public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, - IDtoService dtoService, IUserDataManager userDataManager, IProviderManager providerManager) + IDtoService dtoService, IUserDataManager userDataManager) { _itemRepo = itemRepo; _libraryManager = libraryManager; _userManager = userManager; _dtoService = dtoService; _userDataManager = userDataManager; - _providerManager = providerManager; - } - - public object Get(GetExternalIdInfos request) - { - var item = _dtoService.GetItemByDtoId(request.Id); - - var infos = _providerManager.GetExternalIdInfos(item).ToList(); - - return ToOptimizedResult(infos); } public object Get(GetMediaFolders request) diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index ee2a7eafc..bcc487a5d 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -82,6 +82,7 @@ <Compile Include="Images\ImageService.cs" /> <Compile Include="Images\ImageWriter.cs" /> <Compile Include="InstantMixService.cs" /> + <Compile Include="ItemLookupService.cs" /> <Compile Include="ItemRefreshService.cs" /> <Compile Include="ItemUpdateService.cs" /> <Compile Include="Library\LibraryService.cs" /> diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 83ee6ae83..94b19498a 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -126,5 +127,14 @@ namespace MediaBrowser.Controller.Providers CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo; + + /// <summary> + /// Gets the search image. + /// </summary> + /// <param name="providerName">Name of the provider.</param> + /// <param name="url">The URL.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{HttpResponseInfo}.</returns> + Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken); } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs index f00a22a3a..0ff7ee5a9 100644 --- a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs @@ -18,11 +18,8 @@ namespace MediaBrowser.Controller.Providers Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken); } - public interface IRemoteSearchProvider<in TLookupInfoType> : IMetadataProvider - where TLookupInfoType : ItemLookupInfo + public interface IRemoteSearchProvider : IMetadataProvider { - Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken); - /// <summary> /// Gets the image response. /// </summary> @@ -31,6 +28,12 @@ namespace MediaBrowser.Controller.Providers /// <returns>Task{HttpResponseInfo}.</returns> Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken); } + + public interface IRemoteSearchProvider<in TLookupInfoType> : IRemoteSearchProvider + where TLookupInfoType : ItemLookupInfo + { + Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken); + } public class RemoteSearchQuery<T> where T : ItemLookupInfo diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs index 09939f2d6..d698b4ce0 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -32,20 +32,71 @@ namespace MediaBrowser.Providers.BoxSets private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; + private readonly IHttpClient _httpClient; - public MovieDbBoxSetProvider(ILogger logger, IJsonSerializer json, IServerConfigurationManager config, IFileSystem fileSystem, ILocalizationManager localization) + public MovieDbBoxSetProvider(ILogger logger, IJsonSerializer json, IServerConfigurationManager config, IFileSystem fileSystem, ILocalizationManager localization, IHttpClient httpClient) { _logger = logger; _json = json; _config = config; _fileSystem = fileSystem; _localization = localization; + _httpClient = httpClient; Current = this; } + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(BoxSetInfo searchInfo, CancellationToken cancellationToken) { - return new List<RemoteSearchResult>(); + var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); + + var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); + + var tmdbImageUrl = tmdbSettings.images.base_url + "original"; + + if (!string.IsNullOrEmpty(tmdbId)) + { + await EnsureInfo(tmdbId, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false); + + var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, searchInfo.MetadataLanguage); + var info = _json.DeserializeFromFile<RootObject>(dataFilePath); + + var images = (info.images ?? new Images()).posters ?? new List<Poster>(); + + var result = new RemoteSearchResult + { + Name = info.name, + + SearchProviderName = Name, + + ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path) + }; + + result.SetProviderId(MetadataProviders.Tmdb, info.id.ToString(_usCulture)); + + return new[] { result }; + } + + var results = await new MovieDbSearch(_logger, _json).GetSearchResults(searchInfo, cancellationToken).ConfigureAwait(false); + + return results.Select(i => GetRemoteSearchResult(i, tmdbImageUrl)); + } + + private RemoteSearchResult GetRemoteSearchResult(MovieDbSearch.TmdbMovieSearchResult tmdbResult, string baseImageUrl) + { + var result = new RemoteSearchResult + { + Name = tmdbResult.name, + + SearchProviderName = Name, + + ImageUrl = string.IsNullOrEmpty(tmdbResult.poster_path) ? null : (baseImageUrl + tmdbResult.poster_path) + }; + + result.SetProviderId(MetadataProviders.Tmdb, tmdbResult.id.ToString(_usCulture)); + + return result; } public async Task<MetadataResult<BoxSet>> GetMetadata(BoxSetInfo id, CancellationToken cancellationToken) @@ -55,7 +106,9 @@ namespace MediaBrowser.Providers.BoxSets // We don't already have an Id, need to fetch it if (string.IsNullOrEmpty(tmdbId)) { - var searchResult = await new MovieDbSearch(_logger, _json).FindCollectionId(id, cancellationToken).ConfigureAwait(false); + var searchResults = await new MovieDbSearch(_logger, _json).GetSearchResults(id, cancellationToken).ConfigureAwait(false); + + var searchResult = searchResults.FirstOrDefault(); if (searchResult != null) { @@ -219,10 +272,15 @@ namespace MediaBrowser.Providers.BoxSets private static string GetDataFilePath(IApplicationPaths appPaths, string tmdbId, string preferredLanguage) { + if (string.IsNullOrWhiteSpace(preferredLanguage)) + { + throw new ArgumentNullException("preferredLanguage"); + } + var path = GetDataPath(appPaths, tmdbId); var filename = string.Format("all-{0}.json", - preferredLanguage ?? string.Empty); + preferredLanguage); return Path.Combine(path, filename); } @@ -291,7 +349,12 @@ namespace MediaBrowser.Providers.BoxSets public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) { - throw new NotImplementedException(); + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = MovieDbProvider.Current.MovieDbResourcePool + }); } } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 942f414b6..b35c4887c 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -657,6 +657,15 @@ namespace MediaBrowser.Providers.Manager 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 provider.GetSearchResults(searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false); @@ -665,7 +674,7 @@ namespace MediaBrowser.Providers.Manager if (list.Count > 0) { - return list; + return list.Take(10); } } @@ -673,6 +682,18 @@ namespace MediaBrowser.Providers.Manager return new List<RemoteSearchResult>(); } + public Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken) + { + var provider = _metadataProviders.OfType<IRemoteSearchProvider>().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ArgumentException("Search provider not found."); + } + + return provider.GetImageResponse(url, cancellationToken); + } + public IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item) { return _externalIds.Where(i => diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index abd48e37c..b6dca5b7d 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -39,7 +39,9 @@ namespace MediaBrowser.Providers.Movies // 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 searchResult = await new MovieDbSearch(_logger, _jsonSerializer).FindMovieId(itemId, cancellationToken).ConfigureAwait(false); + var searchResults = await new MovieDbSearch(_logger, _jsonSerializer).GetMovieSearchResults(itemId, cancellationToken).ConfigureAwait(false); + + var searchResult = searchResults.FirstOrDefault(); if (searchResult != null) { diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 32a77a8a6..2c47dbc2f 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -558,7 +558,12 @@ namespace MediaBrowser.Providers.Movies public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) { - throw new NotImplementedException(); + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = MovieDbResourcePool + }); } } } diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs index 383705e0a..ad7335009 100644 --- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs +++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs @@ -29,22 +29,22 @@ namespace MediaBrowser.Providers.Movies _json = json; } - public Task<TmdbMovieSearchResult> FindSeriesId(ItemLookupInfo idInfo, CancellationToken cancellationToken) + public Task<IEnumerable<TmdbMovieSearchResult>> GetSearchResults(SeriesInfo idInfo, CancellationToken cancellationToken) { - return FindId(idInfo, "tv", cancellationToken); + return GetSearchResults(idInfo, "tv", cancellationToken); } - public Task<TmdbMovieSearchResult> FindMovieId(ItemLookupInfo idInfo, CancellationToken cancellationToken) + public Task<IEnumerable<TmdbMovieSearchResult>> GetMovieSearchResults(ItemLookupInfo idInfo, CancellationToken cancellationToken) { - return FindId(idInfo, "movie", cancellationToken); + return GetSearchResults(idInfo, "movie", cancellationToken); } - public Task<TmdbMovieSearchResult> FindCollectionId(ItemLookupInfo idInfo, CancellationToken cancellationToken) + public Task<IEnumerable<TmdbMovieSearchResult>> GetSearchResults(BoxSetInfo idInfo, CancellationToken cancellationToken) { - return FindId(idInfo, "collection", cancellationToken); + return GetSearchResults(idInfo, "collection", cancellationToken); } - private async Task<TmdbMovieSearchResult> FindId(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken) + private async Task<IEnumerable<TmdbMovieSearchResult>> GetSearchResults(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken) { var name = idInfo.Name; var year = idInfo.Year; @@ -60,48 +60,49 @@ namespace MediaBrowser.Providers.Movies //nope - search for it //var searchType = item is BoxSet ? "collection" : "movie"; - var id = await AttemptFindId(name, searchType, year, language, cancellationToken).ConfigureAwait(false); + var results = await GetSearchResults(name, searchType, year, language, cancellationToken).ConfigureAwait(false); - if (id == null) + if (results.Count == 0) { //try in english if wasn't before - if (language != "en") + if (!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) { - id = await AttemptFindId(name, searchType, year, "en", cancellationToken).ConfigureAwait(false); + results = await GetSearchResults(name, searchType, year, "en", cancellationToken).ConfigureAwait(false); } - else - { - // 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("?", " "); + if (results.Count == 0) + { + // try with dot and _ turned to space + var originalName = name; - name = name.Trim(); + name = name.Replace(",", " "); + name = name.Replace(".", " "); + name = name.Replace("_", " "); + name = name.Replace("-", " "); + name = name.Replace("!", " "); + name = name.Replace("?", " "); - // Search again if the new name is different - if (!string.Equals(name, originalName)) - { - id = await AttemptFindId(name, searchType, year, language, cancellationToken).ConfigureAwait(false); + name = name.Trim(); - if (id == null && language != "en") - { - //one more time, in english - id = await AttemptFindId(name, searchType, year, "en", cancellationToken).ConfigureAwait(false); + // Search again if the new name is different + if (!string.Equals(name, originalName)) + { + results = await GetSearchResults(name, searchType, year, language, 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", cancellationToken).ConfigureAwait(false); - } } } } - return id; + return results; } - private async Task<TmdbMovieSearchResult> AttemptFindId(string name, string type, int? year, string language, CancellationToken cancellationToken) + private async Task<List<TmdbMovieSearchResult>> GetSearchResults(string name, string type, int? year, string language, CancellationToken cancellationToken) { var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, type); @@ -113,9 +114,34 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false)) { - var searchResult = _json.DeserializeFromStream<TmdbMovieSearchResults>(json); - return FindBestResult(searchResult.results, name, year); + var searchResults = _json.DeserializeFromStream<TmdbMovieSearchResults>(json); + + var results = searchResults.results ?? new List<TmdbMovieSearchResult>(); + + var index = 0; + var resultTuples = results.Select(result => new Tuple<TmdbMovieSearchResult, int>(result, index++)).ToList(); + + return resultTuples.OrderBy(i => GetSearchResultOrder(i.Item1, year)) + .ThenBy(i => i.Item2) + .Select(i => i.Item1) + .ToList(); + } + } + + private int GetSearchResultOrder(TmdbMovieSearchResult result, int? year) + { + if (year.HasValue) + { + DateTime r; + + // These dates are always in this exact format + if (DateTime.TryParseExact(result.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r)) + { + return Math.Abs(r.Year - year.Value); + } } + + return 0; } private TmdbMovieSearchResult FindBestResult(List<TmdbMovieSearchResult> results, string name, int? year) diff --git a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs index 8c981e2d8..512fee8f8 100644 --- a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs @@ -11,6 +11,13 @@ namespace MediaBrowser.Providers.Movies { public class MovieDbTrailerProvider : IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder { + private readonly IHttpClient _httpClient; + + public MovieDbTrailerProvider(IHttpClient httpClient) + { + _httpClient = httpClient; + } + public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken) { return MovieDbProvider.Current.GetItemMetadata<Trailer>(info, cancellationToken); @@ -42,7 +49,12 @@ namespace MediaBrowser.Providers.Movies public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) { - throw new NotImplementedException(); + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = MovieDbProvider.Current.MovieDbResourcePool + }); } } } diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 01be6bf91..b5bf445bf 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -29,12 +29,14 @@ namespace MediaBrowser.Providers.People private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; + private readonly IHttpClient _httpClient; - public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer) + public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient) { _fileSystem = fileSystem; _configurationManager = configurationManager; _jsonSerializer = jsonSerializer; + _httpClient = httpClient; Current = this; } @@ -64,6 +66,8 @@ namespace MediaBrowser.Providers.People { Name = info.name, + SearchProviderName = Name, + ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path) }; @@ -94,6 +98,8 @@ namespace MediaBrowser.Providers.People { var result = new RemoteSearchResult { + SearchProviderName = Name, + Name = i.Name, ImageUrl = string.IsNullOrEmpty(i.Profile_Path) ? null : (baseImageUrl + i.Profile_Path) @@ -349,7 +355,12 @@ namespace MediaBrowser.Providers.People public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) { - throw new NotImplementedException(); + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = MovieDbProvider.Current.MovieDbResourcePool + }); } } } diff --git a/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs index b46336e90..9f1d5f021 100644 --- a/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs @@ -33,14 +33,16 @@ namespace MediaBrowser.Providers.TV private readonly IServerConfigurationManager _configurationManager; private readonly ILogger _logger; private readonly ILocalizationManager _localization; + private readonly IHttpClient _httpClient; - public MovieDbSeriesProvider(IJsonSerializer jsonSerializer, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger logger, ILocalizationManager localization) + public MovieDbSeriesProvider(IJsonSerializer jsonSerializer, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger logger, ILocalizationManager localization, IHttpClient httpClient) { _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; _configurationManager = configurationManager; _logger = logger; _localization = localization; + _httpClient = httpClient; Current = this; } @@ -82,7 +84,9 @@ namespace MediaBrowser.Providers.TV if (string.IsNullOrEmpty(tmdbId)) { - var searchResult = await new MovieDbSearch(_logger, _jsonSerializer).FindSeriesId(info, cancellationToken).ConfigureAwait(false); + var searchResults = await new MovieDbSearch(_logger, _jsonSerializer).GetSearchResults(info, cancellationToken).ConfigureAwait(false); + + var searchResult = searchResults.FirstOrDefault(); if (searchResult != null) { @@ -462,7 +466,12 @@ namespace MediaBrowser.Providers.TV public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) { - throw new NotImplementedException(); + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = MovieDbProvider.Current.MovieDbResourcePool + }); } } } diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 43037d6ce..c0d784fcc 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints public void Run() { - NatUtility.Logger = new LogWriter(_logger); + //NatUtility.Logger = new LogWriter(_logger); Reload(); } @@ -64,17 +64,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e) { - var ex = e.ExceptionObject as Exception; - - if (ex == null) - { - _logger.Error("Unidentified error reported by Mono.Nat"); - } - else - { - // Seeing some blank exceptions coming through here - _logger.ErrorException("Error reported by Mono.Nat: ", ex); - } + //var ex = e.ExceptionObject as Exception; + + //if (ex == null) + //{ + // _logger.Error("Unidentified error reported by Mono.Nat"); + //} + //else + //{ + // // Seeing some blank exceptions coming through here + // _logger.ErrorException("Error reported by Mono.Nat: ", ex); + //} } void NatUtility_DeviceFound(object sender, DeviceEventArgs e) @@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints } catch (Exception ex) { - _logger.ErrorException("Error creating port forwarding rules", ex); + //_logger.ErrorException("Error creating port forwarding rules", ex); } } @@ -106,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints private void CreatePortMap(INatDevice device, int port) { - _logger.Info("Creating port map on port {0}", port); + _logger.Debug("Creating port map on port {0}", port); device.CreatePortMap(new Mapping(Protocol.Tcp, port, port) { |
