diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index e9911a12d9..6cda8b5d05 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -37,7 +37,7 @@ False - ..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll + ..\packages\ImageMagickSharp.1.0.0.17\lib\net45\ImageMagickSharp.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs index 64ddf7e884..12a98edffa 100644 --- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs @@ -72,11 +72,16 @@ namespace Emby.Drawing.ImageMagick private void LogVersion() { - _logger.Info("ImageMagick version: " + Wand.VersionString); + _logger.Info("ImageMagick version: " + GetVersion()); TestWebp(); Wand.SetMagickThreadCount(1); } + public static string GetVersion() + { + return Wand.VersionString; + } + private bool _webpAvailable = true; private void TestWebp() { @@ -148,7 +153,7 @@ namespace Emby.Drawing.ImageMagick DrawIndicator(originalImage, width, height, options); originalImage.CurrentImage.CompressionQuality = quality; - //originalImage.CurrentImage.StripImage(); + originalImage.CurrentImage.StripImage(); originalImage.SaveImage(outputPath); } @@ -165,7 +170,7 @@ namespace Emby.Drawing.ImageMagick DrawIndicator(wand, width, height, options); wand.CurrentImage.CompressionQuality = quality; - //wand.CurrentImage.StripImage(); + wand.CurrentImage.StripImage(); wand.SaveImage(outputPath); } @@ -176,15 +181,14 @@ namespace Emby.Drawing.ImageMagick private void ScaleImage(MagickWand wand, int width, int height) { - wand.CurrentImage.ResizeImage(width, height); - //if (_config.Configuration.EnableHighQualityImageScaling) - //{ - // wand.CurrentImage.ResizeImage(width, height); - //} - //else - //{ - // wand.CurrentImage.ScaleImage(width, height); - //} + if (_config.Configuration.EnableHighQualityImageScaling) + { + wand.CurrentImage.ResizeImage(width, height); + } + else + { + wand.CurrentImage.ScaleImage(width, height); + } } /// diff --git a/Emby.Drawing/packages.config b/Emby.Drawing/packages.config index 0fcdc278e3..3b8dbcab7c 100644 --- a/Emby.Drawing/packages.config +++ b/Emby.Drawing/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 7a14ace777..ecab943491 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -198,50 +198,6 @@ namespace MediaBrowser.Api return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager)); } - protected IList GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func filter) - { - if (!string.IsNullOrEmpty(parentId)) - { - var folder = (Folder)libraryManager.GetItemById(new Guid(parentId)); - - if (!string.IsNullOrWhiteSpace(userId)) - { - var user = userManager.GetUserById(userId); - - if (user == null) - { - throw new ArgumentException("User not found"); - } - - return folder - .GetRecursiveChildren(user, filter) - .ToList(); - } - - return folder - .GetRecursiveChildren(filter); - } - if (!string.IsNullOrWhiteSpace(userId)) - { - var user = userManager.GetUserById(userId); - - if (user == null) - { - throw new ArgumentException("User not found"); - } - - return userManager - .GetUserById(userId) - .RootFolder - .GetRecursiveChildren(user, filter) - .ToList(); - } - - return libraryManager - .RootFolder - .GetRecursiveChildren(filter); - } - /// /// Deslugs an artist name by finding the correct entry in the library /// diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index 93cc010793..a27c872f15 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -102,12 +102,16 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetGameSystemSummaries request) { - var gameSystems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is GameSystem) + var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId); + var query = new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(GameSystem).Name } + }; + var parentIds = new string[] { } ; + var gameSystems = _libraryManager.GetItems(query, parentIds) .Cast() .ToList(); - var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId); - var result = gameSystems .Select(i => GetSummary(i, user)) .ToList(); @@ -119,8 +123,15 @@ namespace MediaBrowser.Api public object Get(GetPlayerIndex request) { - var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is Game) - .Cast(); + var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId); + var query = new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Game).Name } + }; + var parentIds = new string[] { }; + var games = _libraryManager.GetItems(query, parentIds) + .Cast() + .ToList(); var lookup = games .ToLookup(i => i.PlayersSupported ?? -1) diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 319bc13fd2..80076d0736 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -416,7 +416,7 @@ namespace MediaBrowser.Api.Library public object Get(GetMediaFolders request) { - var items = _libraryManager.GetUserRootFolder().Children.OrderBy(i => i.SortName).ToList(); + var items = _libraryManager.GetUserRootFolder().Children.Concat(_libraryManager.RootFolder.VirtualChildren).OrderBy(i => i.SortName).ToList(); if (request.IsHidden.HasValue) { @@ -610,7 +610,7 @@ namespace MediaBrowser.Api.Library var dtoOptions = GetDtoOptions(request); - BaseItem parent = item.Parent; + BaseItem parent = item.GetParent(); while (parent != null) { @@ -621,7 +621,7 @@ namespace MediaBrowser.Api.Library baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user)); - parent = parent.Parent; + parent = parent.GetParent(); } return baseItemDtos.ToList(); @@ -629,7 +629,7 @@ namespace MediaBrowser.Api.Library private BaseItem TranslateParentItem(BaseItem item, User user) { - if (item.Parent is AggregateFolder) + if (item.GetParent() is AggregateFolder) { return user.RootFolder.GetChildren(user, true).FirstOrDefault(i => i.PhysicalLocations.Contains(item.Path)); } @@ -677,6 +677,50 @@ namespace MediaBrowser.Api.Library return ToOptimizedSerializedResultUsingCache(counts); } + private IList GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func filter) + { + if (!string.IsNullOrEmpty(parentId)) + { + var folder = (Folder)libraryManager.GetItemById(new Guid(parentId)); + + if (!string.IsNullOrWhiteSpace(userId)) + { + var user = userManager.GetUserById(userId); + + if (user == null) + { + throw new ArgumentException("User not found"); + } + + return folder + .GetRecursiveChildren(user, filter) + .ToList(); + } + + return folder + .GetRecursiveChildren(filter); + } + if (!string.IsNullOrWhiteSpace(userId)) + { + var user = userManager.GetUserById(userId); + + if (user == null) + { + throw new ArgumentException("User not found"); + } + + return userManager + .GetUserById(userId) + .RootFolder + .GetRecursiveChildren(user, filter) + .ToList(); + } + + return libraryManager + .RootFolder + .GetRecursiveChildren(filter); + } + private bool FilterItem(BaseItem item, GetItemCounts request, string userId) { if (!string.IsNullOrWhiteSpace(userId)) @@ -817,9 +861,9 @@ namespace MediaBrowser.Api.Library : (Folder)_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); - while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null) + while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null) { - item = item.Parent; + item = item.GetParent(); } var dtoOptions = GetDtoOptions(request); @@ -860,9 +904,9 @@ namespace MediaBrowser.Api.Library : (Folder)_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); - while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null) + while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null) { - item = item.Parent; + item = item.GetParent(); } var dtoOptions = GetDtoOptions(request); diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 7be644bc80..08b99d5a4a 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -49,6 +49,9 @@ False ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll + ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -63,9 +66,6 @@ ..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll - - ..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll - diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index fe8bae1a51..36cbc6ffa6 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -117,10 +117,7 @@ namespace MediaBrowser.Api.Movies public async Task Get(GetSimilarMovies request) { var result = await GetSimilarItemsResult( - // Strip out secondary versions - request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue, - - SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } @@ -128,10 +125,7 @@ namespace MediaBrowser.Api.Movies public async Task Get(GetSimilarTrailers request) { var result = await GetSimilarItemsResult( - // Strip out secondary versions - request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue, - - SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } @@ -140,8 +134,12 @@ namespace MediaBrowser.Api.Movies { var user = _userManager.GetUserById(request.UserId); - IEnumerable movies = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Movie); - + var query = new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Movie).Name } + }; + var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId }; + var movies = _libraryManager.GetItems(query, parentIds); movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies); var listEligibleForCategories = new List(); @@ -184,21 +182,27 @@ namespace MediaBrowser.Api.Movies return ToOptimizedResult(result); } - private async Task GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func includeInSearch, Func, List, BaseItem, int> getSimilarityScore) + private async Task GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func, List, BaseItem, int> getSimilarityScore) { 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); - - Func filter = i => i.Id != item.Id && includeInSearch(i); - - var inputItems = user == null - ? _libraryManager.RootFolder.GetRecursiveChildren(filter) - : user.RootFolder.GetRecursiveChildren(user, filter); - - var list = inputItems.ToList(); + + var query = new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Movie).Name } + }; + var parentIds = new string[] { }; + var list = _libraryManager.GetItems(query, parentIds) + .Where(i => + { + // Strip out secondary versions + var v = i as Video; + return v != null && !v.PrimaryVersionId.HasValue; + }) + .ToList(); if (user != null && user.Configuration.IncludeTrailersInSuggestions) { @@ -379,9 +383,10 @@ namespace MediaBrowser.Api.Movies { foreach (var name in names) { - var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery + var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery(user) { Person = name + }); var items = allMovies diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 4f9efad50d..6d8378aaee 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -233,7 +233,7 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name)); } - Task.Run(() => _installationManager.InstallPackage(package, new Progress(), CancellationToken.None)); + Task.Run(() => _installationManager.InstallPackage(package, true, new Progress(), CancellationToken.None)); } /// diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 4de29b3f2b..9e2e399d78 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1562,6 +1562,13 @@ namespace MediaBrowser.Api.Playback RequestedUrl = url }; + //if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || + // (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || + // (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) + //{ + // state.SegmentLength = 6; + //} + if (!string.IsNullOrWhiteSpace(request.AudioCodec)) { state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 60412159c6..766e8a003e 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -111,7 +111,8 @@ namespace MediaBrowser.Api.Playback.Hls throw; } - await WaitForMinimumSegmentCount(playlist, 3, cancellationTokenSource.Token).ConfigureAwait(false); + var waitForSegments = state.SegmentLength >= 10 ? 2 : 3; + await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false); } } finally diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 302b8d834c..9cb699098e 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -283,7 +283,7 @@ namespace MediaBrowser.Api private T GetParentWithImage(BaseItem item, ImageType type) where T : BaseItem { - return item.Parents.OfType().FirstOrDefault(i => i.HasImage(type)); + return item.GetParents().OfType().FirstOrDefault(i => i.HasImage(type)); } } } diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 399c81ae88..365a9bfa8e 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -68,11 +68,7 @@ namespace MediaBrowser.Api _config.Configuration.EnableLocalizedGuids = true; _config.Configuration.MergeMetadataAndImagesByName = true; _config.Configuration.EnableStandaloneMetadata = true; - _config.Configuration.EnableLibraryMetadataSubFolder = true; _config.Configuration.EnableCustomPathSubFolders = true; - _config.Configuration.DisableXmlSavers = true; - _config.Configuration.DisableStartupScan = true; - _config.Configuration.EnableUserViews = true; _config.Configuration.EnableDateLastRefresh = true; _config.SaveConfiguration(); } diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index 3f2b3d66a3..2661c245fa 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Net; namespace MediaBrowser.Api.System { @@ -32,6 +33,12 @@ namespace MediaBrowser.Api.System } + [Route("/System/Ping", "POST")] + public class PingSystem : IReturnVoid + { + + } + /// /// Class RestartApplication /// @@ -59,7 +66,7 @@ namespace MediaBrowser.Api.System [Route("/System/Endpoint", "GET", Summary = "Gets information about the request endpoint")] [Authenticated] - public class GetEndpointInfo : IReturn + public class GetEndpointInfo : IReturn { public string Endpoint { get; set; } } @@ -104,6 +111,11 @@ namespace MediaBrowser.Api.System _security = security; } + public object Post(PingSystem request) + { + return _appHost.Name; + } + public object Get(GetServerLogs request) { List files; @@ -199,17 +211,11 @@ namespace MediaBrowser.Api.System public object Get(GetEndpointInfo request) { - return ToOptimizedResult(new EndpointInfo + return ToOptimizedResult(new EndPointInfo { IsLocal = Request.IsLocal, IsInNetwork = _network.IsInLocalNetwork(request.Endpoint ?? Request.RemoteIp) }); } } - - public class EndpointInfo - { - public bool IsLocal { get; set; } - public bool IsInNetwork { get; set; } - } } diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 29a4a8bb53..2dad9533fe 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -159,7 +159,7 @@ namespace MediaBrowser.Api [ApiMember(Name = "StartItemId", Description = "Optional. Skip through the list until a given item is found.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string StartItemId { get; set; } - + /// /// Skips over a given number of items within the results. Use for paging. /// @@ -273,29 +273,28 @@ namespace MediaBrowser.Api { var user = _userManager.GetUserById(request.UserId); - var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode); - - var itemsList = _libraryManager - .Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending) - .Cast() - .ToList(); - - var unairedEpisodes = itemsList.Where(i => i.IsUnaired).ToList(); - var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime(); - var previousEpisodes = itemsList.Where(i => !i.IsUnaired && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate).ToList(); - previousEpisodes.AddRange(unairedEpisodes); + var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId }; - var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit); + var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { "PremiereDate", "AirTime", "SortName" }, + SortOrder = SortOrder.Ascending, + MinPremiereDate = minPremiereDate, + StartIndex = request.StartIndex, + Limit = request.Limit + + }, parentIds); var options = GetDtoOptions(request); - var returnItems = _dtoService.GetBaseItemDtos(pagedItems, options, user).ToArray(); + var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user).ToArray(); var result = new ItemsResult { - TotalRecordCount = itemsList.Count, + TotalRecordCount = itemsResult.TotalRecordCount, Items = returnItems }; @@ -440,7 +439,7 @@ namespace MediaBrowser.Api } episodes = season.GetEpisodes(user); - } + } else if (request.Season.HasValue) { var series = _libraryManager.GetItemById(request.Id) as Series; @@ -495,7 +494,7 @@ namespace MediaBrowser.Api .ToList(); var pagedItems = ApplyPaging(returnList, request.StartIndex, request.Limit); - + var dtoOptions = GetDtoOptions(request); var dtos = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user) diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 23d4da60c3..6867f6308c 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -206,6 +206,8 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "Genres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Genres { get; set; } + public string GenreIds { get; set; } + [ApiMember(Name = "OfficialRatings", Description = "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string OfficialRatings { get; set; } @@ -385,6 +387,11 @@ namespace MediaBrowser.Api.UserLibrary return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } + public string[] GetGenreIds() + { + return (GenreIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + } + public string[] GetPersonTypes() { return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 97d0ad7ab0..1c5d5b345e 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -112,6 +112,11 @@ namespace MediaBrowser.Api.UserLibrary user == null ? _libraryManager.RootFolder : user.RootFolder : parentItem; + if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase)) + { + item = user == null ? _libraryManager.RootFolder : user.RootFolder; + } + // Default list type = children if (!string.IsNullOrEmpty(request.Ids)) @@ -211,6 +216,7 @@ namespace MediaBrowser.Api.UserLibrary Tags = request.GetTags(), OfficialRatings = request.GetOfficialRatings(), Genres = request.GetGenres(), + GenreIds = request.GetGenreIds(), Studios = request.GetStudios(), StudioIds = request.GetStudioIds(), Person = request.Person, @@ -423,15 +429,6 @@ namespace MediaBrowser.Api.UserLibrary return false; } - // Min index number - if (request.MinIndexNumber.HasValue) - { - if (!(i.IndexNumber.HasValue && i.IndexNumber.Value >= request.MinIndexNumber.Value)) - { - return false; - } - } - // Min official rating if (!string.IsNullOrEmpty(request.MinOfficialRating)) { diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 9d7c38d6f0..d29191db40 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -26,6 +26,8 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")] public bool? IncludeExternalContent { get; set; } + + public string PresetViews { get; set; } } [Route("/Users/{UserId}/SpecialViewOptions", "GET")] @@ -75,9 +77,24 @@ namespace MediaBrowser.Api.UserLibrary query.IncludeExternalContent = request.IncludeExternalContent.Value; } + if (!string.IsNullOrWhiteSpace(request.PresetViews)) + { + query.PresetViews = request.PresetViews.Split(','); + } + + var app = AuthorizationContext.GetAuthorizationInfo(Request).Client ?? string.Empty; + if (app.IndexOf("emby rt", StringComparison.OrdinalIgnoreCase) != -1) + { + query.PresetViews = new[] { CollectionType.Music, CollectionType.Movies, CollectionType.TvShows }; + } + //query.PresetViews = new[] { CollectionType.Music, CollectionType.Movies, CollectionType.TvShows }; + var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false); var dtoOptions = GetDtoOptions(request); + dtoOptions.Fields = new List(); + dtoOptions.Fields.Add(ItemFields.PrimaryImageAspectRatio); + dtoOptions.Fields.Add(ItemFields.DisplayPreferencesId); var user = _userManager.GetUserById(request.UserId); @@ -123,7 +140,7 @@ namespace MediaBrowser.Api.UserLibrary var views = user.RootFolder .GetChildren(user, true) .OfType() - .Where(i => !UserView.IsExcludedFromGrouping(i)) + .Where(UserView.IsEligibleForGrouping) .ToList(); var list = views @@ -141,9 +158,7 @@ namespace MediaBrowser.Api.UserLibrary private bool IsEligibleForSpecialView(ICollectionFolder view) { - var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music, CollectionType.Photos }; - - return types.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); + return UserView.IsEligibleForEnhancedView(view.CollectionType); } } diff --git a/MediaBrowser.Api/packages.config b/MediaBrowser.Api/packages.config index d960123186..258a097cd2 100644 --- a/MediaBrowser.Api/packages.config +++ b/MediaBrowser.Api/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index 6dc97100db..2a93efcdeb 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -133,7 +133,7 @@ namespace MediaBrowser.Common.Implementations /// Gets the HTTP client. /// /// The HTTP client. - protected IHttpClient HttpClient { get; private set; } + public IHttpClient HttpClient { get; private set; } /// /// Gets the network manager. /// diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 054c5aaafb..c30cdf1a73 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager request.Method = method; request.Timeout = options.TimeoutMs; - + if (httpWebRequest != null) { if (!string.IsNullOrEmpty(options.Host)) diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index d857e58b68..e87a6ad164 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -51,9 +51,11 @@ False ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll - - False - ..\packages\NLog.4.1.1\lib\net45\NLog.dll + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll + + + ..\packages\NLog.4.2.3\lib\net45\NLog.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -62,13 +64,14 @@ False ..\ThirdParty\SharpCompress\SharpCompress.dll - - False - ..\packages\SimpleInjector.3.0.5\lib\net45\SimpleInjector.dll + + ..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll + + @@ -105,6 +108,7 @@ + diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index c27dfd68d4..bc3dc360f7 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; +using MoreLinq; namespace MediaBrowser.Common.Implementations.Networking { @@ -31,14 +32,14 @@ namespace MediaBrowser.Common.Implementations.Networking } } - private volatile List _localIpAddresses; + private volatile List _localIpAddresses; private readonly object _localIpAddressSyncLock = new object(); /// /// Gets the machine's local ip address /// /// IPAddress. - public IEnumerable GetLocalIpAddresses() + public IEnumerable GetLocalIpAddresses() { if (_localIpAddresses == null) { @@ -58,25 +59,24 @@ namespace MediaBrowser.Common.Implementations.Networking return _localIpAddresses; } - private IEnumerable GetLocalIpAddressesInternal() + private IEnumerable GetLocalIpAddressesInternal() { var list = GetIPsDefault() - .Where(i => !IPAddress.IsLoopback(i)) - .Select(i => i.ToString()) - .Where(FilterIpAddress) .ToList(); - if (list.Count > 0) + if (list.Count == 0) { - return list; + list.AddRange(GetLocalIpAddressesFallback()); } - return GetLocalIpAddressesFallback().Where(FilterIpAddress); + return list.Where(FilterIpAddress).DistinctBy(i => i.ToString()); } - private bool FilterIpAddress(string address) + private bool FilterIpAddress(IPAddress address) { - if (address.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) + var addressString = address.ToString (); + + if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) { return false; } @@ -84,8 +84,16 @@ namespace MediaBrowser.Common.Implementations.Networking return true; } - private bool IsInPrivateAddressSpace(string endpoint) + public bool IsInPrivateAddressSpace(string endpoint) { + if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Handle ipv4 mapped to ipv6 + endpoint = endpoint.Replace("::ffff:", string.Empty); + // Private address space: // http://en.wikipedia.org/wiki/Private_network @@ -96,9 +104,6 @@ namespace MediaBrowser.Common.Implementations.Networking return - // If url was requested with computer name, we may see this - endpoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 || - endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || @@ -131,26 +136,41 @@ namespace MediaBrowser.Common.Implementations.Networking throw new ArgumentNullException("endpoint"); } - if (IsInPrivateAddressSpace(endpoint)) - { - return true; - } - - const int lengthMatch = 4; - - if (endpoint.Length >= lengthMatch) - { - var prefix = endpoint.Substring(0, lengthMatch); - - if (GetLocalIpAddresses() - .Any(i => i.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) - { - return true; - } - } - IPAddress address; - if (resolveHost && !IPAddress.TryParse(endpoint, out address)) + if (IPAddress.TryParse(endpoint, out address)) + { + var addressString = address.ToString(); + + int lengthMatch = 100; + if (address.AddressFamily == AddressFamily.InterNetwork) + { + lengthMatch = 4; + if (IsInPrivateAddressSpace(addressString)) + { + return true; + } + } + else if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + lengthMatch = 10; + if (IsInPrivateAddressSpace(endpoint)) + { + return true; + } + } + + // Should be even be doing this with ipv6? + if (addressString.Length >= lengthMatch) + { + var prefix = addressString.Substring(0, lengthMatch); + + if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) + { + return true; + } + } + } + else if (resolveHost) { Uri uri; if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri)) @@ -188,33 +208,45 @@ namespace MediaBrowser.Common.Implementations.Networking return Dns.GetHostAddresses(hostName); } - private IEnumerable GetIPsDefault() - { - foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) - { - var props = adapter.GetIPProperties(); - var gateways = from ga in props.GatewayAddresses - where !ga.Address.Equals(IPAddress.Any) - select true; + private List GetIPsDefault() + { + NetworkInterface[] interfaces; - if (!gateways.Any()) - { - continue; - } + try + { + interfaces = NetworkInterface.GetAllNetworkInterfaces(); + } + catch (Exception ex) + { + Logger.ErrorException("Error in GetAllNetworkInterfaces", ex); + return new List(); + } - foreach (var uni in props.UnicastAddresses) - { - var address = uni.Address; - if (address.AddressFamily != AddressFamily.InterNetwork) - { - continue; - } - yield return address; - } - } - } + return interfaces.SelectMany(network => { - private IEnumerable GetLocalIpAddressesFallback() + try + { + Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus); + + var properties = network.GetIPProperties(); + + return properties.UnicastAddresses + .Where(i => i.IsDnsEligible) + .Select(i => i.Address) + .Where(i => i.AddressFamily == AddressFamily.InterNetwork) + .ToList(); + } + catch (Exception ex) + { + Logger.ErrorException("Error querying network interface", ex); + return new List(); + } + + }).DistinctBy(i => i.ToString()) + .ToList(); + } + + private IEnumerable GetLocalIpAddressesFallback() { var host = Dns.GetHostEntry(Dns.GetHostName()); @@ -222,7 +254,6 @@ namespace MediaBrowser.Common.Implementations.Networking // It's not fool-proof so ultimately the consumer will have to examine them and decide return host.AddressList .Where(i => i.AddressFamily == AddressFamily.InterNetwork) - .Select(i => i.ToString()) .Reverse(); } diff --git a/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs new file mode 100644 index 0000000000..3604280729 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Common.Implementations.Updates +{ + public class GithubUpdater + { + private readonly IHttpClient _httpClient; + private readonly IJsonSerializer _jsonSerializer; + private TimeSpan _cacheLength; + + public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer, TimeSpan cacheLength) + { + _httpClient = httpClient; + _jsonSerializer = jsonSerializer; + _cacheLength = cacheLength; + } + + public async Task CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, CancellationToken cancellationToken) + { + var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository); + + var options = new HttpRequestOptions + { + Url = url, + EnableKeepAlive = false, + CancellationToken = cancellationToken, + UserAgent = "Emby/3.0" + + }; + + if (_cacheLength.Ticks > 0) + { + options.CacheMode = CacheMode.Unconditional; + options.CacheLength = _cacheLength; + } + + using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) + { + var obj = _jsonSerializer.DeserializeFromStream(stream); + + return CheckForUpdateResult(obj, minVersion, updateLevel, assetFilename, packageName, targetFilename); + } + } + + private CheckForUpdateResult CheckForUpdateResult(RootObject[] obj, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename) + { + if (updateLevel == PackageVersionClass.Release) + { + obj = obj.Where(i => !i.prerelease).ToArray(); + } + else if (updateLevel == PackageVersionClass.Beta) + { + obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase)).ToArray(); + } + else if (updateLevel == PackageVersionClass.Dev) + { + obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) || i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray(); + } + + var availableUpdate = obj + .Select(i => CheckForUpdateResult(i, minVersion, assetFilename, packageName, targetFilename)) + .Where(i => i != null) + .OrderByDescending(i => Version.Parse(i.AvailableVersion)) + .FirstOrDefault(); + + return availableUpdate ?? new CheckForUpdateResult + { + IsUpdateAvailable = false + }; + } + + private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename) + { + Version version; + if (!Version.TryParse(obj.tag_name, out version)) + { + return null; + } + + if (version < minVersion) + { + return null; + } + + var asset = (obj.assets ?? new List()).FirstOrDefault(i => IsAsset(i, assetFilename)); + + if (asset == null) + { + return null; + } + + return new CheckForUpdateResult + { + AvailableVersion = version.ToString(), + IsUpdateAvailable = version > minVersion, + Package = new PackageVersionInfo + { + classification = obj.prerelease ? + (obj.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase) ? PackageVersionClass.Dev : PackageVersionClass.Beta) : + PackageVersionClass.Release, + name = packageName, + sourceUrl = asset.browser_download_url, + targetFilename = targetFilename, + versionStr = version.ToString(), + requiredVersionStr = "1.0.0", + description = obj.body + } + }; + } + + private bool IsAsset(Asset asset, string assetFilename) + { + var downloadFilename = Path.GetFileName(asset.browser_download_url) ?? string.Empty; + + if (downloadFilename.IndexOf(assetFilename, StringComparison.OrdinalIgnoreCase) != -1) + { + return true; + } + + return string.Equals(assetFilename, downloadFilename, StringComparison.OrdinalIgnoreCase); + } + + public class Uploader + { + public string login { get; set; } + public int id { get; set; } + public string avatar_url { get; set; } + public string gravatar_id { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string followers_url { get; set; } + public string following_url { get; set; } + public string gists_url { get; set; } + public string starred_url { get; set; } + public string subscriptions_url { get; set; } + public string organizations_url { get; set; } + public string repos_url { get; set; } + public string events_url { get; set; } + public string received_events_url { get; set; } + public string type { get; set; } + public bool site_admin { get; set; } + } + + public class Asset + { + public string url { get; set; } + public int id { get; set; } + public string name { get; set; } + public object label { get; set; } + public Uploader uploader { get; set; } + public string content_type { get; set; } + public string state { get; set; } + public int size { get; set; } + public int download_count { get; set; } + public string created_at { get; set; } + public string updated_at { get; set; } + public string browser_download_url { get; set; } + } + + public class Author + { + public string login { get; set; } + public int id { get; set; } + public string avatar_url { get; set; } + public string gravatar_id { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string followers_url { get; set; } + public string following_url { get; set; } + public string gists_url { get; set; } + public string starred_url { get; set; } + public string subscriptions_url { get; set; } + public string organizations_url { get; set; } + public string repos_url { get; set; } + public string events_url { get; set; } + public string received_events_url { get; set; } + public string type { get; set; } + public bool site_admin { get; set; } + } + + public class RootObject + { + public string url { get; set; } + public string assets_url { get; set; } + public string upload_url { get; set; } + public string html_url { get; set; } + public int id { get; set; } + public string tag_name { get; set; } + public string target_commitish { get; set; } + public string name { get; set; } + public bool draft { get; set; } + public Author author { get; set; } + public bool prerelease { get; set; } + public string created_at { get; set; } + public string published_at { get; set; } + public List assets { get; set; } + public string tarball_url { get; set; } + public string zipball_url { get; set; } + public string body { get; set; } + } + } +} diff --git a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs index 0142753314..d155f11c73 100644 --- a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs +++ b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs @@ -438,11 +438,12 @@ namespace MediaBrowser.Common.Implementations.Updates /// Installs the package. /// /// The package. + /// if set to true [is plugin]. /// The progress. /// The cancellation token. /// Task. /// package - public async Task InstallPackage(PackageVersionInfo package, IProgress progress, CancellationToken cancellationToken) + public async Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress progress, CancellationToken cancellationToken) { if (package == null) { @@ -495,7 +496,7 @@ namespace MediaBrowser.Common.Implementations.Updates try { - await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false); + await InstallPackageInternal(package, isPlugin, innerProgress, linkedToken).ConfigureAwait(false); lock (CurrentInstallations) { @@ -551,18 +552,17 @@ namespace MediaBrowser.Common.Implementations.Updates /// Installs the package internal. /// /// The package. + /// if set to true [is plugin]. /// The progress. /// The cancellation token. /// Task. - private async Task InstallPackageInternal(PackageVersionInfo package, IProgress progress, CancellationToken cancellationToken) + private async Task InstallPackageInternal(PackageVersionInfo package, bool isPlugin, IProgress progress, CancellationToken cancellationToken) { // Do the install await PerformPackageInstallation(progress, package, cancellationToken).ConfigureAwait(false); - var extension = Path.GetExtension(package.targetFilename) ?? ""; - // Do plugin-specific processing - if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase)) + if (isPlugin) { // Set last update time if we were installed before var plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index a0711a9c75..84f6632681 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -1,7 +1,8 @@  - + + - + diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs index 8fc947e8fe..de63ddd513 100644 --- a/MediaBrowser.Common/Net/INetworkManager.cs +++ b/MediaBrowser.Common/Net/INetworkManager.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Common.Net /// Gets the machine's local ip address /// /// IPAddress. - IEnumerable GetLocalIpAddresses(); + IEnumerable GetLocalIpAddresses(); /// /// Gets a random port number that is currently available @@ -25,6 +25,13 @@ namespace MediaBrowser.Common.Net /// [string] MAC Address string GetMacAddress(); + /// + /// Determines whether [is in private address space] [the specified endpoint]. + /// + /// The endpoint. + /// true if [is in private address space] [the specified endpoint]; otherwise, false. + bool IsInPrivateAddressSpace(string endpoint); + /// /// Gets the network shares. /// diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs index 7d721da6f0..68853f05e7 100644 --- a/MediaBrowser.Common/Updates/IInstallationManager.cs +++ b/MediaBrowser.Common/Updates/IInstallationManager.cs @@ -105,11 +105,12 @@ namespace MediaBrowser.Common.Updates /// Installs the package. /// /// The package. + /// if set to true [is plugin]. /// The progress. /// The cancellation token. /// Task. /// package - Task InstallPackage(PackageVersionInfo package, IProgress progress, CancellationToken cancellationToken); + Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress progress, CancellationToken cancellationToken); /// /// Uninstalls a plugin diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs index 653cec9016..17dcf138bf 100644 --- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -18,9 +18,9 @@ namespace MediaBrowser.Controller.Channels public List ChannelMediaSources { get; set; } - protected override bool GetBlockUnratedValue(UserPolicy config) + public override UnratedItem GetBlockUnratedType() { - return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); + return UnratedItem.ChannelContent; } protected override string CreateUserDataKey() diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs index 9010470f8f..f662020bbf 100644 --- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs @@ -6,6 +6,7 @@ using System; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Channels @@ -20,6 +21,11 @@ namespace MediaBrowser.Controller.Channels return false; } + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.ChannelContent; + } + [IgnoreDataMember] public override bool SupportsLocalMetadata { diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs index fb545e57aa..79ad4b36b1 100644 --- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -42,9 +42,9 @@ namespace MediaBrowser.Controller.Channels return ExternalId; } - protected override bool GetBlockUnratedValue(UserPolicy config) + public override UnratedItem GetBlockUnratedType() { - return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); + return UnratedItem.ChannelContent; } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 43b980c20d..766f1e5ed8 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -27,9 +27,22 @@ namespace MediaBrowser.Controller.Entities.Audio public long? Size { get; set; } public string Container { get; set; } public int? TotalBitrate { get; set; } - public List Tags { get; set; } public ExtraType? ExtraType { get; set; } + /// + /// Gets or sets the artist. + /// + /// The artist. + public List Artists { get; set; } + + public List AlbumArtists { get; set; } + + /// + /// Gets or sets the album. + /// + /// The album. + public string Album { get; set; } + [IgnoreDataMember] public bool IsThemeMedia { @@ -43,7 +56,6 @@ namespace MediaBrowser.Controller.Entities.Audio { Artists = new List(); AlbumArtists = new List(); - Tags = new List(); } [IgnoreDataMember] @@ -92,14 +104,6 @@ namespace MediaBrowser.Controller.Entities.Audio locationType != LocationType.Virtual; } - /// - /// Gets or sets the artist. - /// - /// The artist. - public List Artists { get; set; } - - public List AlbumArtists { get; set; } - [IgnoreDataMember] public List AllArtists { @@ -114,12 +118,6 @@ namespace MediaBrowser.Controller.Entities.Audio } } - /// - /// Gets or sets the album. - /// - /// The album. - public string Album { get; set; } - [IgnoreDataMember] public MusicAlbum AlbumEntity { @@ -173,9 +171,9 @@ namespace MediaBrowser.Controller.Entities.Audio return base.CreateUserDataKey(); } - protected override bool GetBlockUnratedValue(UserPolicy config) + public override UnratedItem GetBlockUnratedType() { - return config.BlockUnratedItems.Contains(UnratedItem.Music); + return UnratedItem.Music; } public SongInfo GetLookupInfo() diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 98d1eb4ce2..9a38912ea0 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Entities.Audio { get { - return Parents.OfType().FirstOrDefault(); + return GetParents().OfType().FirstOrDefault(); } } @@ -110,13 +110,18 @@ namespace MediaBrowser.Controller.Entities.Audio return config.BlockUnratedItems.Contains(UnratedItem.Music); } + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.Music; + } + public AlbumInfo GetLookupInfo() { var id = GetItemLookupInfo(); id.AlbumArtists = AlbumArtists; - var artist = Parents.OfType().FirstOrDefault(); + var artist = GetParents().OfType().FirstOrDefault(); if (artist != null) { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index f6d1d32a4c..02bcceada4 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -138,6 +138,11 @@ namespace MediaBrowser.Controller.Entities.Audio return config.BlockUnratedItems.Contains(UnratedItem.Music); } + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.Music; + } + public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress progress, CancellationToken cancellationToken) { var items = GetRecursiveChildren().ToList(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 59e2b87e3a..379697b816 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; @@ -24,6 +23,7 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Controller.Entities { @@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.Entities { protected BaseItem() { + Tags = new List(); Genres = new List(); Studios = new List(); ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -44,7 +45,7 @@ namespace MediaBrowser.Controller.Entities /// /// The supported image extensions /// - public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg" }; + public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn", ".gif" }; public static readonly List SupportedImageExtensionsList = SupportedImageExtensions.ToList(); @@ -103,7 +104,8 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the name. /// /// The name. - public string Name + [IgnoreDataMember] + public virtual string Name { get { @@ -122,14 +124,23 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the id. /// /// The id. + [IgnoreDataMember] public Guid Id { get; set; } /// /// Gets or sets a value indicating whether this instance is hd. /// /// true if this instance is hd; otherwise, false. + [IgnoreDataMember] public bool? IsHD { get; set; } + /// + /// Gets or sets the audio. + /// + /// The audio. + [IgnoreDataMember] + public ProgramAudio? Audio { get; set; } + /// /// Return the id that should be used to key display prefs for this item. /// Default is based on the type for everything except actual generic folders. @@ -149,6 +160,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the path. /// /// The path. + [IgnoreDataMember] public virtual string Path { get; set; } [IgnoreDataMember] @@ -173,7 +185,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Id of the program. + /// If this content came from an external service, the id of the content on that service /// [IgnoreDataMember] public string ExternalId @@ -201,11 +213,6 @@ namespace MediaBrowser.Controller.Entities } } - public virtual bool IsHiddenFromUser(User user) - { - return false; - } - [IgnoreDataMember] public virtual bool IsOwnedItem { @@ -325,12 +332,14 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the date created. /// /// The date created. + [IgnoreDataMember] public DateTime DateCreated { get; set; } /// /// Gets or sets the date modified. /// /// The date modified. + [IgnoreDataMember] public DateTime DateModified { get; set; } public DateTime DateLastSaved { get; set; } @@ -407,6 +416,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the name of the forced sort. /// /// The name of the forced sort. + [IgnoreDataMember] public string ForcedSortName { get { return _forcedSortName; } @@ -447,10 +457,7 @@ namespace MediaBrowser.Controller.Entities { var idString = Id.ToString("N"); - if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder) - { - basePath = System.IO.Path.Combine(basePath, "library"); - } + basePath = System.IO.Path.Combine(basePath, "library"); return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString); } @@ -493,6 +500,7 @@ namespace MediaBrowser.Controller.Entities return sortable; } + [IgnoreDataMember] public Guid ParentId { get; set; } /// @@ -502,15 +510,7 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public Folder Parent { - get - { - if (ParentId != Guid.Empty) - { - return LibraryManager.GetItemById(ParentId) as Folder; - } - - return null; - } + get { return GetParent() as Folder; } set { @@ -525,16 +525,28 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public IEnumerable Parents { - get + get { return GetParents().OfType(); } + } + + public BaseItem GetParent() + { + if (ParentId != Guid.Empty) { - var parent = Parent; + return LibraryManager.GetItemById(ParentId); + } - while (parent != null) - { - yield return parent; + return null; + } - parent = parent.Parent; - } + public IEnumerable GetParents() + { + var parent = GetParent(); + + while (parent != null) + { + yield return parent; + + parent = parent.GetParent(); } } @@ -546,19 +558,20 @@ namespace MediaBrowser.Controller.Entities public T FindParent() where T : Folder { - return Parents.OfType().FirstOrDefault(); + return GetParents().OfType().FirstOrDefault(); } [IgnoreDataMember] public virtual BaseItem DisplayParent { - get { return Parent; } + get { return GetParent(); } } /// /// When the item first debuted. For movies this could be premiere date, episodes would be first aired /// /// The premiere date. + [IgnoreDataMember] public DateTime? PremiereDate { get; set; } /// @@ -572,31 +585,35 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the display type of the media. /// /// The display type of the media. + [IgnoreDataMember] public string DisplayMediaType { get; set; } /// /// Gets or sets the official rating. /// /// The official rating. + [IgnoreDataMember] public string OfficialRating { get; set; } /// /// Gets or sets the official rating description. /// /// The official rating description. + [IgnoreDataMember] public string OfficialRatingDescription { get; set; } /// /// Gets or sets the custom rating. /// /// The custom rating. - //[IgnoreDataMember] + [IgnoreDataMember] public string CustomRating { get; set; } /// /// Gets or sets the overview. /// /// The overview. + [IgnoreDataMember] public string Overview { get; set; } /// @@ -609,37 +626,48 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the genres. /// /// The genres. + [IgnoreDataMember] public List Genres { get; set; } + /// + /// Gets or sets the tags. + /// + /// The tags. + public List Tags { get; set; } + /// /// Gets or sets the home page URL. /// /// The home page URL. + [IgnoreDataMember] public string HomePageUrl { get; set; } /// /// Gets or sets the community rating. /// /// The community rating. - //[IgnoreDataMember] + [IgnoreDataMember] public float? CommunityRating { get; set; } /// /// Gets or sets the community rating vote count. /// /// The community rating vote count. + [IgnoreDataMember] public int? VoteCount { get; set; } /// /// Gets or sets the run time ticks. /// /// The run time ticks. + [IgnoreDataMember] public long? RunTimeTicks { get; set; } /// /// Gets or sets the production year. /// /// The production year. + [IgnoreDataMember] public int? ProductionYear { get; set; } /// @@ -647,19 +675,34 @@ namespace MediaBrowser.Controller.Entities /// This could be episode number, album track number, etc. /// /// The index number. - //[IgnoreDataMember] + [IgnoreDataMember] public int? IndexNumber { get; set; } /// /// For an episode this could be the season number, or for a song this could be the disc number. /// /// The parent index number. + [IgnoreDataMember] public int? ParentIndexNumber { get; set; } [IgnoreDataMember] - public virtual string OfficialRatingForComparison + public string OfficialRatingForComparison { - get { return OfficialRating; } + get + { + if (!string.IsNullOrWhiteSpace(OfficialRating)) + { + return OfficialRating; + } + + var parent = DisplayParent; + if (parent != null) + { + return parent.OfficialRatingForComparison; + } + + return null; + } } [IgnoreDataMember] @@ -721,21 +764,21 @@ namespace MediaBrowser.Controller.Entities return LibraryManager.ResolvePaths(files, directoryService, null) .OfType() .Select(audio => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(audio.Id) as Audio.Audio; - - if (dbItem != null) { - audio = dbItem; - } + // Try to retrieve it from the db. If we don't find it, use the resolved version + var dbItem = LibraryManager.GetItemById(audio.Id) as Audio.Audio; - audio.ExtraType = ExtraType.ThemeSong; + if (dbItem != null) + { + audio = dbItem; + } - return audio; + audio.ExtraType = ExtraType.ThemeSong; - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); + return audio; + + // Sort them so that the list can be easily compared for changes + }).OrderBy(i => i.Path).ToList(); } /// @@ -751,21 +794,21 @@ namespace MediaBrowser.Controller.Entities return LibraryManager.ResolvePaths(files, directoryService, null) .OfType