From 60ac2e87129a1911ed518ea21977b1f689da015d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 27 Oct 2015 10:02:30 -0400 Subject: [PATCH 001/527] rework shutdown --- Emby.Drawing/ImageProcessor.cs | 2 +- MediaBrowser.Api/Images/ImageService.cs | 2 +- .../Drawing/ImageProcessingOptions.cs | 4 +-- .../Probing/ProbeResultNormalizer.cs | 7 +++- .../Persistence/MediaStreamColumns.cs | 32 +++++++++++++++++++ .../Persistence/SqliteItemRepository.cs | 12 +++++-- MediaBrowser.ServerApplication/MainStartup.cs | 21 ++++++++++-- SharedVersion.cs | 4 +-- 8 files changed, 72 insertions(+), 12 deletions(-) diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 05d89406b..ba92e0388 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -225,7 +225,7 @@ namespace Emby.Drawing return originalImagePath; } - var quality = options.Quality ?? 90; + var quality = options.Quality; var outputFormat = GetOutputFormat(options.OutputFormat); var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 259789fd1..8114f9f22 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -623,7 +623,7 @@ namespace MediaBrowser.Api.Images Item = item, MaxHeight = request.MaxHeight, MaxWidth = request.MaxWidth, - Quality = request.Quality, + Quality = request.Quality ?? 100, Width = request.Width, AddPlayedIndicator = request.AddPlayedIndicator, PercentPlayed = request.PercentPlayed ?? 0, diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index d8f5d52c3..e6bf86853 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Drawing public int? MaxHeight { get; set; } - public int? Quality { get; set; } + public int Quality { get; set; } public List Enhancers { get; set; } @@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Drawing public bool HasDefaultOptionsWithoutSize(string originalImagePath) { - return (!Quality.HasValue || Quality.Value == 100) && + return (Quality == 100) && IsOutputFormatDefault(originalImagePath) && !AddPlayedIndicator && PercentPlayed.Equals(0) && diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 7e9fa151b..56ce6b6d6 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -130,13 +130,18 @@ namespace MediaBrowser.MediaEncoding.Probing var stream = new MediaStream { Codec = streamInfo.codec_name, - CodecTag = streamInfo.codec_tag_string, Profile = streamInfo.profile, Level = streamInfo.level, Index = streamInfo.index, PixelFormat = streamInfo.pix_fmt }; + // Filter out junk + if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) + { + stream.CodecTag = streamInfo.codec_tag_string; + } + if (streamInfo.tags != null) { stream.Language = GetDictionaryValue(streamInfo.tags, "language"); diff --git a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs index f54e702d6..c983dd547 100644 --- a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs +++ b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs @@ -27,6 +27,38 @@ namespace MediaBrowser.Server.Implementations.Persistence AddIsCabacColumn(); AddKeyFramesColumn(); AddRefFramesCommand(); + AddCodecTagColumn(); + } + + private void AddCodecTagColumn() + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "PRAGMA table_info(mediastreams)"; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var name = reader.GetString(1); + + if (string.Equals(name, "CodecTag", StringComparison.OrdinalIgnoreCase)) + { + return; + } + } + } + } + } + + var builder = new StringBuilder(); + + builder.AppendLine("alter table mediastreams"); + builder.AppendLine("add column CodecTag TEXT"); + + _connection.RunQueries(new[] { builder.ToString() }, _logger); } private void AddPixelFormatColumnCommand() diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 7fbd9ee89..64ba3f110 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); var createMediaStreamsTableCommand - = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, KeyFrames TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, KeyFrames TEXT NULL, CodecTag TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; string[] queries = { @@ -320,7 +320,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "IsAnamorphic", "RefFrames", "IsCabac", - "KeyFrames" + "KeyFrames", + "CodecTag" }; /// @@ -2209,6 +2210,8 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveStreamCommand.GetParameter(index++).Value = string.Join(",", stream.KeyFrames.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()); } + _saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; + _saveStreamCommand.Transaction = transaction; _saveStreamCommand.ExecuteNonQuery(); } @@ -2370,6 +2373,11 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + if (!reader.IsDBNull(27)) + { + item.CodecTag = reader.GetString(27); + } + return item; } diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index b8af35fde..1032b1716 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -29,6 +29,7 @@ namespace MediaBrowser.ServerApplication private static ILogger _logger; private static bool _isRunningAsService = false; + private static bool _appHostDisposed; /// /// Defines the entry point of the application. @@ -329,7 +330,7 @@ namespace MediaBrowser.ServerApplication { _logger.Info("Shutting down"); - _appHost.Dispose(); + DisposeAppHost(); } /// @@ -500,14 +501,15 @@ namespace MediaBrowser.ServerApplication } else { + DisposeAppHost(); + ShutdownWindowsApplication(); } } public static void Restart() { - _logger.Info("Disposing app host"); - _appHost.Dispose(); + DisposeAppHost(); if (!_isRunningAsService) { @@ -522,11 +524,24 @@ namespace MediaBrowser.ServerApplication } } + private static void DisposeAppHost() + { + if (!_appHostDisposed) + { + _logger.Info("Disposing app host"); + + _appHostDisposed = true; + _appHost.Dispose(); + } + } + private static void ShutdownWindowsApplication() { _logger.Info("Calling Application.Exit"); Application.Exit(); + Environment.Exit(0); + _logger.Info("Calling ApplicationTaskCompletionSource.SetResult"); ApplicationTaskCompletionSource.SetResult(true); } diff --git a/SharedVersion.cs b/SharedVersion.cs index 4b8a8c61d..5aa872085 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5768.7")] +[assembly: AssemblyVersion("3.0.*")] +//[assembly: AssemblyVersion("3.0.5768.7")] From 455468ef944d9789b3d25512530f1f195d1cbd58 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 27 Oct 2015 13:26:04 -0400 Subject: [PATCH 002/527] update db retrieval --- MediaBrowser.Controller/Entities/BaseItem.cs | 36 ++++-- MediaBrowser.Controller/Entities/User.cs | 20 +++ .../Persistence/SqliteItemRepository.cs | 116 +++++++++++++++++- .../Persistence/SqliteUserRepository.cs | 7 +- 4 files changed, 161 insertions(+), 18 deletions(-) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ec688bd9f..e9a29cb7a 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -103,7 +103,8 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the name. /// /// The name. - public string Name + [IgnoreDataMember] + public virtual string Name { get { @@ -122,12 +123,14 @@ 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; } /// @@ -149,6 +152,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the path. /// /// The path. + [IgnoreDataMember] public virtual string Path { get; set; } [IgnoreDataMember] @@ -325,12 +329,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 +413,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; } @@ -493,6 +500,7 @@ namespace MediaBrowser.Controller.Entities return sortable; } + [IgnoreDataMember] public Guid ParentId { get; set; } /// @@ -559,6 +567,7 @@ namespace MediaBrowser.Controller.Entities /// 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 +581,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 +622,42 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the genres. /// /// The genres. + [IgnoreDataMember] public List Genres { 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,13 +665,14 @@ 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] @@ -1307,15 +1326,6 @@ namespace MediaBrowser.Controller.Entities return null; } - /// - /// Adds a person to the item - /// - /// The person. - /// - public void AddPerson(PersonInfo person) - { - } - /// /// Adds a studio to the item /// diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index a9e314ede..3900f0805 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -58,6 +58,26 @@ namespace MediaBrowser.Controller.Entities } } + private string _name; + /// + /// Gets or sets the name. + /// + /// The name. + public override string Name + { + get + { + return _name; + } + set + { + _name = value; + + // lazy load this again + SortName = null; + } + } + /// /// Returns the folder containing the item. /// If the item is a folder, it returns the folder itself diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 64ba3f110..a5e781761 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -76,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteStreamsCommand; private IDbCommand _saveStreamCommand; - private const int LatestSchemaVersion = 13; + private const int LatestSchemaVersion = 16; /// /// Initializes a new instance of the class. @@ -198,6 +198,10 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "ExternalEtag", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "DateLastRefreshed", "DATETIME"); + _connection.AddColumn(_logger, "TypedBaseItems", "DateLastSaved", "DATETIME"); + _connection.AddColumn(_logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); + _connection.AddColumn(_logger, "TypedBaseItems", "LockedFields", "Text"); + PrepareStatements(); new MediaStreamColumns(_connection, _logger).AddColumns(); @@ -289,7 +293,24 @@ namespace MediaBrowser.Server.Implementations.Persistence "PreferredMetadataCountryCode", "IsHD", "ExternalEtag", - "DateLastRefreshed" + "DateLastRefreshed", + "Name", + "Path", + "PremiereDate", + "Overview", + "ParentIndexNumber", + "ProductionYear", + "OfficialRating", + "OfficialRatingDescription", + "HomePageUrl", + "DisplayMediaType", + "ForcedSortName", + "RunTimeTicks", + "VoteCount", + "DateCreated", + "DateModified", + "guid", + "Genres" }; private readonly string[] _mediaStreamSaveColumns = @@ -377,7 +398,10 @@ namespace MediaBrowser.Server.Implementations.Persistence "PreferredMetadataCountryCode", "IsHD", "ExternalEtag", - "DateLastRefreshed" + "DateLastRefreshed", + "DateLastSaved", + "IsInMixedFolder", + "LockedFields" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -606,6 +630,10 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed; } + _saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; + _saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder; + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -827,6 +855,88 @@ namespace MediaBrowser.Server.Implementations.Persistence item.DateLastRefreshed = reader.GetDateTime(23).ToUniversalTime(); } + if (!reader.IsDBNull(24)) + { + item.Name = reader.GetString(24); + } + + if (!reader.IsDBNull(25)) + { + item.Path = reader.GetString(25); + } + + if (!reader.IsDBNull(26)) + { + item.PremiereDate = reader.GetDateTime(26).ToUniversalTime(); + } + + if (!reader.IsDBNull(27)) + { + item.Overview = reader.GetString(27); + } + + if (!reader.IsDBNull(28)) + { + item.ParentIndexNumber = reader.GetInt32(28); + } + + if (!reader.IsDBNull(29)) + { + item.ProductionYear = reader.GetInt32(29); + } + + if (!reader.IsDBNull(30)) + { + item.OfficialRating = reader.GetString(30); + } + + if (!reader.IsDBNull(31)) + { + item.OfficialRating = reader.GetString(31); + } + + if (!reader.IsDBNull(32)) + { + item.HomePageUrl = reader.GetString(32); + } + + if (!reader.IsDBNull(33)) + { + item.DisplayMediaType = reader.GetString(33); + } + + if (!reader.IsDBNull(34)) + { + item.ForcedSortName = reader.GetString(34); + } + + if (!reader.IsDBNull(35)) + { + item.RunTimeTicks = reader.GetInt64(35); + } + + if (!reader.IsDBNull(36)) + { + item.VoteCount = reader.GetInt32(36); + } + + if (!reader.IsDBNull(37)) + { + item.DateCreated = reader.GetDateTime(37).ToUniversalTime(); + } + + if (!reader.IsDBNull(38)) + { + item.DateModified = reader.GetDateTime(38).ToUniversalTime(); + } + + item.Id = reader.GetGuid(39); + + if (!reader.IsDBNull(40)) + { + item.Genres = reader.GetString(40).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + } + return item; } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs index ad784ae5d..9bd7e47f3 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs @@ -144,15 +144,18 @@ namespace MediaBrowser.Server.Implementations.Persistence { using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select data from users"; + cmd.CommandText = "select guid,data from users"; using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { while (reader.Read()) { - using (var stream = reader.GetMemoryStream(0)) + var id = reader.GetGuid(0); + + using (var stream = reader.GetMemoryStream(1)) { var user = _jsonSerializer.DeserializeFromStream(stream); + user.Id = id; yield return user; } } From 818662e051a07b15a9ac15df177835d7e4ef236b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 28 Oct 2015 00:06:13 -0400 Subject: [PATCH 003/527] use ImageMagick scale method --- Emby.Drawing/Emby.Drawing.csproj | 2 +- .../ImageMagick/ImageMagickEncoder.cs | 23 ++++++++++++-- Emby.Drawing/packages.config | 2 +- ...MediaBrowser.Common.Implementations.csproj | 6 ++-- .../packages.config | 4 +-- .../Entities/Audio/Audio.cs | 30 +++++++++---------- MediaBrowser.Controller/Entities/BaseItem.cs | 7 +++++ MediaBrowser.Controller/Entities/Book.cs | 11 ------- MediaBrowser.Controller/Entities/Folder.cs | 2 -- MediaBrowser.Controller/Entities/Game.cs | 7 ----- MediaBrowser.Controller/Entities/Photo.cs | 2 -- MediaBrowser.Controller/Entities/Studio.cs | 7 ----- MediaBrowser.Controller/Entities/Video.cs | 6 ---- .../LiveTv/LiveTvProgram.cs | 12 ++++---- .../Configuration/ServerConfiguration.cs | 18 +++++++---- .../Persistence/SqliteItemRepository.cs | 9 ++++-- .../ApplicationHost.cs | 2 +- .../MediaBrowser.ServerApplication.csproj | 5 ++-- .../packages.config | 2 +- 19 files changed, 77 insertions(+), 80 deletions(-) diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index e9911a12d..6cda8b5d0 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 ed0760ee3..c5ba6d9c8 100644 --- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs @@ -9,6 +9,7 @@ using System; using System.IO; using System.Linq; using CommonIO; +using MediaBrowser.Controller.Configuration; namespace Emby.Drawing.ImageMagick { @@ -18,13 +19,15 @@ namespace Emby.Drawing.ImageMagick private readonly IApplicationPaths _appPaths; private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; + private readonly IServerConfigurationManager _config; - public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem) + public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config) { _logger = logger; _appPaths = appPaths; _httpClient = httpClient; _fileSystem = fileSystem; + _config = config; LogVersion(); } @@ -137,11 +140,12 @@ namespace Emby.Drawing.ImageMagick { using (var originalImage = new MagickWand(inputPath)) { - originalImage.CurrentImage.ResizeImage(width, height); + ScaleImage(originalImage, width, height); DrawIndicator(originalImage, width, height, options); originalImage.CurrentImage.CompressionQuality = quality; + originalImage.CurrentImage.StripImage(); originalImage.SaveImage(outputPath); } @@ -152,12 +156,13 @@ namespace Emby.Drawing.ImageMagick { using (var originalImage = new MagickWand(inputPath)) { - originalImage.CurrentImage.ResizeImage(width, height); + ScaleImage(originalImage, width, height); wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0); DrawIndicator(wand, width, height, options); wand.CurrentImage.CompressionQuality = quality; + wand.CurrentImage.StripImage(); wand.SaveImage(outputPath); } @@ -166,6 +171,18 @@ namespace Emby.Drawing.ImageMagick SaveDelay(); } + private void ScaleImage(MagickWand wand, int width, int height) + { + if (_config.Configuration.EnableHighQualityImageScaling) + { + wand.CurrentImage.ResizeImage(width, height); + } + else + { + wand.CurrentImage.ScaleImage(width, height); + } + } + /// /// Draws the indicator. /// diff --git a/Emby.Drawing/packages.config b/Emby.Drawing/packages.config index 0fcdc278e..3b8dbcab7 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.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index d857e58b6..8615d4f8b 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -53,7 +53,7 @@ False - ..\packages\NLog.4.1.1\lib\net45\NLog.dll + ..\packages\NLog.4.2.0\lib\net45\NLog.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -62,9 +62,9 @@ False ..\ThirdParty\SharpCompress\SharpCompress.dll - + False - ..\packages\SimpleInjector.3.0.5\lib\net45\SimpleInjector.dll + ..\packages\SimpleInjector.3.1.0\lib\net45\SimpleInjector.dll diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index a0711a9c7..769a7c4f6 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -1,7 +1,7 @@  - + - + diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 43b980c20..6feffc3ef 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 { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e9a29cb7a..19d5576c6 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.Entities { protected BaseItem() { + Tags = new List(); Genres = new List(); Studios = new List(); ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -625,6 +626,12 @@ namespace MediaBrowser.Controller.Entities [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. /// diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index d31675baf..8342c1c10 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -17,19 +17,8 @@ namespace MediaBrowser.Controller.Entities } } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - public string SeriesName { get; set; } - public Book() - { - Tags = new List(); - } - public override bool CanDownload() { var locationType = LocationType; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 05965e1b5..fcbe54d05 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -28,7 +28,6 @@ namespace MediaBrowser.Controller.Entities public List ThemeSongIds { get; set; } public List ThemeVideoIds { get; set; } - public List Tags { get; set; } public Folder() { @@ -36,7 +35,6 @@ namespace MediaBrowser.Controller.Entities ThemeSongIds = new List(); ThemeVideoIds = new List(); - Tags = new List(); } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index ed3e85d58..ea518ce35 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -21,7 +21,6 @@ namespace MediaBrowser.Controller.Entities RemoteTrailerIds = new List(); ThemeSongIds = new List(); ThemeVideoIds = new List(); - Tags = new List(); } public List LocalTrailerIds { get; set; } @@ -34,12 +33,6 @@ namespace MediaBrowser.Controller.Entities locationType != LocationType.Virtual; } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - /// /// Gets or sets the remote trailers. /// diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index a3d892181..6c2f2a326 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -9,12 +9,10 @@ namespace MediaBrowser.Controller.Entities { public class Photo : BaseItem, IHasTags, IHasTaglines { - public List Tags { get; set; } public List Taglines { get; set; } public Photo() { - Tags = new List(); Taglines = new List(); } diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 822f305ed..a55527f37 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -10,13 +10,6 @@ namespace MediaBrowser.Controller.Entities /// public class Studio : BaseItem, IItemByName, IHasTags { - public List Tags { get; set; } - - public Studio() - { - Tags = new List(); - } - /// /// Gets the user data key. /// diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 8beee79bf..62d1bc7a1 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -185,12 +185,6 @@ namespace MediaBrowser.Controller.Entities public bool IsShortcut { get; set; } public string ShortcutPath { get; set; } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - /// /// Gets or sets the video bit rate. /// diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index e4b52fd99..96a3743d0 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -49,6 +49,12 @@ namespace MediaBrowser.Controller.LiveTv /// The audio. public ProgramAudio? Audio { get; set; } + /// + /// Gets or sets the name of the service. + /// + /// The name of the service. + public string ServiceName { get; set; } + /// /// Gets or sets a value indicating whether this instance is repeat. /// @@ -63,12 +69,6 @@ namespace MediaBrowser.Controller.LiveTv [IgnoreDataMember] public string EpisodeTitle { get; set; } - /// - /// Gets or sets the name of the service. - /// - /// The name of the service. - public string ServiceName { get; set; } - /// /// Gets or sets a value indicating whether this instance is movie. /// diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index dfcafa32d..e4c4e4762 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -62,6 +62,12 @@ namespace MediaBrowser.Model.Configuration /// true if this instance is port authorized; otherwise, false. public bool IsPortAuthorized { get; set; } + /// + /// Gets or sets a value indicating whether [enable high quality image scaling]. + /// + /// true if [enable high quality image scaling]; otherwise, false. + public bool EnableHighQualityImageScaling { get; set; } + /// /// Gets or sets the item by name path. /// @@ -92,18 +98,18 @@ namespace MediaBrowser.Model.Configuration /// true if [enable localized guids]; otherwise, false. public bool EnableLocalizedGuids { get; set; } - /// - /// Gets or sets a value indicating whether [disable startup scan]. - /// - /// true if [disable startup scan]; otherwise, false. - public bool DisableStartupScan { get; set; } - /// /// Gets or sets a value indicating whether [enable user views]. /// /// true if [enable user views]; otherwise, false. public bool EnableUserViews { get; set; } + /// + /// Gets or sets a value indicating whether [disable startup scan]. + /// + /// true if [disable startup scan]; otherwise, false. + public bool DisableStartupScan { get; set; } + /// /// Gets or sets a value indicating whether [enable library metadata sub folder]. /// diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index a5e781761..256b057d9 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -201,7 +201,8 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "DateLastSaved", "DATETIME"); _connection.AddColumn(_logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); _connection.AddColumn(_logger, "TypedBaseItems", "LockedFields", "Text"); - + _connection.AddColumn(_logger, "TypedBaseItems", "Studios", "Text"); + PrepareStatements(); new MediaStreamColumns(_connection, _logger).AddColumns(); @@ -401,7 +402,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "DateLastRefreshed", "DateLastSaved", "IsInMixedFolder", - "LockedFields" + "LockedFields", + "Studios" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -633,7 +635,8 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; _saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder; _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); - + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray()); + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index aeafc1ede..97a457a1b 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -573,7 +573,7 @@ namespace MediaBrowser.Server.Startup.Common { try { - return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager); + return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager, ServerConfigurationManager); } catch (Exception ex) { diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 3b4b52af3..ee7d782eb 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -64,8 +64,9 @@ False ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll - - ..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll + + False + ..\packages\ImageMagickSharp.1.0.0.17\lib\net45\ImageMagickSharp.dll ..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config index dec8199cc..3ea97a30e 100644 --- a/MediaBrowser.ServerApplication/packages.config +++ b/MediaBrowser.ServerApplication/packages.config @@ -1,7 +1,7 @@  - + From 421c743faa77ef66389f99c8f18ac07e35624f7c Mon Sep 17 00:00:00 2001 From: Jani Date: Wed, 28 Oct 2015 19:16:13 +0200 Subject: [PATCH 004/527] Add support for embedded subtitles in Kodi's DLNA profile --- MediaBrowser.Dlna/Profiles/KodiProfile.cs | 14 ++++++++++++++ MediaBrowser.Dlna/Profiles/Xml/Kodi.xml | 2 ++ 2 files changed, 16 insertions(+) diff --git a/MediaBrowser.Dlna/Profiles/KodiProfile.cs b/MediaBrowser.Dlna/Profiles/KodiProfile.cs index 75c323a1a..a039a26f4 100644 --- a/MediaBrowser.Dlna/Profiles/KodiProfile.cs +++ b/MediaBrowser.Dlna/Profiles/KodiProfile.cs @@ -90,6 +90,20 @@ namespace MediaBrowser.Dlna.Profiles { Format = "sub", Method = SubtitleDeliveryMethod.External, + }, + + new SubtitleProfile + { + Format = "srt", + Method = SubtitleDeliveryMethod.Embed, + DidlMode = "", + }, + + new SubtitleProfile + { + Format = "sub", + Method = SubtitleDeliveryMethod.Embed, + DidlMode = "", } }; } diff --git a/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml b/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml index a174610cb..42a255a37 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml @@ -51,5 +51,7 @@ + + \ No newline at end of file From 9b998a068a2622f43ac813800654e357f94d0c21 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 28 Oct 2015 15:40:38 -0400 Subject: [PATCH 005/527] update image encoding --- .../ImageMagick/ImageMagickEncoder.cs | 3 + MediaBrowser.Api/Movies/MoviesService.cs | 3 +- MediaBrowser.Api/TvShowsService.cs | 35 +++++++---- .../Logging/NlogManager.cs | 2 +- .../Security/PluginSecurityManager.cs | 9 +++ .../MediaBrowser.Common.csproj | 1 + .../Security/PaymentRequiredException.cs | 8 +++ MediaBrowser.Controller/Entities/BaseItem.cs | 10 +++- .../Entities/InternalItemsQuery.cs | 11 ++++ .../Library/ILibraryManager.cs | 8 +++ .../LiveTv/LiveTvAudioRecording.cs | 1 - .../LiveTv/LiveTvProgram.cs | 35 ++++------- .../LiveTv/LiveTvVideoRecording.cs | 1 - .../MediaBrowser.Controller.csproj | 1 + .../Net/PaymentRequiredException.cs | 15 +++++ .../Providers/MetadataStatus.cs | 14 ----- .../Manager/MetadataService.cs | 36 ++++++----- .../Dto/DtoService.cs | 8 ++- .../HttpServer/HttpListenerHost.cs | 4 +- .../HttpServer/LoggerUtils.cs | 5 +- .../SocketSharp/WebSocketSharpListener.cs | 10 +--- .../Library/LibraryManager.cs | 12 ++-- .../Library/SearchEngine.cs | 3 +- .../LiveTv/LiveTvManager.cs | 40 ++++++------- .../Persistence/SqliteItemRepository.cs | 60 +++++++++++++++++-- .../SqliteProviderInfoRepository.cs | 13 +--- .../TV/TVSeriesManager.cs | 20 ++++++- 27 files changed, 239 insertions(+), 129 deletions(-) create mode 100644 MediaBrowser.Common/Security/PaymentRequiredException.cs create mode 100644 MediaBrowser.Controller/Net/PaymentRequiredException.cs diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs index c5ba6d9c8..d097c8da3 100644 --- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs @@ -136,6 +136,9 @@ namespace Emby.Drawing.ImageMagick public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options) { + // Even if the caller specified 100, don't use it because it takes forever + quality = Math.Min(quality, 99); + if (string.IsNullOrWhiteSpace(options.BackgroundColor) || !HasTransparency(inputPath)) { using (var originalImage = new MagickWand(inputPath)) diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index fe8bae1a5..1681c6fc6 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -379,9 +379,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/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 29a4a8bb5..19d12fe65 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,21 +273,32 @@ namespace MediaBrowser.Api { var user = _userManager.GetUserById(request.UserId); - var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode); + var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime(); + + IEnumerable items; + + if (string.IsNullOrWhiteSpace(request.ParentId)) + { + items = _libraryManager.GetItems(new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { "PremiereDate", "SortName" }, + SortOrder = SortOrder.Ascending, + MinPremiereDate = minPremiereDate + + }, user); + } + else + { + items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate); + } 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 pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit); + var pagedItems = ApplyPaging(itemsList, request.StartIndex, request.Limit); var options = GetDtoOptions(request); @@ -440,7 +451,7 @@ namespace MediaBrowser.Api } episodes = season.GetEpisodes(user); - } + } else if (request.Season.HasValue) { var series = _libraryManager.GetItemById(request.Id) as Series; @@ -495,7 +506,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.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs index 391e7c212..1bbcccd88 100644 --- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs +++ b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs @@ -110,7 +110,7 @@ namespace MediaBrowser.Common.Implementations.Logging var logFile = new FileTarget { FileName = path, - Layout = "${longdate} ${level} - ${logger}: ${message}" + Layout = "${longdate} ${level} ${logger}: ${message}" }; logFile.Name = "ApplicationLogFile"; diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs index c17a637fe..7cc31ad7a 100644 --- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs +++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs @@ -219,6 +219,10 @@ namespace MediaBrowser.Common.Implementations.Security { SupporterKey = reg.key; } + else + { + throw new PaymentRequiredException(); + } } } @@ -227,6 +231,11 @@ namespace MediaBrowser.Common.Implementations.Security SaveAppStoreInfo(parameters); throw; } + catch (PaymentRequiredException) + { + SaveAppStoreInfo(parameters); + throw; + } catch (Exception e) { _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT"); diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index b2f62dd21..ccdb319fe 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -89,6 +89,7 @@ + diff --git a/MediaBrowser.Common/Security/PaymentRequiredException.cs b/MediaBrowser.Common/Security/PaymentRequiredException.cs new file mode 100644 index 000000000..27b3e6961 --- /dev/null +++ b/MediaBrowser.Common/Security/PaymentRequiredException.cs @@ -0,0 +1,8 @@ +using System; + +namespace MediaBrowser.Common.Security +{ + public class PaymentRequiredException : Exception + { + } +} diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 19d5576c6..fdf035e8d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -24,6 +24,7 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Controller.Entities { @@ -134,6 +135,13 @@ namespace MediaBrowser.Controller.Entities [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. @@ -178,7 +186,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 diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 785e2fd2b..786c96d36 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -75,6 +75,7 @@ namespace MediaBrowser.Controller.Entities public string[] Tags { get; set; } public string[] OfficialRatings { get; set; } + public DateTime? MinPremiereDate { get; set; } public DateTime? MinStartDate { get; set; } public DateTime? MaxStartDate { get; set; } public DateTime? MinEndDate { get; set; } @@ -121,5 +122,15 @@ namespace MediaBrowser.Controller.Entities ChannelIds = new string[] { }; ItemIds = new string[] { }; } + + public InternalItemsQuery(User user) + : this() + { + if (user != null) + { + var policy = user.Policy; + MaxParentalRating = policy.MaxParentalRating; + } + } } } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index c7ab88524..96bb6e2b6 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -543,5 +543,13 @@ namespace MediaBrowser.Controller.Library /// Index of the image. /// Task. Task ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex); + + /// + /// Gets the items. + /// + /// The query. + /// The user. + /// List<BaseItem>. + IEnumerable GetItems(InternalItemsQuery query, User user); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs index 03c05ec69..dd6a53d45 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs @@ -36,7 +36,6 @@ namespace MediaBrowser.Controller.LiveTv public bool IsLive { get; set; } [IgnoreDataMember] public bool IsPremiere { get; set; } - public ProgramAudio? Audio { get; set; } /// /// Gets the user data key. diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 96a3743d0..aa1a3b9c2 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -32,10 +32,11 @@ namespace MediaBrowser.Controller.LiveTv } /// - /// Gets or sets the type of the channel. + /// Gets or sets the name. /// - /// The type of the channel. - public ChannelType ChannelType { get; set; } + /// The name. + [IgnoreDataMember] + public string ServiceName { get; set; } /// /// The start date of the program, in UTC. @@ -43,18 +44,6 @@ namespace MediaBrowser.Controller.LiveTv [IgnoreDataMember] public DateTime StartDate { get; set; } - /// - /// Gets or sets the audio. - /// - /// The audio. - public ProgramAudio? Audio { get; set; } - - /// - /// Gets or sets the name of the service. - /// - /// The name of the service. - public string ServiceName { get; set; } - /// /// Gets or sets a value indicating whether this instance is repeat. /// @@ -145,14 +134,14 @@ namespace MediaBrowser.Controller.LiveTv } } - [IgnoreDataMember] - public override string MediaType - { - get - { - return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio; - } - } + //[IgnoreDataMember] + //public override string MediaType + //{ + // get + // { + // return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio; + // } + //} [IgnoreDataMember] public bool IsAiring diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index 77404cfe8..de8764e6d 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -36,7 +36,6 @@ namespace MediaBrowser.Controller.LiveTv public bool IsLive { get; set; } [IgnoreDataMember] public bool IsPremiere { get; set; } - public ProgramAudio? Audio { get; set; } /// /// Gets the user data key. diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index bcf4de2a2..600674114 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -248,6 +248,7 @@ + diff --git a/MediaBrowser.Controller/Net/PaymentRequiredException.cs b/MediaBrowser.Controller/Net/PaymentRequiredException.cs new file mode 100644 index 000000000..e09fe092e --- /dev/null +++ b/MediaBrowser.Controller/Net/PaymentRequiredException.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Net +{ + /// + /// Corresponds to a 402 response code + /// + public class PaymentRequiredException : Exception + { + } +} diff --git a/MediaBrowser.Controller/Providers/MetadataStatus.cs b/MediaBrowser.Controller/Providers/MetadataStatus.cs index 9b946aee2..654d72e2a 100644 --- a/MediaBrowser.Controller/Providers/MetadataStatus.cs +++ b/MediaBrowser.Controller/Providers/MetadataStatus.cs @@ -40,22 +40,8 @@ namespace MediaBrowser.Controller.Providers /// The date last images refresh. public DateTime? DateLastImagesRefresh { get; set; } - /// - /// Gets or sets the last result error message. - /// - /// The last result error message. - public string LastErrorMessage { get; set; } - public DateTime? ItemDateModified { get; set; } - public void AddStatus(string errorMessage) - { - if (string.IsNullOrEmpty(LastErrorMessage)) - { - LastErrorMessage = errorMessage; - } - } - public bool IsDirty { get; private set; } public void SetDateLastMetadataRefresh(DateTime? date) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 6860aeff3..a7f58e32b 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -99,7 +99,6 @@ namespace MediaBrowser.Providers.Manager var updateType = ItemUpdateType.None; var refreshResult = GetLastResult(item); - refreshResult.LastErrorMessage = string.Empty; var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem); var localImagesFailed = false; @@ -119,7 +118,6 @@ namespace MediaBrowser.Providers.Manager { localImagesFailed = true; Logger.ErrorException("Error validating images for {0}", ex, item.Path ?? item.Name ?? "Unknown name"); - refreshResult.AddStatus(ex.Message); } var metadataResult = new MetadataResult @@ -150,7 +148,6 @@ namespace MediaBrowser.Providers.Manager var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false); updateType = updateType | result.UpdateType; - refreshResult.AddStatus(result.ErrorMessage); if (result.Failures == 0) { refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow); @@ -172,7 +169,6 @@ namespace MediaBrowser.Providers.Manager var result = await itemImageProvider.RefreshImages(itemOfType, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false); updateType = updateType | result.UpdateType; - refreshResult.AddStatus(result.ErrorMessage); if (result.Failures == 0) { refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow); @@ -231,17 +227,7 @@ namespace MediaBrowser.Providers.Manager private DateTime GetLastRefreshDate(IHasMetadata item) { - if (item.DateLastRefreshed != default(DateTime)) - { - return item.DateLastRefreshed; - } - - if (ServerConfigurationManager.Configuration.EnableDateLastRefresh) - { - return item.DateLastRefreshed; - } - - if (item is BoxSet || (item is IItemByName && !(item is MusicArtist))) + if (EnableDateLastRefreshed(item)) { return item.DateLastRefreshed; } @@ -249,6 +235,26 @@ namespace MediaBrowser.Providers.Manager return item.DateLastSaved; } + private bool EnableDateLastRefreshed(IHasMetadata item) + { + if (ServerConfigurationManager.Configuration.EnableDateLastRefresh) + { + return true; + } + + if (item.DateLastRefreshed != default(DateTime)) + { + return true; + } + + if (item is BoxSet || (item is IItemByName && !(item is MusicArtist))) + { + return true; + } + + return false; + } + protected async Task SaveItem(MetadataResult result, ItemUpdateType reason, CancellationToken cancellationToken) { if (result.Item.SupportsPeople && result.People != null) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 20e1eb543..fcda802f4 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -472,7 +472,7 @@ namespace MediaBrowser.Server.Implementations.Dto // These are just far too slow. // TODO: Disable for CollectionFolder - if (!(folder is UserRootFolder) && !(folder is UserView)) + if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is IChannelItem)) { SetSpecialCounts(folder, user, dto, fields, syncProgress); } @@ -1042,7 +1042,11 @@ namespace MediaBrowser.Server.Implementations.Dto dto.IsFolder = item.IsFolder; dto.MediaType = item.MediaType; dto.LocationType = item.LocationType; - dto.IsHD = item.IsHD; + if (item.IsHD.HasValue && item.IsHD.Value) + { + dto.IsHD = item.IsHD; + } + dto.Audio = item.Audio; dto.PreferredMetadataCountryCode = item.PreferredMetadataCountryCode; dto.PreferredMetadataLanguage = item.PreferredMetadataLanguage; diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index e8bb40ba1..6abfa0674 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -92,7 +92,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer {typeof (FileNotFoundException), 404}, {typeof (DirectoryNotFoundException), 404}, {typeof (SecurityException), 401}, - {typeof (UnauthorizedAccessException), 500} + {typeof (PaymentRequiredException), 402}, + {typeof (UnauthorizedAccessException), 500}, + {typeof (ApplicationException), 500} }; HostConfig.Instance.DebugMode = true; diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs index 02ce38ef1..fae702023 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs @@ -16,7 +16,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The duration. public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration) { - logger.Info("HTTP Response {0} to {1}. Time: {2}ms. {3}", statusCode, endPoint, Convert.ToInt32(duration.TotalMilliseconds).ToString(CultureInfo.InvariantCulture), url); + var durationMs = duration.TotalMilliseconds; + var logSuffix = durationMs >= 1000 ? "ms (slow)" : "ms"; + + logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url); } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index f8178c115..9f80c8ac9 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -183,15 +183,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp /// The request. private static void LogRequest(ILogger logger, HttpListenerRequest request) { - var log = new StringBuilder(); - - var headers = string.Join(",", request.Headers.AllKeys.Where(i => !string.Equals(i, "cookie", StringComparison.OrdinalIgnoreCase) && !string.Equals(i, "Referer", StringComparison.OrdinalIgnoreCase)).Select(k => k + "=" + request.Headers[k])); - - log.AppendLine("Ip: " + request.RemoteEndPoint + ". Headers: " + headers); - - var type = request.IsWebSocketRequest ? "Web Socket" : "HTTP " + request.HttpMethod; - - logger.LogMultiline(type + " " + request.Url, LogSeverity.Info, log); + logger.Info("{0} {1}. UserAgent: {2}", (request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod), request.Url, request.UserAgent ?? string.Empty); } private void HandleError(Exception ex, HttpListenerContext context) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 92acd08d1..daa3d8ad4 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1280,6 +1280,11 @@ namespace MediaBrowser.Server.Implementations.Library return ItemRepository.GetItemIdsList(query); } + public IEnumerable GetItems(InternalItemsQuery query, User user) + { + return GetItemIds(query).Select(GetItemById).Where(i => i.IsVisibleStandalone(user)); + } + /// /// Gets the intros. /// @@ -1811,14 +1816,9 @@ namespace MediaBrowser.Server.Implementations.Library isNew = true; } - if (!item.UserId.HasValue) + if (!item.UserId.HasValue || !string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase)) { item.UserId = user.Id; - await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); - } - - if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase)) - { item.ViewType = viewType; await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index d6aff1192..108a891e0 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -157,12 +157,11 @@ namespace MediaBrowser.Server.Implementations.Library AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name); - var mediaItems = _libraryManager.GetItems(new InternalItemsQuery + var mediaItems = _libraryManager.GetItems(new InternalItemsQuery(user) { NameContains = searchTerm, ExcludeItemTypes = excludeItemTypes.ToArray(), IncludeItemTypes = includeItemTypes.ToArray(), - MaxParentalRating = user == null ? null : user.Policy.MaxParentalRating, Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 3) : null), }).Items; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index edfca0d6c..d7c9edae3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -607,6 +607,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var item = _libraryManager.GetItemById(id) as LiveTvProgram; var isNew = false; + var forceUpdate = false; if (item == null) { @@ -621,7 +622,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv }; } - item.ChannelType = channelType; + //item.ChannelType = channelType; + if (!string.Equals(item.ServiceName, serviceName, StringComparison.Ordinal)) + { + forceUpdate = true; + } item.ServiceName = serviceName; item.Audio = info.Audio; @@ -666,7 +671,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); } - else if (string.IsNullOrWhiteSpace(info.Etag)) + else if (forceUpdate || string.IsNullOrWhiteSpace(info.Etag)) { await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } @@ -814,7 +819,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { - var internalQuery = new InternalItemsQuery + var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); + + var internalQuery = new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, MinEndDate = query.MinEndDate, @@ -832,11 +839,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv SortOrder = query.SortOrder ?? SortOrder.Ascending }; - var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); if (user != null) { - internalQuery.MaxParentalRating = user.Policy.MaxParentalRating; - if (user.Policy.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram)) { internalQuery.HasParentalRating = true; @@ -874,7 +878,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken) { - var internalQuery = new InternalItemsQuery + var user = _userManager.GetUserById(query.UserId); + + var internalQuery = new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, IsAiring = query.IsAiring, @@ -895,11 +901,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - var user = _userManager.GetUserById(query.UserId); if (user != null) { - internalQuery.MaxParentalRating = user.Policy.MaxParentalRating; - if (user.Policy.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram)) { internalQuery.HasParentalRating = true; @@ -1037,6 +1040,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var internalProgram = GetInternalProgram(program.Id); + if (string.IsNullOrWhiteSpace(internalProgram.ServiceName)) + { + continue; + } + List timerList; if (!timers.TryGetValue(internalProgram.ServiceName, out timerList)) { @@ -1052,7 +1060,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - var timer = timerList.FirstOrDefault(i => string.Equals(i.ProgramId, internalProgram.ExternalId, StringComparison.OrdinalIgnoreCase)); if (timer != null) @@ -1429,18 +1436,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv public void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, bool addChannelInfo, User user = null) { var program = (LiveTvProgram)item; - var service = GetService(program); - - dto.Id = _tvDtoService.GetInternalProgramId(service.Name, program.ExternalId).ToString("N"); dto.StartDate = program.StartDate; dto.EpisodeTitle = program.EpisodeTitle; - dto.Audio = program.Audio; - if (program.IsHD.HasValue && program.IsHD.Value) - { - dto.IsHD = program.IsHD; - } if (program.IsRepeat) { dto.IsRepeat = program.IsRepeat; @@ -1499,7 +1498,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv var info = recording; - dto.Id = item.Id.ToString("N"); dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"); @@ -1508,8 +1506,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv dto.RecordingStatus = info.Status; dto.IsRepeat = info.IsRepeat; dto.EpisodeTitle = info.EpisodeTitle; - dto.Audio = info.Audio; - dto.IsHD = info.IsHD; dto.IsMovie = info.IsMovie; dto.IsSeries = info.IsSeries; dto.IsSports = info.IsSports; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 256b057d9..730632bb3 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -19,6 +19,7 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Channels; +using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Server.Implementations.Persistence { @@ -76,7 +77,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteStreamsCommand; private IDbCommand _saveStreamCommand; - private const int LatestSchemaVersion = 16; + private const int LatestSchemaVersion = 17; /// /// Initializes a new instance of the class. @@ -202,7 +203,9 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); _connection.AddColumn(_logger, "TypedBaseItems", "LockedFields", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "Studios", "Text"); - + _connection.AddColumn(_logger, "TypedBaseItems", "Audio", "Text"); + _connection.AddColumn(_logger, "TypedBaseItems", "ExternalServiceId", "Text"); + PrepareStatements(); new MediaStreamColumns(_connection, _logger).AddColumns(); @@ -311,7 +314,10 @@ namespace MediaBrowser.Server.Implementations.Persistence "DateCreated", "DateModified", "guid", - "Genres" + "Genres", + "ParentId", + "Audio", + "ExternalServiceId" }; private readonly string[] _mediaStreamSaveColumns = @@ -403,7 +409,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "DateLastSaved", "IsInMixedFolder", "LockedFields", - "Studios" + "Studios", + "Audio", + "ExternalServiceId" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -637,6 +645,25 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray()); + if (item.Audio.HasValue) + { + _saveItemCommand.GetParameter(index++).Value = item.Audio.Value.ToString(); + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + var tvItem = item as ILiveTvItem; + if (tvItem != null) + { + _saveItemCommand.GetParameter(index++).Value = tvItem.ServiceName; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -940,6 +967,25 @@ namespace MediaBrowser.Server.Implementations.Persistence item.Genres = reader.GetString(40).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); } + if (!reader.IsDBNull(41)) + { + item.ParentId = reader.GetGuid(41); + } + + if (!reader.IsDBNull(42)) + { + item.Audio = (ProgramAudio)Enum.Parse(typeof(ProgramAudio), reader.GetString(42), true); + } + + if (!reader.IsDBNull(43)) + { + var tvItem = item as ILiveTvItem; + if (tvItem != null) + { + item.ForcedSortName = reader.GetString(43); + } + } + return item; } @@ -1668,6 +1714,12 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@MinStartDate", DbType.Date).Value = query.MinStartDate.Value; } + if (query.MinPremiereDate.HasValue) + { + whereClauses.Add("PremiereDate>=@MinPremiereDate"); + cmd.Parameters.Add(cmd, "@MinPremiereDate", DbType.Date).Value = query.MinPremiereDate.Value; + } + if (query.MaxStartDate.HasValue) { whereClauses.Add("StartDate<=@MaxStartDate"); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs index e7853b458..a63b93dc7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence string[] queries = { - "create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, ItemName TEXT, ItemType TEXT, SeriesName TEXT, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, LastErrorMessage TEXT, ItemDateModified DateTimeNull)", + "create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, ItemName TEXT, ItemType TEXT, SeriesName TEXT, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, ItemDateModified DateTimeNull)", "create index if not exists idx_MetadataStatus on MetadataStatus(ItemId)", //pragmas @@ -71,7 +71,6 @@ namespace MediaBrowser.Server.Implementations.Persistence "SeriesName", "DateLastMetadataRefresh", "DateLastImagesRefresh", - "LastErrorMessage", "ItemDateModified" }; @@ -185,12 +184,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (!reader.IsDBNull(6)) { - result.LastErrorMessage = reader.GetString(6); - } - - if (!reader.IsDBNull(7)) - { - result.ItemDateModified = reader.GetDateTime(7).ToUniversalTime(); + result.ItemDateModified = reader.GetDateTime(6).ToUniversalTime(); } return result; @@ -219,8 +213,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveStatusCommand.GetParameter(3).Value = status.SeriesName; _saveStatusCommand.GetParameter(4).Value = status.DateLastMetadataRefresh; _saveStatusCommand.GetParameter(5).Value = status.DateLastImagesRefresh; - _saveStatusCommand.GetParameter(6).Value = status.LastErrorMessage; - _saveStatusCommand.GetParameter(7).Value = status.ItemDateModified; + _saveStatusCommand.GetParameter(6).Value = status.ItemDateModified; _saveStatusCommand.Transaction = transaction; diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs index f34b43e43..93ebd0a1c 100644 --- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs +++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs @@ -36,8 +36,22 @@ namespace MediaBrowser.Server.Implementations.TV ? new string[] { } : new[] { request.ParentId }; - var items = GetAllLibraryItems(user, parentIds, i => i is Series) - .Cast(); + IEnumerable items; + + if (parentIds.Length == 0) + { + items = _libraryManager.GetItems(new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Series).Name }, + SortOrder = SortOrder.Ascending + + }, user).Cast(); + } + else + { + items = GetAllLibraryItems(user, parentIds, i => i is Series) + .Cast(); + } // Avoid implicitly captured closure var episodes = GetNextUpEpisodes(request, user, items); @@ -64,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.TV return GetResult(episodes, null, request); } - private IEnumerable GetAllLibraryItems(User user, string[] parentIds, Func filter) + private IEnumerable GetAllLibraryItems(User user, string[] parentIds, Func filter) { if (parentIds.Length > 0) { From c155d18279a6fbc3cbe2a055ffa1633beac1c01d Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 28 Oct 2015 18:48:56 -0400 Subject: [PATCH 006/527] Partial updates --- .../Security/PluginSecurityManager.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs index 7cc31ad7a..657305188 100644 --- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs +++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs @@ -219,10 +219,6 @@ namespace MediaBrowser.Common.Implementations.Security { SupporterKey = reg.key; } - else - { - throw new PaymentRequiredException(); - } } } @@ -231,13 +227,13 @@ namespace MediaBrowser.Common.Implementations.Security SaveAppStoreInfo(parameters); throw; } - catch (PaymentRequiredException) - { - SaveAppStoreInfo(parameters); - throw; - } catch (Exception e) { + //Right here we need to examine the response code returned by the http call to mb3admin + // that's the part I'm not sure how to do - maybe it is passed in the exception? + //If that response code is a 402 then throw our PaymentRequiredException. There should be no reason to save the data in this case + + //If it was any other response code, execute the block below _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT"); SaveAppStoreInfo(parameters); //TODO - could create a re-try routine on start-up if this file is there. For now we can handle manually. From 0bd1f36ececc04c86bbf49b1ffd07dd30a5878b1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 29 Oct 2015 09:28:05 -0400 Subject: [PATCH 007/527] update db queries --- MediaBrowser.Api/PluginService.cs | 6 +- MediaBrowser.Api/TvShowsService.cs | 34 ++-- .../Security/PluginSecurityManager.cs | 17 +- .../Entities/AggregateFolder.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 21 ++- MediaBrowser.Controller/Entities/Folder.cs | 45 +++-- .../Entities/InternalItemsQuery.cs | 6 +- MediaBrowser.Controller/Entities/Person.cs | 9 + .../Entities/TV/Episode.cs | 14 ++ MediaBrowser.Controller/Entities/UserView.cs | 15 ++ .../Library/ILibraryManager.cs | 12 +- .../LiveTv/LiveTvProgram.cs | 9 + .../Persistence/IItemRepository.cs | 7 + .../ContentDirectory/ControlHandler.cs | 24 +-- .../Configuration/ServerConfiguration.cs | 9 +- .../Collections/CollectionManager.cs | 1 + .../Dto/DtoService.cs | 14 +- .../Intros/DefaultIntroProvider.cs | 8 +- .../Library/LibraryManager.cs | 58 +++++-- .../Library/MusicManager.cs | 8 +- .../Library/SearchEngine.cs | 27 +-- .../LiveTv/LiveTvManager.cs | 34 ++-- .../Persistence/CleanDatabaseScheduledTask.cs | 8 + .../Persistence/SqliteItemRepository.cs | 154 +++++++++++++++++- .../Playlists/PlaylistManager.cs | 1 + .../TV/TVSeriesManager.cs | 48 ++---- .../ApplicationHost.cs | 2 +- .../MediaBrowser.Server.Startup.Common.csproj | 2 +- .../Migrations/DbMigration.cs | 34 ++++ .../Migrations/Release5767.cs | 48 ------ 30 files changed, 432 insertions(+), 245 deletions(-) create mode 100644 MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs delete mode 100644 MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index a7fd14bf0..74b37df92 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -278,9 +278,11 @@ namespace MediaBrowser.Api /// /// /// - public async Task Post(RegisterAppstoreSale request) + public void Post(RegisterAppstoreSale request) { - await _securityManager.RegisterAppStoreSale(request.Parameters); + var task = _securityManager.RegisterAppStoreSale(request.Parameters); + + Task.WaitAll(task); } /// diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 19d12fe65..ead232888 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -275,38 +275,26 @@ namespace MediaBrowser.Api var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime(); - IEnumerable items; + var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId }; - if (string.IsNullOrWhiteSpace(request.ParentId)) + var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { - items = _libraryManager.GetItems(new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(Episode).Name }, - SortBy = new[] { "PremiereDate", "SortName" }, - SortOrder = SortOrder.Ascending, - MinPremiereDate = minPremiereDate + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { "PremiereDate", "AirTime", "SortName" }, + SortOrder = SortOrder.Ascending, + MinPremiereDate = minPremiereDate, + StartIndex = request.StartIndex, + Limit = request.Limit - }, user); - } - else - { - items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate); - } - - var itemsList = _libraryManager - .Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending) - .Cast() - .ToList(); - - var pagedItems = ApplyPaging(itemsList, request.StartIndex, request.Limit); + }, user, 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 }; diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs index 7cc31ad7a..1176407ce 100644 --- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs +++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs @@ -8,8 +8,10 @@ using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Net; namespace MediaBrowser.Common.Implementations.Security { @@ -219,10 +221,6 @@ namespace MediaBrowser.Common.Implementations.Security { SupporterKey = reg.key; } - else - { - throw new PaymentRequiredException(); - } } } @@ -231,10 +229,15 @@ namespace MediaBrowser.Common.Implementations.Security SaveAppStoreInfo(parameters); throw; } - catch (PaymentRequiredException) + catch (HttpException e) { - SaveAppStoreInfo(parameters); - throw; + _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT"); + + if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.PaymentRequired) + { + throw new PaymentRequiredException(); + } + throw new ApplicationException("Error registering store sale"); } catch (Exception e) { diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 14f8c1617..10372eb49 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -128,7 +128,7 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { - return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); + return base.GetNonCachedChildren(directoryService); } /// diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index fdf035e8d..f14e09616 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -639,7 +639,7 @@ namespace MediaBrowser.Controller.Entities /// /// The tags. public List Tags { get; set; } - + /// /// Gets or sets the home page URL. /// @@ -1898,5 +1898,24 @@ namespace MediaBrowser.Controller.Entities DateLastSaved.Ticks.ToString(CultureInfo.InvariantCulture) }; } + + public virtual IEnumerable GetAncestorIds() + { + return Parents.Select(i => i.Id).Concat(LibraryManager.GetCollectionFolders(this).Select(i => i.Id)); + } + + [IgnoreDataMember] + public virtual bool SupportsAncestors + { + get + { + return true; + } + } + + public virtual IEnumerable GetIdsForAncestorQuery() + { + return new[] { Id }; + } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index fcbe54d05..e08eda1ac 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -149,7 +149,15 @@ namespace MediaBrowser.Controller.Entities await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); - await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); + if (!EnableNewFolderQuerying()) + { + await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); + } + } + + private static bool EnableNewFolderQuerying() + { + return ConfigurationManager.Configuration.MigrationVersion >= 1; } protected void AddChildrenInternal(IEnumerable children) @@ -222,7 +230,12 @@ namespace MediaBrowser.Controller.Entities item.SetParent(null); - return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken); + if (!EnableNewFolderQuerying()) + { + return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken); + } + + return Task.FromResult(true); } /// @@ -471,6 +484,7 @@ namespace MediaBrowser.Controller.Entities } else { + child.SetParent(this); newItems.Add(child); validChildren.Add(child); } @@ -478,6 +492,7 @@ namespace MediaBrowser.Controller.Entities else { // Brand new item - needs to be added + child.SetParent(this); newItems.Add(child); validChildren.Add(child); } @@ -506,7 +521,6 @@ namespace MediaBrowser.Controller.Entities } else { - await UpdateIsOffline(item, false).ConfigureAwait(false); actualRemovals.Add(item); } } @@ -517,6 +531,9 @@ namespace MediaBrowser.Controller.Entities foreach (var item in actualRemovals) { + item.SetParent(null); + item.IsOffline = false; + await LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false); LibraryManager.ReportItemRemoved(item); } } @@ -525,7 +542,10 @@ namespace MediaBrowser.Controller.Entities AddChildrenInternal(newItems); - await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); + if (!EnableNewFolderQuerying()) + { + await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); + } } } @@ -755,19 +775,16 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected IEnumerable GetCachedChildren() { - if (ConfigurationManager.Configuration.DisableStartupScan) + if (EnableNewFolderQuerying()) { - return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null); - //return ItemRepository.GetItems(new InternalItemsQuery - //{ - // ParentId = Id + return ItemRepository.GetItemList(new InternalItemsQuery + { + ParentId = Id - //}).Items.Select(RetrieveChild).Where(i => i != null); - } - else - { - return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null); + }).Select(RetrieveChild).Where(i => i != null); } + + return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null); } private BaseItem RetrieveChild(BaseItem child) diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 786c96d36..038a46316 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -102,7 +102,8 @@ namespace MediaBrowser.Controller.Entities public LocationType? LocationType { get; set; } public Guid? ParentId { get; set; } - + public string[] AncestorIds { get; set; } + public InternalItemsQuery() { Tags = new string[] { }; @@ -121,6 +122,7 @@ namespace MediaBrowser.Controller.Entities PersonIds = new string[] { }; ChannelIds = new string[] { }; ItemIds = new string[] { }; + AncestorIds = new string[] { }; } public InternalItemsQuery(User user) @@ -130,6 +132,8 @@ namespace MediaBrowser.Controller.Entities { var policy = user.Policy; MaxParentalRating = policy.MaxParentalRating; + + User = user; } } } diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 6c277da56..120a376d4 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -101,6 +101,15 @@ namespace MediaBrowser.Controller.Entities return false; } } + + [IgnoreDataMember] + public override bool SupportsAncestors + { + get + { + return false; + } + } } /// diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 92ca9e970..3d18b86df 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -265,6 +265,20 @@ namespace MediaBrowser.Controller.Entities.TV } } + public override IEnumerable GetAncestorIds() + { + var list = base.GetAncestorIds().ToList(); + + var seasonId = SeasonId; + + if (seasonId.HasValue && !list.Contains(seasonId.Value)) + { + list.Add(seasonId.Value); + } + + return list; + } + public override IEnumerable GetDeletePaths() { return new[] { Path }; diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 5ee49ae5a..76188ce58 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -24,6 +24,21 @@ namespace MediaBrowser.Controller.Entities { return true; } + + public override IEnumerable GetIdsForAncestorQuery() + { + var list = new List(); + + if (DisplayParentId != Guid.Empty) + { + list.Add(DisplayParentId); + } + else if (ParentId != Guid.Empty) + { + list.Add(ParentId); + } + return list; + } public override Task> GetItems(InternalItemsQuery query) { diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 96bb6e2b6..c24cf9bce 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -549,7 +549,17 @@ namespace MediaBrowser.Controller.Library /// /// The query. /// The user. + /// The parent ids. /// List<BaseItem>. - IEnumerable GetItems(InternalItemsQuery query, User user); + IEnumerable GetItems(InternalItemsQuery query, User user, IEnumerable parentIds); + + /// + /// Gets the items result. + /// + /// The query. + /// The user. + /// The parent ids. + /// QueryResult<BaseItem>. + QueryResult GetItemsResult(InternalItemsQuery query, User user, IEnumerable parentIds); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index aa1a3b9c2..55bc2269e 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -217,5 +217,14 @@ namespace MediaBrowser.Controller.LiveTv return base.SupportsPeople; } } + + [IgnoreDataMember] + public override bool SupportsAncestors + { + get + { + return false; + } + } } } diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 8fc0aedd3..0b1c9c3e0 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -176,6 +176,13 @@ namespace MediaBrowser.Controller.Persistence /// The query. /// QueryResult<Tuple<Guid, System.String>>. QueryResult> GetItemIdsWithPath(InternalItemsQuery query); + + /// + /// Gets the item list. + /// + /// The query. + /// List<BaseItem>. + IEnumerable GetItemList(InternalItemsQuery query); } } diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index a9ce5587d..ba50f2f32 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -481,23 +481,17 @@ namespace MediaBrowser.Dlna.ContentDirectory private QueryResult GetItemsFromPerson(Person person, User user, int? startIndex, int? limit) { - var itemsWithPerson = _libraryManager.GetItems(new InternalItemsQuery + var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { - Person = person.Name + Person = person.Name, + IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name, typeof(ChannelVideoItem).Name }, + SortBy = new[] { ItemSortBy.SortName }, + Limit = limit, + StartIndex = startIndex - }).Items; + }, user, new string[] { }); - var items = itemsWithPerson - .Where(i => i is Movie || i is Series || i is IChannelItem) - .Where(i => i.IsVisibleStandalone(user)) - .ToList(); - - items = _libraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending) - .Skip(startIndex ?? 0) - .Take(limit ?? int.MaxValue) - .ToList(); - - var serverItems = items.Select(i => new ServerItem + var serverItems = itemsResult.Items.Select(i => new ServerItem { Item = i, StubType = null @@ -506,7 +500,7 @@ namespace MediaBrowser.Dlna.ContentDirectory return new QueryResult { - TotalRecordCount = serverItems.Length, + TotalRecordCount = itemsResult.TotalRecordCount, Items = serverItems }; } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index e4c4e4762..ec024e87c 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Configuration /// /// true if [enable high quality image scaling]; otherwise, false. public bool EnableHighQualityImageScaling { get; set; } - + /// /// Gets or sets the item by name path. /// @@ -234,12 +234,14 @@ namespace MediaBrowser.Model.Configuration public string[] Migrations { get; set; } + public int MigrationVersion { get; set; } + /// /// Initializes a new instance of the class. /// public ServerConfiguration() { - Migrations = new string[] {}; + Migrations = new string[] { }; ImageSavingConvention = ImageSavingConvention.Compatible; PublicPort = 8096; @@ -583,7 +585,8 @@ namespace MediaBrowser.Model.Configuration Limit = 0, Type = ImageType.Thumb } - } + }, + DisabledMetadataFetchers = new []{ "TheMovieDb" } } }; } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index 5c98e401f..4e742ca7a 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -40,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.Collections public Folder GetCollectionsFolder(string userId) { return _libraryManager.RootFolder.Children.OfType() + .FirstOrDefault() ?? _libraryManager.GetUserRootFolder().Children.OfType() .FirstOrDefault(); } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index fcda802f4..8439f28f7 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -163,16 +163,11 @@ namespace MediaBrowser.Server.Implementations.Dto if (person != null) { - var items = _libraryManager.GetItems(new InternalItemsQuery + var items = _libraryManager.GetItems(new InternalItemsQuery(user) { Person = byName.Name - }).Items; - - if (user != null) - { - return items.Where(i => i.IsVisibleStandalone(user)).ToList(); - } + }, user, new string[] { }); return items.ToList(); } @@ -471,8 +466,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.ChildCount = GetChildCount(folder, user); // These are just far too slow. - // TODO: Disable for CollectionFolder - if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is IChannelItem)) + if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is IChannelItem) && !(folder is ICollectionFolder)) { SetSpecialCounts(folder, user, dto, fields, syncProgress); } @@ -1524,7 +1518,7 @@ namespace MediaBrowser.Server.Implementations.Dto } dto.ChannelId = item.ChannelId; - + var channelItem = item as IChannelItem; if (channelItem != null) { diff --git a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs index ec94e16db..6310b61d1 100644 --- a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs +++ b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs @@ -83,13 +83,11 @@ namespace MediaBrowser.Server.Implementations.Intros if (config.EnableIntrosFromMoviesInLibrary) { - var inputItems = _libraryManager.GetItems(new InternalItemsQuery + var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user) { - IncludeItemTypes = new[] { typeof(Movie).Name }, + IncludeItemTypes = new[] { typeof(Movie).Name } - User = user - - }).Items; + }, user, new string[]{}); var itemsWithTrailers = inputItems .Where(i => diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index daa3d8ad4..522038b46 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -401,12 +401,12 @@ namespace MediaBrowser.Server.Implementations.Library { foreach (var path in item.GetDeletePaths().ToList()) { - if (_fileSystem.DirectoryExists(path)) + if (_fileSystem.DirectoryExists(path)) { _logger.Debug("Deleting path {0}", path); _fileSystem.DeleteDirectory(path, true); } - else if (_fileSystem.FileExists(path)) + else if (_fileSystem.FileExists(path)) { _logger.Debug("Deleting path {0}", path); _fileSystem.DeleteFile(path); @@ -697,7 +697,7 @@ namespace MediaBrowser.Server.Implementations.Library { var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath; - _fileSystem.CreateDirectory(rootFolderPath); + _fileSystem.CreateDirectory(rootFolderPath); var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath)); @@ -727,6 +727,13 @@ namespace MediaBrowser.Server.Implementations.Library folder = dbItem; } + //if (folder.ParentId != rootFolder.Id) + //{ + // folder.ParentId = rootFolder.Id; + // var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); + // Task.WaitAll(task); + //} + rootFolder.AddVirtualChild(folder); RegisterItem(folder); @@ -748,7 +755,7 @@ namespace MediaBrowser.Server.Implementations.Library { var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; - _fileSystem.CreateDirectory(userRootPath); + _fileSystem.CreateDirectory(userRootPath); var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder; @@ -1000,9 +1007,9 @@ namespace MediaBrowser.Server.Implementations.Library private void SetPropertiesFromSongs(MusicArtist artist, IEnumerable items) { - + } - + /// /// Validate and refresh the People sub-set of the IBN. /// The items are stored in the db but not loaded into memory until actually requested by an operation. @@ -1013,7 +1020,7 @@ namespace MediaBrowser.Server.Implementations.Library public Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) { // Ensure the location is available. - _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath); + _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath); return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress); } @@ -1280,9 +1287,29 @@ namespace MediaBrowser.Server.Implementations.Library return ItemRepository.GetItemIdsList(query); } - public IEnumerable GetItems(InternalItemsQuery query, User user) + public IEnumerable GetItems(InternalItemsQuery query, User user, IEnumerable parentIds) { - return GetItemIds(query).Select(GetItemById).Where(i => i.IsVisibleStandalone(user)); + var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList(); + + query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray(); + + var items = GetItemIds(query).Select(GetItemById); + + if (user != null) + { + items = items.Where(i => i.IsVisibleStandalone(user)); + } + + return items; + } + + public QueryResult GetItemsResult(InternalItemsQuery query, User user, IEnumerable parentIds) + { + var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList(); + + query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray(); + + return GetItems(query); } /// @@ -1700,7 +1727,7 @@ namespace MediaBrowser.Server.Implementations.Library if (item == null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase)) { - _fileSystem.CreateDirectory(path); + _fileSystem.CreateDirectory(path); item = new UserView { @@ -1719,8 +1746,7 @@ namespace MediaBrowser.Server.Implementations.Library if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase)) { - item.ViewType = viewType; - await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); + refresh = true; } if (!refresh) @@ -1793,7 +1819,7 @@ namespace MediaBrowser.Server.Implementations.Library if (item == null) { - _fileSystem.CreateDirectory(path); + _fileSystem.CreateDirectory(path); item = new UserView { @@ -1917,7 +1943,7 @@ namespace MediaBrowser.Server.Implementations.Library return item; } - + public async Task GetNamedView(string name, string parentId, string viewType, @@ -1946,7 +1972,7 @@ namespace MediaBrowser.Server.Implementations.Library if (item == null) { - _fileSystem.CreateDirectory(path); + _fileSystem.CreateDirectory(path); item = new UserView { @@ -2379,7 +2405,7 @@ namespace MediaBrowser.Server.Implementations.Library return ItemRepository.UpdatePeople(item.Id, people); } - private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1,1); + private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1, 1); public async Task ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex) { _logger.Debug("ConvertImageToLocal item {0}", item.Id); diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs index aee101ef4..3d2286e1f 100644 --- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs @@ -80,15 +80,13 @@ namespace MediaBrowser.Server.Implementations.Library { var genreList = genres.ToList(); - var inputItems = _libraryManager.GetItems(new InternalItemsQuery + var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(Audio).Name }, - Genres = genreList.ToArray(), + Genres = genreList.ToArray() - User = user - - }).Items; + }, user, new string[] { }); var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 108a891e0..82e0f92e6 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -156,18 +156,18 @@ namespace MediaBrowser.Server.Implementations.Library } AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name); - + var mediaItems = _libraryManager.GetItems(new InternalItemsQuery(user) { NameContains = searchTerm, ExcludeItemTypes = excludeItemTypes.ToArray(), IncludeItemTypes = includeItemTypes.ToArray(), - Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 3) : null), + Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 2) : null), - }).Items; + }, user, new string[] { }); // Add search hints based on item name - hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && IsVisible(i, user)).Select(item => + hints.AddRange(mediaItems.Where(IncludeInSearch).Select(item => { var index = GetIndex(item.Name, searchTerm, terms); @@ -183,25 +183,6 @@ namespace MediaBrowser.Server.Implementations.Library return Task.FromResult(returnValue); } - private bool IsVisible(BaseItem item, User user) - { - if (user == null) - { - return true; - } - - if (item is IItemByName) - { - var dual = item as IHasDualAccess; - if (dual == null || dual.IsAccessedByName) - { - return true; - } - } - - return item.IsVisibleStandalone(user); - } - private bool IncludeInSearch(BaseItem item) { var episode = item as Episode; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d7c9edae3..1b8966aa0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1357,7 +1357,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv await RefreshRecordings(cancellationToken).ConfigureAwait(false); - var internalQuery = new InternalItemsQuery + var internalQuery = new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name } }; @@ -1367,8 +1367,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv internalQuery.ChannelIds = new[] { query.ChannelId }; } - var queryResult = _libraryManager.GetItems(internalQuery); - IEnumerable recordings = queryResult.Items.Cast(); + var queryResult = _libraryManager.GetItems(internalQuery, user, new string[]{}); + IEnumerable recordings = queryResult.Cast(); if (!string.IsNullOrEmpty(query.Id)) { @@ -1405,12 +1405,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv .Where(i => _tvDtoService.GetInternalSeriesTimerId(i.ServiceName, i.SeriesTimerId) == guid); } - if (user != null) - { - var currentUser = user; - recordings = recordings.Where(i => i.IsParentalAllowed(currentUser)); - } - recordings = recordings.OrderByDescending(i => i.StartDate); var entityList = recordings.ToList(); @@ -1771,19 +1765,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv var now = DateTime.UtcNow; - var programs = _libraryManager.GetItems(new InternalItemsQuery + var programs = _libraryManager.GetItems(new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, ChannelIds = new[] { id }, MaxStartDate = now, MinEndDate = now, - Limit = 1 + Limit = 1, + SortBy = new[] { "StartDate"} - }).Items.Cast(); + }, user, new string[]{}).Cast(); - var currentProgram = programs - .OrderBy(i => i.StartDate) - .FirstOrDefault(); + var currentProgram = programs.FirstOrDefault(); var dto = _tvDtoService.GetChannelInfoDto(channel, new DtoOptions(), currentProgram, user); @@ -1796,19 +1789,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv var now = DateTime.UtcNow; - var programs = _libraryManager.GetItems(new InternalItemsQuery + var programs = _libraryManager.GetItems(new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, ChannelIds = new[] { channel.Id.ToString("N") }, MaxStartDate = now, MinEndDate = now, - Limit = 1 + Limit = 1, + SortBy = new[] { "StartDate" } - }).Items.Cast(); + }, user, new string []{}).Cast(); - var currentProgram = programs - .OrderBy(i => i.StartDate) - .FirstOrDefault(); + var currentProgram = programs.FirstOrDefault(); if (currentProgram != null) { diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs index 60b8c00bd..74688d9b1 100644 --- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs @@ -24,6 +24,8 @@ namespace MediaBrowser.Server.Implementations.Persistence private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; + public const int MigrationVersion = 1; + public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem) { _libraryManager = libraryManager; @@ -121,6 +123,12 @@ namespace MediaBrowser.Server.Implementations.Persistence _config.SaveConfiguration(); } + if (_config.Configuration.MigrationVersion < MigrationVersion) + { + _config.Configuration.MigrationVersion = MigrationVersion; + _config.SaveConfiguration(); + } + progress.Report(100); } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 167c96185..20d890d02 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -77,7 +77,10 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteStreamsCommand; private IDbCommand _saveStreamCommand; - private const int LatestSchemaVersion = 17; + private IDbCommand _deleteAncestorsCommand; + private IDbCommand _saveAncestorCommand; + + private const int LatestSchemaVersion = 18; /// /// Initializes a new instance of the class. @@ -126,9 +129,13 @@ namespace MediaBrowser.Server.Implementations.Persistence string[] queries = { - "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB)", + "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID)", "create index if not exists idx_TypedBaseItems on TypedBaseItems(guid)", + "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)", + "create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, PRIMARY KEY (ItemId, AncestorId))", + "create index if not exists idx_AncestorIds on AncestorIds(ItemId,AncestorId)", + "create table if not exists ChildrenIds (ParentId GUID, ItemId GUID, PRIMARY KEY (ParentId, ItemId))", "create index if not exists idx_ChildrenIds on ChildrenIds(ParentId,ItemId)", @@ -205,6 +212,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "Studios", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "Audio", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "ExternalServiceId", "Text"); + _connection.AddColumn(_logger, "TypedBaseItems", "Tags", "Text"); PrepareStatements(); @@ -429,7 +437,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "LockedFields", "Studios", "Audio", - "ExternalServiceId" + "ExternalServiceId", + "Tags" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -472,6 +481,16 @@ namespace MediaBrowser.Server.Implementations.Persistence _savePersonCommand.Parameters.Add(_savePersonCommand, "@PersonType"); _savePersonCommand.Parameters.Add(_savePersonCommand, "@SortOrder"); _savePersonCommand.Parameters.Add(_savePersonCommand, "@ListOrder"); + + // Ancestors + _deleteAncestorsCommand = _connection.CreateCommand(); + _deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id"; + _deleteAncestorsCommand.Parameters.Add(_deleteAncestorsCommand, "@Id"); + + _saveAncestorCommand = _connection.CreateCommand(); + _saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId) values (@ItemId, @AncestorId)"; + _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@ItemId"); + _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorId"); // Chapters _deleteChaptersCommand = _connection.CreateCommand(); @@ -682,9 +701,16 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = null; } + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); + + if (item.SupportsAncestors) + { + UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction); + } } transaction.Commit(); @@ -765,22 +791,32 @@ namespace MediaBrowser.Server.Implementations.Persistence return null; } - BaseItem item; + BaseItem item = null; using (var stream = reader.GetMemoryStream(1)) { try { item = _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem; - - if (item == null) - { - return null; - } } catch (SerializationException ex) { _logger.ErrorException("Error deserializing item", ex); + } + + if (item == null) + { + try + { + item = Activator.CreateInstance(type) as BaseItem; + } + catch + { + } + } + + if (item == null) + { return null; } } @@ -1328,6 +1364,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId; + //_logger.Debug(cmd.CommandText); + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { while (reader.Read()) @@ -1373,6 +1411,50 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + public IEnumerable GetItemList(InternalItemsQuery query) + { + if (query == null) + { + throw new ArgumentNullException("query"); + } + + CheckDisposed(); + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems"; + + var whereClauses = GetWhereClauses(query, cmd, true); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + } + + //_logger.Debug(cmd.CommandText); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) + { + yield return item; + } + } + } + } + } + public QueryResult GetItems(InternalItemsQuery query) { if (query == null) @@ -1453,6 +1535,12 @@ namespace MediaBrowser.Server.Implementations.Persistence private string MapOrderByField(string name) { + if (string.Equals(name, "airtime", StringComparison.OrdinalIgnoreCase)) + { + // TODO + return "SortName"; + } + return name; } @@ -1813,6 +1901,17 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + if (query.AncestorIds.Length == 1) + { + whereClauses.Add("Guid in (select itemId from AncestorIds where AncestorId=@AncestorId)"); + cmd.Parameters.Add(cmd, "@AncestorId", DbType.Guid).Value = new Guid(query.AncestorIds[0]); + } + if (query.AncestorIds.Length > 1) + { + var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i + "'").ToArray()); + whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause)); + } + if (addPaging) { if (query.StartIndex.HasValue && query.StartIndex.Value > 0) @@ -1847,6 +1946,7 @@ namespace MediaBrowser.Server.Implementations.Persistence typeof(Movie), typeof(BoxSet), typeof(Episode), + typeof(ChannelVideoItem), typeof(Season), typeof(Series), typeof(Book), @@ -1933,6 +2033,11 @@ namespace MediaBrowser.Server.Implementations.Persistence _deleteStreamsCommand.GetParameter(0).Value = id; _deleteStreamsCommand.Transaction = transaction; _deleteStreamsCommand.ExecuteNonQuery(); + + // Delete ancestors + _deleteAncestorsCommand.GetParameter(0).Value = id; + _deleteAncestorsCommand.Transaction = transaction; + _deleteAncestorsCommand.ExecuteNonQuery(); // Delete the item _deleteItemCommand.GetParameter(0).Value = id; @@ -2167,6 +2272,37 @@ namespace MediaBrowser.Server.Implementations.Persistence return whereClauses; } + private void UpdateAncestors(Guid itemId, List ancestorIds, IDbTransaction transaction) + { + if (itemId == Guid.Empty) + { + throw new ArgumentNullException("itemId"); + } + + if (ancestorIds == null) + { + throw new ArgumentNullException("ancestorIds"); + } + + CheckDisposed(); + + // First delete + _deleteAncestorsCommand.GetParameter(0).Value = itemId; + _deleteAncestorsCommand.Transaction = transaction; + + _deleteAncestorsCommand.ExecuteNonQuery(); + + foreach (var ancestorId in ancestorIds) + { + _saveAncestorCommand.GetParameter(0).Value = itemId; + _saveAncestorCommand.GetParameter(1).Value = ancestorId; + + _saveAncestorCommand.Transaction = transaction; + + _saveAncestorCommand.ExecuteNonQuery(); + } + } + public async Task UpdatePeople(Guid itemId, List people) { if (itemId == Guid.Empty) diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs index d9b3ed755..048e2bf8d 100644 --- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs +++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs @@ -264,6 +264,7 @@ namespace MediaBrowser.Server.Implementations.Playlists public Folder GetPlaylistsFolder(string userId) { return _libraryManager.RootFolder.Children.OfType() + .FirstOrDefault() ?? _libraryManager.GetUserRootFolder().Children.OfType() .FirstOrDefault(); } } diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs index 93ebd0a1c..d913360f0 100644 --- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs +++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs @@ -36,22 +36,12 @@ namespace MediaBrowser.Server.Implementations.TV ? new string[] { } : new[] { request.ParentId }; - IEnumerable items; - - if (parentIds.Length == 0) + var items = _libraryManager.GetItems(new InternalItemsQuery(user) { - items = _libraryManager.GetItems(new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(Series).Name }, - SortOrder = SortOrder.Ascending + IncludeItemTypes = new[] { typeof(Series).Name }, + SortOrder = SortOrder.Ascending - }, user).Cast(); - } - else - { - items = GetAllLibraryItems(user, parentIds, i => i is Series) - .Cast(); - } + }, user, parentIds).Cast(); // Avoid implicitly captured closure var episodes = GetNextUpEpisodes(request, user, items); @@ -68,9 +58,12 @@ namespace MediaBrowser.Server.Implementations.TV throw new ArgumentException("User not found"); } - var items = parentsFolders - .SelectMany(i => i.GetRecursiveChildren(user, s => s is Series)) - .Cast(); + var items = _libraryManager.GetItems(new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Series).Name }, + SortOrder = SortOrder.Ascending + + }, user, parentsFolders.Select(i => i.Id.ToString("N"))).Cast(); // Avoid implicitly captured closure var episodes = GetNextUpEpisodes(request, user, items); @@ -78,27 +71,6 @@ namespace MediaBrowser.Server.Implementations.TV return GetResult(episodes, null, request); } - private IEnumerable GetAllLibraryItems(User user, string[] parentIds, Func filter) - { - if (parentIds.Length > 0) - { - return parentIds.SelectMany(i => - { - var folder = (Folder)_libraryManager.GetItemById(new Guid(i)); - - return folder.GetRecursiveChildren(user, filter); - - }); - } - - if (user == null) - { - throw new ArgumentException("User not found"); - } - - return user.RootFolder.GetRecursiveChildren(user, filter); - } - public IEnumerable GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable series) { // Avoid implicitly captured closure diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 97a457a1b..694bd1b79 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -363,7 +363,7 @@ namespace MediaBrowser.Server.Startup.Common { var migrations = new List { - new Release5767(ServerConfigurationManager, TaskManager) + new DbMigration(ServerConfigurationManager, TaskManager) }; foreach (var task in migrations) diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj index 13b782e40..b58646a2e 100644 --- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj +++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj @@ -72,7 +72,7 @@ - + diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs new file mode 100644 index 000000000..de7cba68d --- /dev/null +++ b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Server.Implementations.Persistence; + +namespace MediaBrowser.Server.Startup.Common.Migrations +{ + public class DbMigration : IVersionMigration + { + private readonly IServerConfigurationManager _config; + private readonly ITaskManager _taskManager; + + public DbMigration(IServerConfigurationManager config, ITaskManager taskManager) + { + _config = config; + _taskManager = taskManager; + } + + public void Run() + { + if (_config.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion) + { + return; + } + + Task.Run(async () => + { + await Task.Delay(2000).ConfigureAwait(false); + + _taskManager.QueueScheduledTask(); + }); + } + } +} diff --git a/MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs b/MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs deleted file mode 100644 index 168230b87..000000000 --- a/MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Server.Implementations.LiveTv; -using MediaBrowser.Server.Implementations.Persistence; -using MediaBrowser.Server.Implementations.ScheduledTasks; - -namespace MediaBrowser.Server.Startup.Common.Migrations -{ - public class Release5767 : IVersionMigration - { - private readonly IServerConfigurationManager _config; - private readonly ITaskManager _taskManager; - - public Release5767(IServerConfigurationManager config, ITaskManager taskManager) - { - _config = config; - _taskManager = taskManager; - } - - public async void Run() - { - var name = "5767.1"; - - if (_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase)) - { - return; - } - - Task.Run(async () => - { - await Task.Delay(3000).ConfigureAwait(false); - - _taskManager.QueueScheduledTask(); - }); - - // Wait a few minutes before marking this as done. Make sure the server doesn't get restarted. - await Task.Delay(300000).ConfigureAwait(false); - - var list = _config.Configuration.Migrations.ToList(); - list.Add(name); - _config.Configuration.Migrations = list.ToArray(); - _config.SaveConfiguration(); - } - } -} From 67dc2a0bf98cf02c1ff07608c0f10b4e0ead6f58 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 29 Oct 2015 15:01:04 -0400 Subject: [PATCH 008/527] update item queries --- MediaBrowser.Api/TvShowsService.cs | 2 +- .../Entities/InternalItemsQuery.cs | 5 +- .../Library/ILibraryManager.cs | 2 +- .../LiveTv/LiveTvAudioRecording.cs | 5 + .../LiveTv/LiveTvVideoRecording.cs | 5 + .../ContentDirectory/ControlHandler.cs | 2 +- .../Library/LibraryManager.cs | 13 ++- .../Library/UserViewManager.cs | 95 ++++--------------- .../Persistence/CleanDatabaseScheduledTask.cs | 2 +- .../Persistence/SqliteItemRepository.cs | 28 +++++- 10 files changed, 71 insertions(+), 88 deletions(-) diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index ead232888..2dad9533f 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -286,7 +286,7 @@ namespace MediaBrowser.Api StartIndex = request.StartIndex, Limit = request.Limit - }, user, parentIds); + }, parentIds); var options = GetDtoOptions(request); diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 038a46316..5c60e19f0 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -103,7 +103,9 @@ namespace MediaBrowser.Controller.Entities public Guid? ParentId { get; set; } public string[] AncestorIds { get; set; } - + + public LocationType[] ExcludeLocationTypes { get; set; } + public InternalItemsQuery() { Tags = new string[] { }; @@ -123,6 +125,7 @@ namespace MediaBrowser.Controller.Entities ChannelIds = new string[] { }; ItemIds = new string[] { }; AncestorIds = new string[] { }; + ExcludeLocationTypes = new LocationType[] { }; } public InternalItemsQuery(User user) diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index c24cf9bce..9e434541a 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -560,6 +560,6 @@ namespace MediaBrowser.Controller.Library /// The user. /// The parent ids. /// QueryResult<BaseItem>. - QueryResult GetItemsResult(InternalItemsQuery query, User user, IEnumerable parentIds); + QueryResult GetItemsResult(InternalItemsQuery query, IEnumerable parentIds); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs index dd6a53d45..f1634a8a5 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs @@ -139,5 +139,10 @@ namespace MediaBrowser.Controller.LiveTv return list; } + + public override bool IsVisibleStandalone(User user) + { + return IsVisible(user); + } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index de8764e6d..96a465201 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -149,5 +149,10 @@ namespace MediaBrowser.Controller.LiveTv return list; } + + public override bool IsVisibleStandalone(User user) + { + return IsVisible(user); + } } } diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index ba50f2f32..c70014cb6 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -489,7 +489,7 @@ namespace MediaBrowser.Dlna.ContentDirectory Limit = limit, StartIndex = startIndex - }, user, new string[] { }); + }, new string[] { }); var serverItems = itemsResult.Items.Select(i => new ServerItem { diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 522038b46..f24edf086 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1297,21 +1297,32 @@ namespace MediaBrowser.Server.Implementations.Library if (user != null) { + AddUserToQuery(query, user); items = items.Where(i => i.IsVisibleStandalone(user)); } return items; } - public QueryResult GetItemsResult(InternalItemsQuery query, User user, IEnumerable parentIds) + public QueryResult GetItemsResult(InternalItemsQuery query, IEnumerable parentIds) { var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList(); query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray(); + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + return GetItems(query); } + private void AddUserToQuery(InternalItemsQuery query, User user) + { + + } + /// /// Gets the intros. /// diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index c2938475c..177d82b22 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -245,16 +245,8 @@ namespace MediaBrowser.Server.Implementations.Library var currentUser = user; - Func filter = i => + var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes).Where(i => { - if (includeTypes.Length > 0) - { - if (!includeTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase)) - { - return false; - } - } - if (request.IsPlayed.HasValue) { var val = request.IsPlayed.Value; @@ -264,29 +256,12 @@ namespace MediaBrowser.Server.Implementations.Library } } - return i.LocationType != LocationType.Virtual && !i.IsFolder; - }; - - // Avoid implicitly captured closure - var libraryItems = string.IsNullOrEmpty(request.ParentId) && user != null ? - GetItemsConfiguredForLatest(user, filter) : - GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, filter); - - libraryItems = libraryItems.OrderByDescending(i => i.DateCreated); - - if (request.IsPlayed.HasValue) - { - var takeLimit = (request.Limit ?? 20) * 20; - libraryItems = libraryItems.Take(takeLimit); - } - - // Avoid implicitly captured closure - var items = libraryItems - .ToList(); + return true; + }); var list = new List>>(); - foreach (var item in items) + foreach (var item in libraryItems) { // Only grab the index container for media var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer; @@ -318,59 +293,23 @@ namespace MediaBrowser.Server.Implementations.Library return list; } - protected IList GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func filter) + private IEnumerable GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes) { - if (!string.IsNullOrEmpty(parentId)) + var parentIds = string.IsNullOrEmpty(parentId) + ? new string[] { } + : new[] { parentId }; + + return _libraryManager.GetItems(new InternalItemsQuery(user) { - var folder = (Folder)libraryManager.GetItemById(new Guid(parentId)); + IncludeItemTypes = includeItemTypes, + SortOrder = SortOrder.Descending, + SortBy = new[] { ItemSortBy.DateCreated }, + IsFolder = false, + ExcludeItemTypes = new[] { "ChannelItem", "Recording" }, + ExcludeLocationTypes = new[] { LocationType.Virtual } - if (!string.IsNullOrWhiteSpace(userId)) - { - var user = userManager.GetUserById(userId); + }, user, parentIds); - 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 user - .RootFolder - .GetRecursiveChildren(user, filter) - .ToList(); - } - - return libraryManager - .RootFolder - .GetRecursiveChildren(filter); - } - - private IEnumerable GetItemsConfiguredForLatest(User user, Func filter) - { - // Avoid implicitly captured closure - var currentUser = user; - - return user.RootFolder.GetChildren(user, true) - .OfType() - .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N"))) - .SelectMany(i => i.GetRecursiveChildren(currentUser, filter)) - .DistinctBy(i => i.Id); } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs index 74688d9b1..aef2157c3 100644 --- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; - public const int MigrationVersion = 1; + public const int MigrationVersion = 2; public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem) { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 20d890d02..4d86330e5 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -80,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteAncestorsCommand; private IDbCommand _saveAncestorCommand; - private const int LatestSchemaVersion = 18; + private const int LatestSchemaVersion = 19; /// /// Initializes a new instance of the class. @@ -213,6 +213,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "Audio", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "ExternalServiceId", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "Tags", "Text"); + _connection.AddColumn(_logger, "TypedBaseItems", "IsFolder", "BIT"); PrepareStatements(); @@ -438,7 +439,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "Studios", "Audio", "ExternalServiceId", - "Tags" + "Tags", + "IsFolder" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -702,7 +704,8 @@ namespace MediaBrowser.Server.Implementations.Persistence } _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); - + _saveItemCommand.GetParameter(index++).Value = item.IsFolder; + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -1576,7 +1579,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _logger.Debug(cmd.CommandText); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { while (reader.Read()) { @@ -1760,6 +1763,11 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("IsSports=@IsSports"); cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports; } + if (query.IsFolder.HasValue) + { + whereClauses.Add("IsFolder=@IsFolder"); + cmd.Parameters.Add(cmd, "@IsFolder", DbType.Boolean).Value = query.IsFolder; + } var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); if (includeTypes.Length == 1) @@ -1911,6 +1919,17 @@ namespace MediaBrowser.Server.Implementations.Persistence var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i + "'").ToArray()); whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause)); } + if (query.ExcludeLocationTypes.Length == 1) + { + whereClauses.Add("LocationType<>@LocationType"); + cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.ExcludeLocationTypes[0].ToString(); + } + if (query.ExcludeLocationTypes.Length > 1) + { + var val = string.Join(",", query.ExcludeLocationTypes.Select(i => "'" + i + "'").ToArray()); + + whereClauses.Add("LocationType not in (" + val + ")"); + } if (addPaging) { @@ -1976,6 +1995,7 @@ namespace MediaBrowser.Server.Implementations.Persistence dict[t.Name] = new[] { t.FullName }; } + dict["ChannelItem"] = new[] { typeof(ChannelVideoItem).FullName, typeof(ChannelAudioItem).FullName, typeof(ChannelFolderItem).FullName }; dict["Recording"] = new[] { typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName }; dict["Program"] = new[] { typeof(LiveTvProgram).FullName }; dict["TvChannel"] = new[] { typeof(LiveTvChannel).FullName }; From 50f6ee1039cf0f51aa64e5f55949f0eaa41e44d3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 29 Oct 2015 19:23:43 -0400 Subject: [PATCH 009/527] update polymer components --- .../LiveTv/LiveTvManager.cs | 14 +++++++------- MediaBrowser.sln | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 7244a3c88..f872817cf 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -666,7 +666,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { item.SetImagePath(ImageType.Primary, info.ImageUrl); } - + if (isNew) { await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); @@ -831,7 +831,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); - + var internalQuery = new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, @@ -890,7 +890,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken) { var user = _userManager.GetUserById(query.UserId); - + var internalQuery = new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, @@ -1378,7 +1378,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv internalQuery.ChannelIds = new[] { query.ChannelId }; } - var queryResult = _libraryManager.GetItems(internalQuery, user, new string[]{}); + var queryResult = _libraryManager.GetItems(internalQuery, user, new string[] { }); IEnumerable recordings = queryResult.Cast(); if (!string.IsNullOrEmpty(query.Id)) @@ -1783,9 +1783,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv MaxStartDate = now, MinEndDate = now, Limit = 1, - SortBy = new[] { "StartDate"} + SortBy = new[] { "StartDate" } - }, user, new string[]{}).Cast(); + }, user, new string[] { }).Cast(); var currentProgram = programs.FirstOrDefault(); @@ -1809,7 +1809,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv Limit = 1, SortBy = new[] { "StartDate" } - }, user, new string []{}).Cast(); + }, user, new string[] { }).Cast(); var currentProgram = programs.FirstOrDefault(); diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 3fc5e3f33..0dadf9136 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Performance2.psess = Performance2.psess Performance3.psess = Performance3.psess Performance4.psess = Performance4.psess + Performance5.psess = Performance5.psess EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}" @@ -543,4 +544,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal From 0ac0d6b87858f0d0d8cc3b891b9f295bb8a143d7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Oct 2015 11:23:06 -0400 Subject: [PATCH 010/527] update special folders --- .../Devices/CameraUploadsFolder.cs | 35 ++++++++++--------- .../Playlists/ManualPlaylistsFolder.cs | 5 --- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs index 6d7265972..62069736f 100644 --- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs +++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs @@ -21,22 +21,8 @@ namespace MediaBrowser.Server.Implementations.Devices { return false; } - - return GetChildren(user, true).Any() && - base.IsVisible(user); - } - public override bool IsHidden - { - get - { - return base.IsHidden || !Children.Any(); - } - } - - public override bool IsHiddenFromUser(User user) - { - return false; + return base.IsVisible(user) && HasChildren(); } public override string CollectionType @@ -48,6 +34,23 @@ namespace MediaBrowser.Server.Implementations.Devices { return typeof(CollectionFolder).Name; } + + private bool? _hasChildren; + private bool HasChildren() + { + if (!_hasChildren.HasValue) + { + _hasChildren = LibraryManager.GetItemIds(new InternalItemsQuery { ParentId = Id }).Count > 0; + } + + return _hasChildren.Value; + } + + protected override System.Threading.Tasks.Task ValidateChildrenInternal(IProgress progress, System.Threading.CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, Controller.Providers.MetadataRefreshOptions refreshOptions, Controller.Providers.IDirectoryService directoryService) + { + _hasChildren = null; + return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); + } } public class CameraUploadsDynamicFolder : IVirtualFolderCreator @@ -65,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.Devices { var path = Path.Combine(_appPaths.DataPath, "camerauploads"); - _fileSystem.CreateDirectory(path); + _fileSystem.CreateDirectory(path); return new CameraUploadsFolder { diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index 4d3e091b1..fbf514423 100644 --- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -34,11 +34,6 @@ namespace MediaBrowser.Server.Implementations.Playlists } } - public override bool IsHiddenFromUser(User user) - { - return false; - } - public override string CollectionType { get { return Model.Entities.CollectionType.Playlists; } From 3ef452decb19f3fd35fa1feaed0b4070748e36e0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Oct 2015 11:25:25 -0400 Subject: [PATCH 011/527] update collections folder --- .../Collections/ManualCollectionsFolder.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs index d62918d56..8133fb3ef 100644 --- a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs +++ b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs @@ -11,11 +11,6 @@ namespace MediaBrowser.Server.Implementations.Collections DisplayMediaType = "CollectionFolder"; } - public override bool IsVisible(User user) - { - return base.IsVisible(user) && GetChildren(user, false).Any(); - } - public override bool IsHidden { get From bed740668c4d9e7de1473925c7d6a1e33346bc22 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Oct 2015 12:40:47 -0400 Subject: [PATCH 012/527] update special folders --- MediaBrowser.Controller/Entities/AggregateFolder.cs | 2 +- MediaBrowser.Controller/Entities/UserRootFolder.cs | 7 ++++++- .../Library/LibraryManager.cs | 12 ++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 10372eb49..14f8c1617 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -128,7 +128,7 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { - return base.GetNonCachedChildren(directoryService); + return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); } /// diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index a78beb645..e6f322595 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -55,13 +55,18 @@ namespace MediaBrowser.Controller.Entities } } + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) + { + return base.GetEligibleChildrenForRecursiveChildren(user).Concat(LibraryManager.RootFolder.VirtualChildren); + } + /// /// Get the children of this folder from the actual file system /// /// IEnumerable{BaseItem}. protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { - return base.GetNonCachedChildren(directoryService).Concat(LibraryManager.RootFolder.VirtualChildren); + return base.GetNonCachedChildren(directoryService); } public override bool BeforeMetadataRefresh() diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index f24edf086..b5f1c2132 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -727,12 +727,12 @@ namespace MediaBrowser.Server.Implementations.Library folder = dbItem; } - //if (folder.ParentId != rootFolder.Id) - //{ - // folder.ParentId = rootFolder.Id; - // var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); - // Task.WaitAll(task); - //} + if (folder.ParentId != rootFolder.Id) + { + folder.ParentId = rootFolder.Id; + var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); + Task.WaitAll(task); + } rootFolder.AddVirtualChild(folder); From 9abdf5a0450dbd8925b9360d59c4b27d6c0d5c8b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Oct 2015 12:58:36 -0400 Subject: [PATCH 013/527] update components --- .../MediaBrowser.Controller.csproj | 1 - .../Net/PaymentRequiredException.cs | 15 --------------- .../HttpServer/HttpListenerHost.cs | 1 + 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 MediaBrowser.Controller/Net/PaymentRequiredException.cs diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 600674114..bcf4de2a2 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -248,7 +248,6 @@ - diff --git a/MediaBrowser.Controller/Net/PaymentRequiredException.cs b/MediaBrowser.Controller/Net/PaymentRequiredException.cs deleted file mode 100644 index e09fe092e..000000000 --- a/MediaBrowser.Controller/Net/PaymentRequiredException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Net -{ - /// - /// Corresponds to a 402 response code - /// - public class PaymentRequiredException : Exception - { - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 6abfa0674..e8ed91615 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -19,6 +19,7 @@ using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Security; namespace MediaBrowser.Server.Implementations.HttpServer { From 78ebc966003f9b6114cd3bd9969d719a9e88b698 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Oct 2015 13:04:32 -0400 Subject: [PATCH 014/527] update version --- SharedVersion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 5aa872085..319a682ef 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -[assembly: AssemblyVersion("3.0.*")] -//[assembly: AssemblyVersion("3.0.5768.7")] +//[assembly: AssemblyVersion("3.0.*")] +[assembly: AssemblyVersion("3.0.5781.0")] From c4aa744605d078f8ea5aa801e452df539cab7613 Mon Sep 17 00:00:00 2001 From: softworkz Date: Sun, 1 Nov 2015 19:24:45 +0100 Subject: [PATCH 015/527] Fix exception when episode title is null Sometimes TheTVDb does not have episode. This caused an exception in EpisodeFileOrganizer --- .../FileOrganization/EpisodeFileOrganizer.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index e36813d11..ef226a934 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -504,7 +504,15 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options, int? maxLength) { seriesName = _fileSystem.GetValidFilename(seriesName).Trim(); - episodeTitle = _fileSystem.GetValidFilename(episodeTitle).Trim(); + + if (episodeTitle == null) + { + episodeTitle = string.Empty; + } + else + { + episodeTitle = _fileSystem.GetValidFilename(episodeTitle).Trim(); + } var sourceExtension = (Path.GetExtension(sourcePath) ?? string.Empty).TrimStart('.'); From fbf8d27637a0b3804cf31665425be372420097a5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 2 Nov 2015 12:25:01 -0500 Subject: [PATCH 016/527] update channel db --- .../UserLibrary/UserViewsService.cs | 5 +- MediaBrowser.Controller/Entities/BaseItem.cs | 17 ++ MediaBrowser.Controller/Entities/Folder.cs | 41 ++--- MediaBrowser.Controller/Entities/UserView.cs | 12 +- .../Entities/UserViewBuilder.cs | 8 +- .../Persistence/IItemRepository.cs | 7 + .../MediaBrowser.LocalMetadata.csproj | 3 - .../Parsers/GameXmlParser.cs | 20 --- .../Savers/EpisodeXmlSaver.cs | 166 ------------------ .../Savers/GameXmlSaver.cs | 14 -- .../Savers/MovieXmlSaver.cs | 147 ---------------- .../Savers/SeriesXmlSaver.cs | 154 ---------------- .../Configuration/UserConfiguration.cs | 2 +- MediaBrowser.Model/Dlna/StreamBuilder.cs | 9 + MediaBrowser.Model/Dto/BaseItemDto.cs | 6 - MediaBrowser.Model/Dto/IItemDto.cs | 6 - MediaBrowser.Model/Dto/UserDto.cs | 6 - .../Entities/MetadataProviders.cs | 2 - MediaBrowser.Model/LiveTv/ChannelInfoDto.cs | 6 - MediaBrowser.Model/Querying/ItemFields.cs | 5 - .../Channels/ChannelManager.cs | 17 +- .../Dto/DtoService.cs | 21 +-- .../Library/LibraryManager.cs | 16 +- .../Library/MediaSourceManager.cs | 2 +- .../Library/SearchEngine.cs | 2 +- .../Library/UserViewManager.cs | 44 +++-- .../Persistence/CleanDatabaseScheduledTask.cs | 4 +- .../Persistence/SqliteItemRepository.cs | 93 ++++++++-- .../Sync/SyncManager.cs | 1 - .../ApplicationHost.cs | 14 +- .../Migrations/DbMigration.cs | 14 +- SharedVersion.cs | 4 +- 32 files changed, 224 insertions(+), 644 deletions(-) delete mode 100644 MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs delete mode 100644 MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs delete mode 100644 MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 9d7c38d6f..6ba30a35e 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -78,6 +78,7 @@ namespace MediaBrowser.Api.UserLibrary var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false); var dtoOptions = GetDtoOptions(request); + dtoOptions.Fields = new List(); var user = _userManager.GetUserById(request.UserId); @@ -141,9 +142,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.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f14e09616..798f1b7bb 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1153,6 +1153,23 @@ namespace MediaBrowser.Controller.Entities } public int? GetParentalRatingValue() + { + var rating = CustomRating; + + if (string.IsNullOrWhiteSpace(rating)) + { + rating = OfficialRating; + } + + if (string.IsNullOrWhiteSpace(rating)) + { + return null; + } + + return LocalizationManager.GetRatingLevel(rating); + } + + public int? GetInheritedParentalRatingValue() { var rating = CustomRatingForComparison; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e08eda1ac..4b30e845b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -468,34 +468,25 @@ namespace MediaBrowser.Controller.Entities { BaseItem currentChild; - if (currentChildren.TryGetValue(child.Id, out currentChild)) + if (currentChildren.TryGetValue(child.Id, out currentChild) && IsValidFromResolver(currentChild, child)) { - if (IsValidFromResolver(currentChild, child)) + var currentChildLocationType = currentChild.LocationType; + if (currentChildLocationType != LocationType.Remote && + currentChildLocationType != LocationType.Virtual) { - var currentChildLocationType = currentChild.LocationType; - if (currentChildLocationType != LocationType.Remote && - currentChildLocationType != LocationType.Virtual) - { - currentChild.DateModified = child.DateModified; - } + currentChild.DateModified = child.DateModified; + } - await UpdateIsOffline(currentChild, false).ConfigureAwait(false); - validChildren.Add(currentChild); - } - else - { - child.SetParent(this); - newItems.Add(child); - validChildren.Add(child); - } - } - else - { - // Brand new item - needs to be added - child.SetParent(this); - newItems.Add(child); - validChildren.Add(child); + await UpdateIsOffline(currentChild, false).ConfigureAwait(false); + validChildren.Add(currentChild); + + continue; } + + // Brand new item - needs to be added + child.SetParent(this); + newItems.Add(child); + validChildren.Add(child); } // If any items were added or removed.... @@ -531,6 +522,8 @@ namespace MediaBrowser.Controller.Entities foreach (var item in actualRemovals) { + Logger.Debug("Removed item: " + item.Path); + item.SetParent(null); item.IsOffline = false; await LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 76188ce58..4e3b58778 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Threading.Tasks; +using System.Linq; namespace MediaBrowser.Controller.Entities { @@ -105,7 +106,9 @@ namespace MediaBrowser.Controller.Entities CollectionType.Photos, CollectionType.Playlists, CollectionType.BoxSets, - CollectionType.MusicVideos + CollectionType.MusicVideos, + CollectionType.Games, + CollectionType.Music }; var collectionFolder = folder as ICollectionFolder; @@ -136,6 +139,13 @@ namespace MediaBrowser.Controller.Entities return standaloneTypes.Contains(collectionFolder.CollectionType ?? string.Empty); } + public static bool IsEligibleForEnhancedView(string viewType) + { + var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music }; + + return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); + } + [IgnoreDataMember] public override bool SupportsPeople { diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index f5800ce81..ed81e2d73 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -120,26 +120,22 @@ namespace MediaBrowser.Controller.Entities return await GetLiveTvView(queryParent, user, query).ConfigureAwait(false); } + case CollectionType.Photos: case CollectionType.Books: case CollectionType.HomeVideos: + case CollectionType.Games: case CollectionType.MusicVideos: return GetResult(queryParent.GetChildren(user, true), queryParent, query); case CollectionType.Folders: return GetResult(user.RootFolder.GetChildren(user, true), queryParent, query); - case CollectionType.Games: - return await GetGameView(user, queryParent, query).ConfigureAwait(false); - case CollectionType.Playlists: return await GetPlaylistsView(queryParent, user, query).ConfigureAwait(false); case CollectionType.BoxSets: return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false); - case CollectionType.Photos: - return await GetPhotosView(queryParent, user, query).ConfigureAwait(false); - case CollectionType.TvShows: return await GetTvView(queryParent, user, query).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 0b1c9c3e0..533d66b95 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -183,6 +183,13 @@ namespace MediaBrowser.Controller.Persistence /// The query. /// List<BaseItem>. IEnumerable GetItemList(InternalItemsQuery query); + + /// + /// Updates the inherited values. + /// + /// The cancellation token. + /// Task. + Task UpdateInheritedValues(CancellationToken cancellationToken); } } diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index a74fe7e98..5ef8eaaa3 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -79,14 +79,11 @@ - - - diff --git a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs index b5a68c61f..4bfcae44f 100644 --- a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs @@ -62,26 +62,6 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } - case "NesBox": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - item.SetProviderId(MetadataProviders.NesBox, val); - } - break; - } - - case "NesBoxRom": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - item.SetProviderId(MetadataProviders.NesBoxRom, val); - } - break; - } - case "Players": { var val = reader.ReadElementContentAsString(); diff --git a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs deleted file mode 100644 index dc8a16cd8..000000000 --- a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs +++ /dev/null @@ -1,166 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; -using MediaBrowser.Common.IO; - -namespace MediaBrowser.LocalMetadata.Savers -{ - public class EpisodeXmlProvider : IMetadataFileSaver, IConfigurableProvider - { - private readonly IItemRepository _itemRepository; - - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private IFileSystem _fileSystem; - - public EpisodeXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _itemRepository = itemRepository; - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - /// - /// Determines whether [is enabled for] [the specified item]. - /// - /// The item. - /// Type of the update. - /// true if [is enabled for] [the specified item]; otherwise, false. - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) - { - if (!item.SupportsLocalMetadata) - { - return false; - } - - return item is Episode && updateType >= ItemUpdateType.MetadataDownload; - } - - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - public bool IsEnabled - { - get { return !_config.Configuration.DisableXmlSavers; } - } - - /// - /// Saves the specified item. - /// - /// The item. - /// The cancellation token. - /// Task. - public void Save(IHasMetadata item, CancellationToken cancellationToken) - { - var episode = (Episode)item; - - var builder = new StringBuilder(); - - builder.Append(""); - - if (!string.IsNullOrEmpty(item.Name)) - { - builder.Append("" + SecurityElement.Escape(episode.Name) + ""); - } - - if (episode.IndexNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.IndexNumber.Value.ToString(_usCulture)) + ""); - } - - if (episode.IndexNumberEnd.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.IndexNumberEnd.Value.ToString(_usCulture)) + ""); - } - - if (episode.AirsAfterSeasonNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.AirsAfterSeasonNumber.Value.ToString(_usCulture)) + ""); - } - if (episode.AirsBeforeEpisodeNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)) + ""); - } - if (episode.AirsBeforeSeasonNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.AirsBeforeSeasonNumber.Value.ToString(_usCulture)) + ""); - } - - if (episode.ParentIndexNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.ParentIndexNumber.Value.ToString(_usCulture)) + ""); - } - - if (episode.AbsoluteEpisodeNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.AbsoluteEpisodeNumber.Value.ToString(_usCulture)) + ""); - } - - if (episode.DvdEpisodeNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.DvdEpisodeNumber.Value.ToString(_usCulture)) + ""); - } - - if (episode.DvdSeasonNumber.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.DvdSeasonNumber.Value.ToString(_usCulture)) + ""); - } - - if (episode.PremiereDate.HasValue) - { - builder.Append("" + SecurityElement.Escape(episode.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + ""); - } - - XmlSaverHelpers.AddCommonNodes(episode, _libraryManager, builder); - XmlSaverHelpers.AddMediaInfo(episode, builder, _itemRepository); - - builder.Append(""); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List - { - "FirstAired", - "SeasonNumber", - "EpisodeNumber", - "EpisodeName", - "EpisodeNumberEnd", - "airsafter_season", - "airsbefore_episode", - "airsbefore_season", - "DVD_episodenumber", - "DVD_season", - "absolute_number" - - }, _config, _fileSystem); - } - - /// - /// Gets the save path. - /// - /// The item. - /// System.String. - public string GetSavePath(IHasMetadata item) - { - var filename = Path.ChangeExtension(Path.GetFileName(item.Path), ".xml"); - - return Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename); - } - } -} diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs index 89c274e12..53efc7811 100644 --- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs @@ -79,20 +79,6 @@ namespace MediaBrowser.LocalMetadata.Savers builder.Append("" + SecurityElement.Escape(game.GameSystem) + ""); } - var val = game.GetProviderId(MetadataProviders.NesBox); - - if (!string.IsNullOrEmpty(val)) - { - builder.Append("" + SecurityElement.Escape(val) + ""); - } - - val = game.GetProviderId(MetadataProviders.NesBoxRom); - - if (!string.IsNullOrEmpty(val)) - { - builder.Append("" + SecurityElement.Escape(val) + ""); - } - XmlSaverHelpers.AddCommonNodes(game, _libraryManager, builder); builder.Append(""); diff --git a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs deleted file mode 100644 index 2e3e7aaa1..000000000 --- a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs +++ /dev/null @@ -1,147 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using System.Collections.Generic; -using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; -using MediaBrowser.Common.IO; - -namespace MediaBrowser.LocalMetadata.Savers -{ - /// - /// Saves movie.xml for movies, trailers and music videos - /// - public class MovieXmlProvider : IMetadataFileSaver, IConfigurableProvider - { - private readonly IItemRepository _itemRepository; - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private IFileSystem _fileSystem; - - public MovieXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _itemRepository = itemRepository; - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - public bool IsEnabled - { - get { return !_config.Configuration.DisableXmlSavers; } - } - - /// - /// Determines whether [is enabled for] [the specified item]. - /// - /// The item. - /// Type of the update. - /// true if [is enabled for] [the specified item]; otherwise, false. - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) - { - if (!item.SupportsLocalMetadata) - { - return false; - } - - var video = item as Video; - - // Check parent for null to avoid running this against things like video backdrops - if (video != null && !(item is Episode) && !video.IsOwnedItem) - { - return updateType >= ItemUpdateType.MetadataDownload; - } - - return false; - } - - /// - /// Saves the specified item. - /// - /// The item. - /// The cancellation token. - /// Task. - public void Save(IHasMetadata item, CancellationToken cancellationToken) - { - var video = (Video)item; - - var builder = new StringBuilder(); - - builder.Append(""); - - XmlSaverHelpers.AddCommonNodes(video, _libraryManager, builder); - - var musicVideo = item as MusicVideo; - - if (musicVideo != null) - { - if (musicVideo.Artists.Count > 0) - { - builder.Append("<Artist>" + SecurityElement.Escape(string.Join(";", musicVideo.Artists.ToArray())) + "</Artist>"); - } - if (!string.IsNullOrEmpty(musicVideo.Album)) - { - builder.Append("<Album>" + SecurityElement.Escape(musicVideo.Album) + "</Album>"); - } - } - - var movie = item as Movie; - - if (movie != null) - { - if (!string.IsNullOrEmpty(movie.TmdbCollectionName)) - { - builder.Append("<TmdbCollectionName>" + SecurityElement.Escape(movie.TmdbCollectionName) + "</TmdbCollectionName>"); - } - } - - XmlSaverHelpers.AddMediaInfo(video, builder, _itemRepository); - - builder.Append(""); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List - { - // Deprecated. No longer saving in this field. - "IMDBrating", - - // Deprecated. No longer saving in this field. - "Description", - - "Artist", - "Album", - "TmdbCollectionName" - }, _config, _fileSystem); - } - - public string GetSavePath(IHasMetadata item) - { - return GetMovieSavePath((Video)item); - } - - public static string GetMovieSavePath(Video item) - { - if (item.IsInMixedFolder) - { - return Path.ChangeExtension(item.Path, ".xml"); - } - - return Path.Combine(item.ContainingFolderPath, "movie.xml"); - } - } -} diff --git a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs deleted file mode 100644 index 9806c4216..000000000 --- a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs +++ /dev/null @@ -1,154 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; -using MediaBrowser.Common.IO; - -namespace MediaBrowser.LocalMetadata.Savers -{ - public class SeriesXmlProvider : IMetadataFileSaver, IConfigurableProvider - { - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private IFileSystem _fileSystem; - - public SeriesXmlProvider(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - /// - /// Determines whether [is enabled for] [the specified item]. - /// - /// The item. - /// Type of the update. - /// true if [is enabled for] [the specified item]; otherwise, false. - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) - { - if (!item.SupportsLocalMetadata) - { - return false; - } - - return item is Series && updateType >= ItemUpdateType.MetadataDownload; - } - - public bool IsEnabled - { - get { return !_config.Configuration.DisableXmlSavers; } - } - - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Saves the specified item. - /// - /// The item. - /// The cancellation token. - /// Task. - public void Save(IHasMetadata item, CancellationToken cancellationToken) - { - var series = (Series)item; - - var builder = new StringBuilder(); - - builder.Append(""); - - var tvdb = item.GetProviderId(MetadataProviders.Tvdb); - - if (!string.IsNullOrEmpty(tvdb)) - { - builder.Append("" + SecurityElement.Escape(tvdb) + ""); - } - - if (series.Status.HasValue) - { - builder.Append("" + SecurityElement.Escape(series.Status.Value.ToString()) + ""); - } - - if (series.Studios.Count > 0) - { - builder.Append("" + SecurityElement.Escape(series.Studios[0]) + ""); - } - - if (!string.IsNullOrEmpty(series.AirTime)) - { - builder.Append("" + SecurityElement.Escape(series.AirTime) + ""); - } - - if (series.AirDays != null) - { - if (series.AirDays.Count == 7) - { - builder.Append("" + SecurityElement.Escape("Daily") + ""); - } - else if (series.AirDays.Count > 0) - { - builder.Append("" + SecurityElement.Escape(series.AirDays[0].ToString()) + ""); - } - } - - if (series.PremiereDate.HasValue) - { - builder.Append("" + SecurityElement.Escape(series.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + ""); - } - - if (series.AnimeSeriesIndex.HasValue) - { - builder.Append("" + SecurityElement.Escape(series.AnimeSeriesIndex.Value.ToString(UsCulture)) + ""); - } - - XmlSaverHelpers.AddCommonNodes(series, _libraryManager, builder); - - builder.Append(""); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List - { - "id", - "Status", - "Network", - "Airs_Time", - "Airs_DayOfWeek", - "FirstAired", - - // Don't preserve old series node - "Series", - - "SeriesName", - - // Deprecated. No longer saving in this field. - "AnimeSeriesIndex" - }, _config, _fileSystem); - } - - /// - /// Gets the save path. - /// - /// The item. - /// System.String. - public string GetSavePath(IHasMetadata item) - { - return Path.Combine(item.Path, "series.xml"); - } - } -} diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 349780958..278d22cfb 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -63,9 +63,9 @@ namespace MediaBrowser.Model.Configuration LatestItemsExcludes = new string[] { }; OrderedViews = new string[] { }; DisplayChannelsWithinViews = new string[] { }; + DisplayChannelsInline = true; PlainFolderViews = new string[] { }; - DisplayCollectionsView = true; IncludeTrailersInSuggestions = true; EnableCinemaMode = true; diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 1834e24fe..d451fe8a0 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -525,6 +525,15 @@ namespace MediaBrowser.Model.Dlna bool isEligibleForDirectPlay, bool isEligibleForDirectStream) { + if (videoStream == null) + { + _logger.Info("Profile: {0}, Cannot direct stream with no known video stream. Path: {1}", + profile.Name ?? "Unknown Profile", + mediaSource.Path ?? "Unknown path"); + + return null; + } + // See if it can be direct played DirectPlayProfile directPlay = null; foreach (DirectPlayProfile i in profile.DirectPlayProfiles) diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index ff67db1b6..91beba726 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -530,12 +530,6 @@ namespace MediaBrowser.Model.Dto /// The primary image aspect ratio. public double? PrimaryImageAspectRatio { get; set; } - /// - /// Gets or sets the primary image aspect ratio, before image enhancements. - /// - /// The original primary image aspect ratio. - public double? OriginalPrimaryImageAspectRatio { get; set; } - /// /// Gets or sets the artists. /// diff --git a/MediaBrowser.Model/Dto/IItemDto.cs b/MediaBrowser.Model/Dto/IItemDto.cs index af46d29b9..3e7d1c608 100644 --- a/MediaBrowser.Model/Dto/IItemDto.cs +++ b/MediaBrowser.Model/Dto/IItemDto.cs @@ -11,11 +11,5 @@ namespace MediaBrowser.Model.Dto /// /// The primary image aspect ratio. double? PrimaryImageAspectRatio { get; set; } - - /// - /// Gets or sets the original primary image aspect ratio. - /// - /// The original primary image aspect ratio. - double? OriginalPrimaryImageAspectRatio { get; set; } } } diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs index fc5d2f134..f133f3343 100644 --- a/MediaBrowser.Model/Dto/UserDto.cs +++ b/MediaBrowser.Model/Dto/UserDto.cs @@ -122,12 +122,6 @@ namespace MediaBrowser.Model.Dto /// The primary image aspect ratio. public double? PrimaryImageAspectRatio { get; set; } - /// - /// Gets or sets the original primary image aspect ratio. - /// - /// The original primary image aspect ratio. - public double? OriginalPrimaryImageAspectRatio { get; set; } - /// /// Gets a value indicating whether this instance has primary image. /// diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs index 7644b150a..f5ab0c1d4 100644 --- a/MediaBrowser.Model/Entities/MetadataProviders.cs +++ b/MediaBrowser.Model/Entities/MetadataProviders.cs @@ -36,8 +36,6 @@ namespace MediaBrowser.Model.Entities MusicBrainzArtist = 10, MusicBrainzReleaseGroup = 11, Zap2It = 12, - NesBox = 13, - NesBoxRom = 14, TvRage = 15, AudioDbArtist = 16, AudioDbAlbum = 17, diff --git a/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs b/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs index fd901f29e..91493def8 100644 --- a/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs @@ -105,12 +105,6 @@ namespace MediaBrowser.Model.LiveTv /// The primary image aspect ratio. public double? PrimaryImageAspectRatio { get; set; } - /// - /// Gets or sets the primary image aspect ratio, before image enhancements. - /// - /// The original primary image aspect ratio. - public double? OriginalPrimaryImageAspectRatio { get; set; } - /// /// Gets a value indicating whether this instance has primary image. /// diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index eea561f72..e8b1414b7 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -165,11 +165,6 @@ /// PrimaryImageAspectRatio, - /// - /// The original primary image aspect ratio - /// - OriginalPrimaryImageAspectRatio, - /// /// The revenue /// diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index ba759dcb9..6af0fb691 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -408,6 +408,9 @@ namespace MediaBrowser.Server.Implementations.Channels private async Task GetChannel(IChannel channelInfo, CancellationToken cancellationToken) { + var parentFolder = await GetInternalChannelFolder(cancellationToken).ConfigureAwait(false); + var parentFolderId = parentFolder.Id; + var id = GetInternalChannelId(channelInfo.Name); var path = Channel.GetInternalMetadataPath(_config.ApplicationPaths.InternalMetadataPath, id); @@ -450,6 +453,13 @@ namespace MediaBrowser.Server.Implementations.Channels { isNew = true; } + item.ChannelId = channelId; + + if (item.ParentId != parentFolderId) + { + isNew = true; + } + item.ParentId = parentFolderId; item.OfficialRating = GetOfficialRating(channelInfo.ParentalRating); item.Overview = channelInfo.Description; @@ -1254,7 +1264,6 @@ namespace MediaBrowser.Server.Implementations.Channels item.ProductionYear = info.ProductionYear; item.ProviderIds = info.ProviderIds; item.OfficialRating = info.OfficialRating; - item.DateCreated = info.DateCreated ?? DateTime.UtcNow; } @@ -1262,6 +1271,12 @@ namespace MediaBrowser.Server.Implementations.Channels channelItem.ChannelId = internalChannelId.ToString("N"); + if (item.ParentId != internalChannelId) + { + isNew = true; + } + item.ParentId = internalChannelId; + if (!string.Equals(channelItem.ExternalId, info.Id, StringComparison.OrdinalIgnoreCase)) { isNew = true; diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 8439f28f7..dfe02d7a1 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -463,12 +463,15 @@ namespace MediaBrowser.Server.Implementations.Dto var folder = (Folder)item; - dto.ChildCount = GetChildCount(folder, user); - - // These are just far too slow. - if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is IChannelItem) && !(folder is ICollectionFolder)) + if (!(folder is IChannelItem) && !(folder is Channel)) { - SetSpecialCounts(folder, user, dto, fields, syncProgress); + dto.ChildCount = GetChildCount(folder, user); + + // These are just far too slow. + if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is ICollectionFolder)) + { + SetSpecialCounts(folder, user, dto, fields, syncProgress); + } } dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100; @@ -1763,14 +1766,6 @@ namespace MediaBrowser.Server.Implementations.Dto return; } - if (fields.Contains(ItemFields.OriginalPrimaryImageAspectRatio)) - { - if (size.Width > 0 && size.Height > 0) - { - dto.OriginalPrimaryImageAspectRatio = size.Width / size.Height; - } - } - var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList(); foreach (var enhancer in supportedEnhancers) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index b5f1c2132..3920d6171 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1293,14 +1293,13 @@ namespace MediaBrowser.Server.Implementations.Library query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray(); - var items = GetItemIds(query).Select(GetItemById); - if (user != null) { AddUserToQuery(query, user); - items = items.Where(i => i.IsVisibleStandalone(user)); } + var items = GetItemIds(query).Select(GetItemById); + return items; } @@ -1320,7 +1319,16 @@ namespace MediaBrowser.Server.Implementations.Library private void AddUserToQuery(InternalItemsQuery query, User user) { - + if (query.AncestorIds.Length == 0) + { + // Need to filter on user folders + } + + query.MaxParentalRating = user.Policy.MaxParentalRating; + + // handle blocking by tags + + // handle unrated filter } /// diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 9694965c7..99eeb625c 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -114,7 +114,7 @@ namespace MediaBrowser.Server.Implementations.Library return 10000000; } - return 2000000; + return 4000000; } private IEnumerable GetMediaStreamsForItem(IEnumerable streams) diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 82e0f92e6..94d30f0cb 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -162,7 +162,7 @@ namespace MediaBrowser.Server.Implementations.Library NameContains = searchTerm, ExcludeItemTypes = excludeItemTypes.ToArray(), IncludeItemTypes = includeItemTypes.ToArray(), - Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 2) : null), + Limit = query.Limit, }, user, new string[] { }); diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 177d82b22..03ebcbbdc 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Entities.Audio; namespace MediaBrowser.Server.Implementations.Library { @@ -74,7 +75,7 @@ namespace MediaBrowser.Server.Implementations.Library { list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - else if (plainFolderIds.Contains(folder.Id)) + else if (plainFolderIds.Contains(folder.Id) && UserView.IsEligibleForEnhancedView(folderViewType)) { list.Add(await GetUserView(folder, folderViewType, false, string.Empty, cancellationToken).ConfigureAwait(false)); } @@ -100,7 +101,7 @@ namespace MediaBrowser.Server.Implementations.Library { list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - else if (plainFolderIds.Contains(folder.Id)) + else if (plainFolderIds.Contains(folder.Id) && UserView.IsEligibleForEnhancedView(folderViewType)) { list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false)); } @@ -123,14 +124,6 @@ namespace MediaBrowser.Server.Implementations.Library list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false)); } - parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user))) - .ToList(); - - if (parents.Count > 0) - { - list.Add(await GetUserView(parents, list, CollectionType.Music, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false)); - } - parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user))) .ToList(); @@ -139,14 +132,6 @@ namespace MediaBrowser.Server.Implementations.Library list.Add(await GetUserView(parents, list, CollectionType.Movies, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false)); } - parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Games, StringComparison.OrdinalIgnoreCase)) - .ToList(); - - if (parents.Count > 0) - { - list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false)); - } - if (user.Configuration.DisplayFoldersView) { var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders); @@ -245,7 +230,7 @@ namespace MediaBrowser.Server.Implementations.Library var currentUser = user; - var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes).Where(i => + var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes, request.Limit ?? 10).Where(i => { if (request.IsPlayed.HasValue) { @@ -293,23 +278,34 @@ namespace MediaBrowser.Server.Implementations.Library return list; } - private IEnumerable GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes) + private IEnumerable GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes, int limit) { var parentIds = string.IsNullOrEmpty(parentId) ? new string[] { } : new[] { parentId }; + if (parentIds.Length == 0) + { + parentIds = user.RootFolder.GetChildren(user, true) + .OfType() + .Select(i => i.Id.ToString("N")) + .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i)) + .ToArray(); + } + + var excludeItemTypes = includeItemTypes.Length == 0 ? new[] { "ChannelItem", "LiveTvItem", typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name } : new string[] { }; + return _libraryManager.GetItems(new InternalItemsQuery(user) { IncludeItemTypes = includeItemTypes, SortOrder = SortOrder.Descending, SortBy = new[] { ItemSortBy.DateCreated }, - IsFolder = false, - ExcludeItemTypes = new[] { "ChannelItem", "Recording" }, - ExcludeLocationTypes = new[] { LocationType.Virtual } + IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null, + ExcludeItemTypes = excludeItemTypes, + ExcludeLocationTypes = new[] { LocationType.Virtual }, + Limit = limit * 20 }, user, parentIds); - } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs index aef2157c3..3234336e2 100644 --- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; - public const int MigrationVersion = 2; + public const int MigrationVersion = 4; public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem) { @@ -66,6 +66,8 @@ namespace MediaBrowser.Server.Implementations.Persistence innerProgress.RegisterAction(p => progress.Report(45 + (.55 * p))); await CleanDeletedItems(cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(100); + + await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false); } private async Task UpdateToLatestSchema(CancellationToken cancellationToken, IProgress progress) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 4d86330e5..a33bdc0c7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -80,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteAncestorsCommand; private IDbCommand _saveAncestorCommand; - private const int LatestSchemaVersion = 19; + private const int LatestSchemaVersion = 25; /// /// Initializes a new instance of the class. @@ -133,13 +133,15 @@ namespace MediaBrowser.Server.Implementations.Persistence "create index if not exists idx_TypedBaseItems on TypedBaseItems(guid)", "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)", - "create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, PRIMARY KEY (ItemId, AncestorId))", + "create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))", "create index if not exists idx_AncestorIds on AncestorIds(ItemId,AncestorId)", "create table if not exists ChildrenIds (ParentId GUID, ItemId GUID, PRIMARY KEY (ParentId, ItemId))", "create index if not exists idx_ChildrenIds on ChildrenIds(ParentId,ItemId)", "create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)", + "create index if not exists idxPeopleItemId on People(ItemId)", + "create index if not exists idxPeopleName on People(Name)", "create table if not exists "+ChaptersTableName+" (ItemId GUID, ChapterIndex INT, StartPositionTicks BIGINT, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))", "create index if not exists idx_"+ChaptersTableName+" on "+ChaptersTableName+"(ItemId, ChapterIndex)", @@ -155,6 +157,8 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.RunQueries(queries, _logger); + _connection.AddColumn(_logger, "AncestorIds", "AncestorIdText", "Text"); + _connection.AddColumn(_logger, "TypedBaseItems", "Path", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "StartDate", "DATETIME"); _connection.AddColumn(_logger, "TypedBaseItems", "EndDate", "DATETIME"); @@ -214,6 +218,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "ExternalServiceId", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "Tags", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "IsFolder", "BIT"); + _connection.AddColumn(_logger, "TypedBaseItems", "InheritedParentalRatingValue", "INT"); PrepareStatements(); @@ -416,6 +421,7 @@ namespace MediaBrowser.Server.Implementations.Persistence "ParentId", "Genres", "ParentalRatingValue", + "InheritedParentalRatingValue", "SchemaVersion", "SortName", "RunTimeTicks", @@ -483,16 +489,17 @@ namespace MediaBrowser.Server.Implementations.Persistence _savePersonCommand.Parameters.Add(_savePersonCommand, "@PersonType"); _savePersonCommand.Parameters.Add(_savePersonCommand, "@SortOrder"); _savePersonCommand.Parameters.Add(_savePersonCommand, "@ListOrder"); - + // Ancestors _deleteAncestorsCommand = _connection.CreateCommand(); _deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id"; _deleteAncestorsCommand.Parameters.Add(_deleteAncestorsCommand, "@Id"); _saveAncestorCommand = _connection.CreateCommand(); - _saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId) values (@ItemId, @AncestorId)"; + _saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"; _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@ItemId"); _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorId"); + _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorIdText"); // Chapters _deleteChaptersCommand = _connection.CreateCommand(); @@ -648,7 +655,8 @@ namespace MediaBrowser.Server.Implementations.Persistence } _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Genres.ToArray()); - _saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue(); + _saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue() ?? 0; + _saveItemCommand.GetParameter(index++).Value = item.GetInheritedParentalRatingValue() ?? 0; _saveItemCommand.GetParameter(index++).Value = LatestSchemaVersion; _saveItemCommand.GetParameter(index++).Value = item.SortName; @@ -705,7 +713,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); _saveItemCommand.GetParameter(index++).Value = item.IsFolder; - + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -1368,7 +1376,7 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId; //_logger.Debug(cmd.CommandText); - + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { while (reader.Read()) @@ -1885,7 +1893,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (query.MaxParentalRating.HasValue) { - whereClauses.Add("(ParentalRatingValue is NULL OR ParentalRatingValue<=@MaxParentalRating)"); + whereClauses.Add("InheritedParentalRatingValue<=@MaxParentalRating"); cmd.Parameters.Add(cmd, "@MaxParentalRating", DbType.Int32).Value = query.MaxParentalRating.Value; } @@ -1893,11 +1901,11 @@ namespace MediaBrowser.Server.Implementations.Persistence { if (query.HasParentalRating.Value) { - whereClauses.Add("ParentalRatingValue NOT NULL"); + whereClauses.Add("InheritedParentalRatingValue > 0"); } else { - whereClauses.Add("ParentalRatingValue IS NULL"); + whereClauses.Add("InheritedParentalRatingValue = 0"); } } @@ -1916,8 +1924,8 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (query.AncestorIds.Length > 1) { - var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i + "'").ToArray()); - whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause)); + var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + new Guid(i).ToString("N") + "'").ToArray()); + whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause)); } if (query.ExcludeLocationTypes.Length == 1) { @@ -1986,6 +1994,59 @@ namespace MediaBrowser.Server.Implementations.Persistence typeof(Channel) }; + public async Task UpdateInheritedValues(CancellationToken cancellationToken) + { + await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try + { + transaction = _connection.BeginTransaction(); + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "update TypedBaseItems set InheritedParentalRatingValue = (select Max(ParentalRatingValue, (select COALESCE(MAX(ParentalRatingValue),0) from TypedBaseItems as T where guid in (Select AncestorId from AncestorIds where ItemId=T.guid))))"; + + cmd.Transaction = transaction; + cmd.ExecuteNonQuery(); + + cmd.ExecuteNonQuery(); + } + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + _logger.ErrorException("Error running query:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + _writeLock.Release(); + } + } + private static Dictionary GetTypeMapDictionary() { var dict = new Dictionary(); @@ -1996,6 +2057,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } dict["ChannelItem"] = new[] { typeof(ChannelVideoItem).FullName, typeof(ChannelAudioItem).FullName, typeof(ChannelFolderItem).FullName }; + dict["LiveTvItem"] = new[] { typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName, typeof(LiveTvChannel).FullName, typeof(LiveTvProgram).FullName }; dict["Recording"] = new[] { typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName }; dict["Program"] = new[] { typeof(LiveTvProgram).FullName }; dict["TvChannel"] = new[] { typeof(LiveTvChannel).FullName }; @@ -2053,7 +2115,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _deleteStreamsCommand.GetParameter(0).Value = id; _deleteStreamsCommand.Transaction = transaction; _deleteStreamsCommand.ExecuteNonQuery(); - + // Delete ancestors _deleteAncestorsCommand.GetParameter(0).Value = id; _deleteAncestorsCommand.Transaction = transaction; @@ -2063,7 +2125,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _deleteItemCommand.GetParameter(0).Value = id; _deleteItemCommand.Transaction = transaction; _deleteItemCommand.ExecuteNonQuery(); - + transaction.Commit(); } catch (OperationCanceledException) @@ -2316,6 +2378,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { _saveAncestorCommand.GetParameter(0).Value = itemId; _saveAncestorCommand.GetParameter(1).Value = ancestorId; + _saveAncestorCommand.GetParameter(2).Value = ancestorId.ToString("N"); _saveAncestorCommand.Transaction = transaction; @@ -2550,7 +2613,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } _saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; - + _saveStreamCommand.Transaction = transaction; _saveStreamCommand.ExecuteNonQuery(); } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index c715c3f50..db6a753b7 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -640,7 +640,6 @@ namespace MediaBrowser.Server.Implementations.Sync dtoOptions.Fields.Remove(ItemFields.MediaStreams); dtoOptions.Fields.Remove(ItemFields.IndexOptions); dtoOptions.Fields.Remove(ItemFields.MediaSourceCount); - dtoOptions.Fields.Remove(ItemFields.OriginalPrimaryImageAspectRatio); dtoOptions.Fields.Remove(ItemFields.Path); dtoOptions.Fields.Remove(ItemFields.SeriesGenres); dtoOptions.Fields.Remove(ItemFields.Settings); diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 694bd1b79..6fc25f24c 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -640,11 +640,19 @@ namespace MediaBrowser.Server.Startup.Common /// Task{IUserRepository}. private async Task GetUserRepository() { - var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer); + try + { + var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer); - await repo.Initialize().ConfigureAwait(false); + await repo.Initialize().ConfigureAwait(false); - return repo; + return repo; + } + catch (Exception ex) + { + Logger.ErrorException("Error opening user db", ex); + throw; + } } /// diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs index de7cba68d..cdb69025a 100644 --- a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs +++ b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs @@ -20,15 +20,13 @@ namespace MediaBrowser.Server.Startup.Common.Migrations { if (_config.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion) { - return; + Task.Run(async () => + { + await Task.Delay(2000).ConfigureAwait(false); + + _taskManager.QueueScheduledTask(); + }); } - - Task.Run(async () => - { - await Task.Delay(2000).ConfigureAwait(false); - - _taskManager.QueueScheduledTask(); - }); } } } diff --git a/SharedVersion.cs b/SharedVersion.cs index 319a682ef..299f7d775 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5781.0")] +[assembly: AssemblyVersion("3.0.*")] +//[assembly: AssemblyVersion("3.0.5781.0")] From 4503ec61740c2bc5ef7a2b43af1e2c5167642b4b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 2 Nov 2015 12:32:40 -0500 Subject: [PATCH 017/527] update channel images --- MediaBrowser.Server.Implementations/Channels/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 6af0fb691..645102230 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -1301,7 +1301,7 @@ namespace MediaBrowser.Server.Implementations.Channels item.Path = mediaSource == null ? null : mediaSource.Path; } - if (!string.IsNullOrWhiteSpace(info.ImageUrl)) + if (!string.IsNullOrWhiteSpace(info.ImageUrl) && !item.HasImage(ImageType.Primary)) { item.SetImagePath(ImageType.Primary, info.ImageUrl); } From f6c8e5b4d6a8b3d1643482d2c89bae9176e45025 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 2 Nov 2015 14:29:40 -0500 Subject: [PATCH 018/527] update httplistener --- .../HttpClientManager/HttpClientManager.cs | 13 ----- MediaBrowser.Controller/Entities/UserView.cs | 2 +- .../Folders/DefaultImageProvider.cs | 2 +- .../Manager/ItemImageProvider.cs | 5 ++ .../LiveTv/LiveTvManager.cs | 50 +++++++++++-------- ...MediaBrowser.Server.Implementations.csproj | 4 +- .../packages.config | 2 +- 7 files changed, 38 insertions(+), 40 deletions(-) diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index f4d4826eb..5908cd800 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -164,22 +164,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } } - //request.ServicePoint.BindIPEndPointDelegate = BindIPEndPointCallback; - return request; } - private static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount) - { - // Prefer local ipv4 - if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) - { - return new IPEndPoint(IPAddress.IPv6Any, 0); - } - - return new IPEndPoint(IPAddress.Any, 0); - } - private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options) { foreach (var header in options.RequestHeaders.ToList()) diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 4e3b58778..c5b65f5a8 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -141,7 +141,7 @@ namespace MediaBrowser.Controller.Entities public static bool IsEligibleForEnhancedView(string viewType) { - var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music }; + var types = new[] { CollectionType.Movies, CollectionType.TvShows }; return types.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs index 270867f90..74db70652 100644 --- a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs +++ b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs @@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.Folders } if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase)) { - return urlPrefix + "generic.png"; + //return urlPrefix + "generic.png"; } if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 838306e13..f13fb2613 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -505,6 +505,11 @@ namespace MediaBrowser.Providers.Manager return true; } + if (!item.IsSaveLocalMetadataEnabled()) + { + return true; + } + return false; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index f872817cf..db8ccd9af 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -564,8 +564,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ServiceName = serviceName; item.Number = channelInfo.Number; - var replaceImages = new List(); - //if (!string.Equals(item.ProviderImageUrl, channelInfo.ImageUrl, StringComparison.OrdinalIgnoreCase)) //{ // isNew = true; @@ -577,13 +575,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv // replaceImages.Add(ImageType.Primary); //} - if (!string.IsNullOrWhiteSpace(channelInfo.ImagePath)) + if (!item.HasImage(ImageType.Primary)) { - item.SetImagePath(ImageType.Primary, channelInfo.ImagePath); - } - else if (!string.IsNullOrWhiteSpace(channelInfo.ImageUrl)) - { - item.SetImagePath(ImageType.Primary, channelInfo.ImageUrl); + if (!string.IsNullOrWhiteSpace(channelInfo.ImagePath)) + { + item.SetImagePath(ImageType.Primary, channelInfo.ImagePath); + } + else if (!string.IsNullOrWhiteSpace(channelInfo.ImageUrl)) + { + item.SetImagePath(ImageType.Primary, channelInfo.ImageUrl); + } } if (string.IsNullOrEmpty(item.Name)) @@ -593,8 +594,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { - ForceSave = isNew, - ReplaceImages = replaceImages.Distinct().ToList() + ForceSave = isNew }, cancellationToken); @@ -658,13 +658,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.IndexNumber = info.EpisodeNumber; item.ParentIndexNumber = info.SeasonNumber; - if (!string.IsNullOrWhiteSpace(info.ImagePath)) + if (!item.HasImage(ImageType.Primary)) { - item.SetImagePath(ImageType.Primary, info.ImagePath); - } - else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) - { - item.SetImagePath(ImageType.Primary, info.ImageUrl); + if (!string.IsNullOrWhiteSpace(info.ImagePath)) + { + item.SetImagePath(ImageType.Primary, info.ImagePath); + } + else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) + { + item.SetImagePath(ImageType.Primary, info.ImageUrl); + } } if (isNew) @@ -761,13 +764,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv } recording.IsSeries = info.IsSeries; - if (!string.IsNullOrWhiteSpace(info.ImagePath)) + if (!item.HasImage(ImageType.Primary)) { - item.SetImagePath(ImageType.Primary, info.ImagePath); - } - else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) - { - item.SetImagePath(ImageType.Primary, info.ImageUrl); + if (!string.IsNullOrWhiteSpace(info.ImagePath)) + { + item.SetImagePath(ImageType.Primary, info.ImagePath); + } + else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) + { + item.SetImagePath(ImageType.Primary, info.ImageUrl); + } } var statusChanged = info.Status != recording.Status; diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 99ef3f1f2..24bc42024 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -58,9 +58,9 @@ ..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll - + False - ..\packages\SocketHttpListener.1.0.0.10\lib\net45\SocketHttpListener.dll + ..\packages\SocketHttpListener.1.0.0.13\lib\net45\SocketHttpListener.dll diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 22206997f..603c86333 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -6,5 +6,5 @@ - + \ No newline at end of file From 60067b4c29ccdfe19102a47eb9347715e1904b22 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 2 Nov 2015 23:34:47 -0500 Subject: [PATCH 019/527] fix camera upload folder --- MediaBrowser.Api/Library/LibraryService.cs | 2 +- .../Entities/UserRootFolder.cs | 5 +- .../Folders/DefaultImageProvider.cs | 22 ++--- .../Devices/CameraUploadsFolder.cs | 5 +- .../Devices/DeviceManager.cs | 98 +++++++++++++++++-- ...MediaBrowser.Server.Implementations.csproj | 2 +- .../ApplicationHost.cs | 2 +- 7 files changed, 112 insertions(+), 24 deletions(-) diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 319bc13fd..904e8cdf6 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) { diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index e6f322595..b7946cb92 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -57,7 +57,10 @@ namespace MediaBrowser.Controller.Entities protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) { - return base.GetEligibleChildrenForRecursiveChildren(user).Concat(LibraryManager.RootFolder.VirtualChildren); + var list = base.GetEligibleChildrenForRecursiveChildren(user).ToList(); + list.AddRange(LibraryManager.RootFolder.VirtualChildren); + + return list; } /// diff --git a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs index 74db70652..830a8c016 100644 --- a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs +++ b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs @@ -77,15 +77,15 @@ namespace MediaBrowser.Providers.Folders if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "books.png"; + return urlPrefix + "books.jpg"; } if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "games.png"; + return urlPrefix + "games.jpg"; } if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "music.png"; + return urlPrefix + "music.jpg"; } if (string.Equals(viewType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) { @@ -93,11 +93,11 @@ namespace MediaBrowser.Providers.Folders } if (string.Equals(viewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "tv.png"; + return urlPrefix + "tv.jpg"; } if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "generic.png"; + return urlPrefix + "channels.jpg"; } if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase)) { @@ -105,27 +105,27 @@ namespace MediaBrowser.Providers.Folders } if (string.Equals(viewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "movies.png"; + return urlPrefix + "movies.jpg"; } if (string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "playlists.png"; + return urlPrefix + "playlists.jpg"; } if (string.Equals(viewType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "homevideos.png"; + return urlPrefix + "homevideos.jpg"; } if (string.Equals(viewType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "musicvideos.png"; + return urlPrefix + "musicvideos.jpg"; } if (string.Equals(viewType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) { - //return urlPrefix + "generic.png"; + return urlPrefix + "collections.jpg"; } if (string.IsNullOrWhiteSpace(viewType)) { - //return urlPrefix + "generic.png"; + return urlPrefix + "generic.jpg"; } return null; diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs index 62069736f..d1e66abce 100644 --- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs +++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs @@ -3,8 +3,11 @@ using MediaBrowser.Controller.Entities; using System; using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using CommonIO; using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Providers; namespace MediaBrowser.Server.Implementations.Devices { @@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Devices return _hasChildren.Value; } - protected override System.Threading.Tasks.Task ValidateChildrenInternal(IProgress progress, System.Threading.CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, Controller.Providers.MetadataRefreshOptions refreshOptions, Controller.Providers.IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { _hasChildren = null; return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs index 0b2c082a8..e0713bfd5 100644 --- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs +++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs @@ -18,6 +18,9 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Server.Implementations.Devices { @@ -27,7 +30,7 @@ namespace MediaBrowser.Server.Implementations.Devices private readonly IUserManager _userManager; private readonly IFileSystem _fileSystem; private readonly ILibraryMonitor _libraryMonitor; - private readonly IConfigurationManager _config; + private readonly IServerConfigurationManager _config; private readonly ILogger _logger; private readonly INetworkManager _network; @@ -38,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Devices /// public event EventHandler> DeviceOptionsUpdated; - public DeviceManager(IDeviceRepository repo, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IConfigurationManager config, ILogger logger, INetworkManager network) + public DeviceManager(IDeviceRepository repo, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IServerConfigurationManager config, ILogger logger, INetworkManager network) { _repo = repo; _userManager = userManager; @@ -187,11 +190,6 @@ namespace MediaBrowser.Server.Implementations.Devices } } - private string GetUploadPath(string deviceId) - { - return GetUploadPath(GetDevice(deviceId)); - } - private string GetUploadPath(DeviceInfo device) { if (!string.IsNullOrWhiteSpace(device.CameraUploadPath)) @@ -205,16 +203,81 @@ namespace MediaBrowser.Server.Implementations.Devices return config.CameraUploadPath; } - var path = Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); + var path = DefaultCameraUploadsPath; if (config.EnableCameraUploadSubfolders) { path = Path.Combine(path, _fileSystem.GetValidFilename(device.Name)); } + EnsureMediaLibrarySetup(); + return path; } + private string DefaultCameraUploadsPath + { + get { return Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); } + } + + internal void EnsureMediaLibrarySetup() + { + //EnsureMediaLibrarySetup(DefaultCameraUploadsPath, false); + } + + private void EnsureMediaLibrarySetup(string libraryPath, bool force) + { + var requiresSetup = false; + + var path = Path.Combine(_config.ApplicationPaths.DefaultUserViewsPath, "Camera Uploads"); + + var collectionMarkerFile = Path.Combine(path, CollectionType.Photos + ".collection"); + if (!_fileSystem.FileExists(collectionMarkerFile)) + { + requiresSetup = true; + } + + var shortcutFile = Path.Combine(path, "camerauploads.mblink"); + try + { + if (!string.Equals(_fileSystem.ReadAllText(shortcutFile), libraryPath)) + { + requiresSetup = true; + } + } + catch + { + requiresSetup = true; + } + + if (requiresSetup) + { + if (!force) + { + var extensions = new[] { ".jpg", ".png" }; + var hasPhotos = _fileSystem.GetFiles(libraryPath, true).Any(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase)); + + // Nothing to do + if (!hasPhotos) + { + return; + } + } + } + + if (requiresSetup) + { + Directory.CreateDirectory(path); + + using (File.Create(collectionMarkerFile)) + { + + } + + _fileSystem.CreateShortcut(shortcutFile, libraryPath); + } + } + public async Task UpdateDeviceInfo(string id, DeviceOptions options) { var device = GetDevice(id); @@ -274,6 +337,25 @@ namespace MediaBrowser.Server.Implementations.Devices } } + public class DeviceManagerEntryPoint : IServerEntryPoint + { + private readonly IDeviceManager _deviceManager; + + public DeviceManagerEntryPoint(IDeviceManager deviceManager) + { + _deviceManager = deviceManager; + } + + public void Run() + { + ((DeviceManager)_deviceManager).EnsureMediaLibrarySetup(); + } + + public void Dispose() + { + } + } + public class DevicesConfigStore : IConfigurationFactory { public IEnumerable GetConfigurations() diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 24bc42024..b4d019d13 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -120,9 +120,9 @@ + - diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 6fc25f24c..2f098aad0 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -465,7 +465,7 @@ namespace MediaBrowser.Server.Startup.Common ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager, FileSystemManager); RegisterSingleInstance(ConnectManager); - DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager); + DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager); RegisterSingleInstance(DeviceManager); var newsService = new Implementations.News.NewsService(ApplicationPaths, JsonSerializer); From 6aa3313bc05fe5a26cee8944c00489c022612069 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 4 Nov 2015 18:49:06 -0500 Subject: [PATCH 020/527] make sure ._ osx files are properly ignored --- .../Playback/BaseStreamingService.cs | 1 - .../Playback/Hls/DynamicHlsService.cs | 8 ++- .../UserLibrary/UserViewsService.cs | 1 + .../Library/ILibraryManager.cs | 9 ++- .../Resolvers/IResolverIgnoreRule.cs | 5 +- .../Configuration/EncodingOptions.cs | 2 +- .../Channels/ChannelManager.cs | 13 ++-- .../Library/CoreResolutionIgnoreRule.cs | 63 +++++++++++-------- .../Library/LibraryManager.cs | 9 ++- .../Library/Resolvers/Movies/MovieResolver.cs | 20 +++--- .../MediaBrowser.WebDashboard.csproj | 6 +- 11 files changed, 85 insertions(+), 52 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 36207c8b4..426f1883e 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1662,7 +1662,6 @@ namespace MediaBrowser.Api.Playback state.InputContainer = mediaSource.Container; state.InputFileSize = mediaSource.Size; state.InputBitrate = mediaSource.Bitrate; - state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; state.RunTimeTicks = mediaSource.RunTimeTicks; state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders; diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 6ca2677e7..4d7a10f02 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -173,11 +173,14 @@ namespace MediaBrowser.Api.Playback.Hls } await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); + var released = false; try { if (FileSystem.FileExists(segmentPath)) { job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); + ApiEntryPoint.Instance.TranscodingStartLock.Release(); + released = true; return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false); } else @@ -238,7 +241,10 @@ namespace MediaBrowser.Api.Playback.Hls } finally { - ApiEntryPoint.Instance.TranscodingStartLock.Release(); + if (!released) + { + ApiEntryPoint.Instance.TranscodingStartLock.Release(); + } } //Logger.Info("waiting for {0}", segmentPath); diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 6ba30a35e..6db195e3e 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -79,6 +79,7 @@ namespace MediaBrowser.Api.UserLibrary var dtoOptions = GetDtoOptions(request); dtoOptions.Fields = new List(); + dtoOptions.Fields.Add(ItemFields.PrimaryImageAspectRatio); var user = _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9e434541a..4a9ee312f 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -557,9 +557,16 @@ namespace MediaBrowser.Controller.Library /// Gets the items result. /// /// The query. - /// The user. /// The parent ids. /// QueryResult<BaseItem>. QueryResult GetItemsResult(InternalItemsQuery query, IEnumerable parentIds); + + /// + /// Ignores the file. + /// + /// The file. + /// The parent. + /// true if XXXX, false otherwise. + bool IgnoreFile(FileSystemMetadata file, BaseItem parent); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs index e85535548..2c82882c6 100644 --- a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs +++ b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Library; +using CommonIO; +using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Resolvers { @@ -7,6 +8,6 @@ namespace MediaBrowser.Controller.Resolvers /// public interface IResolverIgnoreRule { - bool ShouldIgnore(ItemResolveArgs args); + bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent); } } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 77b894eb8..4c3d1be37 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Model.Configuration { DownMixAudioBoost = 2; EnableThrottling = true; - ThrottleThresholdInSeconds = 120; + ThrottleThresholdInSeconds = 100; EncodingThreadCount = -1; } } diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 645102230..34e7f33fc 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -1235,6 +1235,7 @@ namespace MediaBrowser.Server.Implementations.Channels { BaseItem item; bool isNew; + bool forceUpdate = false; if (info.Type == ChannelItemType.Folder) { @@ -1265,6 +1266,7 @@ namespace MediaBrowser.Server.Implementations.Channels item.ProviderIds = info.ProviderIds; item.OfficialRating = info.OfficialRating; item.DateCreated = info.DateCreated ?? DateTime.UtcNow; + item.Tags = info.Tags; } var channelItem = (IChannelItem)item; @@ -1273,7 +1275,7 @@ namespace MediaBrowser.Server.Implementations.Channels if (item.ParentId != internalChannelId) { - isNew = true; + forceUpdate = true; } item.ParentId = internalChannelId; @@ -1283,11 +1285,6 @@ namespace MediaBrowser.Server.Implementations.Channels } channelItem.ExternalId = info.Id; - if (isNew) - { - channelItem.Tags = info.Tags; - } - var channelMediaItem = item as IChannelMediaItem; if (channelMediaItem != null) @@ -1315,6 +1312,10 @@ namespace MediaBrowser.Server.Implementations.Channels await _libraryManager.UpdatePeople(item, info.People ?? new List()).ConfigureAwait(false); } } + else if (forceUpdate) + { + await item.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false); + } return item; } diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 9035d6479..043996403 100644 --- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -47,11 +47,14 @@ namespace MediaBrowser.Server.Implementations.Library /// /// Shoulds the ignore. /// - /// The args. + /// The file information. + /// The parent. /// true if XXXX, false otherwise - public bool ShouldIgnore(ItemResolveArgs args) + public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent) { - var filename = args.FileInfo.Name; + var filename = fileInfo.Name; + var isHidden = (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; + var path = fileInfo.FullName; // Handle mac .DS_Store // https://github.com/MediaBrowser/MediaBrowser/issues/427 @@ -61,21 +64,24 @@ namespace MediaBrowser.Server.Implementations.Library } // Ignore hidden files and folders - if (args.IsHidden) + if (isHidden) { - var parentFolderName = Path.GetFileName(Path.GetDirectoryName(args.Path)); + if (parent != null) + { + var parentFolderName = Path.GetFileName(Path.GetDirectoryName(path)); - if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - if (string.Equals(parentFolderName, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) - { - return false; + if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + if (string.Equals(parentFolderName, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) + { + return false; + } } // Sometimes these are marked hidden - if (_fileSystem.IsRootPath(args.Path)) + if (_fileSystem.IsRootPath(path)) { return false; } @@ -83,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.Library return true; } - if (args.IsDirectory) + if (fileInfo.IsDirectory) { // Ignore any folders in our list if (IgnoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase)) @@ -91,26 +97,29 @@ namespace MediaBrowser.Server.Implementations.Library return true; } - // Ignore trailer folders but allow it at the collection level - if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase) && - !(args.Parent is AggregateFolder) && !(args.Parent is UserRootFolder)) + if (parent != null) { - return true; - } + // Ignore trailer folders but allow it at the collection level + if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase) && + !(parent is AggregateFolder) && !(parent is UserRootFolder)) + { + return true; + } - if (string.Equals(filename, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } + if (string.Equals(filename, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } - if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) - { - return true; + if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } } } else { - if (args.Parent != null) + if (parent != null) { // Don't resolve these into audio files if (string.Equals(_fileSystem.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename)) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 3920d6171..70d28547c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -580,7 +580,7 @@ namespace MediaBrowser.Server.Implementations.Library }; // Return null if ignore rules deem that we should do so - if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(args))) + if (IgnoreFile(args.FileInfo, args.Parent)) { return null; } @@ -616,6 +616,11 @@ namespace MediaBrowser.Server.Implementations.Library return ResolveItem(args); } + public bool IgnoreFile(FileSystemMetadata file, BaseItem parent) + { + return EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)); + } + public IEnumerable NormalizeRootPathList(IEnumerable paths) { var list = paths.Select(_fileSystem.NormalizePath) @@ -646,7 +651,7 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType) { - var fileList = files.ToList(); + var fileList = files.Where(i => !IgnoreFile(i, parent)).ToList(); if (parent != null) { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 3252db505..e84fc242f 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies string collectionType, IDirectoryService directoryService) { - if (IsInvalid(parent, collectionType, files)) + if (IsInvalid(parent, collectionType)) { return null; } @@ -185,7 +185,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { var collectionType = args.GetCollectionType(); - if (IsInvalid(args.Parent, collectionType, args.FileSystemChildren)) + if (IsInvalid(args.Parent, collectionType)) { return null; } @@ -193,14 +193,18 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies // Find movies with their own folders if (args.IsDirectory) { + var files = args.FileSystemChildren + .Where(i => !LibraryManager.IgnoreFile(i, args.Parent)) + .ToList(); + if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType); + return FindMovie(args.Path, args.Parent, files, args.DirectoryService, collectionType); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie