diff --git a/MediaBrowser.Controller/Providers/ItemId.cs b/MediaBrowser.Controller/Providers/ItemId.cs index 1116eb8b5d..b3fe5bee53 100644 --- a/MediaBrowser.Controller/Providers/ItemId.cs +++ b/MediaBrowser.Controller/Providers/ItemId.cs @@ -26,6 +26,11 @@ namespace MediaBrowser.Controller.Providers /// /// The provider ids. public Dictionary ProviderIds { get; set; } + /// + /// Gets or sets the year. + /// + /// The year. + public int? Year { get; set; } public ItemId() { diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index eef6f0f2f4..424c9c48e5 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -189,6 +189,7 @@ namespace MediaBrowser.Model.Configuration /// true if [enable tv db updates]; otherwise, false. public bool EnableTvDbUpdates { get; set; } public bool EnableTmdbUpdates { get; set; } + public bool EnableFanArtUpdates { get; set; } public bool EnableVideoImageExtraction { get; set; } @@ -243,8 +244,9 @@ namespace MediaBrowser.Model.Configuration LegacyWebSocketPortNumber = 8945; EnableHttpLevelLogging = true; EnableDashboardResponseCaching = true; - EnableVideoImageExtraction = true; + EnableFanArtUpdates = true; + EnableVideoImageExtraction = true; EnableMovieChapterImageExtraction = true; EnableEpisodeChapterImageExtraction = false; EnableOtherVideoChapterImageExtraction = false; diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs new file mode 100644 index 0000000000..62b2e627f3 --- /dev/null +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -0,0 +1,41 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.BoxSets +{ + public class BoxSetMetadataService : ConcreteMetadataService + { + private readonly ILibraryManager _libraryManager; + + public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager) + : base(serverConfigurationManager, logger, providerManager, providerRepo) + { + _libraryManager = libraryManager; + } + + /// + /// Merges the specified source. + /// + /// The source. + /// The target. + /// The locked fields. + /// if set to true [replace data]. + protected override void MergeData(BoxSet source, BoxSet target, List lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + + protected override Task SaveItem(BoxSet item, ItemUpdateType reason, CancellationToken cancellationToken) + { + return _libraryManager.UpdateItem(item, reason, cancellationToken); + } + } +} diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs new file mode 100644 index 0000000000..8b8c8bffd8 --- /dev/null +++ b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs @@ -0,0 +1,62 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.BoxSets +{ + /// + /// Class SeriesProviderFromXml + /// + public class BoxSetXmlProvider : BaseXmlProvider, ILocalMetadataProvider + { + private readonly ILogger _logger; + + public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger) + : base(fileSystem) + { + _logger = logger; + } + + public async Task> GetMetadata(string path, CancellationToken cancellationToken) + { + path = GetXmlPath(path); + + var result = new MetadataResult(); + + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + var item = new BoxSet(); + + new BaseItemXmlParser(_logger).Fetch(item, path, cancellationToken); + result.HasMetadata = true; + result.Item = item; + } + catch (FileNotFoundException) + { + result.HasMetadata = false; + } + finally + { + XmlParsingResourcePool.Release(); + } + + return result; + } + + public string Name + { + get { return "Media Browser Xml"; } + } + + protected override string GetXmlPath(string path) + { + return Path.Combine(path, "collection.xml"); + } + } +} diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs new file mode 100644 index 0000000000..2fe18fafab --- /dev/null +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -0,0 +1,255 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Providers.Movies; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.BoxSets +{ + public class MovieDbBoxSetProvider : IRemoteMetadataProvider + { + private readonly CultureInfo _enUs = new CultureInfo("en-US"); + private const string GetCollectionInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images"; + + private readonly ILogger _logger; + private readonly IJsonSerializer _json; + private readonly IServerConfigurationManager _config; + private readonly IFileSystem _fileSystem; + + public MovieDbBoxSetProvider(ILogger logger, IJsonSerializer json, IServerConfigurationManager config, IFileSystem fileSystem) + { + _logger = logger; + _json = json; + _config = config; + _fileSystem = fileSystem; + } + + public async Task> GetMetadata(ItemId id, CancellationToken cancellationToken) + { + var tmdbId = id.GetProviderId(MetadataProviders.Tmdb); + + // We don't already have an Id, need to fetch it + if (string.IsNullOrEmpty(tmdbId)) + { + tmdbId = await GetTmdbId(id, cancellationToken).ConfigureAwait(false); + } + + var result = new MetadataResult(); + + if (!string.IsNullOrEmpty(tmdbId)) + { + await EnsureInfo(tmdbId, id.MetadataLanguage, cancellationToken).ConfigureAwait(false); + + var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, id.MetadataLanguage); + + if (!string.IsNullOrEmpty(dataFilePath)) + { + var mainResult = _json.DeserializeFromFile(dataFilePath); + + result.HasMetadata = true; + result.Item = GetItem(mainResult); + } + + } + + return result; + } + + private BoxSet GetItem(RootObject obj) + { + var item = new BoxSet(); + + item.Name = obj.name; + item.Overview = obj.overview; + item.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_enUs)); + + return item; + } + + private async Task DownloadInfo(string tmdbId, string preferredMetadataLanguage, CancellationToken cancellationToken) + { + var mainResult = await FetchMainResult(tmdbId, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + + if (mainResult == null) return; + + var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, preferredMetadataLanguage); + + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + + _json.SerializeToFile(mainResult, dataFilePath); + } + + private async Task FetchMainResult(string id, string language, CancellationToken cancellationToken) + { + var url = string.Format(GetCollectionInfo3, id, MovieDbSearch.ApiKey); + + // Get images in english and with no language + url += "&include_image_language=en,null"; + + if (!string.IsNullOrEmpty(language)) + { + // If preferred language isn't english, get those images too + if (!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) + { + url += string.Format(",{0}", language); + } + + url += string.Format("&language={0}", language); + } + + cancellationToken.ThrowIfCancellationRequested(); + + RootObject mainResult = null; + + using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions + { + Url = url, + CancellationToken = cancellationToken, + AcceptHeader = MovieDbSearch.AcceptHeader + + }).ConfigureAwait(false)) + { + mainResult = _json.DeserializeFromStream(json); + } + + cancellationToken.ThrowIfCancellationRequested(); + + if (mainResult != null && string.IsNullOrEmpty(mainResult.overview)) + { + if (!string.IsNullOrEmpty(language) && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) + { + url = string.Format(GetCollectionInfo3, id, MovieDbSearch.ApiKey) + "&include_image_language=en,null&language=en"; + + using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions + { + Url = url, + CancellationToken = cancellationToken, + AcceptHeader = MovieDbSearch.AcceptHeader + + }).ConfigureAwait(false)) + { + mainResult = _json.DeserializeFromStream(json); + } + + if (String.IsNullOrEmpty(mainResult.overview)) + { + _logger.Error("Unable to find information for (id:" + id + ")"); + return null; + } + } + } + return mainResult; + } + + internal Task EnsureInfo(string tmdbId, string preferredMetadataLanguage, CancellationToken cancellationToken) + { + var path = GetDataFilePath(_config.ApplicationPaths, tmdbId, preferredMetadataLanguage); + + var fileInfo = _fileSystem.GetFileSystemInfo(path); + + if (fileInfo.Exists) + { + // If it's recent or automatic updates are enabled, don't re-download + if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7) + { + return Task.FromResult(true); + } + } + + return DownloadInfo(tmdbId, preferredMetadataLanguage, cancellationToken); + } + + private Task GetTmdbId(ItemId id, CancellationToken cancellationToken) + { + return new MovieDbSearch(_logger, _json).FindCollectionId(id, cancellationToken); + } + + public string Name + { + get { return "TheMovieDb"; } + } + + private static string GetDataFilePath(IApplicationPaths appPaths, string tmdbId, string preferredLanguage) + { + var path = GetDataPath(appPaths, tmdbId); + + var filename = string.Format("all-{0}.json", + preferredLanguage ?? string.Empty); + + return Path.Combine(path, filename); + } + + private static string GetDataPath(IApplicationPaths appPaths, string tmdbId) + { + var dataPath = GetCollectionsDataPath(appPaths); + + return Path.Combine(dataPath, tmdbId); + } + + private static string GetCollectionsDataPath(IApplicationPaths appPaths) + { + var dataPath = Path.Combine(appPaths.DataPath, "tmdb-collections"); + + return dataPath; + } + + internal class Part + { + public string title { get; set; } + public int id { get; set; } + public string release_date { get; set; } + public string poster_path { get; set; } + public string backdrop_path { get; set; } + } + + internal class Backdrop + { + public double aspect_ratio { get; set; } + public string file_path { get; set; } + public int height { get; set; } + public string iso_639_1 { get; set; } + public object vote_average { get; set; } + public int vote_count { get; set; } + public int width { get; set; } + } + + internal class Poster + { + public double aspect_ratio { get; set; } + public string file_path { get; set; } + public int height { get; set; } + public string iso_639_1 { get; set; } + public object vote_average { get; set; } + public int vote_count { get; set; } + public int width { get; set; } + } + + internal class Images + { + public List backdrops { get; set; } + public List posters { get; set; } + } + + internal class RootObject + { + public int id { get; set; } + public string name { get; set; } + public string overview { get; set; } + public string poster_path { get; set; } + public string backdrop_path { get; set; } + public List parts { get; set; } + public Images images { get; set; } + } + } +} diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs index 389e2a2755..94209c309c 100644 --- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs +++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.GameGenres { - public class GameGenreMetadataService : MetadataService + public class GameGenreMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs index 83253a190f..21addc3908 100644 --- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs +++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Genres { - public class GenreMetadataService : MetadataService + public class GenreMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/ImagesByNameProvider.cs b/MediaBrowser.Providers/ImagesByNameProvider.cs index 8c5636580f..f634170269 100644 --- a/MediaBrowser.Providers/ImagesByNameProvider.cs +++ b/MediaBrowser.Providers/ImagesByNameProvider.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Providers public override bool Supports(BaseItem item) { // Only run for these generic types since we are expensive in file i/o - return item is BasePluginFolder || item is CollectionFolder; + return item is ICollectionFolder; } /// diff --git a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs index dd44ba7aae..0678943371 100644 --- a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.LiveTv { - public class ChannelMetadataService : MetadataService + public class ChannelMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs index da032eb8f0..6f08b199a5 100644 --- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.LiveTv { - public class ProgramMetadataService : MetadataService + public class ProgramMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/Manager/ConcreteMetadataService.cs b/MediaBrowser.Providers/Manager/ConcreteMetadataService.cs new file mode 100644 index 0000000000..3a4bc06ca5 --- /dev/null +++ b/MediaBrowser.Providers/Manager/ConcreteMetadataService.cs @@ -0,0 +1,20 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.Providers.Manager +{ + public abstract class ConcreteMetadataService : MetadataService + where TItemType : IHasMetadata, new() + { + protected ConcreteMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo) + : base(serverConfigurationManager, logger, providerManager, providerRepo) + { + } + + protected override TItemType CreateNew() + { + return new TItemType(); + } + } +} diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index e8b3a6ad64..d946f9cbdb 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -14,7 +14,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Manager { public abstract class MetadataService : IMetadataService - where TItemType : IHasMetadata, new() + where TItemType : IHasMetadata { protected readonly IServerConfigurationManager ServerConfigurationManager; protected readonly ILogger Logger; @@ -263,7 +263,7 @@ namespace MediaBrowser.Providers.Manager Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList() }; - var temp = new TItemType(); + var temp = CreateNew(); // If replacing all metadata, run internet providers first if (options.ReplaceAllMetadata) @@ -317,6 +317,8 @@ namespace MediaBrowser.Providers.Manager return refreshResult; } + protected abstract TItemType CreateNew(); + private async Task ExecuteRemoteProviders(TItemType item, TItemType temp, IEnumerable> providers, RefreshResult refreshResult, CancellationToken cancellationToken) { var id = GetId(item); diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index b44d3608e1..ce996ccfc4 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -65,11 +65,14 @@ + + + @@ -83,6 +86,7 @@ + @@ -92,7 +96,7 @@ - + @@ -169,6 +173,7 @@ + diff --git a/MediaBrowser.Providers/Movies/BoxSetProviderFromXml.cs b/MediaBrowser.Providers/Movies/BoxSetProviderFromXml.cs deleted file mode 100644 index 7c88243b3a..0000000000 --- a/MediaBrowser.Providers/Movies/BoxSetProviderFromXml.cs +++ /dev/null @@ -1,97 +0,0 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.IO; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Providers.Movies -{ - /// - /// Class SeriesProviderFromXml - /// - public class BoxSetProviderFromXml : BaseMetadataProvider - { - private readonly IFileSystem _fileSystem; - - public BoxSetProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) - : base(logManager, configurationManager) - { - _fileSystem = fileSystem; - } - - /// - /// Supportses the specified item. - /// - /// The item. - /// true if XXXX, false otherwise - public override bool Supports(BaseItem item) - { - return item is BoxSet && item.LocationType == LocationType.FileSystem; - } - - /// - /// Gets the priority. - /// - /// The priority. - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.First; } - } - - private const string XmlFileName = "collection.xml"; - protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) - { - var xml = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName)); - - if (xml == null) - { - return false; - } - - return _fileSystem.GetLastWriteTimeUtc(xml) > item.DateLastSaved; - } - - /// - /// Fetches metadata and returns true or false indicating if any work that requires persistence was done - /// - /// The item. - /// if set to true [force]. - /// The cancellation token. - /// Task{System.Boolean}. - public override async Task FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName)); - - if (metadataFile != null) - { - var path = metadataFile.FullName; - - await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - new BaseItemXmlParser(Logger).Fetch((BoxSet)item, path, cancellationToken); - } - finally - { - XmlParsingResourcePool.Release(); - } - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - - return true; - } - - return false; - } - } -} diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 2682cf3c0d..3c8fd4612d 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -111,11 +111,6 @@ namespace MediaBrowser.Providers.Movies /// The item. /// true if XXXX, false otherwise public override bool Supports(BaseItem item) - { - return SupportsItem(item); - } - - internal static bool SupportsItem(IHasImages item) { var trailer = item as Trailer; @@ -124,7 +119,7 @@ namespace MediaBrowser.Providers.Movies return !trailer.IsLocalTrailer; } - return item is Movie || item is BoxSet || item is MusicVideo; + return item is Movie || item is MusicVideo; } /// @@ -254,6 +249,23 @@ namespace MediaBrowser.Providers.Movies } } + internal Task EnsureMovieXml(string tmdbId, CancellationToken cancellationToken) + { + var path = GetFanartXmlPath(tmdbId); + + var fileInfo = _fileSystem.GetFileSystemInfo(path); + + if (fileInfo.Exists) + { + if (ConfigurationManager.Configuration.EnableFanArtUpdates || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7) + { + return Task.FromResult(true); + } + } + + return DownloadMovieXml(tmdbId, cancellationToken); + } + private async Task FetchImages(BaseItem item, List images, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs index c34bd47d7e..7e0222f722 100644 --- a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -41,7 +42,14 @@ namespace MediaBrowser.Providers.Movies public bool Supports(IHasImages item) { - return FanArtMovieProvider.SupportsItem(item); + var trailer = item as Trailer; + + if (trailer != null) + { + return !trailer.IsLocalTrailer; + } + + return item is Movie || item is BoxSet || item is MusicVideo; } public IEnumerable GetSupportedImages(IHasImages item) @@ -65,7 +73,7 @@ namespace MediaBrowser.Providers.Movies return images.Where(i => i.Type == imageType); } - public Task> GetAllImages(IHasImages item, CancellationToken cancellationToken) + public async Task> GetAllImages(IHasImages item, CancellationToken cancellationToken) { var baseItem = (BaseItem)item; var list = new List(); @@ -74,6 +82,8 @@ namespace MediaBrowser.Providers.Movies if (!string.IsNullOrEmpty(movieId)) { + await FanArtMovieProvider.Current.EnsureMovieXml(movieId, cancellationToken).ConfigureAwait(false); + var xmlPath = FanArtMovieProvider.Current.GetFanartXmlPath(movieId); try @@ -91,7 +101,7 @@ namespace MediaBrowser.Providers.Movies var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); // Sort first by width to prioritize HD versions - list = list.OrderByDescending(i => i.Width ?? 0) + return list.OrderByDescending(i => i.Width ?? 0) .ThenByDescending(i => { if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase)) @@ -111,10 +121,7 @@ namespace MediaBrowser.Providers.Movies } return 0; }) - .ThenByDescending(i => i.CommunityRating ?? 0) - .ToList(); - - return Task.FromResult>(list); + .ThenByDescending(i => i.CommunityRating ?? 0); } private void AddImages(List list, string xmlPath, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs index ee1f14e09d..c8cd746dc2 100644 --- a/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs @@ -1,6 +1,6 @@ using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -18,13 +18,11 @@ namespace MediaBrowser.Providers.Movies class ManualMovieDbImageProvider : IRemoteImageProvider { private readonly IJsonSerializer _jsonSerializer; - private readonly IServerConfigurationManager _config; private readonly IHttpClient _httpClient; - public ManualMovieDbImageProvider(IJsonSerializer jsonSerializer, IServerConfigurationManager config, IHttpClient httpClient) + public ManualMovieDbImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient) { _jsonSerializer = jsonSerializer; - _config = config; _httpClient = httpClient; } @@ -40,7 +38,15 @@ namespace MediaBrowser.Providers.Movies public bool Supports(IHasImages item) { - return MovieDbImagesProvider.SupportsItem(item); + var trailer = item as Trailer; + + if (trailer != null) + { + return !trailer.IsLocalTrailer; + } + + // Don't support local trailers + return item is Movie || item is BoxSet || item is MusicVideo; } public IEnumerable GetSupportedImages(IHasImages item) diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs index 7386f47f46..55d1b7588d 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs @@ -57,11 +57,6 @@ namespace MediaBrowser.Providers.Movies /// The item. /// true if XXXX, false otherwise public override bool Supports(BaseItem item) - { - return SupportsItem(item); - } - - internal static bool SupportsItem(IHasImages item) { var trailer = item as Trailer; @@ -71,7 +66,7 @@ namespace MediaBrowser.Providers.Movies } // Don't support local trailers - return item is Movie || item is BoxSet || item is MusicVideo; + return item is Movie || item is MusicVideo; } public override ItemUpdateType ItemUpdateType diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 6f32aa1358..d1cc17e15c 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Providers.Movies } // Don't support local trailers - return item is Movie || item is BoxSet || item is MusicVideo; + return item is Movie || item is MusicVideo; } /// @@ -182,9 +182,7 @@ namespace MediaBrowser.Providers.Movies } private const string TmdbConfigUrl = "http://api.themoviedb.org/3/configuration?api_key={0}"; - private const string Search3 = @"http://api.themoviedb.org/3/search/{3}?api_key={1}&query={0}&language={2}"; private const string GetMovieInfo3 = @"http://api.themoviedb.org/3/movie/{0}?api_key={1}&append_to_response=casts,releases,images,keywords,trailers"; - private const string GetBoxSetInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images"; internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669"; internal static string AcceptHeader = "application/json,image/*"; @@ -217,12 +215,11 @@ namespace MediaBrowser.Providers.Movies /// Gets the movie data path. /// /// The app paths. - /// if set to true [is box set]. /// The TMDB id. /// System.String. - internal static string GetMovieDataPath(IApplicationPaths appPaths, bool isBoxSet, string tmdbId) + internal static string GetMovieDataPath(IApplicationPaths appPaths, string tmdbId) { - var dataPath = isBoxSet ? GetBoxSetsDataPath(appPaths) : GetMoviesDataPath(appPaths); + var dataPath = GetMoviesDataPath(appPaths); return Path.Combine(dataPath, tmdbId); } @@ -234,13 +231,6 @@ namespace MediaBrowser.Providers.Movies return dataPath; } - internal static string GetBoxSetsDataPath(IApplicationPaths appPaths) - { - var dataPath = Path.Combine(appPaths.DataPath, "tmdb-collections"); - - return dataPath; - } - /// /// Fetches metadata and returns true or false indicating if any work that requires persistence was done /// @@ -262,7 +252,8 @@ namespace MediaBrowser.Providers.Movies // Don't search for music video id's because it is very easy to misidentify. if (string.IsNullOrEmpty(id) && !(item is MusicVideo)) { - id = await FindId(item, cancellationToken).ConfigureAwait(false); + id = await new MovieDbSearch(Logger, JsonSerializer) + .FindMovieId(GetId(item), cancellationToken).ConfigureAwait(false); } if (!string.IsNullOrEmpty(id)) @@ -276,6 +267,17 @@ namespace MediaBrowser.Providers.Movies return true; } + private ItemId GetId(IHasMetadata item) + { + return new ItemId + { + MetadataCountryCode = item.GetPreferredMetadataCountryCode(), + MetadataLanguage = item.GetPreferredMetadataLanguage(), + Name = item.Name, + ProviderIds = item.ProviderIds + }; + } + /// /// Determines whether [has alt meta] [the specified item]. /// @@ -283,11 +285,6 @@ namespace MediaBrowser.Providers.Movies /// true if [has alt meta] [the specified item]; otherwise, false. internal static bool HasAltMeta(BaseItem item) { - if (item is BoxSet) - { - return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName("collection.xml"); - } - var path = MovieXmlSaver.GetMovieSavePath(item); if (item.LocationType == LocationType.FileSystem) @@ -299,191 +296,6 @@ namespace MediaBrowser.Providers.Movies return false; } - /// - /// Finds the id. - /// - /// The item. - /// The cancellation token - /// Task{System.String}. - public async Task FindId(BaseItem item, CancellationToken cancellationToken) - { - int? yearInName; - string name = item.Name; - NameParser.ParseName(name, out name, out yearInName); - - var year = item.ProductionYear ?? yearInName; - - Logger.Info("MovieDbProvider: Finding id for item: " + name); - var language = item.GetPreferredMetadataLanguage().ToLower(); - - //if we are a boxset - look at our first child - var boxset = item as BoxSet; - if (boxset != null) - { - // See if any movies have a collection id already - var collId = boxset.Children.Concat(boxset.GetLinkedChildren()).OfType /// The ids. - /// if set to true [is box set]. - /// The movies data path. /// The progress. /// The cancellation token. /// Task. - private async Task UpdateMovies(IEnumerable ids, bool isBoxSet, string moviesDataPath, IProgress progress, CancellationToken cancellationToken) + private async Task UpdateMovies(IEnumerable ids, IProgress progress, CancellationToken cancellationToken) { var list = ids.ToList(); var numComplete = 0; @@ -219,7 +195,7 @@ namespace MediaBrowser.Providers.Movies { try { - await UpdateMovie(id, isBoxSet, language, cancellationToken).ConfigureAwait(false); + await UpdateMovie(id, language, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -240,15 +216,14 @@ namespace MediaBrowser.Providers.Movies /// Updates the movie. /// /// The id. - /// if set to true [is box set]. /// The preferred metadata language. /// The cancellation token. /// Task. - private Task UpdateMovie(string id, bool isBoxSet, string preferredMetadataLanguage, CancellationToken cancellationToken) + private Task UpdateMovie(string id, string preferredMetadataLanguage, CancellationToken cancellationToken) { _logger.Info("Updating movie from tmdb " + id + ", language " + preferredMetadataLanguage); - return MovieDbProvider.Current.DownloadMovieInfo(id, isBoxSet, preferredMetadataLanguage, cancellationToken); + return MovieDbProvider.Current.DownloadMovieInfo(id, preferredMetadataLanguage, cancellationToken); } class Result diff --git a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs index b88ca92bc6..aba60e7ba1 100644 --- a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs +++ b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.MusicGenres { - public class MusicGenreMetadataService : MetadataService + public class MusicGenreMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 088ba0322e..15a54474ba 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -88,6 +88,7 @@ namespace MediaBrowser.Providers.People item.SetProviderId(MetadataProviders.Imdb, info.imdb_id); } + result.HasMetadata = true; result.Item = item; } diff --git a/MediaBrowser.Providers/People/PersonMetadataService.cs b/MediaBrowser.Providers/People/PersonMetadataService.cs index e040139348..fe17f67b18 100644 --- a/MediaBrowser.Providers/People/PersonMetadataService.cs +++ b/MediaBrowser.Providers/People/PersonMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.People { - public class PersonMetadataService : MetadataService + public class PersonMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/Studios/StudioMetadataService.cs b/MediaBrowser.Providers/Studios/StudioMetadataService.cs index 1a35b94b37..f27a5c3b06 100644 --- a/MediaBrowser.Providers/Studios/StudioMetadataService.cs +++ b/MediaBrowser.Providers/Studios/StudioMetadataService.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Studios { - public class StudioMetadataService : MetadataService + public class StudioMetadataService : ConcreteMetadataService { private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Providers/Users/UserMetadataService.cs b/MediaBrowser.Providers/Users/UserMetadataService.cs new file mode 100644 index 0000000000..f2b2da0874 --- /dev/null +++ b/MediaBrowser.Providers/Users/UserMetadataService.cs @@ -0,0 +1,41 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Users +{ + public class UserMetadataService : ConcreteMetadataService + { + private readonly IUserManager _userManager; + + public UserMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager, IUserManager userManager) + : base(serverConfigurationManager, logger, providerManager, providerRepo) + { + _userManager = userManager; + } + + /// + /// Merges the specified source. + /// + /// The source. + /// The target. + /// The locked fields. + /// if set to true [replace data]. + protected override void MergeData(User source, User target, List lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + + protected override Task SaveItem(User item, ItemUpdateType reason, CancellationToken cancellationToken) + { + return _userManager.UpdateUser(item); + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs index 7ae740508b..0f7e94ac59 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs @@ -18,9 +18,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer { var log = new StringBuilder(); - var headers = string.Join(",", request.Headers.AllKeys.Where(i => !string.Equals(i, "cookie", StringComparison.OrdinalIgnoreCase) && !string.Equals(i, "Referer", StringComparison.OrdinalIgnoreCase)).Select(k => k + "=" + request.Headers[k])); + //var headers = string.Join(",", request.Headers.AllKeys.Where(i => !string.Equals(i, "cookie", StringComparison.OrdinalIgnoreCase) && !string.Equals(i, "Referer", StringComparison.OrdinalIgnoreCase)).Select(k => k + "=" + request.Headers[k])); - log.AppendLine("Ip: " + request.RemoteEndPoint + ". Headers: " + headers); + //log.AppendLine("Ip: " + request.RemoteEndPoint + ". Headers: " + headers); var type = request.IsWebSocketRequest ? "Web Socket" : "HTTP " + request.HttpMethod; @@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer log.AppendLine(string.Format("Url: {0}", url)); - log.AppendLine("Headers: " + string.Join(",", response.Headers.AllKeys.Select(k => k + "=" + response.Headers[k]))); + //log.AppendLine("Headers: " + string.Join(",", response.Headers.AllKeys.Select(k => k + "=" + response.Headers[k]))); var responseTime = string.Format(". Response time: {0} ms", duration.TotalMilliseconds); diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 91112b4099..12686f5426 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.Library { var user = _userManager.GetUserById(new Guid(query.UserId)); - var inputItems = user.RootFolder.GetRecursiveChildren(user, null); + var inputItems = user.RootFolder.GetRecursiveChildren(user, null).Where(i => !(i is ICollectionFolder)); var results = await GetSearchHints(inputItems, query).ConfigureAwait(false);