diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index c4419531c5..b3b75359aa 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -80,7 +80,7 @@ namespace MediaBrowser.Api .OrderBy(i => i) .ToArray(); - result.Tags = items.OfType() + result.Tags = items .SelectMany(i => i.Tags) .Distinct(StringComparer.OrdinalIgnoreCase) .OrderBy(i => i) diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index 387771b6d5..cb77e62adf 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Api { @@ -187,18 +188,40 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetSimilarGames request) { + var result = GetSimilarItemsResult(request); + + return ToOptimizedSerializedResultUsingCache(result); + } + + private QueryResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) + { + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + var item = string.IsNullOrEmpty(request.Id) ? + (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : + _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); + + var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Limit = request.Limit, + IncludeItemTypes = new[] + { + typeof(Game).Name + }, + SimilarTo = item + + }).ToList(); + var dtoOptions = GetDtoOptions(request); - var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, - _itemRepo, - _libraryManager, - _userDataRepository, - _dtoService, - Logger, - request, new[] { typeof(Game) }, - SimilarItemsHelper.GetSimiliarityScore); + var result = new QueryResult + { + Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(), - return ToOptimizedSerializedResultUsingCache(result); + TotalRecordCount = itemsResult.Count + }; + + return result; } } } diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 5bb4ed5f00..79aaccfe80 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -280,11 +280,7 @@ namespace MediaBrowser.Api episode.AbsoluteEpisodeNumber = request.AbsoluteEpisodeNumber; } - var hasTags = item as IHasTags; - if (hasTags != null) - { - hasTags.Tags = request.Tags; - } + item.Tags = request.Tags; var hasTaglines = item as IHasTaglines; if (hasTaglines != null) @@ -298,11 +294,7 @@ namespace MediaBrowser.Api hasShortOverview.ShortOverview = request.ShortOverview; } - var hasKeywords = item as IHasKeywords; - if (hasKeywords != null) - { - hasKeywords.Keywords = request.Keywords; - } + item.Keywords = request.Keywords; if (request.Studios != null) { @@ -427,11 +419,6 @@ namespace MediaBrowser.Api series.Status = request.SeriesStatus; series.AirDays = request.AirDays; series.AirTime = request.AirTime; - - if (request.DisplaySpecialsWithSeasons.HasValue) - { - series.DisplaySpecialsWithSeasons = request.DisplaySpecialsWithSeasons.Value; - } } } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index d3a4558c88..41c0c39eae 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -439,6 +439,12 @@ namespace MediaBrowser.Api.LiveTv public string Id { get; set; } } + [Route("/LiveTv/ListingProviders/Default", "GET")] + [Authenticated(AllowBeforeStartupWizard = true)] + public class GetDefaultListingProvider : ListingsProviderInfo, IReturn + { + } + [Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")] [Authenticated(AllowBeforeStartupWizard = true)] public class AddListingProvider : ListingsProviderInfo, IReturn @@ -478,6 +484,40 @@ namespace MediaBrowser.Api.LiveTv { } + [Route("/LiveTv/ChannelMappingOptions")] + [Authenticated(AllowBeforeStartupWizard = true)] + public class GetChannelMappingOptions + { + [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ProviderId { get; set; } + } + + [Route("/LiveTv/ChannelMappings")] + [Authenticated(AllowBeforeStartupWizard = true)] + public class SetChannelMapping + { + [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ProviderId { get; set; } + public string TunerChannelNumber { get; set; } + public string ProviderChannelNumber { get; set; } + } + + public class ChannelMappingOptions + { + public List TunerChannels { get; set; } + public List ProviderChannels { get; set; } + public List Mappings { get; set; } + public string ProviderName { get; set; } + } + + public class TunerChannelMapping + { + public string Name { get; set; } + public string Number { get; set; } + public string ProviderChannelNumber { get; set; } + public string ProviderChannelName { get; set; } + } + [Route("/LiveTv/Registration", "GET")] [Authenticated] public class GetLiveTvRegistrationInfo : IReturn @@ -525,6 +565,11 @@ namespace MediaBrowser.Api.LiveTv _dtoService = dtoService; } + public object Get(GetDefaultListingProvider request) + { + return ToOptimizedResult(new ListingsProviderInfo()); + } + public async Task Get(GetSatChannnelScanResult request) { var result = await _liveTvManager.GetSatChannelScanResult(request, CancellationToken.None).ConfigureAwait(false); @@ -539,6 +584,102 @@ namespace MediaBrowser.Api.LiveTv return ToOptimizedResult(result); } + public async Task Post(SetChannelMapping request) + { + var config = GetConfiguration(); + + var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase)); + listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, request.TunerChannelNumber, StringComparison.OrdinalIgnoreCase)).ToArray(); + + if (!string.Equals(request.TunerChannelNumber, request.ProviderChannelNumber, StringComparison.OrdinalIgnoreCase)) + { + var list = listingsProviderInfo.ChannelMappings.ToList(); + list.Add(new NameValuePair + { + Name = request.TunerChannelNumber, + Value = request.ProviderChannelNumber + }); + listingsProviderInfo.ChannelMappings = list.ToArray(); + } + + UpdateConfiguration(config); + + var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None) + .ConfigureAwait(false); + + var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None) + .ConfigureAwait(false); + + var mappings = listingsProviderInfo.ChannelMappings.ToList(); + + var tunerChannelMappings = + tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList(); + + return tunerChannelMappings.First(i => string.Equals(i.Number, request.TunerChannelNumber, StringComparison.OrdinalIgnoreCase)); + } + + public async Task Get(GetChannelMappingOptions request) + { + var config = GetConfiguration(); + + var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase)); + + var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name; + + var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None) + .ConfigureAwait(false); + + var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None) + .ConfigureAwait(false); + + var mappings = listingsProviderInfo.ChannelMappings.ToList(); + + var result = new ChannelMappingOptions + { + TunerChannels = tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList(), + + ProviderChannels = providerChannels.Select(i => new NameIdPair + { + Name = i.Name, + Id = i.Number + + }).ToList(), + + Mappings = mappings, + + ProviderName = listingsProviderName + }; + + return ToOptimizedResult(result); + } + + private TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, List mappings, List providerChannels) + { + var result = new TunerChannelMapping + { + Name = channel.Number + " " + channel.Name, + Number = channel.Number + }; + + var mapping = mappings.FirstOrDefault(i => string.Equals(i.Name, channel.Number, StringComparison.OrdinalIgnoreCase)); + var providerChannelNumber = channel.Number; + + if (mapping != null) + { + providerChannelNumber = mapping.Value; + } + + var providerChannel = providerChannels.FirstOrDefault(i => string.Equals(i.Number, providerChannelNumber, StringComparison.OrdinalIgnoreCase)); + + if (providerChannel != null) + { + result.ProviderChannelNumber = providerChannel.Number; + result.ProviderChannelName = providerChannel.Name; + } + + return result; + } + public object Get(GetSatIniMappings request) { return ToOptimizedResult(_liveTvManager.GetSatIniMappings()); @@ -550,9 +691,7 @@ namespace MediaBrowser.Api.LiveTv var response = await _httpClient.Get(new HttpRequestOptions { - Url = "https://json.schedulesdirect.org/20141201/available/countries", - CacheLength = TimeSpan.FromDays(1), - CacheMode = CacheMode.Unconditional + Url = "https://json.schedulesdirect.org/20141201/available/countries" }).ConfigureAwait(false); @@ -609,6 +748,11 @@ namespace MediaBrowser.Api.LiveTv return _config.GetConfiguration("livetv"); } + private void UpdateConfiguration(LiveTvOptions options) + { + _config.SaveConfiguration("livetv", options); + } + public async Task Get(GetLineups request) { var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false); @@ -648,7 +792,7 @@ namespace MediaBrowser.Api.LiveTv Items = returnArray, TotalRecordCount = channelResult.TotalRecordCount }; - + return ToOptimizedSerializedResultUsingCache(result); } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index d8946e416f..ff18d440c1 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Controller.LiveTv; namespace MediaBrowser.Api.Movies { @@ -110,18 +111,16 @@ namespace MediaBrowser.Api.Movies /// /// The request. /// System.Object. - public async Task Get(GetSimilarMovies request) + public object Get(GetSimilarMovies request) { - var result = await GetSimilarItemsResult( - request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + var result = GetSimilarItemsResult(request); return ToOptimizedSerializedResultUsingCache(result); } - public async Task Get(GetSimilarTrailers request) + public object Get(GetSimilarTrailers request) { - var result = await GetSimilarItemsResult( - request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + var result = GetSimilarItemsResult(request); return ToOptimizedSerializedResultUsingCache(result); } @@ -130,148 +129,85 @@ namespace MediaBrowser.Api.Movies { var user = _userManager.GetUserById(request.UserId); - var query = new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(Movie).Name } - }; - - if (user.Configuration.IncludeTrailersInSuggestions) - { - var includeList = query.IncludeItemTypes.ToList(); - includeList.Add(typeof(Trailer).Name); - query.IncludeItemTypes = includeList.ToArray(); - } - - var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId }; - var movies = _libraryManager.GetItemList(query, parentIds) - .OrderBy(i => (int)i.SourceType); - - var listEligibleForCategories = new List(); - var listEligibleForSuggestion = new List(); - - var list = movies.ToList(); - - listEligibleForCategories.AddRange(list); - listEligibleForSuggestion.AddRange(list); - - listEligibleForCategories = listEligibleForCategories - // Exclude trailers from the suggestion categories - .Where(i => i is Movie) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) - .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase) - .ToList(); - - listEligibleForSuggestion = listEligibleForSuggestion - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) - .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase) - .ToList(); - var dtoOptions = GetDtoOptions(request); dtoOptions.Fields = request.GetItemFields().ToList(); - var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions); + var result = GetRecommendationCategories(user, request.ParentId, request.CategoryLimit, request.ItemLimit, dtoOptions); return ToOptimizedResult(result); } - private async Task GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func, List, BaseItem, int> getSimilarityScore) + private QueryResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; var item = string.IsNullOrEmpty(request.Id) ? (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); - - var query = new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(Movie).Name } - }; - - if (user == null || user.Configuration.IncludeTrailersInSuggestions) - { - var includeList = query.IncludeItemTypes.ToList(); - includeList.Add(typeof(Trailer).Name); - query.IncludeItemTypes = includeList.ToArray(); - } - - var list = _libraryManager.GetItemList(query) - .OrderBy(i => (int)i.SourceType) - .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) - .ToList(); - if (item is Video) + var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) { - var imdbId = item.GetProviderId(MetadataProviders.Imdb); - - // Use imdb id to try to filter duplicates of the same item - if (!string.IsNullOrWhiteSpace(imdbId)) + Limit = request.Limit, + IncludeItemTypes = new[] { - list = list - .Where(i => !string.Equals(imdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)) - .ToList(); - } - } - - var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList(); - - IEnumerable returnItems = items; - - if (request.Limit.HasValue) - { - returnItems = returnItems.Take(request.Limit.Value); - } + typeof(Movie).Name, + typeof(Trailer).Name, + typeof(LiveTvProgram).Name + }, + IsMovie = true, + SimilarTo = item + }).ToList(); var dtoOptions = GetDtoOptions(request); - var result = new ItemsResult + var result = new QueryResult { - Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(), + Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(), - TotalRecordCount = items.Count + TotalRecordCount = itemsResult.Count }; return result; } - private IEnumerable GetRecommendationCategories(User user, List allMoviesForCategories, List allMovies, int categoryLimit, int itemLimit, DtoOptions dtoOptions) + private IEnumerable GetRecommendationCategories(User user, string parentId, int categoryLimit, int itemLimit, DtoOptions dtoOptions) { var categories = new List(); - var recentlyPlayedMovies = allMoviesForCategories - .Select(i => + var parentIds = string.IsNullOrWhiteSpace(parentId) ? new string[] { } : new[] { parentId }; + var query = new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { - var userdata = _userDataRepository.GetUserData(user, i); - return new Tuple(i, userdata.Played, userdata.LastPlayedDate ?? DateTime.MinValue); - }) - .Where(i => i.Item2) - .OrderByDescending(i => i.Item3) - .Select(i => i.Item1) - .ToList(); + typeof(Movie).Name, + //typeof(Trailer).Name, + //typeof(LiveTvProgram).Name + }, + // IsMovie = true + SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.Random }, + SortOrder = SortOrder.Descending, + Limit = 7 + }; - var excludeFromLiked = recentlyPlayedMovies.Take(10); - var likedMovies = allMovies - .Select(i => - { - var score = 0; - var userData = _userDataRepository.GetUserData(user, i); + var recentlyPlayedMovies = _libraryManager.GetItemList(query, parentIds).ToList(); - if (userData.IsFavorite) - { - score = 2; - } - else - { - score = userData.Likes.HasValue ? userData.Likes.Value ? 1 : -1 : 0; - } + var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + IncludeItemTypes = new[] + { + typeof(Movie).Name, + typeof(Trailer).Name, + typeof(LiveTvProgram).Name + }, + IsMovie = true, + SortBy = new[] { ItemSortBy.Random }, + SortOrder = SortOrder.Descending, + Limit = 10, + IsFavoriteOrLiked = true, + ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray() - return new Tuple(i, score); - }) - .OrderByDescending(i => i.Item2) - .ThenBy(i => Guid.NewGuid()) - .Where(i => i.Item2 > 0) - .Select(i => i.Item1) - .Where(i => !excludeFromLiked.Contains(i)); + }, parentIds).ToList(); var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList(); // Get recently played directors @@ -284,11 +220,11 @@ namespace MediaBrowser.Api.Movies .OrderBy(i => Guid.NewGuid()) .ToList(); - var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator(); - var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator(); + var similarToRecentlyPlayed = GetSimilarTo(user, recentlyPlayedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator(); + var similarToLiked = GetSimilarTo(user, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator(); - var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator(); - var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator(); + var hasDirectorFromRecentlyPlayed = GetWithDirector(user, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator(); + var hasActorFromRecentlyPlayed = GetWithActor(user, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator(); var categoryTypes = new List> { @@ -331,23 +267,34 @@ namespace MediaBrowser.Api.Movies return categories.OrderBy(i => i.RecommendationType).ThenBy(i => Guid.NewGuid()); } - private IEnumerable GetWithDirector(User user, List allMovies, IEnumerable directors, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetWithDirector(User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { - var userId = user.Id; - - foreach (var director in directors) + foreach (var name in names) { - var items = allMovies - .Where(i => _libraryManager.GetPeople(i).Any(p => string.Equals(p.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Name, director, StringComparison.OrdinalIgnoreCase))) - .Take(itemLimit) - .ToList(); + var items = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Person = name, + // Account for duplicates by imdb id, since the database doesn't support this yet + Limit = itemLimit + 2, + PersonTypes = new[] { PersonType.Director }, + IncludeItemTypes = new[] + { + typeof(Movie).Name, + typeof(Trailer).Name, + typeof(LiveTvProgram).Name + }, + IsMovie = true + + }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) + .Take(itemLimit) + .ToList(); if (items.Count > 0) { yield return new RecommendationDto { - BaselineItemName = director, - CategoryId = director.GetMD5().ToString("N"), + BaselineItemName = name, + CategoryId = name.GetMD5().ToString("N"), RecommendationType = type, Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray() }; @@ -355,20 +302,26 @@ namespace MediaBrowser.Api.Movies } } - private IEnumerable GetWithActor(User user, List allMovies, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetWithActor(User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { foreach (var name in names) { - var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery(user) + var items = _libraryManager.GetItemList(new InternalItemsQuery(user) { - Person = name - - }); - - var items = allMovies - .Where(i => itemsWithActor.Contains(i.Id)) - .Take(itemLimit) - .ToList(); + Person = name, + // Account for duplicates by imdb id, since the database doesn't support this yet + Limit = itemLimit + 2, + IncludeItemTypes = new[] + { + typeof(Movie).Name, + typeof(Trailer).Name, + typeof(LiveTvProgram).Name + }, + IsMovie = true + + }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) + .Take(itemLimit) + .ToList(); if (items.Count > 0) { @@ -383,14 +336,23 @@ namespace MediaBrowser.Api.Movies } } - private IEnumerable GetSimilarTo(User user, List allMovies, IEnumerable baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetSimilarTo(User user, List baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { foreach (var item in baselineItems) { - var similar = SimilarItemsHelper - .GetSimilaritems(item, _libraryManager, allMovies, SimilarItemsHelper.GetSimiliarityScore) - .Take(itemLimit) - .ToList(); + var similar = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Limit = itemLimit, + IncludeItemTypes = new[] + { + typeof(Movie).Name, + typeof(Trailer).Name, + typeof(LiveTvProgram).Name + }, + IsMovie = true, + SimilarTo = item + + }).ToList(); if (similar.Count > 0) { diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 421ccdb5d0..7913f547a2 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -846,7 +846,7 @@ namespace MediaBrowser.Api.Playback if (MediaEncoder.SupportsDecoder("h264_qsv")) { // Seeing stalls and failures with decoding. Not worth it compared to encoding. - //return "-c:v h264_qsv "; + return "-c:v h264_qsv "; } break; case "mpeg2video": @@ -980,11 +980,6 @@ namespace MediaBrowser.Api.Playback var transcodingId = Guid.NewGuid().ToString("N"); var commandLineArgs = GetCommandLineArguments(outputPath, state, true); - if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging) - { - commandLineArgs = "-loglevel debug " + commandLineArgs; - } - var process = new Process { StartInfo = new ProcessStartInfo @@ -1212,7 +1207,7 @@ namespace MediaBrowser.Api.Playback } } - private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream) + private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream, string outputVideoCodec) { var bitrate = request.VideoBitRate; @@ -1237,6 +1232,18 @@ namespace MediaBrowser.Api.Playback } } + if (bitrate.HasValue) + { + var inputVideoCodec = videoStream == null ? null : videoStream.Codec; + bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec); + + // If a max bitrate was requested, don't let the scaled bitrate exceed it + if (request.VideoBitRate.HasValue) + { + bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value); + } + } + return bitrate; } @@ -1518,6 +1525,13 @@ namespace MediaBrowser.Api.Playback } } else if (i == 25) + { + if (videoRequest != null) + { + videoRequest.ForceLiveStream = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + } + else if (i == 26) { if (!string.IsNullOrWhiteSpace(val) && videoRequest != null) { @@ -1528,7 +1542,7 @@ namespace MediaBrowser.Api.Playback } } } - else if (i == 26) + else if (i == 27) { request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture); } @@ -1690,7 +1704,7 @@ namespace MediaBrowser.Api.Playback if (videoRequest != null) { state.OutputVideoCodec = state.VideoRequest.VideoCodec; - state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream); + state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec); if (state.OutputVideoBitrate.HasValue) { diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 061afed6d9..fbcccbaca2 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.Api.Playback public long? InputFileSize { get; set; } public string OutputAudioSync = "1"; - public string OutputVideoSync = "vfr"; + public string OutputVideoSync = "-1"; public List SupportedAudioCodecs { get; set; } diff --git a/MediaBrowser.Api/Reports/ReportsService.cs b/MediaBrowser.Api/Reports/ReportsService.cs index cb16158268..36a2a4b619 100644 --- a/MediaBrowser.Api/Reports/ReportsService.cs +++ b/MediaBrowser.Api/Reports/ReportsService.cs @@ -213,7 +213,6 @@ namespace MediaBrowser.Api.Reports NameStartsWith = request.NameStartsWith, NameStartsWithOrGreater = request.NameStartsWithOrGreater, HasImdbId = request.HasImdbId, - IsYearMismatched = request.IsYearMismatched, IsPlaceHolder = request.IsPlaceHolder, IsLocked = request.IsLocked, IsInBoxSet = request.IsInBoxSet, diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index 277bba1dd1..537ffc913c 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -116,24 +116,12 @@ namespace MediaBrowser.Api private static IEnumerable GetTags(BaseItem item) { - var hasTags = item as IHasTags; - if (hasTags != null) - { - return hasTags.Tags; - } - - return new List(); + return item.Tags; } private static IEnumerable GetKeywords(BaseItem item) { - var hasTags = item as IHasKeywords; - if (hasTags != null) - { - return hasTags.Keywords; - } - - return new List(); + return item.Keywords; } /// diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index ca934830d1..f4aee080a7 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -111,10 +111,10 @@ namespace MediaBrowser.Api { config.EnableLocalizedGuids = true; config.EnableCustomPathSubFolders = true; - config.EnableDateLastRefresh = true; config.EnableStandaloneMusicKeys = true; config.EnableCaseSensitiveItemIds = true; - config.SchemaVersion = 79; + config.EnableFolderView = true; + config.SchemaVersion = 92; } public void Post(UpdateStartupConfiguration request) diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index c2183ad7b9..160fda065f 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -98,6 +98,10 @@ namespace MediaBrowser.Api.Subtitles [ApiMember(Name = "EndPositionTicks", Description = "EndPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public long? EndPositionTicks { get; set; } + + [ApiMember(Name = "CopyTimestamps", Description = "CopyTimestamps", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool CopyTimestamps { get; set; } + public bool AddVttTimeMap { get; set; } } [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")] @@ -175,7 +179,7 @@ namespace MediaBrowser.Api.Subtitles var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks); - var url = string.Format("stream.vtt?StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}", + var url = string.Format("stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}", positionTicks.ToString(CultureInfo.InvariantCulture), endPositionTicks.ToString(CultureInfo.InvariantCulture), accessToken); @@ -190,7 +194,7 @@ namespace MediaBrowser.Api.Subtitles return ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); } - public object Get(GetSubtitle request) + public async Task Get(GetSubtitle request) { if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase)) { @@ -209,20 +213,32 @@ namespace MediaBrowser.Api.Subtitles return ToStaticFileResult(subtitleStream.Path); } - var stream = GetSubtitles(request).Result; + using (var stream = await GetSubtitles(request).ConfigureAwait(false)) + { + using (var reader = new StreamReader(stream)) + { + var text = reader.ReadToEnd(); + + if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap) + { + text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000"); + } - return ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format)); + return ResultFactory.GetResult(text, MimeTypes.GetMimeType("file." + request.Format)); + } + } } - private async Task GetSubtitles(GetSubtitle request) + private Task GetSubtitles(GetSubtitle request) { - return await _subtitleEncoder.GetSubtitles(request.Id, + return _subtitleEncoder.GetSubtitles(request.Id, request.MediaSourceId, request.Index, request.Format, request.StartPositionTicks, request.EndPositionTicks, - CancellationToken.None).ConfigureAwait(false); + request.CopyTimestamps, + CancellationToken.None); } public object Get(SearchRemoteSubtitles request) diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index aa0485d57e..5ccfede1ef 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -12,6 +12,7 @@ using ServiceStack; using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Api { @@ -273,18 +274,40 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetSimilarShows request) { + var result = GetSimilarItemsResult(request); + + return ToOptimizedSerializedResultUsingCache(result); + } + + private QueryResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) + { + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + var item = string.IsNullOrEmpty(request.Id) ? + (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : + _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); + + var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Limit = request.Limit, + IncludeItemTypes = new[] + { + typeof(Series).Name + }, + SimilarTo = item + + }).ToList(); + var dtoOptions = GetDtoOptions(request); - var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, - _itemRepo, - _libraryManager, - _userDataManager, - _dtoService, - Logger, - request, new[] { typeof(Series) }, - SimilarItemsHelper.GetSimiliarityScore); + var result = new QueryResult + { + Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(), - return ToOptimizedSerializedResultUsingCache(result); + TotalRecordCount = itemsResult.Count + }; + + return result; } public object Get(GetUpcomingEpisodes request) diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 565bed0531..18dec3253a 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -333,12 +333,7 @@ namespace MediaBrowser.Api.UserLibrary var tags = request.GetTags(); if (tags.Length > 0) { - var hasTags = i as IHasTags; - if (hasTags == null) - { - return false; - } - if (!tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase))) + if (!tags.Any(v => i.Tags.Contains(v, StringComparer.OrdinalIgnoreCase))) { return false; } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index aee1a8d545..d27a560ba5 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -100,9 +100,6 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "HasTvdbId", Description = "Optional filter by items that have a tvdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? HasTvdbId { get; set; } - [ApiMember(Name = "IsYearMismatched", Description = "Optional filter by items that are potentially misidentified.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] - public bool? IsYearMismatched { get; set; } - [ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsInBoxSet { get; set; } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index dac1a6b1a8..644b284370 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -187,7 +187,6 @@ namespace MediaBrowser.Api.UserLibrary NameStartsWith = request.NameStartsWith, NameStartsWithOrGreater = request.NameStartsWithOrGreater, HasImdbId = request.HasImdbId, - IsYearMismatched = request.IsYearMismatched, IsPlaceHolder = request.IsPlaceHolder, IsLocked = request.IsLocked, IsInBoxSet = request.IsInBoxSet, diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 9b611c3971..07ff36c41f 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -385,7 +385,7 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException("User not found"); } - await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false); + await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null).ConfigureAwait(false); await _userManager.DeleteUser(user).ConfigureAwait(false); } @@ -465,6 +465,10 @@ namespace MediaBrowser.Api } await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false); + + var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token; + + await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false); } } @@ -602,7 +606,8 @@ namespace MediaBrowser.Api throw new ArgumentException("There must be at least one enabled user in the system."); } - await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false); + var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token; + await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false); } await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false); diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index f44c975d41..a76ab9f07e 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -552,7 +552,7 @@ namespace MediaBrowser.Common.Implementations } catch (Exception ex) { - Logger.Error("Error creating {0}", ex, type.Name); + Logger.ErrorException("Error creating {0}", ex, type.Name); throw; } @@ -571,7 +571,7 @@ namespace MediaBrowser.Common.Implementations } catch (Exception ex) { - Logger.Error("Error creating {0}", ex, type.Name); + Logger.ErrorException("Error creating {0}", ex, type.Name); // Don't blow up in release mode return null; } diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index f9dbd766f8..ce1e9fd7f7 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -143,7 +143,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager }; } - private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression) + private WebRequest GetRequest(HttpRequestOptions options, string method) { var request = CreateWebRequest(options.Url); var httpWebRequest = request as HttpWebRequest; @@ -154,7 +154,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager AddRequestHeaders(httpWebRequest, options); - httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None; + httpWebRequest.AutomaticDecompression = options.EnableHttpCompression ? + (options.DecompressionMethod ?? DecompressionMethods.Deflate) : + DecompressionMethods.None; } request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache); @@ -366,7 +368,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager }; } - var httpWebRequest = GetRequest(options, httpMethod, options.EnableHttpCompression); + var httpWebRequest = GetRequest(options, httpMethod); if (options.RequestContentBytes != null || !string.IsNullOrEmpty(options.RequestContent) || @@ -556,7 +558,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.CancellationToken.ThrowIfCancellationRequested(); - var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression); + var httpWebRequest = GetRequest(options, "GET"); if (options.ResourcePool != null) { diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 70489d7142..a889879d55 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -65,8 +65,8 @@ False ..\ThirdParty\SharpCompress\SharpCompress.dll - - ..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll + + ..\packages\SimpleInjector.3.1.5\lib\net45\SimpleInjector.dll True diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index d1d135b20c..d1ede89a11 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs index 75368a5fc3..1a7f414a77 100644 --- a/MediaBrowser.Common/Net/HttpRequestOptions.cs +++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading; namespace MediaBrowser.Common.Net @@ -16,6 +17,8 @@ namespace MediaBrowser.Common.Net /// The URL. public string Url { get; set; } + public DecompressionMethods? DecompressionMethod { get; set; } + /// /// Gets or sets the accept header. /// diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs index 587023ab48..6135240e91 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs @@ -53,6 +53,8 @@ namespace MediaBrowser.Controller.Channels public bool IsInfiniteStream { get; set; } + public string HomePageUrl { get; set; } + public ChannelItemInfo() { MediaSources = new List(); diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs index 676ef9c561..27e06fb8dd 100644 --- a/MediaBrowser.Controller/Chapters/IChapterManager.cs +++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Chapters /// The chapters. /// The cancellation token. /// Task. - Task SaveChapters(string itemId, IEnumerable chapters, CancellationToken cancellationToken); + Task SaveChapters(string itemId, List chapters, CancellationToken cancellationToken); /// /// Searches the specified video. diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index c34a884ff5..06710b0301 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -20,7 +20,6 @@ namespace MediaBrowser.Controller.Entities.Audio IHasArtist, IHasMusicGenres, IHasLookupInfo, - IHasTags, IHasMediaSources, IThemeMedia, IArchivable diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 615276e837..1f3b0c92a5 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -179,17 +179,13 @@ namespace MediaBrowser.Controller.Entities.Audio { var items = GetRecursiveChildren().ToList(); - var songs = items.OfType /// The image providers. /// The metadata services. - /// The identity providers. - /// The identity converters. /// The metadata providers. /// The metadata savers. /// The image savers. /// The external ids. public void AddParts(IEnumerable imageProviders, IEnumerable metadataServices, - IEnumerable identityProviders, IEnumerable identityConverters, IEnumerable metadataProviders, IEnumerable metadataSavers, IEnumerable imageSavers, IEnumerable externalIds) { ImageProviders = imageProviders.ToArray(); _metadataServices = metadataServices.OrderBy(i => i.Order).ToArray(); - _identityProviders = identityProviders.ToArray(); - _identityConverters = identityConverters.ToArray(); _metadataProviders = metadataProviders.ToArray(); _imageSavers = imageSavers.ToArray(); _externalIds = externalIds.OrderBy(i => i.Name).ToArray(); @@ -301,18 +294,6 @@ namespace MediaBrowser.Providers.Manager .ThenBy(GetDefaultOrder); } - public IEnumerable> GetItemIdentityProviders() - where TLookupInfo : ItemLookupInfo - { - return _identityProviders.OfType>(); - } - - public IEnumerable> GetItemIdentityConverters() - where TLookupInfo : ItemLookupInfo - { - return _identityConverters.OfType>(); - } - private IEnumerable GetRemoteImageProviders(IHasImages item, bool includeDisabled) { var options = GetMetadataOptions(item); @@ -849,7 +830,7 @@ namespace MediaBrowser.Providers.Manager }); } - public IEnumerable GetExternalUrls(IHasProviderIds item) + public IEnumerable GetExternalUrls(BaseItem item) { return GetExternalIds(item) .Select(i => @@ -872,7 +853,7 @@ namespace MediaBrowser.Providers.Manager Url = string.Format(i.UrlFormatString, value) }; - }).Where(i => i != null); + }).Where(i => i != null).Concat(item.GetRelatedUrls()); } public IEnumerable GetExternalIdInfos(IHasProviderIds item) diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index 59a2da4603..5f23cf69c9 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -151,29 +151,17 @@ namespace MediaBrowser.Providers.Manager if (!lockedFields.Contains(MetadataFields.Tags)) { - var sourceHasTags = source as IHasTags; - var targetHasTags = target as IHasTags; - - if (sourceHasTags != null && targetHasTags != null) + if (replaceData || target.Tags.Count == 0) { - if (replaceData || targetHasTags.Tags.Count == 0) - { - targetHasTags.Tags = sourceHasTags.Tags; - } + target.Tags = source.Tags; } } if (!lockedFields.Contains(MetadataFields.Keywords)) { - var sourceHasKeywords = source as IHasKeywords; - var targetHasKeywords = target as IHasKeywords; - - if (sourceHasKeywords != null && targetHasKeywords != null) + if (replaceData || target.Keywords.Count == 0) { - if (replaceData || targetHasKeywords.Keywords.Count == 0) - { - targetHasKeywords.Keywords = sourceHasKeywords.Keywords; - } + target.Keywords = source.Keywords; } } diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index f07478f986..240b2e2cca 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -89,7 +89,6 @@ - @@ -145,10 +144,7 @@ - - - @@ -168,7 +164,6 @@ - @@ -182,7 +177,6 @@ - diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs deleted file mode 100644 index 5262f8e3b1..0000000000 --- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs +++ /dev/null @@ -1,196 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Providers.Music; -using MediaBrowser.Providers.TV; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using CommonIO; - -namespace MediaBrowser.Providers.Movies -{ - class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask - { - private const string UpdatesUrl = "https://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}"; - - /// - /// The _HTTP client - /// - private readonly IHttpClient _httpClient; - /// - /// The _logger - /// - private readonly ILogger _logger; - /// - /// The _config - /// - private readonly IServerConfigurationManager _config; - private readonly IJsonSerializer _jsonSerializer; - private readonly IFileSystem _fileSystem; - - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - public FanartMovieUpdatesPostScanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem) - { - _jsonSerializer = jsonSerializer; - _config = config; - _logger = logger; - _httpClient = httpClient; - _fileSystem = fileSystem; - } - - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var options = FanartSeriesProvider.Current.GetFanartOptions(); - - if (!options.EnableAutomaticUpdates) - { - progress.Report(100); - return; - } - - var path = FanartMovieImageProvider.GetMoviesDataPath(_config.CommonApplicationPaths); - - _fileSystem.CreateDirectory(path); - - var timestampFile = Path.Combine(path, "time.txt"); - - var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile); - - // Don't check for updates every single time - if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3) - { - return; - } - - // Find out the last time we queried for updates - var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty; - - var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList(); - - // If this is our first time, don't do any updates and just record the timestamp - if (!string.IsNullOrEmpty(lastUpdateTime)) - { - var moviesToUpdate = await GetMovieIdsToUpdate(existingDirectories, lastUpdateTime, options, cancellationToken).ConfigureAwait(false); - - progress.Report(5); - - await UpdateMovies(moviesToUpdate, progress, cancellationToken).ConfigureAwait(false); - } - - var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture); - - _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8); - - progress.Report(100); - } - - private async Task> GetMovieIdsToUpdate(IEnumerable existingIds, string lastUpdateTime, FanartOptions options, CancellationToken cancellationToken) - { - var url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime); - - var clientKey = options.UserApiKey; - if (!string.IsNullOrWhiteSpace(clientKey)) - { - url += "&client_key=" + clientKey; - } - - // First get last time - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - EnableHttpCompression = true, - ResourcePool = FanartArtistProvider.Current.FanArtResourcePool - - }).ConfigureAwait(false)) - { - using (var reader = new StreamReader(stream)) - { - var json = await reader.ReadToEndAsync().ConfigureAwait(false); - - // If empty fanart will return a string of "null", rather than an empty list - if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase)) - { - return new List(); - } - - var updates = _jsonSerializer.DeserializeFromString>(json); - - var existingDictionary = existingIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - - return updates.SelectMany(i => - { - var list = new List(); - - if (!string.IsNullOrWhiteSpace(i.imdb_id)) - { - list.Add(i.imdb_id); - } - if (!string.IsNullOrWhiteSpace(i.tmdb_id)) - { - list.Add(i.tmdb_id); - } - - return list; - - }).Where(existingDictionary.ContainsKey); - } - } - } - - private async Task UpdateMovies(IEnumerable idList, IProgress progress, CancellationToken cancellationToken) - { - var list = idList.ToList(); - var numComplete = 0; - - foreach (var id in list) - { - _logger.Info("Updating movie " + id); - - await FanartMovieImageProvider.Current.DownloadMovieJson(id, cancellationToken).ConfigureAwait(false); - - numComplete++; - double percent = numComplete; - percent /= list.Count; - percent *= 95; - - progress.Report(percent + 5); - } - } - - /// - /// Dates the time to unix timestamp. - /// - /// The date time. - /// System.Double. - private static double DateTimeToUnixTimestamp(DateTime dateTime) - { - return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds; - } - - public class RootObject - { - public string tmdb_id { get; set; } - public string imdb_id { get; set; } - public string name { get; set; } - public string new_images { get; set; } - public string total_images { get; set; } - } - } -} diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 775e6dfb9c..18f1779325 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -24,7 +24,7 @@ using MediaBrowser.Providers.TV; namespace MediaBrowser.Providers.Movies { - public class FanartMovieImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder + public class FanartMovieImageProvider : IRemoteImageProvider, IHasOrder { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IServerConfigurationManager _config; @@ -241,33 +241,6 @@ namespace MediaBrowser.Providers.Movies }); } - public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) - { - var options = FanartSeriesProvider.Current.GetFanartOptions(); - if (!options.EnableAutomaticUpdates) - { - return false; - } - - var id = item.GetProviderId(MetadataProviders.Tmdb); - if (string.IsNullOrEmpty(id)) - { - id = item.GetProviderId(MetadataProviders.Imdb); - } - - if (!string.IsNullOrEmpty(id)) - { - // Process images - var path = GetFanartJsonPath(id); - - var fileInfo = _fileSystem.GetFileInfo(path); - - return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed; - } - - return false; - } - /// /// Gets the movie data path. /// diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index d13716cba1..3b3065893c 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -314,11 +314,7 @@ namespace MediaBrowser.Providers.Movies if (movieData.keywords != null && movieData.keywords.keywords != null) { - var hasTags = movie as IHasKeywords; - if (hasTags != null) - { - hasTags.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList(); - } + movie.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList(); } if (movieData.trailers != null && movieData.trailers.youtube != null && diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs index 5958c3a0ad..f9e9bc947f 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs @@ -17,7 +17,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Movies { - class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor + class MovieDbImageProvider : IRemoteImageProvider, IHasOrder { private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; @@ -221,10 +221,5 @@ namespace MediaBrowser.Providers.Movies ResourcePool = MovieDbProvider.Current.MovieDbResourcePool }); } - - public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) - { - return MovieDbProvider.Current.HasChanged(item); - } } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index c588a9a690..6a2e727439 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -409,33 +409,6 @@ namespace MediaBrowser.Providers.Movies return await _httpClient.Get(options).ConfigureAwait(false); } - public TheMovieDbOptions GetTheMovieDbOptions() - { - return _configurationManager.GetConfiguration("themoviedb"); - } - - public bool HasChanged(IHasMetadata item) - { - if (!GetTheMovieDbOptions().EnableAutomaticUpdates) - { - return false; - } - - var tmdbId = item.GetProviderId(MetadataProviders.Tmdb); - - if (!String.IsNullOrEmpty(tmdbId)) - { - // Process images - var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage()); - - var fileInfo = _fileSystem.GetFileInfo(dataFilePath); - - return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed; - } - - return false; - } - public void Dispose() { Dispose(true); @@ -659,19 +632,4 @@ namespace MediaBrowser.Providers.Movies }); } } - - public class TmdbConfigStore : IConfigurationFactory - { - public IEnumerable GetConfigurations() - { - return new List - { - new ConfigurationStore - { - Key = "themoviedb", - ConfigurationType = typeof(TheMovieDbOptions) - } - }; - } - } } diff --git a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs index 5fb3ea3696..1d8691ab8e 100644 --- a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs @@ -33,11 +33,6 @@ namespace MediaBrowser.Providers.Movies get { return MovieDbProvider.Current.Name; } } - public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) - { - return MovieDbProvider.Current.HasChanged(item); - } - public int Order { get diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index 3bceb976e7..a6b7bde6fa 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -148,6 +148,13 @@ namespace MediaBrowser.Providers.Movies public bool Supports(IHasProviderIds item) { + // Supports images for tv movies + var tvProgram = item as LiveTvProgram; + if (tvProgram != null && tvProgram.IsMovie) + { + return true; + } + return item is Movie || item is MusicVideo || item is Series || item is Episode || item is Trailer; } } diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index e70ec00576..83be9ca6f9 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -13,10 +13,6 @@ namespace MediaBrowser.Providers.Movies { public class MovieMetadataService : MetadataService { - public MovieMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager) - { - } - protected override bool IsFullLocalMetadata(Movie item) { if (string.IsNullOrWhiteSpace(item.Overview)) @@ -42,15 +38,14 @@ namespace MediaBrowser.Providers.Movies targetItem.CollectionName = sourceItem.CollectionName; } } - } - public class TrailerMetadataService : MetadataService - { - public TrailerMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager) + public MovieMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) { } + } + public class TrailerMetadataService : MetadataService + { protected override bool IsFullLocalMetadata(Trailer item) { if (string.IsNullOrWhiteSpace(item.Overview)) @@ -73,6 +68,10 @@ namespace MediaBrowser.Providers.Movies target.Item.TrailerTypes = source.Item.TrailerTypes; } } + + public TrailerMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) + { + } } } diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs deleted file mode 100644 index 70c155ad5d..0000000000 --- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs +++ /dev/null @@ -1,249 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using CommonIO; - -namespace MediaBrowser.Providers.Movies -{ - public class MovieUpdatesPreScanTask : ILibraryPostScanTask - { - /// - /// The updates URL - /// - private const string UpdatesUrl = "https://api.themoviedb.org/3/movie/changes?start_date={0}&api_key={1}&page={2}"; - - /// - /// The _HTTP client - /// - private readonly IHttpClient _httpClient; - /// - /// The _logger - /// - private readonly ILogger _logger; - /// - /// The _config - /// - private readonly IServerConfigurationManager _config; - private readonly IJsonSerializer _json; - private readonly IFileSystem _fileSystem; - private readonly ILibraryManager _libraryManager; - - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// The HTTP client. - /// The config. - /// The json. - public MovieUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem, ILibraryManager libraryManager) - { - _logger = logger; - _httpClient = httpClient; - _config = config; - _json = json; - _fileSystem = fileSystem; - _libraryManager = libraryManager; - } - - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - if (!MovieDbProvider.Current.GetTheMovieDbOptions().EnableAutomaticUpdates) - { - progress.Report(100); - return; - } - - var path = MovieDbProvider.GetMoviesDataPath(_config.CommonApplicationPaths); - - _fileSystem.CreateDirectory(path); - - var timestampFile = Path.Combine(path, "time.txt"); - - var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile); - - // Don't check for updates every single time - if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 7) - { - return; - } - - // Find out the last time we queried tvdb for updates - var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty; - - var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList(); - - if (!string.IsNullOrEmpty(lastUpdateTime)) - { - long lastUpdateTicks; - - if (long.TryParse(lastUpdateTime, NumberStyles.Any, UsCulture, out lastUpdateTicks)) - { - var lastUpdateDate = new DateTime(lastUpdateTicks, DateTimeKind.Utc); - - // They only allow up to 14 days of updates - if ((DateTime.UtcNow - lastUpdateDate).TotalDays > 13) - { - lastUpdateDate = DateTime.UtcNow.AddDays(-13); - } - - var updatedIds = await GetIdsToUpdate(lastUpdateDate, 1, cancellationToken).ConfigureAwait(false); - - var existingDictionary = existingDirectories.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - - var idsToUpdate = updatedIds.Where(i => !string.IsNullOrWhiteSpace(i) && existingDictionary.ContainsKey(i)); - - await UpdateMovies(idsToUpdate, progress, cancellationToken).ConfigureAwait(false); - } - } - - _fileSystem.WriteAllText(timestampFile, DateTime.UtcNow.Ticks.ToString(UsCulture), Encoding.UTF8); - progress.Report(100); - } - - - /// - /// Gets the ids to update. - /// - /// The last update time. - /// The page. - /// The cancellation token. - /// Task{IEnumerable{System.String}}. - private async Task> GetIdsToUpdate(DateTime lastUpdateTime, int page, CancellationToken cancellationToken) - { - bool hasMorePages; - var list = new List(); - - // First get last time - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = string.Format(UpdatesUrl, lastUpdateTime.ToString("yyyy-MM-dd"), MovieDbProvider.ApiKey, page), - CancellationToken = cancellationToken, - EnableHttpCompression = true, - ResourcePool = MovieDbProvider.Current.MovieDbResourcePool, - AcceptHeader = MovieDbProvider.AcceptHeader - - }).ConfigureAwait(false)) - { - var obj = _json.DeserializeFromStream(stream); - - var data = obj.results.Select(i => i.id.ToString(UsCulture)); - - list.AddRange(data); - - hasMorePages = page < obj.total_pages; - } - - if (hasMorePages) - { - var more = await GetIdsToUpdate(lastUpdateTime, page + 1, cancellationToken).ConfigureAwait(false); - - list.AddRange(more); - } - - return list; - } - - /// - /// Updates the movies. - /// - /// The ids. - /// The progress. - /// The cancellation token. - /// Task. - private async Task UpdateMovies(IEnumerable ids, IProgress progress, CancellationToken cancellationToken) - { - var list = ids.ToList(); - var numComplete = 0; - - // Gather all movies into a lookup by tmdb id - var allMovies = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery - { - IncludeItemTypes = new[] {typeof (Movie).Name}, - Recursive = true - - }).Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb))) - .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb)); - - foreach (var id in list) - { - // Find the preferred language(s) for the movie in the library - var languages = allMovies[id] - .Select(i => i.GetPreferredMetadataLanguage()) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var language in languages) - { - try - { - await UpdateMovie(id, language, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error updating tmdb movie id {0}, language {1}", ex, id, language); - } - } - - numComplete++; - double percent = numComplete; - percent /= list.Count; - percent *= 100; - - progress.Report(percent); - } - } - - /// - /// Updates the movie. - /// - /// The id. - /// The preferred metadata language. - /// The cancellation token. - /// Task. - private Task UpdateMovie(string id, string preferredMetadataLanguage, CancellationToken cancellationToken) - { - _logger.Info("Updating movie from tmdb " + id + ", language " + preferredMetadataLanguage); - - return MovieDbProvider.Current.DownloadMovieInfo(id, preferredMetadataLanguage, cancellationToken); - } - - class Result - { - public int id { get; set; } - public bool? adult { get; set; } - } - - class RootObject - { - public List results { get; set; } - public int page { get; set; } - public int total_pages { get; set; } - public int total_results { get; set; } - - public RootObject() - { - results = new List(); - } - } - } -} diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index 8f951723e8..4f87b2036b 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -15,10 +15,6 @@ namespace MediaBrowser.Providers.Music { public class AlbumMetadataService : MetadataService { - public AlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager) - { - } - protected override async Task BeforeSave(MusicAlbum item, bool isFullRefresh, ItemUpdateType currentUpdateType) { var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); @@ -166,5 +162,9 @@ namespace MediaBrowser.Providers.Music targetItem.Artists = sourceItem.Artists; } } + + public AlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) + { + } } } diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs index 21e9b006bf..b2f975b131 100644 --- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -15,10 +15,6 @@ namespace MediaBrowser.Providers.Music { public class ArtistMetadataService : MetadataService { - public ArtistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager) - { - } - protected override async Task BeforeSave(MusicArtist item, bool isFullRefresh, ItemUpdateType currentUpdateType) { var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); @@ -58,5 +54,9 @@ namespace MediaBrowser.Providers.Music { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } + + public ArtistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) + { + } } } diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index 161a161938..5321281869 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Music { public class AudioMetadataService : MetadataService { - public AudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager) - { - } - protected override void MergeData(MetadataResult