From 433254c498d2e43acfd34e5c4fcee2fdcc2e767b Mon Sep 17 00:00:00 2001 From: softworkz Date: Fri, 5 Aug 2016 06:08:11 +0200 Subject: [PATCH 01/85] Async stream handling: Use interface instead of Func No functional changes --- .../BaseProgressiveStreamingService.cs | 4 +- .../Progressive/ProgressiveStreamWriter.cs | 23 ++- .../MediaBrowser.Controller.csproj | 1 + .../Net/IAsyncStreamSource.cs | 18 +++ .../Net/IHttpResultFactory.cs | 2 +- ...reamWriterFunc.cs => AsyncStreamWriter.cs} | 35 ++-- .../HttpServer/AsyncStreamWriterEx.cs | 153 ++++++++++++++++++ .../HttpServer/HttpResultFactory.cs | 9 +- ...MediaBrowser.Server.Implementations.csproj | 3 +- 9 files changed, 223 insertions(+), 25 deletions(-) create mode 100644 MediaBrowser.Controller/Net/IAsyncStreamSource.cs rename MediaBrowser.Server.Implementations/HttpServer/{AsyncStreamWriterFunc.cs => AsyncStreamWriter.cs} (50%) create mode 100644 MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 4649499c46..5a5cb80000 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -362,9 +362,9 @@ namespace MediaBrowser.Api.Playback.Progressive outputHeaders[item.Key] = item.Value; } - Func streamWriter = stream => new ProgressiveFileCopier(FileSystem, job, Logger).StreamFile(outputPath, stream, CancellationToken.None); + var streamSource = new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, CancellationToken.None); - return ResultFactory.GetAsyncStreamWriter(streamWriter, outputHeaders); + return ResultFactory.GetAsyncStreamWriter(streamSource); } finally { diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index 63d71b85ef..8c4e23a397 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -4,28 +4,45 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.Net; +using System.Collections.Generic; +using ServiceStack.Web; namespace MediaBrowser.Api.Playback.Progressive { - public class ProgressiveFileCopier + public class ProgressiveFileCopier : IAsyncStreamSource, IHasOptions { private readonly IFileSystem _fileSystem; private readonly TranscodingJob _job; private readonly ILogger _logger; + private readonly string _path; + private readonly CancellationToken _cancellationToken; + private readonly Dictionary _outputHeaders; // 256k private const int BufferSize = 81920; private long _bytesWritten = 0; - public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job, ILogger logger) + public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) { _fileSystem = fileSystem; + _path = path; + _outputHeaders = outputHeaders; _job = job; _logger = logger; + _cancellationToken = cancellationToken; } - public async Task StreamFile(string path, Stream outputStream, CancellationToken cancellationToken) + public IDictionary Options + { + get + { + return _outputHeaders; + } + } + + public async Task WriteToAsync(Stream outputStream) { try { diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 0462117cb5..e7eaa1dc0b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -236,6 +236,7 @@ + diff --git a/MediaBrowser.Controller/Net/IAsyncStreamSource.cs b/MediaBrowser.Controller/Net/IAsyncStreamSource.cs new file mode 100644 index 0000000000..0f41f60a55 --- /dev/null +++ b/MediaBrowser.Controller/Net/IAsyncStreamSource.cs @@ -0,0 +1,18 @@ +using ServiceStack.Web; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Net +{ + /// + /// Interface IAsyncStreamSource + /// Enables asynchronous writing to http resonse streams + /// + public interface IAsyncStreamSource + { + /// + /// Asynchronously write to the response stream. + /// + Task WriteToAsync(Stream responseStream); + } +} diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index 49d4614d81..8fdb1ce37e 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Controller.Net /// System.Object. object GetResult(object content, string contentType, IDictionary responseHeaders = null); - object GetAsyncStreamWriter(Func streamWriter, IDictionary responseHeaders = null); + object GetAsyncStreamWriter(IAsyncStreamSource streamSource); /// /// Gets the optimized result. diff --git a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterFunc.cs b/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriter.cs similarity index 50% rename from MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterFunc.cs rename to MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriter.cs index 5aa01c7062..e44b0c6af1 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterFunc.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriter.cs @@ -4,38 +4,41 @@ using System.IO; using System.Threading.Tasks; using ServiceStack; using ServiceStack.Web; +using MediaBrowser.Controller.Net; namespace MediaBrowser.Server.Implementations.HttpServer { - public class AsyncStreamWriterFunc : IStreamWriter, IAsyncStreamWriter, IHasOptions + public class AsyncStreamWriter : IStreamWriter, IAsyncStreamWriter, IHasOptions { /// /// Gets or sets the source stream. /// /// The source stream. - private Func Writer { get; set; } - - /// - /// Gets the options. - /// - /// The options. - public IDictionary Options { get; private set; } + private IAsyncStreamSource _source; public Action OnComplete { get; set; } public Action OnError { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public AsyncStreamWriterFunc(Func writer, IDictionary headers) + public AsyncStreamWriter(IAsyncStreamSource source) { - Writer = writer; + _source = source; + } - if (headers == null) + public IDictionary Options + { + get { - headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + var hasOptions = _source as IHasOptions; + if (hasOptions != null) + { + return hasOptions.Options; + } + + return new Dictionary(StringComparer.OrdinalIgnoreCase); } - Options = headers; } /// @@ -44,13 +47,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The response stream. public void WriteTo(Stream responseStream) { - var task = Writer(responseStream); + var task = _source.WriteToAsync(responseStream); Task.WaitAll(task); } public async Task WriteToAsync(Stream responseStream) { - await Writer(responseStream).ConfigureAwait(false); + await _source.WriteToAsync(responseStream).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs b/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs new file mode 100644 index 0000000000..b98addb317 --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using ServiceStack; +using ServiceStack.Web; +using MediaBrowser.Controller.Net; + +namespace MediaBrowser.Server.Implementations.HttpServer +{ + public class AsyncStreamWriterEx : AsyncStreamWriter, IHttpResult + { + /// + /// Gets or sets the source stream. + /// + /// The source stream. + private IAsyncStreamSource _source; + + /// + /// Initializes a new instance of the class. + /// + public AsyncStreamWriterEx(IAsyncStreamSource source) : base(source) + { + _source = source; + } + + public string ContentType + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public List Cookies + { + get { throw new NotImplementedException(); } + } + + public Dictionary Headers + { + get { throw new NotImplementedException(); } + } + + public int PaddingLength + { + get + { + return Result.PaddingLength; + } + set + { + Result.PaddingLength = value; + } + } + + public IRequest RequestContext + { + get + { + return Result.RequestContext; + } + set + { + Result.RequestContext = value; + } + } + + public object Response + { + get + { + return Result.Response; + } + set + { + Result.Response = value; + } + } + + public IContentTypeWriter ResponseFilter + { + get + { + return Result.ResponseFilter; + } + set + { + Result.ResponseFilter = value; + } + } + + public Func ResultScope + { + get + { + return Result.ResultScope; + } + set + { + Result.ResultScope = value; + } + } + + public int Status + { + get + { + return Result.Status; + } + set + { + Result.Status = value; + } + } + + public System.Net.HttpStatusCode StatusCode + { + get + { + return Result.StatusCode; + } + set + { + Result.StatusCode = value; + } + } + + public string StatusDescription + { + get + { + return Result.StatusDescription; + } + set + { + Result.StatusDescription = value; + } + } + + private IHttpResult Result + { + get + { + return _source as IHttpResult; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index c0a2a5eb35..f234674d82 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -704,9 +704,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer throw error; } - public object GetAsyncStreamWriter(Func streamWriter, IDictionary responseHeaders = null) + public object GetAsyncStreamWriter(IAsyncStreamSource streamSource) { - return new AsyncStreamWriterFunc(streamWriter, responseHeaders); + if (streamSource as IHttpResult != null) + { + return new AsyncStreamWriterEx(streamSource); + } + + return new AsyncStreamWriter(streamSource); } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index dca7531934..8025e3594e 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -156,7 +156,8 @@ - + + From 7d16988b1b81cc73608c07d61eabb83f8fcbbb05 Mon Sep 17 00:00:00 2001 From: softworkz Date: Fri, 5 Aug 2016 19:07:43 +0200 Subject: [PATCH 02/85] Remove handling IHttpResult --- .../HttpServer/AsyncStreamWriterEx.cs | 153 ------------------ .../HttpServer/HttpResultFactory.cs | 5 - ...MediaBrowser.Server.Implementations.csproj | 1 - 3 files changed, 159 deletions(-) delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs diff --git a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs b/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs deleted file mode 100644 index b98addb317..0000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriterEx.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using ServiceStack; -using ServiceStack.Web; -using MediaBrowser.Controller.Net; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public class AsyncStreamWriterEx : AsyncStreamWriter, IHttpResult - { - /// - /// Gets or sets the source stream. - /// - /// The source stream. - private IAsyncStreamSource _source; - - /// - /// Initializes a new instance of the class. - /// - public AsyncStreamWriterEx(IAsyncStreamSource source) : base(source) - { - _source = source; - } - - public string ContentType - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public List Cookies - { - get { throw new NotImplementedException(); } - } - - public Dictionary Headers - { - get { throw new NotImplementedException(); } - } - - public int PaddingLength - { - get - { - return Result.PaddingLength; - } - set - { - Result.PaddingLength = value; - } - } - - public IRequest RequestContext - { - get - { - return Result.RequestContext; - } - set - { - Result.RequestContext = value; - } - } - - public object Response - { - get - { - return Result.Response; - } - set - { - Result.Response = value; - } - } - - public IContentTypeWriter ResponseFilter - { - get - { - return Result.ResponseFilter; - } - set - { - Result.ResponseFilter = value; - } - } - - public Func ResultScope - { - get - { - return Result.ResultScope; - } - set - { - Result.ResultScope = value; - } - } - - public int Status - { - get - { - return Result.Status; - } - set - { - Result.Status = value; - } - } - - public System.Net.HttpStatusCode StatusCode - { - get - { - return Result.StatusCode; - } - set - { - Result.StatusCode = value; - } - } - - public string StatusDescription - { - get - { - return Result.StatusDescription; - } - set - { - Result.StatusDescription = value; - } - } - - private IHttpResult Result - { - get - { - return _source as IHttpResult; - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index f234674d82..b26cf5b769 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -706,11 +706,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer public object GetAsyncStreamWriter(IAsyncStreamSource streamSource) { - if (streamSource as IHttpResult != null) - { - return new AsyncStreamWriterEx(streamSource); - } - return new AsyncStreamWriter(streamSource); } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 8025e3594e..07cb9fa0d7 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -156,7 +156,6 @@ - From b309e06cb8741b7b697a57e230bd9f6ee452e8d9 Mon Sep 17 00:00:00 2001 From: softworkz Date: Mon, 8 Aug 2016 20:49:31 +0200 Subject: [PATCH 03/85] FileRefresher.IsFileLocked: Don't log Exceptions in case of no write permission --- MediaBrowser.Server.Implementations/IO/FileRefresher.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs index f48beacb57..5c72ac9c7e 100644 --- a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs +++ b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs @@ -254,6 +254,11 @@ namespace MediaBrowser.Server.Implementations.IO // File may have been deleted return false; } + catch (UnauthorizedAccessException) + { + Logger.Debug("No write permission for: {0}.", path); + return false; + } catch (IOException) { //the file is unavailable because it is: From 9349cc5bebf1196bfc9f90e3838e89acb95d41d4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 10 Aug 2016 15:15:41 -0400 Subject: [PATCH 04/85] update thread count on image extraction --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 08ab99f9b2..c8a28e832a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -874,8 +874,8 @@ namespace MediaBrowser.MediaEncoding.Encoder var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. - var args = useIFrame ? string.Format("-i {0}{3} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg) : - string.Format("-i {0}{3} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); + var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg) : + string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol); @@ -980,7 +980,7 @@ namespace MediaBrowser.MediaEncoding.Encoder FileSystem.CreateDirectory(targetDirectory); var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg"); - var args = string.Format("-i {0} -threads 1 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); + var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol); From 438507b53d554f110cc092e98cc9659766b9224b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 10 Aug 2016 15:15:57 -0400 Subject: [PATCH 05/85] don't throttle when using hardware encoding --- .../Playback/BaseStreamingService.cs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 164d607d28..59dfd87ecd 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1118,22 +1118,23 @@ namespace MediaBrowser.Api.Playback private void StartThrottler(StreamState state, TranscodingJob transcodingJob) { - if (EnableThrottling(state) && state.InputProtocol == MediaProtocol.File && - state.RunTimeTicks.HasValue && - state.VideoType == VideoType.VideoFile && - !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EnableThrottling(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo) - { - transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager); - state.TranscodingThrottler.Start(); - } + transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager); + state.TranscodingThrottler.Start(); } } protected virtual bool EnableThrottling(StreamState state) { - return true; + // do not use throttling with hardware encoders + return state.InputProtocol == MediaProtocol.File && + state.RunTimeTicks.HasValue && + state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && + state.IsInputVideo && + state.VideoType == VideoType.VideoFile && + !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && + string.Equals(GetVideoEncoder(state), "libx264", StringComparison.OrdinalIgnoreCase); } private async Task StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target) From 00307b9a44e6940a7c8c547cf0ffa6232f805cca Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 10 Aug 2016 15:16:09 -0400 Subject: [PATCH 06/85] updated inherited parental rating value --- .../Persistence/SqliteItemRepository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index b4f8245ed8..0836560fc2 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2230,7 +2230,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (string.Equals(name, ItemSortBy.OfficialRating, StringComparison.OrdinalIgnoreCase)) { - return new Tuple("ParentalRatingValue", false); + return new Tuple("InheritedParentalRatingValue", false); } if (string.Equals(name, ItemSortBy.Studio, StringComparison.OrdinalIgnoreCase)) { @@ -3473,7 +3473,7 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select Guid,InheritedParentalRatingValue,(select Max(ParentalRatingValue, (select COALESCE(MAX(ParentalRatingValue),0) from TypedBaseItems where guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid)))) as NewInheritedParentalRatingValue from typedbaseitems as Outer where InheritedParentalRatingValue <> NewInheritedParentalRatingValue"; + cmd.CommandText = "select Guid,InheritedParentalRatingValue,(select Max(InheritedParentalRatingValue, (select COALESCE(MAX(InheritedParentalRatingValue),0) from TypedBaseItems where guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid)))) as NewInheritedParentalRatingValue from typedbaseitems as Outer where InheritedParentalRatingValue <> NewInheritedParentalRatingValue"; using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { From 4dcd381701014cdf3c26b13874dc69cca10a7dc8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 10 Aug 2016 15:19:50 -0400 Subject: [PATCH 07/85] 3.1.98 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 6dfb8bc40e..82411e4964 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.97")] +[assembly: AssemblyVersion("3.1.98")] From 6f20a8ca059f4266082e41b0fd58eae5d0229940 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 10 Aug 2016 23:56:01 -0400 Subject: [PATCH 08/85] don't restart timer if disposed --- MediaBrowser.Server.Implementations/IO/FileRefresher.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs index f48beacb57..742585143f 100644 --- a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs +++ b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs @@ -61,6 +61,11 @@ namespace MediaBrowser.Server.Implementations.IO public void RestartTimer() { + if (_disposed) + { + return; + } + lock (_timerLock) { if (_timer == null) @@ -281,8 +286,10 @@ namespace MediaBrowser.Server.Implementations.IO } } + private bool _disposed; public void Dispose() { + _disposed = true; DisposeTimer(); } } From de0f97159b72ed43b59316ad108781759b623ec9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 10 Aug 2016 23:56:14 -0400 Subject: [PATCH 09/85] check item path for null/empty --- MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 11280cff21..e36be54191 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -171,10 +171,13 @@ namespace MediaBrowser.Providers.MediaInfo public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) { - var file = directoryService.GetFile(item.Path); - if (file != null && file.LastWriteTimeUtc != item.DateModified) + if (!string.IsNullOrWhiteSpace(item.Path)) { - return true; + var file = directoryService.GetFile(item.Path); + if (file != null && file.LastWriteTimeUtc != item.DateModified) + { + return true; + } } if (item.SupportsLocalMetadata) From cb0d6cc8c780fb4ac41f4ce7b87ee82112f65cc8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Aug 2016 01:38:17 -0400 Subject: [PATCH 10/85] moved icons --- .../MediaBrowser.WebDashboard.csproj | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index cc064dc813..2917ec2ced 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -233,10 +233,7 @@ PreserveNewest - - PreserveNewest - - + PreserveNewest @@ -1196,13 +1193,13 @@ - + PreserveNewest - + PreserveNewest - + PreserveNewest From 72f9a4e4780a9b242822cd21494c0372e7a31295 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Aug 2016 01:38:40 -0400 Subject: [PATCH 11/85] update app manifest --- MediaBrowser.WebDashboard/Api/PackageCreator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index b7b1f1dfd7..4913faab35 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -372,12 +372,12 @@ namespace MediaBrowser.WebDashboard.Api sb.Append(""); // http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html - sb.Append(""); - sb.Append(""); - sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); sb.Append(""); sb.Append(""); - sb.Append(""); + sb.Append(""); sb.Append(""); sb.Append(""); From c929fb187e5927ee46359a41f8ecf146ba293d57 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Aug 2016 01:38:53 -0400 Subject: [PATCH 12/85] add endpoint to get file list --- .../Api/DashboardService.cs | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 34ad32111b..ce6369ec5e 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -58,6 +58,11 @@ namespace MediaBrowser.WebDashboard.Api { } + [Route("/web/cachefiles", "GET")] + public class GetCacheFiles + { + } + /// /// Class GetDashboardResource /// @@ -140,6 +145,22 @@ namespace MediaBrowser.WebDashboard.Api return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml("dummy.html", page.GetHtmlStream(), null, _appHost.ApplicationVersion.ToString(), null, false)); } + public object Get(GetCacheFiles request) + { + var creator = GetPackageCreator(); + var directory = creator.DashboardUIPath; + + var skipExtensions = GetUndeployedExtensions(); + + var allFiles = + Directory.GetFiles(directory, "*", SearchOption.AllDirectories) + .Where(i => !skipExtensions.Contains(Path.GetExtension(i) ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + .Select(i => i.Replace(directory, string.Empty, StringComparison.OrdinalIgnoreCase).Replace("\\", "/").TrimStart('/') + "?v=" + _appHost.ApplicationVersion.ToString()) + .ToList(); + + return ResultFactory.GetOptimizedResult(Request, _jsonSerializer.SerializeToString(allFiles)); + } + /// /// Gets the specified request. /// @@ -274,6 +295,21 @@ namespace MediaBrowser.WebDashboard.Api return new PackageCreator(_fileSystem, _localization, Logger, _serverConfigurationManager, _jsonSerializer); } + private List GetUndeployedExtensions() + { + var list = new List(); + + list.Add(".log"); + list.Add(".txt"); + list.Add(".map"); + list.Add(".md"); + list.Add(".gz"); + list.Add(".bat"); + list.Add(".sh"); + + return list; + } + public async Task Get(GetDashboardPackage request) { var path = Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath, @@ -313,14 +349,9 @@ namespace MediaBrowser.WebDashboard.Api //bowerPath = versionedBowerPath; } - DeleteFilesByExtension(bowerPath, ".log"); - DeleteFilesByExtension(bowerPath, ".txt"); - DeleteFilesByExtension(bowerPath, ".map"); - DeleteFilesByExtension(bowerPath, ".md"); + GetUndeployedExtensions().ForEach(i => DeleteFilesByExtension(bowerPath, i)); + DeleteFilesByExtension(bowerPath, ".json", "strings\\"); - DeleteFilesByExtension(bowerPath, ".gz"); - DeleteFilesByExtension(bowerPath, ".bat"); - DeleteFilesByExtension(bowerPath, ".sh"); DeleteFilesByName(bowerPath, "copying", true); DeleteFilesByName(bowerPath, "license", true); DeleteFilesByName(bowerPath, "license-mit", true); @@ -359,13 +390,11 @@ namespace MediaBrowser.WebDashboard.Api //DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "meteor"); //DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "st"); //DeleteFoldersByName(Path.Combine(bowerPath, "Swiper"), "src"); - + if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) { // Delete things that are unneeded in an attempt to keep the output as trim as possible _fileSystem.DeleteDirectory(Path.Combine(path, "css", "images", "tour"), true); - - _fileSystem.DeleteFile(Path.Combine(path, "thirdparty", "jquerymobile-1.4.5", "jquery.mobile-1.4.5.min.map")); } else { From 071f455d58514636d5eb0630b44a16903ac738cf Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Aug 2016 16:28:49 -0400 Subject: [PATCH 13/85] update card layouts --- .../Api/DashboardService.cs | 20 ++++++++++--------- .../Api/PackageCreator.cs | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index ce6369ec5e..4e4a980605 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.WebDashboard.Api { } - [Route("/web/cachefiles", "GET")] + [Route("/web/staticfiles", "GET")] public class GetCacheFiles { } @@ -146,19 +146,24 @@ namespace MediaBrowser.WebDashboard.Api } public object Get(GetCacheFiles request) + { + var allFiles = GetCacheFileList(); + + return ResultFactory.GetOptimizedResult(Request, _jsonSerializer.SerializeToString(allFiles)); + } + + private List GetCacheFileList() { var creator = GetPackageCreator(); var directory = creator.DashboardUIPath; var skipExtensions = GetUndeployedExtensions(); - var allFiles = + return Directory.GetFiles(directory, "*", SearchOption.AllDirectories) .Where(i => !skipExtensions.Contains(Path.GetExtension(i) ?? string.Empty, StringComparer.OrdinalIgnoreCase)) .Select(i => i.Replace(directory, string.Empty, StringComparison.OrdinalIgnoreCase).Replace("\\", "/").TrimStart('/') + "?v=" + _appHost.ApplicationVersion.ToString()) .ToList(); - - return ResultFactory.GetOptimizedResult(Request, _jsonSerializer.SerializeToString(allFiles)); } /// @@ -332,12 +337,9 @@ namespace MediaBrowser.WebDashboard.Api var appVersion = _appHost.ApplicationVersion.ToString(); - var mode = request.Mode; + File.WriteAllText(Path.Combine(path, "staticfiles"), _jsonSerializer.SerializeToString(GetCacheFileList())); - if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) - { - _fileSystem.DeleteFile(Path.Combine(path, "scripts", "registrationservices.js")); - } + var mode = request.Mode; // Try to trim the output size a bit var bowerPath = Path.Combine(path, "bower_components"); diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 4913faab35..c5af1cee7b 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -431,7 +431,7 @@ namespace MediaBrowser.WebDashboard.Api var files = new List(); - files.Add("bower_components/requirejs/require.js"); + files.Add("bower_components/requirejs/require.js" + versionString); files.Add("scripts/site.js" + versionString); From b399ce8dbc8def3c99ab7489af2856db49e4b088 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Aug 2016 18:41:25 -0400 Subject: [PATCH 14/85] rework series timer page --- MediaBrowser.Dlna/DlnaManager.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 931cc208f5..a01d73451e 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -73,8 +73,13 @@ namespace MediaBrowser.Dlna lock (_profiles) { var list = _profiles.Values.ToList(); - return list.Select(i => i.Item2).OrderBy(i => i.Name); + return list + .OrderBy(i => i.Item1.Info.Type == DeviceProfileType.User ? 0 : 1) + .ThenBy(i => i.Item1.Info.Name) + .Select(i => i.Item2) + .ToList(); } + } public DeviceProfile GetDefaultProfile() From 36542d3cc1a14a6b723640f917ef11af2f4d8454 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Aug 2016 18:43:31 -0400 Subject: [PATCH 15/85] 3.1.99 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 82411e4964..4c5b645407 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.98")] +[assembly: AssemblyVersion("3.1.99")] From 75513170751d0213fc0e6c9121c383f83c14ed06 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 12 Aug 2016 11:54:37 -0400 Subject: [PATCH 16/85] update sync menus --- .../Library/Validators/PeopleValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs index 191c7ef282..d90b9615ba 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators var item = _libraryManager.GetPerson(person.Key); var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview); - var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 60; + var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30; var defaultMetadataRefreshMode = performFullRefresh ? MetadataRefreshMode.FullRefresh From d9ee4f81fdd161af7bd27f5dba420341e266262d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 12 Aug 2016 15:11:45 -0400 Subject: [PATCH 17/85] rework storage of PresentationUniqueKey --- .../Entities/Audio/MusicArtist.cs | 8 ++--- .../Entities/Audio/MusicGenre.cs | 8 ++--- MediaBrowser.Controller/Entities/BaseItem.cs | 13 ++++++-- MediaBrowser.Controller/Entities/GameGenre.cs | 7 ++-- MediaBrowser.Controller/Entities/Genre.cs | 8 ++--- MediaBrowser.Controller/Entities/Person.cs | 8 ++--- MediaBrowser.Controller/Entities/Studio.cs | 8 ++--- MediaBrowser.Controller/Entities/TV/Season.cs | 18 ++++------ MediaBrowser.Controller/Entities/TV/Series.cs | 33 ++++++++++++------- .../Entities/UserViewBuilder.cs | 2 +- MediaBrowser.Controller/Entities/Video.cs | 14 +++----- .../Persistence/SqliteItemRepository.cs | 11 +++++-- .../TV/TVSeriesManager.cs | 2 +- 13 files changed, 67 insertions(+), 73 deletions(-) diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 6790a1bcf1..56f9a5b888 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -169,13 +169,9 @@ namespace MediaBrowser.Controller.Entities.Audio list.Add("Artist-" + (item.Name ?? string.Empty).RemoveDiacritics()); return list; } - - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - return "Artist-" + (Name ?? string.Empty).RemoveDiacritics(); - } + return "Artist-" + (Name ?? string.Empty).RemoveDiacritics(); } protected override bool GetBlockUnratedValue(UserPolicy config) { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 798bc79fbb..9aa5625fac 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -18,13 +18,9 @@ namespace MediaBrowser.Controller.Entities.Audio list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } - - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - return GetUserDataKeys()[0]; - } + return GetUserDataKeys()[0]; } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 8d00f38beb..1d623c3acc 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1194,10 +1194,17 @@ namespace MediaBrowser.Controller.Entities get { return null; } } - [IgnoreDataMember] - public virtual string PresentationUniqueKey + public virtual string CreatePresentationUniqueKey() { - get { return Id.ToString("N"); } + return Id.ToString("N"); + } + + [IgnoreDataMember] + public string PresentationUniqueKey { get; set; } + + public string GetPresentationUniqueKey() + { + return PresentationUniqueKey ?? CreatePresentationUniqueKey(); } public virtual bool RequiresRefresh() diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 45e766c0f0..5d66bf3abc 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -16,12 +16,9 @@ namespace MediaBrowser.Controller.Entities return list; } - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - return GetUserDataKeys()[0]; - } + return GetUserDataKeys()[0]; } /// diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index cc5aebb2a4..c7fe25a962 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -19,13 +19,9 @@ namespace MediaBrowser.Controller.Entities list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } - - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - return GetUserDataKeys()[0]; - } + return GetUserDataKeys()[0]; } /// diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 8ef0d70bf9..4ee140b2b1 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -26,13 +26,9 @@ namespace MediaBrowser.Controller.Entities list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } - - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - return GetUserDataKeys()[0]; - } + return GetUserDataKeys()[0]; } public PersonLookupInfo GetLookupInfo() diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 762798b553..7e3d6fe8e1 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -18,13 +18,9 @@ namespace MediaBrowser.Controller.Entities list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } - - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - return GetUserDataKeys()[0]; - } + return GetUserDataKeys()[0]; } /// diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index f6ca19005b..c64de399f2 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -114,22 +114,18 @@ namespace MediaBrowser.Controller.Entities.TV } } - [IgnoreDataMember] - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get + if (IndexNumber.HasValue) { - if (IndexNumber.HasValue) + var series = Series; + if (series != null) { - var series = Series; - if (series != null) - { - return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000"); - } + return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000"); } - - return base.PresentationUniqueKey; } + + return base.CreatePresentationUniqueKey(); } /// diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index ad35b3d369..3297c2c6a6 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -96,19 +96,30 @@ namespace MediaBrowser.Controller.Entities.TV } } - [IgnoreDataMember] - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get - { - var userdatakeys = GetUserDataKeys(); + var userdatakeys = GetUserDataKeys(); - if (userdatakeys.Count > 1) - { - return userdatakeys[0]; - } - return base.PresentationUniqueKey; + if (userdatakeys.Count > 1) + { + return AddLibrariesToPresentationUniqueKey(userdatakeys[0]); } + return base.CreatePresentationUniqueKey(); + } + + private string AddLibrariesToPresentationUniqueKey(string key) + { + return key; + //var folders = LibraryManager.GetCollectionFolders(this) + // .Select(i => i.Id.ToString("N")) + // .ToArray(); + + //if (folders.Length == 0) + //{ + // return key; + //} + + //return key + "-" + string.Join("-", folders); } private static string GetUniqueSeriesKey(BaseItem series) @@ -117,7 +128,7 @@ namespace MediaBrowser.Controller.Entities.TV { return series.Id.ToString("N"); } - return series.PresentationUniqueKey; + return series.GetPresentationUniqueKey(); } public override int GetChildCount(User user) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 11ed269317..d0f7efa8c8 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1198,7 +1198,7 @@ namespace MediaBrowser.Controller.Entities { var user = query.User; - items = items.DistinctBy(i => i.PresentationUniqueKey, StringComparer.OrdinalIgnoreCase); + items = items.DistinctBy(i => i.GetPresentationUniqueKey(), StringComparer.OrdinalIgnoreCase); if (query.SortBy.Length > 0) { diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index eba1e466a2..7110b76cc6 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -44,18 +44,14 @@ namespace MediaBrowser.Controller.Entities } } - [IgnoreDataMember] - public override string PresentationUniqueKey + public override string CreatePresentationUniqueKey() { - get + if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) { - if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) - { - return PrimaryVersionId; - } - - return base.PresentationUniqueKey; + return PrimaryVersionId; } + + return base.CreatePresentationUniqueKey(); } [IgnoreDataMember] diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 0836560fc2..c01261d738 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -412,7 +412,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "SeasonName", "SeasonId", "SeriesId", - "SeriesSortName" + "SeriesSortName", + "PresentationUniqueKey" }; private readonly string[] _mediaStreamSaveColumns = @@ -918,7 +919,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = GetCleanValue(item.Name); } - _saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey; + _saveItemCommand.GetParameter(index++).Value = item.GetPresentationUniqueKey(); _saveItemCommand.GetParameter(index++).Value = item.SlugName; _saveItemCommand.GetParameter(index++).Value = item.OriginalTitle; @@ -1454,6 +1455,12 @@ namespace MediaBrowser.Server.Implementations.Persistence } index++; + if (!reader.IsDBNull(index)) + { + item.PresentationUniqueKey = reader.GetString(index); + } + index++; + return item; } diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs index ddc1de9cdb..03e8a9178e 100644 --- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs +++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs @@ -152,7 +152,7 @@ namespace MediaBrowser.Server.Implementations.TV { return series.Id.ToString("N"); } - return series.PresentationUniqueKey; + return series.GetPresentationUniqueKey(); } /// From e0e6c98e43047caa3869dd8bf69204c9ee8f4d7e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 12 Aug 2016 15:30:04 -0400 Subject: [PATCH 18/85] limit series pooling to common libraries --- .../Entities/IHasMetadata.cs | 8 ++++++- MediaBrowser.Controller/Entities/TV/Series.cs | 17 +++++++-------- .../Manager/MetadataService.cs | 7 +++++++ .../TV/SeasonMetadataService.cs | 21 ++++++------------- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 378c4a390b..c7a3c7778e 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Entities /// /// The date last refreshed. DateTime DateLastRefreshed { get; set; } - + /// /// This is called before any metadata refresh and returns true or false indicating if changes were made /// @@ -53,5 +53,11 @@ namespace MediaBrowser.Controller.Entities bool RequiresRefresh(); bool EnableForceSaveOnDateModifiedChange { get; } + + string PresentationUniqueKey { get; set; } + + string GetPresentationUniqueKey(); + string CreatePresentationUniqueKey(); + } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 3297c2c6a6..f01eddcebb 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -109,17 +109,16 @@ namespace MediaBrowser.Controller.Entities.TV private string AddLibrariesToPresentationUniqueKey(string key) { - return key; - //var folders = LibraryManager.GetCollectionFolders(this) - // .Select(i => i.Id.ToString("N")) - // .ToArray(); + var folders = LibraryManager.GetCollectionFolders(this) + .Select(i => i.Id.ToString("N")) + .ToArray(); - //if (folders.Length == 0) - //{ - // return key; - //} + if (folders.Length == 0) + { + return key; + } - //return key + "-" + string.Join("-", folders); + return key + "-" + string.Join("-", folders); } private static string GetUniqueSeriesKey(BaseItem series) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index ac942d1a76..0a70a2cc43 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -284,6 +284,13 @@ namespace MediaBrowser.Providers.Manager updateType |= SaveCumulativeRunTimeTicks(item, isFullRefresh, currentUpdateType); updateType |= SaveDateLastMediaAdded(item, isFullRefresh, currentUpdateType); + var presentationUniqueKey = item.CreatePresentationUniqueKey(); + if (!string.Equals(item.PresentationUniqueKey, presentationUniqueKey, StringComparison.Ordinal)) + { + item.PresentationUniqueKey = presentationUniqueKey; + updateType |= ItemUpdateType.MetadataImport; + } + return updateType; } diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs index addab3918e..cf04a14184 100644 --- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs @@ -35,26 +35,17 @@ namespace MediaBrowser.Providers.TV updateType |= SaveIsVirtualItem(item, episodes); } - if (updateType <= ItemUpdateType.None) + if (!string.Equals(item.SeriesName, item.FindSeriesName(), StringComparison.Ordinal)) { - if (!string.Equals(item.SeriesName, item.FindSeriesName(), StringComparison.Ordinal)) - { - updateType |= ItemUpdateType.MetadataImport; - } + updateType |= ItemUpdateType.MetadataImport; } - if (updateType <= ItemUpdateType.None) + if (!string.Equals(item.SeriesSortName, item.FindSeriesSortName(), StringComparison.Ordinal)) { - if (!string.Equals(item.SeriesSortName, item.FindSeriesSortName(), StringComparison.Ordinal)) - { - updateType |= ItemUpdateType.MetadataImport; - } + updateType |= ItemUpdateType.MetadataImport; } - if (updateType <= ItemUpdateType.None) + if (item.SeriesId != item.FindSeriesId()) { - if (item.SeriesId != item.FindSeriesId()) - { - updateType |= ItemUpdateType.MetadataImport; - } + updateType |= ItemUpdateType.MetadataImport; } return updateType; From 3878da49a5323902a77c997fe5a409bfbc125c1c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 12 Aug 2016 15:32:58 -0400 Subject: [PATCH 19/85] 3.1.100 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 4c5b645407..9d398aa90d 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.99")] +[assembly: AssemblyVersion("3.1.100")] From 93346830eb28c430477c6cdf6285bcbbea1f2f2a Mon Sep 17 00:00:00 2001 From: Softworkz Date: Sat, 13 Aug 2016 04:24:21 +0200 Subject: [PATCH 20/85] Fix incorrect calculation of content length --- .../Playback/Progressive/BaseProgressiveStreamingService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index d6dea0fe52..f4cc9f4bc6 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -383,7 +383,7 @@ namespace MediaBrowser.Api.Playback.Progressive if (totalBitrate > 0 && state.RunTimeTicks.HasValue) { - return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds); + return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds / 8); } return null; From 319dcda4beb5cde9cd858a33a9603f0cff54d831 Mon Sep 17 00:00:00 2001 From: Softworkz Date: Sat, 13 Aug 2016 06:57:21 +0200 Subject: [PATCH 21/85] Fix: ETag-Values MUST be quoted according to W3C spec --- .../HttpServer/HttpResultFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index c0a2a5eb35..194904320c 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -275,7 +275,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// System.Object. private object GetCachedResult(IRequest requestContext, IDictionary responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) { - responseHeaders["ETag"] = cacheKeyString; + responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString); if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) { From 68d1b609647d0a592afc7d994fad2dedcb135f6b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 13 Aug 2016 01:49:00 -0400 Subject: [PATCH 22/85] stub out objects for per library settings --- .../Library/LibraryStructureService.cs | 7 +- .../Playback/BaseStreamingService.cs | 6 +- .../Configuration/LibraryOptions.cs | 14 ++++ .../Entities/Audio/Audio.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 6 +- MediaBrowser.Controller/Entities/Book.cs | 2 +- .../Entities/CollectionFolder.cs | 60 ++++++++++++++ MediaBrowser.Controller/Entities/Folder.cs | 4 +- MediaBrowser.Controller/Entities/Game.cs | 2 +- .../Entities/IHasMetadata.cs | 2 +- .../Entities/Movies/BoxSet.cs | 13 ++++ MediaBrowser.Controller/Entities/Photo.cs | 2 +- MediaBrowser.Controller/Entities/Video.cs | 7 +- .../Library/ILibraryManager.cs | 18 +++-- .../Library/ItemResolveArgs.cs | 8 ++ .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Controller/Playlists/Playlist.cs | 6 ++ .../Configuration/ServerConfiguration.cs | 2 - .../Manager/MetadataService.cs | 2 +- .../MediaInfo/FFProbeProvider.cs | 2 +- .../MediaInfo/VideoImageProvider.cs | 9 ++- .../Library/LibraryManager.cs | 78 ++++++++++++++----- .../Library/Resolvers/Audio/AudioResolver.cs | 6 +- .../Resolvers/Audio/MusicAlbumResolver.cs | 30 +++---- .../Resolvers/Audio/MusicArtistResolver.cs | 2 +- .../Library/Resolvers/BaseVideoResolver.cs | 2 +- .../Library/Resolvers/PhotoResolver.cs | 7 +- .../Library/Resolvers/TV/SeriesResolver.cs | 6 +- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../Persistence/SqliteItemRepository.cs | 2 +- .../Playlists/ManualPlaylistsFolder.cs | 2 +- .../ApplicationHost.cs | 1 + 32 files changed, 234 insertions(+), 79 deletions(-) create mode 100644 MediaBrowser.Controller/Configuration/LibraryOptions.cs diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 3cf0d5d937..3af2134937 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.Configuration; namespace MediaBrowser.Api.Library { @@ -52,6 +53,8 @@ namespace MediaBrowser.Api.Library /// /// The path. public string[] Paths { get; set; } + + public LibraryOptions LibraryOptions { get; set; } } [Route("/Library/VirtualFolders", "DELETE")] @@ -190,7 +193,9 @@ namespace MediaBrowser.Api.Library /// The request. public void Post(AddVirtualFolder request) { - _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, request.RefreshLibrary); + var libraryOptions = request.LibraryOptions ?? new LibraryOptions(); + + _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, libraryOptions, request.RefreshLibrary); } /// diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 59dfd87ecd..a9489cecce 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1055,14 +1055,14 @@ namespace MediaBrowser.Api.Playback var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; Logger.Info(commandLineLogMessage); - var logFilePrefix = "transcode"; + var logFilePrefix = "ffmpeg-transcode"; if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - logFilePrefix = "directstream"; + logFilePrefix = "ffmpeg-directstream"; } else if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - logFilePrefix = "remux"; + logFilePrefix = "ffmpeg-remux"; } var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); diff --git a/MediaBrowser.Controller/Configuration/LibraryOptions.cs b/MediaBrowser.Controller/Configuration/LibraryOptions.cs new file mode 100644 index 0000000000..1a824c08bf --- /dev/null +++ b/MediaBrowser.Controller/Configuration/LibraryOptions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Configuration +{ + public class LibraryOptions + { + public bool EnableAudioArchiveFiles { get; set; } + public bool EnableVideoArchiveFiles { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 1897511af7..6326bbd4f4 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.Controller.Entities.Audio } [IgnoreDataMember] - public override bool EnableForceSaveOnDateModifiedChange + public override bool EnableRefreshOnDateModifiedChange { get { return true; } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 1d623c3acc..cc3646cdcb 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -455,7 +455,7 @@ namespace MediaBrowser.Controller.Entities public DateTime DateLastRefreshed { get; set; } [IgnoreDataMember] - public virtual bool EnableForceSaveOnDateModifiedChange + public virtual bool EnableRefreshOnDateModifiedChange { get { return false; } } @@ -951,7 +951,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => !i.IsDirectory && string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase)) ); - return LibraryManager.ResolvePaths(files, directoryService, null) + return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions()) .OfType() .Select(audio => { @@ -981,7 +981,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) .SelectMany(i => directoryService.GetFiles(i.FullName)); - return LibraryManager.ResolvePaths(files, directoryService, null) + return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions()) .OfType public class CollectionFolder : Folder, ICollectionFolder { + public static IXmlSerializer XmlSerializer { get; set; } + public CollectionFolder() { PhysicalLocationsList = new List(); @@ -39,6 +44,61 @@ namespace MediaBrowser.Controller.Entities public string CollectionType { get; set; } + private readonly Dictionary _libraryOptions = new Dictionary(); + public LibraryOptions GetLibraryOptions() + { + lock (_libraryOptions) + { + LibraryOptions options; + if (!_libraryOptions.TryGetValue(Path, out options)) + { + options = LoadLibraryOptions(); + _libraryOptions[Path] = options; + } + + return options; + } + } + + private LibraryOptions LoadLibraryOptions() + { + try + { + var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(Path)) as LibraryOptions; + + if (result == null) + { + return new LibraryOptions(); + } + + return result; + } + catch (FileNotFoundException) + { + return new LibraryOptions(); + } + catch (DirectoryNotFoundException) + { + return new LibraryOptions(); + } + catch (Exception ex) + { + Logger.ErrorException("Error loading library options", ex); + + return new LibraryOptions(); + } + } + + private static string GetLibraryOptionsPath(string path) + { + return System.IO.Path.Combine(path, "options.xml"); + } + + public static void SaveLibraryOptions(string path, LibraryOptions options) + { + XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path)); + } + /// /// Allow different display preferences for each collection folder /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index c1728ce389..bf04c643ce 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -273,6 +273,7 @@ namespace MediaBrowser.Controller.Entities /// protected virtual IEnumerable LoadChildren() { + //Logger.Debug("Loading children from {0} {1}", Id, Path); //just load our children from the repo - the library will be validated and maintained in other processes return GetCachedChildren(); } @@ -643,8 +644,9 @@ namespace MediaBrowser.Controller.Entities protected virtual IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { var collectionType = LibraryManager.GetContentType(this); + var libraryOptions = LibraryManager.GetLibraryOptions(this); - return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, collectionType); + return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, libraryOptions, collectionType); } /// diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index 54386a1795..24910498f5 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Entities } [IgnoreDataMember] - public override bool EnableForceSaveOnDateModifiedChange + public override bool EnableRefreshOnDateModifiedChange { get { return true; } } diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index c7a3c7778e..d5891c6552 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Entities bool RequiresRefresh(); - bool EnableForceSaveOnDateModifiedChange { get; } + bool EnableRefreshOnDateModifiedChange { get; } string PresentationUniqueKey { get; set; } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 4effc162e4..ba50a1e0de 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -62,6 +62,19 @@ namespace MediaBrowser.Controller.Entities.Movies return UnratedItem.Movie; } + protected override IEnumerable LoadChildren() + { + var first = LinkedChildren.FirstOrDefault(); + + if (first != null && first.Type == LinkedChildType.Shortcut) + { + return base.LoadChildren(); + } + + // Save a trip to the database + return new List(); + } + [IgnoreDataMember] public override bool IsPreSorted { diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 804ea04a59..965616eb53 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Entities } [IgnoreDataMember] - public override bool EnableForceSaveOnDateModifiedChange + public override bool EnableRefreshOnDateModifiedChange { get { return true; } } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 7110b76cc6..830747d3c9 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -55,9 +55,12 @@ namespace MediaBrowser.Controller.Entities } [IgnoreDataMember] - public override bool EnableForceSaveOnDateModifiedChange + public override bool EnableRefreshOnDateModifiedChange { - get { return true; } + get + { + return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso; + } } public int? TotalBitrate { get; set; } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index ff7f2fe678..edbacb5e70 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.Library @@ -32,15 +33,11 @@ namespace MediaBrowser.Controller.Library /// /// Resolves a set of files into a list of BaseItem /// - /// The files. - /// The directory service. - /// The parent. - /// Type of the collection. - /// List{``0}. IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, - Folder parent, string - collectionType = null); + Folder parent, + LibraryOptions libraryOptions, + string collectionType = null); /// /// Gets the root folder. @@ -397,6 +394,9 @@ namespace MediaBrowser.Controller.Library /// true if [is audio file] [the specified path]; otherwise, false. bool IsAudioFile(string path); + bool IsAudioFile(string path, LibraryOptions libraryOptions); + bool IsVideoFile(string path, LibraryOptions libraryOptions); + /// /// Gets the season number from path. /// @@ -453,6 +453,8 @@ namespace MediaBrowser.Controller.Library /// IEnumerable<Folder>. IEnumerable GetCollectionFolders(BaseItem item); + LibraryOptions GetLibraryOptions(BaseItem item); + /// /// Gets the people. /// @@ -551,7 +553,7 @@ namespace MediaBrowser.Controller.Library /// true if XXXX, false otherwise. bool IgnoreFile(FileSystemMetadata file, BaseItem parent); - void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, bool refreshLibrary); + void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, LibraryOptions options, bool refreshLibrary); void RemoveVirtualFolder(string name, bool refreshLibrary); void AddMediaPath(string virtualFolderName, string path); void RemoveMediaPath(string virtualFolderName, string path); diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index ea3199b318..56ec0a2138 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using CommonIO; +using MediaBrowser.Controller.Configuration; namespace MediaBrowser.Controller.Library { @@ -51,6 +52,13 @@ namespace MediaBrowser.Controller.Library } } + public LibraryOptions LibraryOptions { get; set; } + + public LibraryOptions GetLibraryOptions() + { + return LibraryOptions ?? (LibraryOptions = (Parent == null ? new LibraryOptions() : BaseItem.LibraryManager.GetLibraryOptions(Parent))); + } + /// /// Gets or sets the file system dictionary. /// diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 0462117cb5..e621eafded 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -98,6 +98,7 @@ + diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 5ffe3d5daf..3e706f1fa7 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -58,6 +58,12 @@ namespace MediaBrowser.Controller.Playlists return true; } + protected override IEnumerable LoadChildren() + { + // Save a trip to the database + return new List(); + } + public override IEnumerable GetChildren(User user, bool includeLinkedChildren) { return GetPlayableItems(user).Result; diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 58b74ba64a..303ba1acf7 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -180,8 +180,6 @@ namespace MediaBrowser.Model.Configuration public NameValuePair[] ContentTypes { get; set; } - public bool EnableAudioArchiveFiles { get; set; } - public bool EnableVideoArchiveFiles { get; set; } public int RemoteClientBitrateLimit { get; set; } public AutoOnOff EnableLibraryMonitor { get; set; } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 0a70a2cc43..0483a74ed1 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -149,7 +149,7 @@ namespace MediaBrowser.Providers.Manager if (file != null) { var fileLastWriteTime = file.LastWriteTimeUtc; - if (item.EnableForceSaveOnDateModifiedChange && fileLastWriteTime != item.DateModified) + if (item.EnableRefreshOnDateModifiedChange && fileLastWriteTime != item.DateModified) { Logger.Debug("Date modified for {0}. Old date {1} new date {2} Id {3}", item.Path, item.DateModified, fileLastWriteTime, item.Id); requiresRefresh = true; diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index e36be54191..0df8b6c4b7 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -171,7 +171,7 @@ namespace MediaBrowser.Providers.MediaInfo public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) { - if (!string.IsNullOrWhiteSpace(item.Path)) + if (item.EnableRefreshOnDateModifiedChange && !string.IsNullOrWhiteSpace(item.Path)) { var file = directoryService.GetFile(item.Path); if (file != null && file.LastWriteTimeUtc != item.DateModified) diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index fb08f00c19..280e92beb9 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -194,10 +194,13 @@ namespace MediaBrowser.Providers.MediaInfo public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) { - var file = directoryService.GetFile(item.Path); - if (file != null && file.LastWriteTimeUtc != item.DateModified) + if (item.EnableRefreshOnDateModifiedChange) { - return true; + var file = directoryService.GetFile(item.Path); + if (file != null && file.LastWriteTimeUtc != item.DateModified) + { + return true; + } } return false; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 055fde504b..b00303f295 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -556,7 +556,12 @@ namespace MediaBrowser.Server.Implementations.Library return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent); } - private BaseItem ResolvePath(FileSystemMetadata fileInfo, IDirectoryService directoryService, IItemResolver[] resolvers, Folder parent = null, string collectionType = null) + private BaseItem ResolvePath(FileSystemMetadata fileInfo, + IDirectoryService directoryService, + IItemResolver[] resolvers, + Folder parent = null, + string collectionType = null, + LibraryOptions libraryOptions = null) { if (fileInfo == null) { @@ -575,7 +580,8 @@ namespace MediaBrowser.Server.Implementations.Library Parent = parent, Path = fullPath, FileInfo = fileInfo, - CollectionType = collectionType + CollectionType = collectionType, + LibraryOptions = libraryOptions }; // Return null if ignore rules deem that we should do so @@ -653,12 +659,17 @@ namespace MediaBrowser.Server.Implementations.Library return !args.ContainsFileSystemEntryByName(".ignore"); } - public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType) + public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType) { - return ResolvePaths(files, directoryService, parent, collectionType, EntityResolvers); + return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers); } - public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType, IItemResolver[] resolvers) + public IEnumerable ResolvePaths(IEnumerable files, + IDirectoryService directoryService, + Folder parent, + LibraryOptions libraryOptions, + string collectionType, + IItemResolver[] resolvers) { var fileList = files.Where(i => !IgnoreFile(i, parent)).ToList(); @@ -679,22 +690,27 @@ namespace MediaBrowser.Server.Implementations.Library { ResolverHelper.SetInitialItemValues(item, parent, _fileSystem, this, directoryService); } - items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers)); + items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers, libraryOptions)); return items; } } } - return ResolveFileList(fileList, directoryService, parent, collectionType, resolvers); + return ResolveFileList(fileList, directoryService, parent, collectionType, resolvers, libraryOptions); } - private IEnumerable ResolveFileList(IEnumerable fileList, IDirectoryService directoryService, Folder parent, string collectionType, IItemResolver[] resolvers) + private IEnumerable ResolveFileList(IEnumerable fileList, + IDirectoryService directoryService, + Folder parent, + string collectionType, + IItemResolver[] resolvers, + LibraryOptions libraryOptions) { return fileList.Select(f => { try { - return ResolvePath(f, directoryService, resolvers, parent, collectionType); + return ResolvePath(f, directoryService, resolvers, parent, collectionType, libraryOptions); } catch (Exception ex) { @@ -1891,6 +1907,15 @@ namespace MediaBrowser.Server.Implementations.Library .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path, StringComparer.OrdinalIgnoreCase)); } + public LibraryOptions GetLibraryOptions(BaseItem item) + { + var collectionFolder = GetCollectionFolders(item) + .OfType() + .FirstOrDefault(); + + return collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions(); + } + public string GetContentType(BaseItem item) { string configuredContentType = GetConfiguredContentType(item, false); @@ -2242,16 +2267,26 @@ namespace MediaBrowser.Server.Implementations.Library return item; } + public bool IsVideoFile(string path, LibraryOptions libraryOptions) + { + var resolver = new VideoResolver(GetNamingOptions(libraryOptions), new PatternsLogger()); + return resolver.IsVideoFile(path); + } + public bool IsVideoFile(string path) { - var resolver = new VideoResolver(GetNamingOptions(), new PatternsLogger()); - return resolver.IsVideoFile(path); + return IsVideoFile(path, new LibraryOptions()); + } + + public bool IsAudioFile(string path, LibraryOptions libraryOptions) + { + var parser = new AudioFileParser(GetNamingOptions(libraryOptions)); + return parser.IsAudioFile(path); } public bool IsAudioFile(string path) { - var parser = new AudioFileParser(GetNamingOptions()); - return parser.IsAudioFile(path); + return IsAudioFile(path, new LibraryOptions()); } public int? GetSeasonNumberFromPath(string path) @@ -2379,6 +2414,11 @@ namespace MediaBrowser.Server.Implementations.Library } public NamingOptions GetNamingOptions() + { + return GetNamingOptions(new LibraryOptions()); + } + + public NamingOptions GetNamingOptions(LibraryOptions libraryOptions) { var options = new ExtendedNamingOptions(); @@ -2386,13 +2426,13 @@ namespace MediaBrowser.Server.Implementations.Library options.AudioFileExtensions.Remove(".m3u"); options.AudioFileExtensions.Remove(".wpl"); - if (!ConfigurationManager.Configuration.EnableAudioArchiveFiles) + if (!libraryOptions.EnableAudioArchiveFiles) { options.AudioFileExtensions.Remove(".rar"); options.AudioFileExtensions.Remove(".zip"); } - if (!ConfigurationManager.Configuration.EnableVideoArchiveFiles) + if (!libraryOptions.EnableVideoArchiveFiles) { options.VideoFileExtensions.Remove(".rar"); options.VideoFileExtensions.Remove(".zip"); @@ -2443,7 +2483,7 @@ namespace MediaBrowser.Server.Implementations.Library new GenericVideoResolver(this) }; - return ResolvePaths(files, directoryService, null, null, resolvers) + return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers) .OfType() .Select(video => { @@ -2487,7 +2527,7 @@ namespace MediaBrowser.Server.Implementations.Library files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path))); } - return ResolvePaths(files, directoryService, null, null) + return ResolvePaths(files, directoryService, null, new LibraryOptions(), null) .OfType /// The game count. public int GameCount { get; set; } + public int ArtistCount { get; set; } /// /// Gets or sets the game system count. /// diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index 1161ab005f..d8ec04ff64 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MediaBrowser.Model.Configuration; namespace MediaBrowser.Model.Entities { @@ -25,6 +26,8 @@ namespace MediaBrowser.Model.Entities /// The type of the collection. public string CollectionType { get; set; } + public LibraryOptions LibraryOptions { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index e3c1e52a53..db70b86063 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -95,6 +95,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index cc165da6a7..4f903a2c28 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -408,12 +408,19 @@ namespace MediaBrowser.Server.Implementations.Dto private void SetItemByNameInfo(BaseItem item, BaseItemDto dto, List taggedItems, User user = null) { - if (item is MusicArtist || item is MusicGenre) + if (item is MusicArtist) { dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum); dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo); dto.SongCount = taggedItems.Count(i => i is Audio); } + else if (item is MusicGenre) + { + dto.ArtistCount = taggedItems.Count(i => i is MusicArtist); + dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum); + dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo); + dto.SongCount = taggedItems.Count(i => i is Audio); + } else if (item is GameGenre) { dto.GameCount = taggedItems.Count(i => i is Game); @@ -422,6 +429,7 @@ namespace MediaBrowser.Server.Implementations.Dto { // This populates them all and covers Genre, Person, Studio, Year + dto.ArtistCount = taggedItems.Count(i => i is MusicArtist); dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum); dto.EpisodeCount = taggedItems.Count(i => i is Episode); dto.GameCount = taggedItems.Count(i => i is Game); diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index b00303f295..52961668d0 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1223,7 +1223,7 @@ namespace MediaBrowser.Server.Implementations.Library .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders)); } - private VirtualFolderInfo GetVirtualFolderInfo(string dir, List collectionFolders) + private VirtualFolderInfo GetVirtualFolderInfo(string dir, List allCollectionFolders) { var info = new VirtualFolderInfo { @@ -1237,7 +1237,7 @@ namespace MediaBrowser.Server.Implementations.Library CollectionType = GetCollectionType(dir) }; - var libraryFolder = collectionFolders.FirstOrDefault(i => string.Equals(i.Path, dir, StringComparison.OrdinalIgnoreCase)); + var libraryFolder = allCollectionFolders.FirstOrDefault(i => string.Equals(i.Path, dir, StringComparison.OrdinalIgnoreCase)); if (libraryFolder != null && libraryFolder.HasImage(ImageType.Primary)) { @@ -1249,6 +1249,12 @@ namespace MediaBrowser.Server.Implementations.Library info.ItemId = libraryFolder.Id.ToString("N"); } + var collectionFolder = libraryFolder as CollectionFolder; + if (collectionFolder != null) + { + info.LibraryOptions = collectionFolder.GetLibraryOptions(); + } + return info; } @@ -2426,13 +2432,13 @@ namespace MediaBrowser.Server.Implementations.Library options.AudioFileExtensions.Remove(".m3u"); options.AudioFileExtensions.Remove(".wpl"); - if (!libraryOptions.EnableAudioArchiveFiles) + if (!libraryOptions.EnableArchiveMediaFiles) { options.AudioFileExtensions.Remove(".rar"); options.AudioFileExtensions.Remove(".zip"); } - if (!libraryOptions.EnableVideoArchiveFiles) + if (!libraryOptions.EnableArchiveMediaFiles) { options.VideoFileExtensions.Remove(".rar"); options.VideoFileExtensions.Remove(".zip"); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 546f64d3c3..1a8295800f 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.IO; using CommonIO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Configuration; namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 09a9a3b4e9..78df465b13 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using CommonIO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Configuration; namespace MediaBrowser.Server.Implementations.Library.Resolvers { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index f1bbc1f327..aefb29f1a6 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using CommonIO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Configuration; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 4c9b2a4d97..3d8e7a3d6d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -28,6 +28,7 @@ using CommonIO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Power; +using MediaBrowser.Model.Configuration; using Microsoft.Win32; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index bbb36b46e1..0e36ede7ac 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -3975,7 +3975,8 @@ namespace MediaBrowser.Server.Implementations.Persistence AlbumArtistStartsWithOrGreater = query.AlbumArtistStartsWithOrGreater, Tags = query.Tags, OfficialRatings = query.OfficialRatings, - Genres = query.GenreIds, + GenreIds = query.GenreIds, + Genres = query.Genres, Years = query.Years }; @@ -4128,6 +4129,10 @@ namespace MediaBrowser.Server.Implementations.Persistence { counts.AlbumCount = value; } + else if (string.Equals(typeName, typeof(MusicArtist).FullName, StringComparison.OrdinalIgnoreCase)) + { + counts.ArtistCount = value; + } else if (string.Equals(typeName, typeof(Audio).FullName, StringComparison.OrdinalIgnoreCase)) { counts.SongCount = value; From 49255561fb4aab64bdf353de80ea444139af5055 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 13 Aug 2016 16:58:44 -0400 Subject: [PATCH 28/85] 3.1.102 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index e6e05a04bc..0143c3b13e 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.101")] +[assembly: AssemblyVersion("3.1.102")] From 6e9828ddadd6a86e8422d863afecc8a2fb4a88a6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 13 Aug 2016 18:27:14 -0400 Subject: [PATCH 29/85] add remuxing permission --- MediaBrowser.Api/Playback/MediaInfoService.cs | 14 ++++++++++++++ MediaBrowser.Model/Dlna/ResolutionNormalizer.cs | 5 +++-- MediaBrowser.Model/Users/UserPolicy.cs | 2 ++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 0b989784c0..91e62b4e32 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -284,6 +284,13 @@ namespace MediaBrowser.Api.Playback options.ForceDirectPlay = true; } } + else if (item is Video) + { + if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing) + { + options.ForceDirectPlay = true; + } + } // The MediaSource supports direct stream, now test to see if the client supports it var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ? @@ -315,6 +322,13 @@ namespace MediaBrowser.Api.Playback options.ForceDirectStream = true; } } + else if (item is Video) + { + if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing) + { + options.ForceDirectStream = true; + } + } // The MediaSource supports direct stream, now test to see if the client supports it var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ? diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs index ed18fed655..fb353b016b 100644 --- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs +++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Model.Dlna { @@ -59,8 +60,8 @@ namespace MediaBrowser.Model.Dlna private static double GetVideoBitrateScaleFactor(string codec) { - if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || - string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) + if (StringHelper.EqualsIgnoreCase(codec, "h265") || + StringHelper.EqualsIgnoreCase(codec, "hevc")) { return .5; } diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 16b4b673d9..3917b1662d 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -41,6 +41,7 @@ namespace MediaBrowser.Model.Users public bool EnableMediaPlayback { get; set; } public bool EnableAudioPlaybackTranscoding { get; set; } public bool EnableVideoPlaybackTranscoding { get; set; } + public bool EnablePlaybackRemuxing { get; set; } public bool EnableContentDeletion { get; set; } public bool EnableContentDownloading { get; set; } @@ -76,6 +77,7 @@ namespace MediaBrowser.Model.Users EnableMediaPlayback = true; EnableAudioPlaybackTranscoding = true; EnableVideoPlaybackTranscoding = true; + EnablePlaybackRemuxing = true; EnableLiveTvManagement = true; EnableLiveTvAccess = true; From 7dbeeadea6edff204276bf87c03c85886d0ff321 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 13 Aug 2016 20:52:32 -0400 Subject: [PATCH 30/85] fix lastmodified header --- .../HttpServer/HttpResultFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index 194904320c..27065d0f5c 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -534,7 +534,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (lastDateModified.HasValue && (string.IsNullOrEmpty(cacheKey) || cacheDuration.HasValue)) { AddAgeHeader(responseHeaders, lastDateModified); - responseHeaders["LastModified"] = lastDateModified.Value.ToString("r"); + responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); } if (cacheDuration.HasValue) From 89dd4f0be1721ef8f8357051cafea2703ab38b2e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 13 Aug 2016 23:12:26 -0400 Subject: [PATCH 31/85] save library options on dialog close --- .../Library/LibraryStructureService.cs | 24 +++++++++++++++---- .../Entities/CollectionFolder.cs | 12 +++++++++- .../Entities/Movies/BoxSet.cs | 3 +-- .../Collections/CollectionsDynamicFolder.cs | 2 +- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index dd3c7211a4..72966a7cdc 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using CommonIO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; namespace MediaBrowser.Api.Library @@ -140,6 +141,14 @@ namespace MediaBrowser.Api.Library public bool RefreshLibrary { get; set; } } + [Route("/Library/VirtualFolders/LibraryOptions", "POST")] + public class UpdateLibraryOptions : IReturnVoid + { + public string Id { get; set; } + + public LibraryOptions LibraryOptions { get; set; } + } + /// /// Class LibraryStructureService /// @@ -188,6 +197,13 @@ namespace MediaBrowser.Api.Library return ToOptimizedSerializedResultUsingCache(result); } + public void Post(UpdateLibraryOptions request) + { + var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(request.Id); + + collectionFolder.UpdateLibraryOptions(request.LibraryOptions); + } + /// /// Posts the specified request. /// @@ -220,12 +236,12 @@ namespace MediaBrowser.Api.Library var currentPath = Path.Combine(rootFolderPath, request.Name); var newPath = Path.Combine(rootFolderPath, request.NewName); - if (!_fileSystem.DirectoryExists(currentPath)) + if (!_fileSystem.DirectoryExists(currentPath)) { throw new DirectoryNotFoundException("The media collection does not exist"); } - if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath)) + if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath)) { throw new ArgumentException("There is already a media collection with the name " + newPath + "."); } @@ -240,11 +256,11 @@ namespace MediaBrowser.Api.Library //Create an unique name var temporaryName = Guid.NewGuid().ToString(); var temporaryPath = Path.Combine(rootFolderPath, temporaryName); - _fileSystem.MoveDirectory(currentPath, temporaryPath); + _fileSystem.MoveDirectory(currentPath, temporaryPath); currentPath = temporaryPath; } - _fileSystem.MoveDirectory(currentPath, newPath); + _fileSystem.MoveDirectory(currentPath, newPath); } finally { diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index b81f021da9..e120f2e23d 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -95,9 +95,19 @@ namespace MediaBrowser.Controller.Entities return System.IO.Path.Combine(path, "options.xml"); } + public void UpdateLibraryOptions(LibraryOptions options) + { + SaveLibraryOptions(Path, options); + } + public static void SaveLibraryOptions(string path, LibraryOptions options) { - XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path)); + lock (LibraryOptions) + { + LibraryOptions[path] = options; + + XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path)); + } } /// diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 742ade2009..caf440a83f 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -110,8 +110,7 @@ namespace MediaBrowser.Controller.Entities.Movies { get { - // TODO - return false; + return !FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, Path); } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs index cb95bfd147..6cd9e96205 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Server.Implementations.Collections public class CollectionsDynamicFolder : IVirtualFolderCreator { private readonly IApplicationPaths _appPaths; - private IFileSystem _fileSystem; + private readonly IFileSystem _fileSystem; public CollectionsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem) { From a9e65b93cccd0705aa3a3802c86dda09b9b38401 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 02:29:49 -0400 Subject: [PATCH 32/85] 3.1.103 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 0143c3b13e..bf039f0225 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.102")] +[assembly: AssemblyVersion("3.1.103")] From fb779d89d22bfe0c2930d277d817956e956db30c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 02:41:53 -0400 Subject: [PATCH 33/85] update translations --- .../MediaBrowser.WebDashboard.csproj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index f1b234b903..9b51fd489c 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -116,6 +116,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -1557,6 +1563,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 325a3cc844e338dfac2dd136aa49c05ad9517388 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 12:39:23 -0400 Subject: [PATCH 34/85] cache ids in UserRootFolder --- .../Entities/UserRootFolder.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index a62c67c4fe..d043cba47f 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -18,20 +18,20 @@ namespace MediaBrowser.Controller.Entities { private List _childrenIds = null; private readonly object _childIdsLock = new object(); - //protected override IEnumerable LoadChildren() - //{ - // lock (_childIdsLock) - // { - // if (_childrenIds == null) - // { - // var list = base.LoadChildren().ToList(); - // _childrenIds = list.Select(i => i.Id).ToList(); - // return list; - // } + protected override IEnumerable LoadChildren() + { + lock (_childIdsLock) + { + if (_childrenIds == null) + { + var list = base.LoadChildren().ToList(); + _childrenIds = list.Select(i => i.Id).ToList(); + return list; + } - // return _childrenIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList(); - // } - //} + return _childrenIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList(); + } + } private void ResetCachedChildren() { From 4a63f24ae785bf972c284d18598fb1198359b5d6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 16:02:02 -0400 Subject: [PATCH 35/85] 3.1.104 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index bf039f0225..d31177a374 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.103")] +[assembly: AssemblyVersion("3.1.104")] From 1adcfaadef7436a4ec6252927bffd477415d7145 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 17:29:35 -0400 Subject: [PATCH 36/85] refresh people on demand, when needed --- .../UserLibrary/UserLibraryService.cs | 39 ++++++++++++++++++- MediaBrowser.Controller/Entities/BaseItem.cs | 9 +++++ .../Entities/IHasMetadata.cs | 2 +- .../Entities/Movies/Movie.cs | 10 +++++ MediaBrowser.Controller/Entities/TV/Series.cs | 10 +++++ MediaBrowser.Controller/Entities/Trailer.cs | 10 +++++ .../Manager/MetadataService.cs | 2 +- 7 files changed, 78 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 3be11bdc56..eba17e7763 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -12,6 +12,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using CommonIO; +using MediaBrowser.Controller.Providers; namespace MediaBrowser.Api.UserLibrary { @@ -262,14 +264,16 @@ namespace MediaBrowser.Api.UserLibrary private readonly ILibraryManager _libraryManager; private readonly IDtoService _dtoService; private readonly IUserViewManager _userViewManager; + private readonly IFileSystem _fileSystem; - public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, IUserViewManager userViewManager) + public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, IUserViewManager userViewManager, IFileSystem fileSystem) { _userManager = userManager; _libraryManager = libraryManager; _userDataRepository = userDataRepository; _dtoService = dtoService; _userViewManager = userViewManager; + _fileSystem = fileSystem; } /// @@ -426,12 +430,14 @@ namespace MediaBrowser.Api.UserLibrary /// /// The request. /// System.Object. - public object Get(GetItem request) + public async Task Get(GetItem request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id); + await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false); + var dtoOptions = GetDtoOptions(request); var result = _dtoService.GetBaseItemDto(item, dtoOptions, user); @@ -439,6 +445,35 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedSerializedResultUsingCache(result); } + private async Task RefreshItemOnDemandIfNeeded(BaseItem item) + { + if (item is Person) + { + var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary); + var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 7; + + if (!hasMetdata) + { + var defaultMetadataRefreshMode = performFullRefresh + ? MetadataRefreshMode.FullRefresh + : MetadataRefreshMode.Default; + + var imageRefreshMode = performFullRefresh + ? ImageRefreshMode.FullRefresh + : ImageRefreshMode.Default; + + var options = new MetadataRefreshOptions(_fileSystem) + { + MetadataRefreshMode = defaultMetadataRefreshMode, + ImageRefreshMode = imageRefreshMode, + ForceSave = performFullRefresh + }; + + await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false); + } + } + } + /// /// Gets the specified request. /// diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cc3646cdcb..cbbb9a89a3 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2213,6 +2213,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual bool StopRefreshIfLocalMetadataFound + { + get + { + return true; + } + } + public virtual IEnumerable GetIdsForAncestorQuery() { return new[] { Id }; diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index d5891c6552..26f425ff0b 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -58,6 +58,6 @@ namespace MediaBrowser.Controller.Entities string GetPresentationUniqueKey(); string CreatePresentationUniqueKey(); - + bool StopRefreshIfLocalMetadataFound { get; } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index c7a833c58f..f0270497c0 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -179,5 +179,15 @@ namespace MediaBrowser.Controller.Entities.Movies return list; } + + [IgnoreDataMember] + public override bool StopRefreshIfLocalMetadataFound + { + get + { + // Need people id's from internet metadata + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index f01eddcebb..757c052bb4 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -519,5 +519,15 @@ namespace MediaBrowser.Controller.Entities.TV return list; } + + [IgnoreDataMember] + public override bool StopRefreshIfLocalMetadataFound + { + get + { + // Need people id's from internet metadata + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 6604be977d..306ce35ece 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -124,5 +124,15 @@ namespace MediaBrowser.Controller.Entities return list; } + + [IgnoreDataMember] + public override bool StopRefreshIfLocalMetadataFound + { + get + { + // Need people id's from internet metadata + return false; + } + } } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 0483a74ed1..04437cff79 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -532,7 +532,7 @@ namespace MediaBrowser.Providers.Manager } // Local metadata is king - if any is found don't run remote providers - if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh)) + if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !item.StopRefreshIfLocalMetadataFound)) { var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType>(), cancellationToken) .ConfigureAwait(false); From 51411fff8278b5c05e0fe46057a83f83585e6528 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 17:45:36 -0400 Subject: [PATCH 37/85] add on demand people refresh --- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index eba17e7763..bbccef6dea 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -450,22 +450,14 @@ namespace MediaBrowser.Api.UserLibrary if (item is Person) { var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary); - var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 7; + var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 3; if (!hasMetdata) { - var defaultMetadataRefreshMode = performFullRefresh - ? MetadataRefreshMode.FullRefresh - : MetadataRefreshMode.Default; - - var imageRefreshMode = performFullRefresh - ? ImageRefreshMode.FullRefresh - : ImageRefreshMode.Default; - var options = new MetadataRefreshOptions(_fileSystem) { - MetadataRefreshMode = defaultMetadataRefreshMode, - ImageRefreshMode = imageRefreshMode, + MetadataRefreshMode = MetadataRefreshMode.FullRefresh, + ImageRefreshMode = ImageRefreshMode.FullRefresh, ForceSave = performFullRefresh }; From a85de2984ab4f4d7899794e8b4cb8c2ee2c9a3b6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 14 Aug 2016 17:59:34 -0400 Subject: [PATCH 38/85] 3.1.105 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index d31177a374..81a71f8141 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.104")] +[assembly: AssemblyVersion("3.1.105")] From caab8299d1c8ebb7db7de1c83fc7a26070309a6e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 15 Aug 2016 00:36:17 -0400 Subject: [PATCH 39/85] add setting for photo libraries --- MediaBrowser.Model/Configuration/LibraryOptions.cs | 6 ++++++ .../Library/LibraryManager.cs | 2 +- .../Library/Resolvers/PhotoResolver.cs | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index c6f7bbb9da..e15df37c1a 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -3,5 +3,11 @@ public class LibraryOptions { public bool EnableArchiveMediaFiles { get; set; } + public bool EnablePhotos { get; set; } + + public LibraryOptions() + { + EnablePhotos = true; + } } } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 52961668d0..a19f70e68c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -364,7 +364,7 @@ namespace MediaBrowser.Server.Implementations.Library if (item.IsFolder) { - if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel)) + if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder)) { if (item.SourceType != SourceType.Library) { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 78df465b13..3f9475480a 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -34,8 +34,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers // Must be an image file within a photo collection var collectionType = args.GetCollectionType(); + if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase) || - string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) + (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.GetLibraryOptions().EnablePhotos)) { if (IsImageFile(args.Path, _imageProcessor)) { From 8bd8282a115bc9f679e28d814bce451b29c7721e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 15 Aug 2016 14:18:05 -0400 Subject: [PATCH 40/85] update docked tabs --- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 9b51fd489c..b9d647c367 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -101,6 +101,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest From 6186e3a4ff6614552e008d93add8fdcd744ae018 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 15 Aug 2016 17:02:43 -0400 Subject: [PATCH 41/85] reduce dlna chatter --- MediaBrowser.Dlna/PlayTo/Device.cs | 39 ++++++++++++++++++++ MediaBrowser.Dlna/PlayTo/PlayToController.cs | 24 ++++++++---- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index 1ec7a4ce09..6ad5899da1 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net; using System.Security; using System.Threading; using System.Threading.Tasks; @@ -91,6 +92,7 @@ namespace MediaBrowser.Dlna.PlayTo private readonly IServerConfigurationManager _config; public DateTime DateLastActivity { get; private set; } + public Action OnDeviceUnavailable { get; set; } public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config) { @@ -134,6 +136,9 @@ namespace MediaBrowser.Dlna.PlayTo private async void RefreshVolume() { + if (_disposed) + return; + try { await GetVolume().ConfigureAwait(false); @@ -149,6 +154,9 @@ namespace MediaBrowser.Dlna.PlayTo private bool _timerActive; private void RestartTimer() { + if (_disposed) + return; + if (!_timerActive) { lock (_timerLock) @@ -169,6 +177,9 @@ namespace MediaBrowser.Dlna.PlayTo /// private void RestartTimerInactive() { + if (_disposed) + return; + if (_timerActive) { lock (_timerLock) @@ -398,6 +409,7 @@ namespace MediaBrowser.Dlna.PlayTo #region Get data private int _successiveStopCount; + private int _connectFailureCount; private async void TimerCallback(object sender) { if (_disposed) @@ -435,6 +447,8 @@ namespace MediaBrowser.Dlna.PlayTo } } + _connectFailureCount = 0; + if (_disposed) return; @@ -455,8 +469,33 @@ namespace MediaBrowser.Dlna.PlayTo } } } + catch (WebException ex) + { + if (_disposed) + return; + + _logger.ErrorException("Error updating device info for {0}", ex, Properties.Name); + + _successiveStopCount++; + _connectFailureCount++; + + if (_successiveStopCount >= maxSuccessiveStopReturns) + { + RestartTimerInactive(); + } + if (_connectFailureCount >= maxSuccessiveStopReturns) + { + if (OnDeviceUnavailable != null) + { + OnDeviceUnavailable(); + } + } + } catch (Exception ex) { + if (_disposed) + return; + _logger.ErrorException("Error updating device info for {0}", ex, Properties.Name); _successiveStopCount++; diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index 873ae5ae41..7429330bd6 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -103,11 +103,25 @@ namespace MediaBrowser.Dlna.PlayTo _device.PlaybackProgress += _device_PlaybackProgress; _device.PlaybackStopped += _device_PlaybackStopped; _device.MediaChanged += _device_MediaChanged; + _device.OnDeviceUnavailable = OnDeviceUnavailable; + _device.Start(); _deviceDiscovery.DeviceLeft += _deviceDiscovery_DeviceLeft; } + private void OnDeviceUnavailable() + { + try + { + _sessionManager.ReportSessionEnded(_session.Id); + } + catch + { + // Could throw if the session is already gone + } + } + void _deviceDiscovery_DeviceLeft(object sender, SsdpMessageEventArgs e) { string nts; @@ -125,14 +139,7 @@ namespace MediaBrowser.Dlna.PlayTo if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1 || nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1) { - try - { - _sessionManager.ReportSessionEnded(_session.Id); - } - catch - { - // Could throw if the session is already gone - } + OnDeviceUnavailable(); } } } @@ -647,6 +654,7 @@ namespace MediaBrowser.Dlna.PlayTo _device.PlaybackStopped -= _device_PlaybackStopped; _device.MediaChanged -= _device_MediaChanged; _deviceDiscovery.DeviceLeft -= _deviceDiscovery_DeviceLeft; + _device.OnDeviceUnavailable = null; _device.Dispose(); } From 053ea1a6baffbd3bd1c50ef88efea81ede54d03f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 15 Aug 2016 17:06:18 -0400 Subject: [PATCH 42/85] 3.1.106 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 81a71f8141..b85021de4d 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.105")] +[assembly: AssemblyVersion("3.1.106")] From ec111eebd3ac70bed57e7645fd562960c7c72030 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 15 Aug 2016 20:22:59 -0400 Subject: [PATCH 43/85] fix folder caching --- .../Progressive/ProgressiveStreamWriter.cs | 6 ++--- .../Entities/AggregateFolder.cs | 27 ++++++++++--------- .../Entities/UserRootFolder.cs | 15 ++++++++--- MediaBrowser.Model/Dlna/StreamBuilder.cs | 13 ++++++--- .../Persistence/SqliteItemRepository.cs | 2 +- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index 8c4e23a397..0a9a446412 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -48,11 +48,11 @@ namespace MediaBrowser.Api.Playback.Progressive { var eofCount = 0; - using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) + using (var fs = _fileSystem.GetFileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) { while (eofCount < 15) { - var bytesRead = await CopyToAsyncInternal(fs, outputStream, BufferSize, cancellationToken).ConfigureAwait(false); + var bytesRead = await CopyToAsyncInternal(fs, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false); //var position = fs.Position; //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); @@ -63,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Progressive { eofCount++; } - await Task.Delay(100, cancellationToken).ConfigureAwait(false); + await Task.Delay(100, _cancellationToken).ConfigureAwait(false); } else { diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 4aa99ae87b..b1e5a2135c 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -5,6 +5,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; using CommonIO; using MediaBrowser.Controller.Providers; @@ -84,7 +86,7 @@ namespace MediaBrowser.Controller.Entities } } - private void ResetCachedChildren() + private void ClearCache() { lock (_childIdsLock) { @@ -114,7 +116,7 @@ namespace MediaBrowser.Controller.Entities public override bool BeforeMetadataRefresh() { - ResetCachedChildren(); + ClearCache(); var changed = base.BeforeMetadataRefresh() || _requiresRefresh; _requiresRefresh = false; @@ -123,7 +125,7 @@ namespace MediaBrowser.Controller.Entities private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations) { - ResetCachedChildren(); + ClearCache(); var path = ContainingFolderPath; @@ -165,6 +167,16 @@ namespace MediaBrowser.Controller.Entities return args; } + protected override async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + { + ClearCache(); + + await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService) + .ConfigureAwait(false); + + ClearCache(); + } + /// /// Adds the virtual child. /// @@ -180,15 +192,6 @@ namespace MediaBrowser.Controller.Entities _virtualChildren.Add(child); } - /// - /// Get the children of this folder from the actual file system - /// - /// IEnumerable{BaseItem}. - protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) - { - return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); - } - /// /// Finds the virtual child. /// diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index d043cba47f..bd25d3a6ae 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Entities } } - private void ResetCachedChildren() + private void ClearCache() { lock (_childIdsLock) { @@ -94,7 +94,7 @@ namespace MediaBrowser.Controller.Entities public override bool BeforeMetadataRefresh() { - ResetCachedChildren(); + ClearCache(); var hasChanges = base.BeforeMetadataRefresh(); @@ -107,13 +107,22 @@ namespace MediaBrowser.Controller.Entities return hasChanges; } + protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) + { + ClearCache(); + + return base.GetNonCachedChildren(directoryService); + } + protected override async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { - ResetCachedChildren(); + ClearCache(); await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService) .ConfigureAwait(false); + ClearCache(); + // Not the best way to handle this, but it solves an issue // CollectionFolders aren't always getting saved after changes // This means that grabbing the item by Id may end up returning the old one diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 80e81a41a4..0710417c85 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -570,7 +570,7 @@ namespace MediaBrowser.Model.Dlna playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } - int audioBitrate = GetAudioBitrate(options.GetMaxBitrate(), playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec, audioStream); + int audioBitrate = GetAudioBitrate(playlistItem.SubProtocol, options.GetMaxBitrate(), playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec, audioStream); playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate); int? maxBitrateSetting = options.GetMaxBitrate(); @@ -593,7 +593,7 @@ namespace MediaBrowser.Model.Dlna return playlistItem; } - private int GetAudioBitrate(int? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream) + private int GetAudioBitrate(string subProtocol, int? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream) { var defaultBitrate = 128000; if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3")) @@ -611,7 +611,14 @@ namespace MediaBrowser.Model.Dlna { if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3")) { - defaultBitrate = Math.Max(448000, defaultBitrate); + if (string.Equals(subProtocol, "hls", StringComparison.OrdinalIgnoreCase)) + { + defaultBitrate = Math.Max(384000, defaultBitrate); + } + else + { + defaultBitrate = Math.Max(448000, defaultBitrate); + } } else { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 0e36ede7ac..cf8e2fe36c 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2152,7 +2152,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { if (query.User != null) { - query.SortBy = new[] { ItemSortBy.IsPlayed, "SimilarityScore", ItemSortBy.Random }; + query.SortBy = new[] { "SimilarityScore", ItemSortBy.Random }; } else { From ea62399fe8f46797a85ee65f7e6612aedfcaa785 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 15 Aug 2016 22:40:29 -0400 Subject: [PATCH 44/85] use shared headroom --- MediaBrowser.Controller/Entities/AggregateFolder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index b1e5a2135c..efc4502481 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -167,6 +167,11 @@ namespace MediaBrowser.Controller.Entities return args; } + protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) + { + return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); + } + protected override async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { ClearCache(); From 9a956f5e29ea6e880e53df34d3919fffb1b9d405 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 00:10:14 -0400 Subject: [PATCH 45/85] fix merge conflict --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index b85021de4d..a81b44de7a 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.106")] +[assembly: AssemblyVersion("3.0.6060")] From 42cbe6299007aa7e1344b032fcbba907e830504e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 00:11:02 -0400 Subject: [PATCH 46/85] restore version --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index a81b44de7a..b85021de4d 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.0.6060")] +[assembly: AssemblyVersion("3.1.106")] From c1e8d85bca08a6bd08d3234d249b3d72f80c772d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 00:12:12 -0400 Subject: [PATCH 47/85] update local sync --- MediaBrowser.Api/Sync/SyncService.cs | 2 +- SharedVersion.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs index a15ce216f2..4f6aced57d 100644 --- a/MediaBrowser.Api/Sync/SyncService.cs +++ b/MediaBrowser.Api/Sync/SyncService.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Api.Sync public string Id { get; set; } } - [Route("/Sync/{TargetId}/Items", "DELETE", Summary = "Cancels items from a sync target")] + [Route("/Sync/Items/Cancel", "POST", Summary = "Cancels items from a sync target")] public class CancelItems : IReturnVoid { [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "Items")] diff --git a/SharedVersion.cs b/SharedVersion.cs index a81b44de7a..ded2038b03 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.0.6060")] +[assembly: AssemblyVersion("3.1.*")] +//[assembly: AssemblyVersion("3.0.6060")] From cff77c7359f38001674d0d15a005bfac91f438fb Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 16 Aug 2016 00:15:09 -0400 Subject: [PATCH 48/85] update mac project --- .../Emby.Server.Mac.csproj | 64 +++++++++++++------ 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj index 236b0879f9..9422b7fa36 100644 --- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj +++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj @@ -639,6 +639,18 @@ Resources\dashboard-ui\syncsettings.html + + Resources\dashboard-ui\touchicon.png + + + Resources\dashboard-ui\touchicon114.png + + + Resources\dashboard-ui\touchicon144.png + + + Resources\dashboard-ui\touchicon72.png + Resources\dashboard-ui\tv.html @@ -1005,8 +1017,11 @@ Resources\dashboard-ui\bower_components\emby-apiclient\apiclient.js - - Resources\dashboard-ui\bower_components\emby-apiclient\appstorage.js + + Resources\dashboard-ui\bower_components\emby-apiclient\appstorage-localstorage.js + + + Resources\dashboard-ui\bower_components\emby-apiclient\appstorage-memory.js Resources\dashboard-ui\bower_components\emby-apiclient\bower.json @@ -1050,9 +1065,6 @@ Resources\dashboard-ui\bower_components\emby-apiclient\sync\serversync.js - - Resources\dashboard-ui\bower_components\emby-icons\emby-icons.html - Resources\dashboard-ui\bower_components\emby-webcomponents\.bower.json @@ -1251,6 +1263,12 @@ Resources\dashboard-ui\bower_components\emby-webcomponents\emby-slider\emby-slider.js + + Resources\dashboard-ui\bower_components\emby-webcomponents\emby-tabs\emby-tabs.css + + + Resources\dashboard-ui\bower_components\emby-webcomponents\emby-tabs\emby-tabs.js + Resources\dashboard-ui\bower_components\emby-webcomponents\emby-textarea\emby-textarea.css @@ -3603,6 +3621,12 @@ Resources\dashboard-ui\components\viewcontainer-lite.js + + Resources\dashboard-ui\components\appfooter\appfooter.css + + + Resources\dashboard-ui\components\appfooter\appfooter.js + Resources\dashboard-ui\components\channelmapper\channelmapper.js @@ -3612,6 +3636,12 @@ Resources\dashboard-ui\components\directorybrowser\directorybrowser.js + + Resources\dashboard-ui\components\dockedtabs\dockedtabs.css + + + Resources\dashboard-ui\components\dockedtabs\dockedtabs.js + Resources\dashboard-ui\components\fileorganizer\fileorganizer.js @@ -3657,6 +3687,12 @@ Resources\dashboard-ui\components\imageuploader\imageuploader.template.html + + Resources\dashboard-ui\components\libraryoptionseditor\libraryoptionseditor.js + + + Resources\dashboard-ui\components\libraryoptionseditor\libraryoptionseditor.template.html + Resources\dashboard-ui\components\medialibrarycreator\medialibrarycreator.js @@ -3750,9 +3786,6 @@ Resources\dashboard-ui\css\images\logo.png - - Resources\dashboard-ui\css\images\logo536.png - Resources\dashboard-ui\css\images\mblogoicon.png @@ -3762,18 +3795,6 @@ Resources\dashboard-ui\css\images\rotten.png - - Resources\dashboard-ui\css\images\touchicon.png - - - Resources\dashboard-ui\css\images\touchicon114.png - - - Resources\dashboard-ui\css\images\touchicon144.png - - - Resources\dashboard-ui\css\images\touchicon72.png - Resources\dashboard-ui\css\images\userflyoutdefault.png @@ -4434,6 +4455,9 @@ Resources\dashboard-ui\strings\ar.json + + Resources\dashboard-ui\strings\be-BY.json + Resources\dashboard-ui\strings\bg-BG.json From f450ce4e14d722221224b21ec383daf6a44b70c7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 01:34:36 -0400 Subject: [PATCH 49/85] update sync --- MediaBrowser.Api/Sync/SyncService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs index 4f6aced57d..b9544d71ba 100644 --- a/MediaBrowser.Api/Sync/SyncService.cs +++ b/MediaBrowser.Api/Sync/SyncService.cs @@ -67,6 +67,7 @@ namespace MediaBrowser.Api.Sync } [Route("/Sync/Items/Cancel", "POST", Summary = "Cancels items from a sync target")] + [Route("/Sync/{TargetId}/Items", "DELETE", Summary = "Cancels items from a sync target")] public class CancelItems : IReturnVoid { [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "Items")] @@ -211,7 +212,7 @@ namespace MediaBrowser.Api.Sync return ToOptimizedResult(result); } - public void Delete(CancelItems request) + public void Any(CancelItems request) { var itemIds = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); From b55c02f25d2aa7fd2901b42df4789b2c838896d8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 01:36:41 -0400 Subject: [PATCH 50/85] target 4.6.2 --- MediaBrowser.ServerApplication/App.config | 2 +- .../MediaBrowser.ServerApplication.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config index 6d840c1910..fa7bc9f895 100644 --- a/MediaBrowser.ServerApplication/App.config +++ b/MediaBrowser.ServerApplication/App.config @@ -17,7 +17,7 @@ - + diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index b01d8c43f6..9c5470358e 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -9,7 +9,7 @@ Properties MediaBrowser.ServerApplication MediaBrowser.ServerApplication - v4.6 + v4.6.2 512 ..\ From 14be817766fe55cfeeb3184f3e1a999ce5759188 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 01:48:03 -0400 Subject: [PATCH 51/85] update WebMarkupMin --- MediaBrowser.WebDashboard/Api/DashboardService.cs | 2 +- MediaBrowser.WebDashboard/Api/PackageCreator.cs | 2 -- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 6 +++--- MediaBrowser.WebDashboard/packages.config | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 4e4a980605..601ebfba73 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -17,7 +17,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using CommonIO; -using WebMarkupMin.Core.Minifiers; +using WebMarkupMin.Core; namespace MediaBrowser.WebDashboard.Api { diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index c5af1cee7b..65e7fa5d39 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -11,8 +11,6 @@ using System.Threading.Tasks; using CommonIO; using MediaBrowser.Controller.Net; using WebMarkupMin.Core; -using WebMarkupMin.Core.Minifiers; -using WebMarkupMin.Core.Settings; namespace MediaBrowser.WebDashboard.Api { diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index b9d647c367..50e1cfbbea 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -63,9 +63,9 @@ ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll - - False - ..\packages\WebMarkupMin.Core.1.0.1\lib\net40\WebMarkupMin.Core.dll + + ..\packages\WebMarkupMin.Core.2.1.0\lib\net40-client\WebMarkupMin.Core.dll + True diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index a2d13fdf5f..3637c6c84e 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file From f66a25db1cd80025c0a334495e112ff4e0e35eb8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 01:54:27 -0400 Subject: [PATCH 52/85] fix merge conflict --- SharedVersion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index b85021de4d..ded2038b03 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.106")] +[assembly: AssemblyVersion("3.1.*")] +//[assembly: AssemblyVersion("3.0.6060")] From 352842c5d60425bccaf205003cc363279ecf3b8b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 01:55:03 -0400 Subject: [PATCH 53/85] restore version --- SharedVersion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index ded2038b03..b85021de4d 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -[assembly: AssemblyVersion("3.1.*")] -//[assembly: AssemblyVersion("3.0.6060")] +//[assembly: AssemblyVersion("3.1.*")] +[assembly: AssemblyVersion("3.1.106")] From 184d4470239fcec3a46b602f44c742d32a7c2ac1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 02:13:54 -0400 Subject: [PATCH 54/85] update series queries --- MediaBrowser.Controller/Entities/TV/Series.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 757c052bb4..38ddb89ca7 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -243,24 +243,30 @@ namespace MediaBrowser.Controller.Entities.TV public IEnumerable GetSeasons(User user, bool includeMissingSeasons, bool includeVirtualUnaired) { - IEnumerable seasons; + var seriesKey = GetUniqueSeriesKey(this); - seasons = LibraryManager.GetItemList(new InternalItemsQuery(user) + Logger.Debug("GetSeasons SeriesKey: {0}", seriesKey); + var seasons = LibraryManager.GetItemList(new InternalItemsQuery(user) { - AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), + AncestorWithPresentationUniqueKey = seriesKey, IncludeItemTypes = new[] { typeof(Season).Name }, SortBy = new[] { ItemSortBy.SortName } - }).Cast(); + }).Cast().ToList(); + + Logger.Debug("GetSeasons returned {0} items from database", seasons.Count); if (!includeMissingSeasons) { - seasons = seasons.Where(i => !(i.IsMissingSeason)); + seasons = seasons.Where(i => !(i.IsMissingSeason)).ToList(); } + Logger.Debug("GetSeasons has {0} items after includeMissingSeasons filter", seasons.Count); + if (!includeVirtualUnaired) { - seasons = seasons.Where(i => !i.IsVirtualUnaired); + seasons = seasons.Where(i => !i.IsVirtualUnaired).ToList(); } + Logger.Debug("GetSeasons has {0} items after includeVirtualUnaired filter", seasons.Count); return seasons; } From 65636721a1c7183243e8ccff3038898d9c924b5c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 02:16:48 -0400 Subject: [PATCH 55/85] 3.1.107 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index b85021de4d..3273f2f4c6 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.106")] +[assembly: AssemblyVersion("3.1.107")] From 8a7b24000da7a9e917ea041095b55fc95e98a17c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 13:08:37 -0400 Subject: [PATCH 56/85] update season queries --- MediaBrowser.Api/TvShowsService.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 11 ++++++++- MediaBrowser.Controller/Entities/TV/Season.cs | 8 +++++-- MediaBrowser.Controller/Entities/TV/Series.cs | 24 +++++++++++-------- .../Dto/DtoService.cs | 2 +- .../IO/LibraryMonitor.cs | 14 +++++++++-- 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 3f248ea8f0..92189c2458 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -490,7 +490,7 @@ namespace MediaBrowser.Api } else { - episodes = series.GetEpisodes(user, season); + episodes = series.GetSeasonEpisodes(user, season); } } else diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 23055690ca..f8eb414b60 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using CommonIO; using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Channels; @@ -1427,7 +1428,7 @@ namespace MediaBrowser.Controller.Entities itemDto.RecursiveItemCount = allItemsQueryResult.TotalRecordCount; } - double recursiveItemCount = allItemsQueryResult.TotalRecordCount; + var recursiveItemCount = allItemsQueryResult.TotalRecordCount; double unplayedCount = unplayedQueryResult.TotalRecordCount; if (recursiveItemCount > 0) @@ -1437,6 +1438,14 @@ namespace MediaBrowser.Controller.Entities dto.Played = dto.PlayedPercentage.Value >= 100; dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount; } + + if (itemDto != null) + { + if (this is Season || this is MusicAlbum) + { + itemDto.ChildCount = recursiveItemCount; + } + } } } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index c64de399f2..66fe1cc756 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -85,7 +85,11 @@ namespace MediaBrowser.Controller.Entities.TV public override int GetChildCount(User user) { - return GetChildren(user, true).Count(); + Logger.Debug("Season {0} getting child cound", (Path ?? Name)); + var result = GetChildren(user, true).Count(); + Logger.Debug("Season {0} child cound: ", result); + + return result; } /// @@ -192,7 +196,7 @@ namespace MediaBrowser.Controller.Entities.TV public IEnumerable GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable allSeriesEpisodes) { - return series.GetEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes, allSeriesEpisodes); + return series.GetSeasonEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes, allSeriesEpisodes); } public IEnumerable GetEpisodes() diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 38ddb89ca7..02ac42b2af 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -254,19 +254,16 @@ namespace MediaBrowser.Controller.Entities.TV }).Cast().ToList(); - Logger.Debug("GetSeasons returned {0} items from database", seasons.Count); if (!includeMissingSeasons) { seasons = seasons.Where(i => !(i.IsMissingSeason)).ToList(); } - Logger.Debug("GetSeasons has {0} items after includeMissingSeasons filter", seasons.Count); if (!includeVirtualUnaired) { seasons = seasons.Where(i => !i.IsVirtualUnaired).ToList(); } - Logger.Debug("GetSeasons has {0} items after includeVirtualUnaired filter", seasons.Count); return seasons; } @@ -280,14 +277,19 @@ namespace MediaBrowser.Controller.Entities.TV public IEnumerable GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired) { + var seriesKey = GetUniqueSeriesKey(this); + Logger.Debug("GetEpisodes seriesKey: {0}", seriesKey); + var allItems = LibraryManager.GetItemList(new InternalItemsQuery(user) { - AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), + AncestorWithPresentationUniqueKey = seriesKey, IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }, SortBy = new[] { ItemSortBy.SortName } }).ToList(); + Logger.Debug("GetEpisodes return {0} items from database", allItems.Count); + var allSeriesEpisodes = allItems.OfType().ToList(); var allEpisodes = allItems.OfType() @@ -368,11 +370,11 @@ namespace MediaBrowser.Controller.Entities.TV progress.Report(100); } - public IEnumerable GetEpisodes(User user, Season season) + public IEnumerable GetSeasonEpisodes(User user, Season season) { var config = user.Configuration; - return GetEpisodes(user, season, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + return GetSeasonEpisodes(user, season, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); } private IEnumerable GetAllEpisodes(User user) @@ -386,20 +388,22 @@ namespace MediaBrowser.Controller.Entities.TV }).Cast(); } - public IEnumerable GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) + public IEnumerable GetSeasonEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) { IEnumerable episodes = GetAllEpisodes(user); - return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes); + return GetSeasonEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes); } - public IEnumerable GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable allSeriesEpisodes) + public IEnumerable GetSeasonEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable allSeriesEpisodes) { if (allSeriesEpisodes == null) { - return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes); + Logger.Debug("GetSeasonEpisodes allSeriesEpisodes is null"); + return GetSeasonEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes); } + Logger.Debug("GetSeasonEpisodes FilterEpisodesBySeason"); var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons); if (!includeMissingEpisodes) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 4f903a2c28..b646605ed4 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -458,7 +458,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false); - if (item.SourceType == SourceType.Library) + if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library) { dto.ChildCount = GetChildCount(folder, user); } diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index 8c2b927e3a..dea0a978bf 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -38,7 +38,6 @@ namespace MediaBrowser.Server.Implementations.IO /// private readonly IReadOnlyList _alwaysIgnoreFiles = new List { - "thumbs.db", "small.jpg", "albumart.jpg", @@ -47,6 +46,15 @@ namespace MediaBrowser.Server.Implementations.IO "TempSBE" }; + private readonly IReadOnlyList _alwaysIgnoreExtensions = new List + { + // thumbs.db + ".db", + + // bts sync files + ".bts" + }; + /// /// Add the path to our temporary ignore list. Use when writing to a path within our listening scope. /// @@ -411,7 +419,9 @@ namespace MediaBrowser.Server.Implementations.IO var filename = Path.GetFileName(path); - var monitorPath = !(!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase)); + var monitorPath = !string.IsNullOrEmpty(filename) && + !_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) && + !_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase); // Ignore certain files var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList(); From c8299b4cee166f4c4bb40ddba8679c36fac747dc Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 13:10:50 -0400 Subject: [PATCH 57/85] 3.1.108 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 3273f2f4c6..70e05d2a42 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.107")] +[assembly: AssemblyVersion("3.1.108")] From 1d37f9ad0e8281a612580c438f0130c5796ff8c4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 14:45:57 -0400 Subject: [PATCH 58/85] fix music brainz album search results --- .../Music/MusicBrainzAlbumProvider.cs | 100 +++++++++--------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index 1710ec2b0f..a0ce806105 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -81,46 +81,24 @@ namespace MediaBrowser.Providers.Music private IEnumerable GetResultsFromResponse(XmlDocument doc) { - var ns = new XmlNamespaceManager(doc.NameTable); - ns.AddNamespace("mb", MusicBrainzBaseUrl + "/ns/mmd-2.0#"); - - var list = new List(); - - var nodes = doc.SelectNodes("//mb:release-list/mb:release", ns); - - if (nodes != null) + return ReleaseResult.Parse(doc).Select(i => { - foreach (var node in nodes.Cast()) + var result = new RemoteSearchResult { - if (node.Attributes != null) - { - string name = null; + Name = i.Title + }; - string mbzId = node.Attributes["id"].Value; - - var nameNode = node.SelectSingleNode("//mb:title", ns); - - if (nameNode != null) - { - name = nameNode.InnerText; - } - - if (!string.IsNullOrWhiteSpace(mbzId) && !string.IsNullOrWhiteSpace(name)) - { - var result = new RemoteSearchResult - { - Name = name - }; - - result.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbzId); - - list.Add(result); - } - } + if (!string.IsNullOrWhiteSpace(i.ReleaseId)) + { + result.SetProviderId(MetadataProviders.MusicBrainzAlbum, i.ReleaseId); + } + if (!string.IsNullOrWhiteSpace(i.ReleaseGroupId)) + { + result.SetProviderId(MetadataProviders.MusicBrainzAlbum, i.ReleaseGroupId); } - } - return list; + return result; + }); } public async Task> GetMetadata(AlbumInfo id, CancellationToken cancellationToken) @@ -208,7 +186,7 @@ namespace MediaBrowser.Providers.Music var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false); - return ReleaseResult.Parse(doc); + return ReleaseResult.Parse(doc, 1).FirstOrDefault(); } private async Task GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken) @@ -219,32 +197,32 @@ namespace MediaBrowser.Providers.Music var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false); - return ReleaseResult.Parse(doc); + return ReleaseResult.Parse(doc, 1).FirstOrDefault(); } private class ReleaseResult { public string ReleaseId; public string ReleaseGroupId; + public string Title; - public static ReleaseResult Parse(XmlDocument doc) + public static List Parse(XmlDocument doc, int? limit = null) { var docElem = doc.DocumentElement; + var list = new List(); if (docElem == null) { - return new ReleaseResult(); + return list; } var releaseList = docElem.FirstChild; if (releaseList == null) { - return new ReleaseResult(); + return list; } var nodes = releaseList.ChildNodes; - string releaseId = null; - string releaseGroupId = null; if (nodes != null) { @@ -252,18 +230,42 @@ namespace MediaBrowser.Providers.Music { if (string.Equals(node.Name, "release", StringComparison.OrdinalIgnoreCase)) { - releaseId = node.Attributes["id"].Value; - releaseGroupId = GetReleaseGroupIdFromReleaseNode(node); - break; + var releaseId = node.Attributes["id"].Value; + var releaseGroupId = GetReleaseGroupIdFromReleaseNode(node); + + list.Add(new ReleaseResult + { + ReleaseId = releaseId, + ReleaseGroupId = releaseGroupId, + Title = GetTitleFromReleaseNode(node) + }); + + if (limit.HasValue && list.Count >= limit.Value) + { + break; + } } } } - return new ReleaseResult + return list; + } + + private static string GetTitleFromReleaseNode(XmlNode node) + { + var subNodes = node.ChildNodes; + if (subNodes != null) { - ReleaseId = releaseId, - ReleaseGroupId = releaseGroupId - }; + foreach (var subNode in subNodes.Cast()) + { + if (string.Equals(subNode.Name, "title", StringComparison.OrdinalIgnoreCase)) + { + return subNode.InnerText; + } + } + } + + return null; } private static string GetReleaseGroupIdFromReleaseNode(XmlNode node) From ae887d9157335db66bf569ab31f274fc24503146 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 14:46:12 -0400 Subject: [PATCH 59/85] remove readinputatnativeframerate --- .../LiveTv/TunerHosts/M3UTunerHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 5b83e7cbe8..5c508aacd3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -136,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts RequiresOpening = false, RequiresClosing = false, - ReadAtNativeFramerate = true + ReadAtNativeFramerate = false }; return new List { mediaSource }; From 1dc5911f068e2c3a7035081ee3fdbbedc4f09225 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Aug 2016 16:54:13 -0400 Subject: [PATCH 60/85] update multi-select --- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 50e1cfbbea..61facf8ec4 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -173,6 +173,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 1c815d2e720b95e93cc993fbbdba71551f7bd214 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 01:29:05 -0400 Subject: [PATCH 61/85] update sync display --- MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index dea0a978bf..ea9e58ee47 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -52,7 +52,8 @@ namespace MediaBrowser.Server.Implementations.IO ".db", // bts sync files - ".bts" + ".bts", + ".sync" }; /// From a69f8ecb3dd9267d9b94d8b6ab60e7193c21cf7c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 01:33:30 -0400 Subject: [PATCH 62/85] update logging --- MediaBrowser.Controller/Entities/TV/Season.cs | 3 +++ MediaBrowser.Controller/Entities/TV/Series.cs | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 66fe1cc756..78a974bf76 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -170,10 +170,13 @@ namespace MediaBrowser.Controller.Entities.TV Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + Logger.Debug("Season.GetItemsInternal entering GetEpisodes"); var items = GetEpisodes(user).Where(filter); + Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort"); var result = PostFilterAndSort(items, query); + Logger.Debug("Season.GetItemsInternal complete"); return Task.FromResult(result); } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 02ac42b2af..30c06b2442 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -379,13 +379,19 @@ namespace MediaBrowser.Controller.Entities.TV private IEnumerable GetAllEpisodes(User user) { - return LibraryManager.GetItemList(new InternalItemsQuery(user) + Logger.Debug("Series.GetAllEpisodes entering GetItemList"); + + var result = LibraryManager.GetItemList(new InternalItemsQuery(user) { AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), IncludeItemTypes = new[] { typeof(Episode).Name }, SortBy = new[] { ItemSortBy.SortName } - }).Cast(); + }).Cast().ToList(); + + Logger.Debug("Series.GetAllEpisodes returning {0} episodes", result.Count); + + return result; } public IEnumerable GetSeasonEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) From 186c5f5085ed65d548bf267a614c0e9618748463 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 01:51:07 -0400 Subject: [PATCH 63/85] 3.1.109 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 70e05d2a42..0c52c5dfe9 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.108")] +[assembly: AssemblyVersion("3.1.109")] From fd6aa72dac2fe4a118603eebab192b46b8f7401e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 15:28:43 -0400 Subject: [PATCH 64/85] add guide optimizations --- MediaBrowser.Api/BaseApiService.cs | 4 +++ MediaBrowser.Api/IHasDtoOptions.cs | 1 + MediaBrowser.Api/LiveTv/LiveTvService.cs | 27 +++++++++++++- MediaBrowser.Api/PlaylistService.cs | 14 +++++++- MediaBrowser.Api/SimilarItemsHelper.cs | 14 +++++++- MediaBrowser.Api/Sync/SyncHelper.cs | 4 +-- MediaBrowser.Api/TvShowsService.cs | 14 ++++++++ .../UserLibrary/BaseItemsRequest.cs | 3 ++ .../UserLibrary/UserLibraryService.cs | 3 ++ MediaBrowser.Controller/Dto/DtoOptions.cs | 4 +++ MediaBrowser.Model/Dto/BaseItemDto.cs | 13 +++++-- .../LiveTv/LiveTvChannelQuery.cs | 6 ++++ MediaBrowser.Model/LiveTv/ProgramQuery.cs | 2 ++ MediaBrowser.Model/Sync/SyncJobQuery.cs | 1 + .../Dto/DtoService.cs | 36 +++++++++++++------ .../LiveTv/LiveTvManager.cs | 36 +++++++++++++++---- .../Sync/SyncRepository.cs | 14 ++++++++ 17 files changed, 172 insertions(+), 24 deletions(-) diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 44a367be09..3ff432d741 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -139,6 +139,10 @@ namespace MediaBrowser.Api { options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value; } + if (hasDtoOptions.EnableUserData.HasValue) + { + options.EnableUserData = hasDtoOptions.EnableUserData.Value; + } if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes)) { diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs index dac366113c..6ed1670c21 100644 --- a/MediaBrowser.Api/IHasDtoOptions.cs +++ b/MediaBrowser.Api/IHasDtoOptions.cs @@ -4,6 +4,7 @@ namespace MediaBrowser.Api public interface IHasDtoOptions : IHasItemFields { bool? EnableImages { get; set; } + bool? EnableUserData { get; set; } int? ImageTypeLimit { get; set; } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 91157cd11f..545ac162ff 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -82,6 +82,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public bool AddCurrentProgram { get; set; } + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + public GetChannels() { AddCurrentProgram = true; @@ -149,6 +152,9 @@ namespace MediaBrowser.Api.LiveTv public bool EnableTotalRecordCount { get; set; } + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + public GetRecordings() { EnableTotalRecordCount = true; @@ -271,6 +277,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string EnableImageTypes { get; set; } + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + /// /// Fields to return within the items, in addition to basic information /// @@ -331,6 +340,9 @@ namespace MediaBrowser.Api.LiveTv /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Fields { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } } [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")] @@ -726,7 +738,12 @@ namespace MediaBrowser.Api.LiveTv var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId); - var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ConfigureAwait(false)).ToArray(); + var options = GetDtoOptions(request); + RemoveFields(options); + + options.AddCurrentProgram = request.AddCurrentProgram; + + var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user).ConfigureAwait(false)).ToArray(); var result = new QueryResult { @@ -737,6 +754,14 @@ namespace MediaBrowser.Api.LiveTv return ToOptimizedSerializedResultUsingCache(result); } + private void RemoveFields(DtoOptions options) + { + options.Fields.Remove(ItemFields.CanDelete); + options.Fields.Remove(ItemFields.CanDownload); + options.Fields.Remove(ItemFields.DisplayPreferencesId); + options.Fields.Remove(ItemFields.Etag); + } + public object Get(GetChannel request) { var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs index 604227a150..9693992882 100644 --- a/MediaBrowser.Api/PlaylistService.cs +++ b/MediaBrowser.Api/PlaylistService.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Api } [Route("/Playlists/{Id}/Items", "GET", Summary = "Gets the original items of a playlist")] - public class GetPlaylistItems : IReturn>, IHasItemFields + public class GetPlaylistItems : IReturn>, IHasDtoOptions { [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public string Id { get; set; } @@ -104,6 +104,18 @@ namespace MediaBrowser.Api /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Fields { get; set; } + + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableImages { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } } [Authenticated] diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index a1e47bd8fd..1621c80567 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -29,8 +29,20 @@ namespace MediaBrowser.Api public string ExcludeArtistIds { get; set; } } - public class BaseGetSimilarItems : IReturn, IHasItemFields + public class BaseGetSimilarItems : IReturn, IHasDtoOptions { + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableImages { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + /// /// Gets or sets the user id. /// diff --git a/MediaBrowser.Api/Sync/SyncHelper.cs b/MediaBrowser.Api/Sync/SyncHelper.cs index 0d3e8707db..2f857000c0 100644 --- a/MediaBrowser.Api/Sync/SyncHelper.cs +++ b/MediaBrowser.Api/Sync/SyncHelper.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Api.Sync } break; } - if (item.IsFolder && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre) + if (item.IsFolderItem && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre) { options.Add(SyncJobOption.Quality); options.Add(SyncJobOption.Profile); @@ -44,7 +44,7 @@ namespace MediaBrowser.Api.Sync { if (item.SupportsSync ?? false) { - if (item.IsFolder || item.IsGameGenre || item.IsMusicGenre || item.IsGenre || item.IsArtist || item.IsStudio || item.IsPerson) + if (item.IsFolderItem || item.IsGameGenre || item.IsMusicGenre || item.IsGenre || item.IsArtist || item.IsStudio || item.IsPerson) { options.Add(SyncJobOption.SyncNewContent); options.Add(SyncJobOption.ItemLimit); diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 92189c2458..e295f3b3a6 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -69,6 +69,9 @@ namespace MediaBrowser.Api [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string EnableImageTypes { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } } [Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")] @@ -117,6 +120,9 @@ namespace MediaBrowser.Api [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string EnableImageTypes { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } } [Route("/Shows/{Id}/Similar", "GET", Summary = "Finds tv shows similar to a given one.")] @@ -184,6 +190,10 @@ namespace MediaBrowser.Api [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string EnableImageTypes { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + } [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")] @@ -226,6 +236,10 @@ namespace MediaBrowser.Api [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string EnableImageTypes { get; set; } + + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + } /// diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 3e9a541c0c..96acb1f607 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -226,6 +226,9 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableImages { get; set; } + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? ImageTypeLimit { get; set; } diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index bbccef6dea..c392ef4634 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -246,6 +246,9 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string EnableImageTypes { get; set; } + [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableUserData { get; set; } + public GetLatestMedia() { Limit = 20; diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index d627cc67ae..e69b649488 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -19,12 +19,16 @@ namespace MediaBrowser.Controller.Dto public bool EnableImages { get; set; } public bool AddProgramRecordingInfo { get; set; } public string DeviceId { get; set; } + public bool EnableUserData { get; set; } + public bool AddCurrentProgram { get; set; } public DtoOptions() { Fields = new List(); ImageTypeLimit = int.MaxValue; EnableImages = true; + EnableUserData = true; + AddCurrentProgram = true; Fields = Enum.GetNames(typeof (ItemFields)) .Select(i => (ItemFields) Enum.Parse(typeof (ItemFields), i, true)) diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 7d69359d1a..348a781ae1 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -346,7 +346,16 @@ namespace MediaBrowser.Model.Dto /// Gets or sets a value indicating whether this instance is folder. /// /// true if this instance is folder; otherwise, false. - public bool IsFolder { get; set; } + public bool? IsFolder { get; set; } + + [IgnoreDataMember] + public bool IsFolderItem + { + get + { + return IsFolder ?? false; + } + } /// /// Gets or sets the parent id. @@ -656,7 +665,7 @@ namespace MediaBrowser.Model.Dto { get { - return RunTimeTicks.HasValue || IsFolder || IsGenre || IsMusicGenre || IsArtist; + return RunTimeTicks.HasValue || IsFolderItem || IsGenre || IsMusicGenre || IsArtist; } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 3a6ad04448..0ece1e4a00 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -59,5 +59,11 @@ namespace MediaBrowser.Model.LiveTv /// /// true if [add current program]; otherwise, false. public bool AddCurrentProgram { get; set; } + public bool EnableUserData { get; set; } + + public LiveTvChannelQuery() + { + EnableUserData = true; + } } } diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 0141191c18..bf459237a0 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -15,9 +15,11 @@ namespace MediaBrowser.Model.LiveTv SortBy = new string[] { }; Genres = new string[] { }; EnableTotalRecordCount = true; + EnableUserData = true; } public bool EnableTotalRecordCount { get; set; } + public bool EnableUserData { get; set; } /// /// Fields to return within the items, in addition to basic information diff --git a/MediaBrowser.Model/Sync/SyncJobQuery.cs b/MediaBrowser.Model/Sync/SyncJobQuery.cs index e86ec929f2..bb99b5d5f3 100644 --- a/MediaBrowser.Model/Sync/SyncJobQuery.cs +++ b/MediaBrowser.Model/Sync/SyncJobQuery.cs @@ -23,6 +23,7 @@ namespace MediaBrowser.Model.Sync /// /// The user identifier. public string UserId { get; set; } + public string ExcludeTargetIds { get; set; } /// /// Gets or sets the status. /// diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index b646605ed4..3d257d1947 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -329,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (user != null) { - await AttachUserSpecificInfo(dto, item, user, fields).ConfigureAwait(false); + await AttachUserSpecificInfo(dto, item, user, options).ConfigureAwait(false); } var hasMediaSources = item as IHasMediaSources; @@ -446,17 +446,18 @@ namespace MediaBrowser.Server.Implementations.Dto /// /// Attaches the user specific info. /// - /// The dto. - /// The item. - /// The user. - /// The fields. - private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List fields) + private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions) { + var fields = dtoOptions.Fields; + if (item.IsFolder) { var folder = (Folder)item; - dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false); + if (dtoOptions.EnableUserData) + { + dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false); + } if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library) { @@ -476,7 +477,10 @@ namespace MediaBrowser.Server.Implementations.Dto else { - dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result; + if (dtoOptions.EnableUserData) + { + dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result; + } } dto.PlayAccess = item.GetPlayAccess(user); @@ -484,7 +488,10 @@ namespace MediaBrowser.Server.Implementations.Dto if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo)) { var userCanSync = user != null && user.Policy.EnableSync; - dto.SupportsSync = userCanSync && _syncManager.SupportsSync(item); + if (userCanSync && _syncManager.SupportsSync(item)) + { + dto.SupportsSync = true; + } } if (fields.Contains(ItemFields.SeasonUserData)) @@ -969,7 +976,16 @@ namespace MediaBrowser.Server.Implementations.Dto dto.Id = GetDtoId(item); dto.IndexNumber = item.IndexNumber; dto.ParentIndexNumber = item.ParentIndexNumber; - dto.IsFolder = item.IsFolder; + + if (item.IsFolder) + { + dto.IsFolder = true; + } + else if (item is IHasMediaSources) + { + dto.IsFolder = false; + } + dto.MediaType = item.MediaType; dto.LocationType = item.LocationType; if (item.IsHD.HasValue && item.IsHD.Value) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 09d156661d..ccbcb910d3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -951,6 +951,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv var queryResult = _libraryManager.QueryItems(internalQuery); + RemoveFields(options); + var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray(); var result = new QueryResult @@ -1031,6 +1033,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv var user = _userManager.GetUserById(query.UserId); + RemoveFields(options); + var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray(); var result = new QueryResult @@ -1662,6 +1666,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv var internalResult = await GetInternalRecordings(query, cancellationToken).ConfigureAwait(false); + RemoveFields(options); + var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray(); return new QueryResult @@ -1922,7 +1928,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var channelIds = tuples.Select(i => i.Item2.Id.ToString("N")).Distinct().ToArray(); - var programs = _libraryManager.GetItemList(new InternalItemsQuery(user) + var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, ChannelIds = channelIds, @@ -1932,7 +1938,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv SortBy = new[] { "StartDate" }, TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") } - }).ToList(); + }).ToList() : new List(); + + RemoveFields(options); foreach (var tuple in tuples) { @@ -1944,14 +1952,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv dto.ChannelType = channel.ChannelType; dto.ServiceName = GetService(channel).Name; - dto.MediaSources = channel.GetMediaSources(true).ToList(); + if (options.Fields.Contains(ItemFields.MediaSources)) + { + dto.MediaSources = channel.GetMediaSources(true).ToList(); + } var channelIdString = channel.Id.ToString("N"); - var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString)); - - if (currentProgram != null) + if (options.AddCurrentProgram) { - dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user); + var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString)); + + if (currentProgram != null) + { + dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user); + } } } } @@ -2447,6 +2461,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user); } + private void RemoveFields(DtoOptions options) + { + options.Fields.Remove(ItemFields.CanDelete); + options.Fields.Remove(ItemFields.CanDownload); + options.Fields.Remove(ItemFields.DisplayPreferencesId); + options.Fields.Remove(ItemFields.Etag); + } + public async Task GetInternalLiveTvFolder(CancellationToken cancellationToken) { var name = _localization.GetLocalizedString("ViewTypeLiveTV"); diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs index d7c77e655b..6b7bcfa010 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs @@ -414,6 +414,20 @@ namespace MediaBrowser.Server.Implementations.Sync whereClauses.Add("TargetId=@TargetId"); cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId; } + if (!string.IsNullOrWhiteSpace(query.ExcludeTargetIds)) + { + var excludeIds = (query.ExcludeTargetIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if (excludeIds.Length == 1) + { + whereClauses.Add("TargetId<>@ExcludeTargetId"); + cmd.Parameters.Add(cmd, "@ExcludeTargetId", DbType.String).Value = excludeIds[0]; + } + else if (excludeIds.Length > 1) + { + whereClauses.Add("TargetId<>@ExcludeTargetId"); + cmd.Parameters.Add(cmd, "@ExcludeTargetId", DbType.String).Value = excludeIds[0]; + } + } if (!string.IsNullOrWhiteSpace(query.UserId)) { whereClauses.Add("UserId=@UserId"); From acc02aa3c3186a3a99de64a42740e74e03ec0327 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 16:35:39 -0400 Subject: [PATCH 65/85] fix parsing of added value --- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 2e34135a62..0c8501e626 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -231,7 +231,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers DateTime added; if (DateTime.TryParseExact(val, BaseNfoSaver.DateAddedFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added)) { - item.EndDate = added.ToUniversalTime(); + item.DateCreated = added.ToUniversalTime(); } else if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added)) { From 43c94884e72b5537cd68928614bf8c9ecdb98844 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 16:45:47 -0400 Subject: [PATCH 66/85] update logging --- MediaBrowser.Controller/Entities/TV/Season.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 78a974bf76..33d4f16a90 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -170,13 +170,15 @@ namespace MediaBrowser.Controller.Entities.TV Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - Logger.Debug("Season.GetItemsInternal entering GetEpisodes"); + var id = Guid.NewGuid().ToString("N"); + + Logger.Debug("Season.GetItemsInternal entering GetEpisodes. Request id: " + id); var items = GetEpisodes(user).Where(filter); - Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort"); + Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort. Request id: " + id); var result = PostFilterAndSort(items, query); - Logger.Debug("Season.GetItemsInternal complete"); + Logger.Debug("Season.GetItemsInternal complete. Request id: " + id); return Task.FromResult(result); } From d6dc6ffe7e6f7a9699c764cba2bf32c996dcd771 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 16:52:16 -0400 Subject: [PATCH 67/85] update season methods --- MediaBrowser.Controller/Entities/Folder.cs | 10 ++++---- MediaBrowser.Controller/Entities/TV/Season.cs | 2 +- MediaBrowser.Controller/Entities/TV/Series.cs | 2 +- .../Entities/UserRootFolder.cs | 2 +- .../Entities/UserViewBuilder.cs | 25 ++++++++++++------- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f8eb414b60..b19667942d 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -702,7 +702,7 @@ namespace MediaBrowser.Controller.Entities items = GetRecursiveChildren(user, query); } - return PostFilterAndSort(items, query); + return PostFilterAndSort(items, query, true, true); } if (!(this is UserRootFolder) && !(this is AggregateFolder)) @@ -903,7 +903,7 @@ namespace MediaBrowser.Controller.Entities if (query.ItemIds.Length > 0) { var specificItems = query.ItemIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList(); - return Task.FromResult(PostFilterAndSort(specificItems, query)); + return Task.FromResult(PostFilterAndSort(specificItems, query, true, true)); } return GetItemsInternal(query); @@ -959,12 +959,12 @@ namespace MediaBrowser.Controller.Entities : GetChildren(user, true).Where(filter); } - return PostFilterAndSort(items, query); + return PostFilterAndSort(items, query, true, true); } - protected QueryResult PostFilterAndSort(IEnumerable items, InternalItemsQuery query) + protected QueryResult PostFilterAndSort(IEnumerable items, InternalItemsQuery query, bool collapseBoxSetItems, bool enableSorting) { - return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager); + return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager, collapseBoxSetItems, enableSorting); } public virtual IEnumerable GetChildren(User user, bool includeLinkedChildren) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 33d4f16a90..628e27c02e 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -176,7 +176,7 @@ namespace MediaBrowser.Controller.Entities.TV var items = GetEpisodes(user).Where(filter); Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort. Request id: " + id); - var result = PostFilterAndSort(items, query); + var result = PostFilterAndSort(items, query, false, false); Logger.Debug("Season.GetItemsInternal complete. Request id: " + id); return Task.FromResult(result); diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 30c06b2442..e48c32a25e 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -237,7 +237,7 @@ namespace MediaBrowser.Controller.Entities.TV Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); var items = GetSeasons(user).Where(filter); - var result = PostFilterAndSort(items, query); + var result = PostFilterAndSort(items, query, false, true); return Task.FromResult(result); } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index bd25d3a6ae..aff1f5e286 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Entities var user = query.User; Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - return PostFilterAndSort(result.Where(filter), query); + return PostFilterAndSort(result.Where(filter), query, true, true); } public override int GetChildCount(User user) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index d0f7efa8c8..6128192ea2 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -424,7 +424,7 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new string[] { }; - return PostFilterAndSort(items, parent, null, query); + return PostFilterAndSort(items, parent, null, query, false, true); } private QueryResult GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query) @@ -780,7 +780,7 @@ namespace MediaBrowser.Controller.Entities { items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager)); - return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config); + return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config, true, true); } public static bool FilterItem(BaseItem item, InternalItemsQuery query) @@ -791,9 +791,11 @@ namespace MediaBrowser.Controller.Entities private QueryResult PostFilterAndSort(IEnumerable items, BaseItem queryParent, int? totalRecordLimit, - InternalItemsQuery query) + InternalItemsQuery query, + bool collapseBoxSetItems, + bool enableSorting) { - return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config); + return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config, collapseBoxSetItems, enableSorting); } public static QueryResult PostFilterAndSort(IEnumerable items, @@ -801,7 +803,9 @@ namespace MediaBrowser.Controller.Entities int? totalRecordLimit, InternalItemsQuery query, ILibraryManager libraryManager, - IServerConfigurationManager configurationManager) + IServerConfigurationManager configurationManager, + bool collapseBoxSetItems, + bool enableSorting) { var user = query.User; @@ -810,7 +814,10 @@ namespace MediaBrowser.Controller.Entities query.IsVirtualUnaired, query.IsUnaired); - items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager); + if (collapseBoxSetItems) + { + items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager); + } // This must be the last filter if (!string.IsNullOrEmpty(query.AdjacentTo)) @@ -818,7 +825,7 @@ namespace MediaBrowser.Controller.Entities items = FilterForAdjacency(items, query.AdjacentTo); } - return Sort(items, totalRecordLimit, query, libraryManager); + return SortAndPage(items, totalRecordLimit, query, libraryManager, enableSorting); } public static IEnumerable CollapseBoxSetItemsIfNeeded(IEnumerable items, @@ -1191,10 +1198,10 @@ namespace MediaBrowser.Controller.Entities return items; } - public static QueryResult Sort(IEnumerable items, + public static QueryResult SortAndPage(IEnumerable items, int? totalRecordLimit, InternalItemsQuery query, - ILibraryManager libraryManager) + ILibraryManager libraryManager, bool enableSorting) { var user = query.User; From 6b47232b15f7398af28843049f11070de20fab3f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Aug 2016 16:53:12 -0400 Subject: [PATCH 68/85] 3.1.110 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 0c52c5dfe9..bfd63aaf2a 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.109")] +[assembly: AssemblyVersion("3.1.110")] From cc62faa1c2c212d07c556e5368888ecc3ee537eb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 01:56:10 -0400 Subject: [PATCH 69/85] update season queries --- MediaBrowser.Api/TvShowsService.cs | 38 +--- .../Entities/Audio/MusicArtist.cs | 49 +++++ .../Entities/Audio/MusicGenre.cs | 43 ++++ MediaBrowser.Controller/Entities/GameGenre.cs | 43 ++++ MediaBrowser.Controller/Entities/Genre.cs | 43 ++++ .../Entities/InternalItemsQuery.cs | 2 + MediaBrowser.Controller/Entities/Person.cs | 58 ++++++ MediaBrowser.Controller/Entities/Studio.cs | 43 ++++ MediaBrowser.Controller/Entities/TV/Season.cs | 30 +-- MediaBrowser.Controller/Entities/TV/Series.cs | 183 ++++++++++-------- .../Entities/UserViewBuilder.cs | 53 ----- MediaBrowser.Controller/Entities/Year.cs | 43 ++++ .../IServerApplicationPaths.cs | 2 + .../Encoder/MediaEncoder.cs | 8 +- .../Manager/MetadataService.cs | 11 +- .../Dto/DtoService.cs | 116 ++--------- .../Library/LibraryManager.cs | 72 +------ .../Library/SearchEngine.cs | 20 +- .../Persistence/SqliteItemRepository.cs | 11 ++ .../ServerApplicationPaths.cs | 8 + .../Session/SessionManager.cs | 3 +- 21 files changed, 492 insertions(+), 387 deletions(-) diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index e295f3b3a6..daaa6343d1 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -423,23 +423,14 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException("No series exists with Id " + request.Id); } - var seasons = series.GetSeasons(user); - - if (request.IsSpecialSeason.HasValue) + var seasons = (await series.GetItems(new InternalItemsQuery(user) { - var val = request.IsSpecialSeason.Value; + IsMissing = request.IsMissing, + IsVirtualUnaired = request.IsVirtualUnaired, + IsSpecialSeason = request.IsSpecialSeason, + AdjacentTo = request.AdjacentTo - seasons = seasons.Where(i => i.IsSpecialSeason == val); - } - - seasons = FilterVirtualSeasons(request, seasons); - - // This must be the last filter - if (!string.IsNullOrEmpty(request.AdjacentTo)) - { - seasons = UserViewBuilder.FilterForAdjacency(seasons, request.AdjacentTo) - .Cast(); - } + }).ConfigureAwait(false)).Items.OfType(); var dtoOptions = GetDtoOptions(request); @@ -453,23 +444,6 @@ namespace MediaBrowser.Api }; } - private IEnumerable FilterVirtualSeasons(GetSeasons request, IEnumerable items) - { - if (request.IsMissing.HasValue) - { - var val = request.IsMissing.Value; - items = items.Where(i => (i.IsMissingSeason) == val); - } - - if (request.IsVirtualUnaired.HasValue) - { - var val = request.IsVirtualUnaired.Value; - items = items.Where(i => i.IsVirtualUnaired == val); - } - - return items; - } - public async Task Get(GetEpisodes request) { var user = _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 56f9a5b888..81d1deaa23 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -270,5 +270,54 @@ namespace MediaBrowser.Controller.Entities.Audio return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.ArtistsPath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + if (IsAccessedByName) + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + if (IsAccessedByName) + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 9aa5625fac..bd991d9f47 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -92,5 +92,48 @@ namespace MediaBrowser.Controller.Entities.Audio return LibraryManager.GetItemList(query); } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.MusicGenrePath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 5d66bf3abc..6448828fb3 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -84,5 +84,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GameGenrePath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index c7fe25a962..1736ba8c76 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -87,5 +87,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GenrePath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 69cab5ec53..deea631127 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -37,6 +37,7 @@ namespace MediaBrowser.Controller.Entities public string[] Genres { get; set; } public string[] Keywords { get; set; } + public bool? IsSpecialSeason { get; set; } public bool? IsMissing { get; set; } public bool? IsUnaired { get; set; } public bool? IsVirtualUnaired { get; set; } @@ -50,6 +51,7 @@ namespace MediaBrowser.Controller.Entities public string PresentationUniqueKey { get; set; } public string Path { get; set; } + public string PathNotStartsWith { get; set; } public string Name { get; set; } public string SlugName { get; set; } diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 4ee140b2b1..f21bc0a71e 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -122,6 +122,64 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validFilename = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + string subFolderPrefix = null; + + foreach (char c in validFilename) + { + if (char.IsLetterOrDigit(c)) + { + subFolderPrefix = c.ToString(); + break; + } + } + + var path = ConfigurationManager.ApplicationPaths.PeoplePath; + + return string.IsNullOrEmpty(subFolderPrefix) ? + System.IO.Path.Combine(path, validFilename) : + System.IO.Path.Combine(path, subFolderPrefix, validFilename); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } /// diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 7e3d6fe8e1..04b09b7442 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -85,5 +85,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.StudioPath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 628e27c02e..842b2fd602 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -141,24 +141,6 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } - [IgnoreDataMember] - public bool IsMissingSeason - { - get { return (IsVirtualItem) && !IsUnaired; } - } - - [IgnoreDataMember] - public bool IsVirtualUnaired - { - get { return (IsVirtualItem) && IsUnaired; } - } - - [IgnoreDataMember] - public bool IsSpecialSeason - { - get { return (IndexNumber ?? -1) == 0; } - } - protected override Task> GetItemsInternal(InternalItemsQuery query) { if (query.User == null) @@ -189,19 +171,17 @@ namespace MediaBrowser.Controller.Entities.TV /// IEnumerable{Episode}. public IEnumerable GetEpisodes(User user) { - var config = user.Configuration; - - return GetEpisodes(Series, user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + return GetEpisodes(Series, user); } - public IEnumerable GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) + public IEnumerable GetEpisodes(Series series, User user) { - return GetEpisodes(series, user, includeMissingEpisodes, includeVirtualUnairedEpisodes, null); + return GetEpisodes(series, user, null); } - public IEnumerable GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable allSeriesEpisodes) + public IEnumerable GetEpisodes(Series series, User user, IEnumerable allSeriesEpisodes) { - return series.GetSeasonEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes, allSeriesEpisodes); + return series.GetSeasonEpisodes(user, this, allSeriesEpisodes); } public IEnumerable GetEpisodes() diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index e48c32a25e..4915cfedc7 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -207,7 +207,30 @@ namespace MediaBrowser.Controller.Entities.TV { var config = user.Configuration; - return GetSeasons(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + var seriesKey = GetUniqueSeriesKey(this); + + Logger.Debug("GetSeasons SeriesKey: {0}", seriesKey); + var query = new InternalItemsQuery(user) + { + AncestorWithPresentationUniqueKey = seriesKey, + IncludeItemTypes = new[] {typeof (Season).Name}, + SortBy = new[] {ItemSortBy.SortName} + }; + + if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes) + { + query.IsVirtualItem = false; + } + else if (!config.DisplayMissingEpisodes) + { + query.IsMissing = false; + } + else if (!config.DisplayUnairedEpisodes) + { + query.IsVirtualUnaired = false; + } + + return LibraryManager.GetItemList(query).Cast(); } protected override Task> GetItemsInternal(InternalItemsQuery query) @@ -241,59 +264,39 @@ namespace MediaBrowser.Controller.Entities.TV return Task.FromResult(result); } - public IEnumerable GetSeasons(User user, bool includeMissingSeasons, bool includeVirtualUnaired) - { - var seriesKey = GetUniqueSeriesKey(this); - - Logger.Debug("GetSeasons SeriesKey: {0}", seriesKey); - var seasons = LibraryManager.GetItemList(new InternalItemsQuery(user) - { - AncestorWithPresentationUniqueKey = seriesKey, - IncludeItemTypes = new[] { typeof(Season).Name }, - SortBy = new[] { ItemSortBy.SortName } - - }).Cast().ToList(); - - - if (!includeMissingSeasons) - { - seasons = seasons.Where(i => !(i.IsMissingSeason)).ToList(); - } - - if (!includeVirtualUnaired) - { - seasons = seasons.Where(i => !i.IsVirtualUnaired).ToList(); - } - - return seasons; - } - public IEnumerable GetEpisodes(User user) - { - var config = user.Configuration; - - return GetEpisodes(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); - } - - public IEnumerable GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired) { var seriesKey = GetUniqueSeriesKey(this); Logger.Debug("GetEpisodes seriesKey: {0}", seriesKey); - var allItems = LibraryManager.GetItemList(new InternalItemsQuery(user) + var query = new InternalItemsQuery(user) { AncestorWithPresentationUniqueKey = seriesKey, - IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }, - SortBy = new[] { ItemSortBy.SortName } + IncludeItemTypes = new[] {typeof (Episode).Name, typeof (Season).Name}, + SortBy = new[] {ItemSortBy.SortName} + }; + var config = user.Configuration; + if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes) + { + query.IsVirtualItem = false; + } + else if (!config.DisplayMissingEpisodes) + { + query.IsMissing = false; + } + else if (!config.DisplayUnairedEpisodes) + { + query.IsVirtualUnaired = false; + } - }).ToList(); + var allItems = LibraryManager.GetItemList(query).ToList(); Logger.Debug("GetEpisodes return {0} items from database", allItems.Count); var allSeriesEpisodes = allItems.OfType().ToList(); var allEpisodes = allItems.OfType() - .SelectMany(i => i.GetEpisodes(this, user, includeMissing, includeVirtualUnaired, allSeriesEpisodes)) + .SelectMany(i => i.GetEpisodes(this, user, allSeriesEpisodes)) .Reverse() .ToList(); @@ -370,13 +373,6 @@ namespace MediaBrowser.Controller.Entities.TV progress.Report(100); } - public IEnumerable GetSeasonEpisodes(User user, Season season) - { - var config = user.Configuration; - - return GetSeasonEpisodes(user, season, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); - } - private IEnumerable GetAllEpisodes(User user) { Logger.Debug("Series.GetAllEpisodes entering GetItemList"); @@ -394,64 +390,53 @@ namespace MediaBrowser.Controller.Entities.TV return result; } - public IEnumerable GetSeasonEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) + public IEnumerable GetSeasonEpisodes(User user, Season parentSeason) { - IEnumerable episodes = GetAllEpisodes(user); + var seriesKey = GetUniqueSeriesKey(this); + Logger.Debug("GetSeasonEpisodes seriesKey: {0}", seriesKey); - return GetSeasonEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes); + var query = new InternalItemsQuery(user) + { + AncestorWithPresentationUniqueKey = seriesKey, + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { ItemSortBy.SortName } + }; + var config = user.Configuration; + if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes) + { + query.IsVirtualItem = false; + } + else if (!config.DisplayMissingEpisodes) + { + query.IsMissing = false; + } + else if (!config.DisplayUnairedEpisodes) + { + query.IsVirtualUnaired = false; + } + + var allItems = LibraryManager.GetItemList(query).OfType(); + + return GetSeasonEpisodes(user, parentSeason, allItems); } - public IEnumerable GetSeasonEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable allSeriesEpisodes) + public IEnumerable GetSeasonEpisodes(User user, Season parentSeason, IEnumerable allSeriesEpisodes) { if (allSeriesEpisodes == null) { Logger.Debug("GetSeasonEpisodes allSeriesEpisodes is null"); - return GetSeasonEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes); + return GetSeasonEpisodes(user, parentSeason); } Logger.Debug("GetSeasonEpisodes FilterEpisodesBySeason"); var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons); - if (!includeMissingEpisodes) - { - episodes = episodes.Where(i => !i.IsMissingEpisode); - } - if (!includeVirtualUnairedEpisodes) - { - episodes = episodes.Where(i => !i.IsVirtualUnaired); - } - var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder; return LibraryManager.Sort(episodes, user, new[] { sortBy }, SortOrder.Ascending) .Cast(); } - /// - /// Filters the episodes by season. - /// - public static IEnumerable FilterEpisodesBySeason(IEnumerable episodes, int seasonNumber, bool includeSpecials) - { - if (!includeSpecials || seasonNumber < 1) - { - return episodes.Where(i => (i.ParentIndexNumber ?? -1) == seasonNumber); - } - - return episodes.Where(i => - { - var episode = i; - - if (episode != null) - { - var currentSeasonNumber = episode.AiredSeasonNumber; - - return currentSeasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber; - } - - return false; - }); - } - /// /// Filters the episodes by season. /// @@ -480,6 +465,32 @@ namespace MediaBrowser.Controller.Entities.TV }); } + /// + /// Filters the episodes by season. + /// + public static IEnumerable FilterEpisodesBySeason(IEnumerable episodes, int seasonNumber, bool includeSpecials) + { + if (!includeSpecials || seasonNumber < 1) + { + return episodes.Where(i => (i.ParentIndexNumber ?? -1) == seasonNumber); + } + + return episodes.Where(i => + { + var episode = i; + + if (episode != null) + { + var currentSeasonNumber = episode.AiredSeasonNumber; + + return currentSeasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber; + } + + return false; + }); + } + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Series); diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 6128192ea2..9f3acc3fc3 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1100,8 +1100,6 @@ namespace MediaBrowser.Controller.Entities bool? isVirtualUnaired, bool? isUnaired) { - items = FilterVirtualSeasons(items, isMissing, isVirtualUnaired, isUnaired); - if (isMissing.HasValue) { var val = isMissing.Value; @@ -1147,57 +1145,6 @@ namespace MediaBrowser.Controller.Entities return items; } - private static IEnumerable FilterVirtualSeasons( - IEnumerable items, - bool? isMissing, - bool? isVirtualUnaired, - bool? isUnaired) - { - if (isMissing.HasValue) - { - var val = isMissing.Value; - items = items.Where(i => - { - var e = i as Season; - if (e != null) - { - return (e.IsMissingSeason) == val; - } - return true; - }); - } - - if (isUnaired.HasValue) - { - var val = isUnaired.Value; - items = items.Where(i => - { - var e = i as Season; - if (e != null) - { - return e.IsUnaired == val; - } - return true; - }); - } - - if (isVirtualUnaired.HasValue) - { - var val = isVirtualUnaired.Value; - items = items.Where(i => - { - var e = i as Season; - if (e != null) - { - return e.IsVirtualUnaired == val; - } - return true; - }); - } - - return items; - } - public static QueryResult SortAndPage(IEnumerable items, int? totalRecordLimit, InternalItemsQuery query, diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index db896f1fc7..4197ea93e5 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -112,5 +112,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.YearPath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index c07934d0b1..c89a60a6f8 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -106,5 +106,7 @@ namespace MediaBrowser.Controller /// /// The internal metadata path. string InternalMetadataPath { get; } + + string ArtistsPath { get; } } } \ No newline at end of file diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index c8a28e832a..e90f6bdc36 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -343,14 +343,16 @@ namespace MediaBrowser.MediaEncoding.Encoder // If that doesn't pan out, then do a recursive search var files = Directory.GetFiles(path); - var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); - var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); + var excludeExtensions = new[] { ".c" }; + + var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); + var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); if (string.IsNullOrWhiteSpace(ffmpegPath) || !File.Exists(ffmpegPath)) { files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); - ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); + ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); if (!string.IsNullOrWhiteSpace(ffmpegPath)) { diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 04437cff79..2a69948b1a 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -42,6 +42,13 @@ namespace MediaBrowser.Providers.Manager var config = ProviderManager.GetMetadataOptions(item); var updateType = ItemUpdateType.None; + var requiresRefresh = false; + + if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) + { + // TODO: If this returns true, should we instead just change metadata refresh mode to Full? + requiresRefresh = item.RequiresRefresh(); + } var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem); var localImagesFailed = false; @@ -70,14 +77,10 @@ namespace MediaBrowser.Providers.Manager bool hasRefreshedMetadata = true; bool hasRefreshedImages = true; - var requiresRefresh = false; // Next run metadata providers if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) { - // TODO: If this returns true, should we instead just change metadata refresh mode to Full? - requiresRefresh = item.RequiresRefresh(); - var providers = GetProviders(item, refreshOptions, requiresRefresh) .ToList(); diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 3d257d1947..be68162caf 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -955,20 +955,23 @@ namespace MediaBrowser.Server.Implementations.Dto dto.Genres = item.Genres; } - dto.ImageTags = new Dictionary(); - - // Prevent implicitly captured closure - var currentItem = item; - foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type)) - .ToList()) + if (options.EnableImages) { - if (options.GetImageLimit(image.Type) > 0) - { - var tag = GetImageCacheTag(item, image); + dto.ImageTags = new Dictionary(); - if (tag != null) + // Prevent implicitly captured closure + var currentItem = item; + foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type)) + .ToList()) + { + if (options.GetImageLimit(image.Type) > 0) { - dto.ImageTags[image.Type] = tag; + var tag = GetImageCacheTag(item, image); + + if (tag != null) + { + dto.ImageTags[image.Type] = tag; + } } } } @@ -1527,97 +1530,6 @@ namespace MediaBrowser.Server.Implementations.Dto } } - /// - /// Since it can be slow to make all of these calculations independently, this method will provide a way to do them all at once - /// - /// The folder. - /// The user. - /// The dto. - /// The fields. - /// The synchronize progress. - /// Task. - private async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List fields, Dictionary syncProgress) - { - var recursiveItemCount = 0; - var unplayed = 0; - - double totalPercentPlayed = 0; - double totalSyncPercent = 0; - - var children = await folder.GetItems(new InternalItemsQuery - { - IsFolder = false, - Recursive = true, - ExcludeLocationTypes = new[] { LocationType.Virtual }, - User = user - - }).ConfigureAwait(false); - - // Loop through each recursive child - foreach (var child in children.Items) - { - var userdata = _userDataRepository.GetUserData(user, child); - - recursiveItemCount++; - - var isUnplayed = true; - - // Incrememt totalPercentPlayed - if (userdata != null) - { - if (userdata.Played) - { - totalPercentPlayed += 100; - - isUnplayed = false; - } - else if (userdata.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0) - { - double itemPercent = userdata.PlaybackPositionTicks; - itemPercent /= child.RunTimeTicks.Value; - totalPercentPlayed += itemPercent; - } - } - - if (isUnplayed) - { - unplayed++; - } - - double percent = 0; - SyncJobItemStatus syncItemProgress; - if (syncProgress.TryGetValue(child.Id.ToString("N"), out syncItemProgress)) - { - switch (syncItemProgress) - { - case SyncJobItemStatus.Synced: - percent = 100; - break; - case SyncJobItemStatus.Converting: - case SyncJobItemStatus.ReadyToTransfer: - case SyncJobItemStatus.Transferring: - percent = 50; - break; - } - } - totalSyncPercent += percent; - } - - dto.RecursiveItemCount = recursiveItemCount; - dto.UserData.UnplayedItemCount = unplayed; - - if (recursiveItemCount > 0) - { - dto.UserData.PlayedPercentage = totalPercentPlayed / recursiveItemCount; - - var pct = totalSyncPercent / recursiveItemCount; - if (pct > 0) - { - dto.SyncPercent = pct; - } - } - } - /// /// Attaches the primary image aspect ratio. /// diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index a19f70e68c..a5e6c1b92d 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -829,7 +829,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Task{Person}. public Person GetPerson(string name) { - return GetItemByName(ConfigurationManager.ApplicationPaths.PeoplePath, name); + return CreateItemByName(Person.GetPath(name), name); } /// @@ -839,7 +839,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Task{Studio}. public Studio GetStudio(string name) { - return GetItemByName(ConfigurationManager.ApplicationPaths.StudioPath, name); + return CreateItemByName(Studio.GetPath(name), name); } /// @@ -849,7 +849,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Task{Genre}. public Genre GetGenre(string name) { - return GetItemByName(ConfigurationManager.ApplicationPaths.GenrePath, name); + return CreateItemByName(Genre.GetPath(name), name); } /// @@ -859,7 +859,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Task{MusicGenre}. public MusicGenre GetMusicGenre(string name) { - return GetItemByName(ConfigurationManager.ApplicationPaths.MusicGenrePath, name); + return CreateItemByName(MusicGenre.GetPath(name), name); } /// @@ -869,14 +869,9 @@ namespace MediaBrowser.Server.Implementations.Library /// Task{GameGenre}. public GameGenre GetGameGenre(string name) { - return GetItemByName(ConfigurationManager.ApplicationPaths.GameGenrePath, name); + return CreateItemByName(GameGenre.GetPath(name), name); } - /// - /// The us culture - /// - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// /// Gets a Year /// @@ -890,19 +885,9 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentOutOfRangeException("Years less than or equal to 0 are invalid."); } - return GetItemByName(ConfigurationManager.ApplicationPaths.YearPath, value.ToString(UsCulture)); - } + var name = value.ToString(CultureInfo.InvariantCulture); - /// - /// Gets the artists path. - /// - /// The artists path. - public string ArtistsPath - { - get - { - return Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "artists"); - } + return CreateItemByName(Year.GetPath(name), name); } /// @@ -912,48 +897,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Task{Genre}. public MusicArtist GetArtist(string name) { - return GetItemByName(ArtistsPath, name); - } - - private T GetItemByName(string path, string name) - where T : BaseItem, new() - { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException("path"); - } - - if (string.IsNullOrWhiteSpace(name)) - { - throw new ArgumentNullException("name"); - } - - // Trim the period at the end because windows will have a hard time with that - var validFilename = _fileSystem.GetValidFilename(name) - .Trim() - .TrimEnd('.'); - - string subFolderPrefix = null; - - var type = typeof(T); - - if (type == typeof(Person)) - { - foreach (char c in validFilename) - { - if (char.IsLetterOrDigit(c)) - { - subFolderPrefix = c.ToString(); - break; - } - } - } - - var fullPath = string.IsNullOrEmpty(subFolderPrefix) ? - Path.Combine(path, validFilename) : - Path.Combine(path, subFolderPrefix, validFilename); - - return CreateItemByName(fullPath, name); + return CreateItemByName(MusicArtist.GetPath(name), name); } private T CreateItemByName(string path, string name) diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index cf6f070d03..a6d6b5cb8b 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -166,12 +166,12 @@ namespace MediaBrowser.Server.Implementations.Library ExcludeItemTypes = excludeItemTypes.ToArray(), IncludeItemTypes = includeItemTypes.ToArray(), Limit = query.Limit, - IncludeItemsByName = true - + IncludeItemsByName = true, + IsVirtualItem = false }); // Add search hints based on item name - hints.AddRange(mediaItems.Where(IncludeInSearch).Select(item => + hints.AddRange(mediaItems.Select(item => { var index = GetIndex(item.Name, searchTerm, terms); @@ -187,20 +187,6 @@ namespace MediaBrowser.Server.Implementations.Library return Task.FromResult(returnValue); } - private bool IncludeInSearch(BaseItem item) - { - var episode = item as Episode; - - if (episode != null) - { - if (episode.IsMissingEpisode) - { - return false; - } - } - return true; - } - /// /// Gets the index. /// diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index cf8e2fe36c..8006e2b08d 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -3095,6 +3095,17 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("LocationType<>'Virtual'"); } } + if (query.IsSpecialSeason.HasValue) + { + if (query.IsSpecialSeason.Value) + { + whereClauses.Add("IndexNumber = 0"); + } + else + { + whereClauses.Add("IndexNumber <> 0"); + } + } if (query.IsUnaired.HasValue) { if (query.IsUnaired.Value) diff --git a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs index 8a04f29a2c..237d49fdae 100644 --- a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs +++ b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs @@ -88,6 +88,14 @@ namespace MediaBrowser.Server.Implementations } } + public string ArtistsPath + { + get + { + return Path.Combine(ItemsByNamePath, "artists"); + } + } + /// /// Gets the path to the Genre directory /// diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 84aab5e1f8..f495e557a3 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1001,7 +1001,8 @@ namespace MediaBrowser.Server.Implementations.Session var series = episode.Series; if (series != null) { - var episodes = series.GetEpisodes(user, false, false) + var episodes = series.GetEpisodes(user) + .Where(i => !i.IsVirtualItem) .SkipWhile(i => i.Id != episode.Id) .ToList(); From 3162d71c45a51ea8a66d5cc8ab26d93397299aae Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 02:01:28 -0400 Subject: [PATCH 70/85] 3.1.111 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index bfd63aaf2a..3d1700aeea 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.110")] +[assembly: AssemblyVersion("3.1.111")] From 389487638ec358c975f7573c8b6132525f3925ab Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 02:26:47 -0400 Subject: [PATCH 71/85] fixes #1851 - EmbyServer crashes if staticly assigned IP address changes --- .../HttpServer/HttpListenerHost.cs | 50 +++++++++++++++++++ .../ApplicationHost.cs | 35 +------------ 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 90055d8ec1..6332087391 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -331,6 +331,46 @@ namespace MediaBrowser.Server.Implementations.HttpServer return url; } + private string NormalizeConfiguredLocalAddress(string address) + { + var index = address.Trim('/').IndexOf('/'); + + if (index != -1) + { + address = address.Substring(index + 1); + } + + return address.Trim('/'); + } + + private bool ValidateHost(Uri url) + { + var hosts = _config + .Configuration + .LocalNetworkAddresses + .Select(NormalizeConfiguredLocalAddress) + .ToList(); + + if (hosts.Count == 0) + { + return true; + } + + var host = url.Host ?? string.Empty; + + _logger.Debug("Validating host {0}", host); + + if (_networkManager.IsInPrivateAddressSpace(host)) + { + hosts.Add("localhost"); + hosts.Add("127.0.0.1"); + + return hosts.Any(i => host.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1); + } + + return true; + } + /// /// Overridable method that can be used to implement a custom hnandler /// @@ -350,6 +390,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer return ; } + if (!ValidateHost(url)) + { + httpRes.StatusCode = 400; + httpRes.ContentType = "text/plain"; + httpRes.Write("Invalid host"); + + httpRes.Close(); + return; + } + var operationName = httpReq.OperationName; var localPath = url.LocalPath; diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 74438abbcf..9eb8a47366 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -821,42 +821,11 @@ namespace MediaBrowser.Server.Startup.Common private string CertificatePath { get; set; } - private string NormalizeConfiguredLocalAddress(string address) - { - var index = address.Trim('/').IndexOf('/'); - - if (index != -1) - { - address = address.Substring(index + 1); - } - - return address.Trim('/'); - } private IEnumerable GetUrlPrefixes() { - var hosts = ServerConfigurationManager - .Configuration - .LocalNetworkAddresses - .Select(NormalizeConfiguredLocalAddress) - .ToList(); + var hosts = new List(); - if (hosts.Count == 0) - { - hosts.Add("+"); - } - - if (!hosts.Contains("+", StringComparer.OrdinalIgnoreCase)) - { - if (!hosts.Contains("localhost", StringComparer.OrdinalIgnoreCase)) - { - hosts.Add("localhost"); - } - - if (!hosts.Contains("127.0.0.1", StringComparer.OrdinalIgnoreCase)) - { - hosts.Add("127.0.0.1"); - } - } + hosts.Add("+"); return hosts.SelectMany(i => { From 845c4a0d62e05b89d0a8bc3900b54e3c2cb75168 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 11:13:18 -0400 Subject: [PATCH 72/85] update item by name validators --- MediaBrowser.Api/UserLibrary/ItemsService.cs | 19 +------- MediaBrowser.Controller/Entities/Folder.cs | 8 ++++ .../Persistence/IItemRepository.cs | 4 ++ .../Probing/ProbeResultNormalizer.cs | 7 +-- .../Resolvers/SpecialFolderResolver.cs | 3 +- .../Library/Validators/ArtistsPostScanTask.cs | 7 ++- .../Library/Validators/ArtistsValidator.cs | 18 ++++---- .../Library/Validators/StudiosPostScanTask.cs | 7 ++- .../Library/Validators/StudiosValidator.cs | 18 ++++---- .../Persistence/SqliteItemRepository.cs | 46 +++++++++++++++++++ 10 files changed, 95 insertions(+), 42 deletions(-) diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 97a81b7909..9194cdb354 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -157,24 +157,7 @@ namespace MediaBrowser.Api.UserLibrary folder = user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder(); } - if (!string.IsNullOrEmpty(request.Ids)) - { - request.Recursive = true; - var query = GetItemsQuery(request, user); - var result = await folder.GetItems(query).ConfigureAwait(false); - - if (string.IsNullOrWhiteSpace(request.SortBy)) - { - var ids = query.ItemIds.ToList(); - - // Try to preserve order - result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray(); - } - - return result; - } - - if (request.Recursive) + if (request.Recursive || !string.IsNullOrEmpty(request.Ids)) { return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b19667942d..b5c76c0ebc 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -903,6 +903,14 @@ namespace MediaBrowser.Controller.Entities if (query.ItemIds.Length > 0) { var specificItems = query.ItemIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList(); + + if (query.SortBy.Length == 0) + { + var ids = query.ItemIds.ToList(); + + // Try to preserve order + specificItems = specificItems.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToList(); + } return Task.FromResult(PostFilterAndSort(specificItems, query, true, true)); } diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 437f0e157a..edfec902b8 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -170,6 +170,10 @@ namespace MediaBrowser.Controller.Persistence QueryResult> GetArtists(InternalItemsQuery query); QueryResult> GetAlbumArtists(InternalItemsQuery query); QueryResult> GetAllArtists(InternalItemsQuery query); + + List GetStudioNames(); + + List GetAllArtistNames(); } } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 9e9bc0780e..700af682bf 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Text; using System.Xml; using CommonIO; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -793,7 +794,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrWhiteSpace(artists)) { audio.Artists = SplitArtists(artists, new[] { '/', ';' }, false) - .Distinct(StringComparer.OrdinalIgnoreCase) + .DistinctNames() .ToList(); } else @@ -806,7 +807,7 @@ namespace MediaBrowser.MediaEncoding.Probing else { audio.Artists = SplitArtists(artist, _nameDelimiters, true) - .Distinct(StringComparer.OrdinalIgnoreCase) + .DistinctNames() .ToList(); } } @@ -828,7 +829,7 @@ namespace MediaBrowser.MediaEncoding.Probing else { audio.AlbumArtists = SplitArtists(albumArtist, _nameDelimiters, true) - .Distinct(StringComparer.OrdinalIgnoreCase) + .DistinctNames() .ToList(); } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs index 144f788a72..7bb66ed89d 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -50,7 +50,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers { return new CollectionFolder { - CollectionType = GetCollectionType(args) + CollectionType = GetCollectionType(args), + PhysicalLocationsList = args.PhysicalLocations.ToList() }; } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs index 079867ddd8..91b035a350 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -16,15 +17,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; /// /// Initializes a new instance of the class. /// /// The library manager. - public ArtistsPostScanTask(ILibraryManager libraryManager, ILogger logger) + public ArtistsPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -35,7 +38,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public Task Run(IProgress progress, CancellationToken cancellationToken) { - return new ArtistsValidator(_libraryManager, _logger).Run(progress, cancellationToken); + return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs index 353be1a44f..3dcdbeae9d 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -24,16 +25,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _logger /// private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; /// /// Initializes a new instance of the class. /// /// The library manager. /// The logger. - public ArtistsValidator(ILibraryManager libraryManager, ILogger logger) + public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -44,18 +47,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var items = _libraryManager.GetAllArtists(new InternalItemsQuery()) - .Items - .Select(i => i.Item1) - .ToList(); + var names = _itemRepo.GetAllArtistNames(); var numComplete = 0; - var count = items.Count; + var count = names.Count; - foreach (var item in items) + foreach (var name in names) { try { + var item = _libraryManager.GetArtist(name); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -65,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing {0}", ex, item.Name); + _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs index 0ff609da15..77c6d51465 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -17,15 +18,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; /// /// Initializes a new instance of the class. /// /// The library manager. - public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger) + public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -36,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public Task Run(IProgress progress, CancellationToken cancellationToken) { - return new StudiosValidator(_libraryManager, _logger).Run(progress, cancellationToken); + return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs index 722b74891e..a19b8158a0 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -15,15 +16,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// private readonly ILibraryManager _libraryManager; + private readonly IItemRepository _itemRepo; /// /// The _logger /// private readonly ILogger _logger; - public StudiosValidator(ILibraryManager libraryManager, ILogger logger) + public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -34,18 +37,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var items = _libraryManager.GetStudios(new InternalItemsQuery()) - .Items - .Select(i => i.Item1) - .ToList(); + var names = _itemRepo.GetStudioNames(); var numComplete = 0; - var count = items.Count; + var count = names.Count; - foreach (var item in items) + foreach (var name in names) { try { + var item = _libraryManager.GetStudio(name); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -55,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing {0}", ex, item.Name); + _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 8006e2b08d..f04b9f50a4 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -3880,6 +3880,52 @@ namespace MediaBrowser.Server.Implementations.Persistence return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName); } + public List GetStudioNames() + { + return GetItemValueNames(new[] { 3 }); + } + + public List GetAllArtistNames() + { + return GetItemValueNames(new[] { 0, 1 }); + } + + private List GetItemValueNames(int[] itemValueTypes) + { + CheckDisposed(); + + var now = DateTime.UtcNow; + + var typeClause = itemValueTypes.Length == 1 ? + ("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) : + ("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()) + ")"); + + var list = new List(); + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "Select Value From ItemValues where " + typeClause + " Group By CleanValue"; + + var commandBehavior = CommandBehavior.SequentialAccess | CommandBehavior.SingleResult; + + using (var reader = cmd.ExecuteReader(commandBehavior)) + { + LogQueryTime("GetItemValueNames", cmd, now); + + while (reader.Read()) + { + if (!reader.IsDBNull(0)) + { + list.Add(reader.GetString(0)); + } + } + } + + } + + return list; + } + private QueryResult> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType) { if (query == null) From db9c02fffddc15f4660f2462093e72ba257f8acb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 12:45:36 -0400 Subject: [PATCH 73/85] update notifications --- MediaBrowser.Api/UserLibrary/ItemsService.cs | 25 ++++++++++++++----- .../Library/LibraryManager.cs | 7 +++++- .../Persistence/SqliteItemRepository.cs | 6 ++--- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 9194cdb354..ce7905b42f 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -149,6 +149,24 @@ namespace MediaBrowser.Api.UserLibrary item = user == null ? _libraryManager.RootFolder : user.RootFolder; } + if (!string.IsNullOrEmpty(request.Ids)) + { + var query = GetItemsQuery(request, user); + var specificItems = _libraryManager.GetItemList(query).ToArray(); + if (query.SortBy.Length == 0) + { + var ids = query.ItemIds.ToList(); + + // Try to preserve order + specificItems = specificItems.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray(); + } + return new QueryResult + { + Items = specificItems.ToArray(), + TotalRecordCount = specificItems.Length + }; + } + // Default list type = children var folder = item as Folder; @@ -157,16 +175,11 @@ namespace MediaBrowser.Api.UserLibrary folder = user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder(); } - if (request.Recursive || !string.IsNullOrEmpty(request.Ids)) + if (request.Recursive || !string.IsNullOrEmpty(request.Ids) || user == null) { return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); } - if (user == null) - { - return await folder.GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); - } - var userRoot = item as UserRootFolder; if (userRoot == null) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index a5e6c1b92d..cc3a7e41f8 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1465,7 +1465,12 @@ namespace MediaBrowser.Server.Implementations.Library private void AddUserToQuery(InternalItemsQuery query, User user) { - if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0 && string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)) + if (query.AncestorIds.Length == 0 && + !query.ParentId.HasValue && + query.ChannelIds.Length == 0 && + query.TopParentIds.Length == 0 && + string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey) + && query.ItemIds.Length == 0) { var userViews = _userviewManager().GetUserViews(new UserViewQuery { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index f04b9f50a4..2ac625ebc7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -3152,17 +3152,17 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (query.ItemIds.Length > 0) { - var excludeIds = new List(); + var includeIds = new List(); var index = 0; foreach (var id in query.ItemIds) { - excludeIds.Add("Guid = @IncludeId" + index); + includeIds.Add("Guid = @IncludeId" + index); cmd.Parameters.Add(cmd, "@IncludeId" + index, DbType.Guid).Value = new Guid(id); index++; } - whereClauses.Add(string.Join(" OR ", excludeIds.ToArray())); + whereClauses.Add(string.Join(" OR ", includeIds.ToArray())); } if (query.ExcludeItemIds.Length > 0) { From a1a5446342ca653f57ba21a9ac291f42897c4caf Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 13:35:52 -0400 Subject: [PATCH 74/85] 3.1.112 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 3d1700aeea..4edf0e251a 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.111")] +[assembly: AssemblyVersion("3.1.112")] From 66a80ac6b9fee945631e2f1a0a4b6871b7465950 Mon Sep 17 00:00:00 2001 From: softworkz Date: Thu, 18 Aug 2016 22:05:54 +0200 Subject: [PATCH 75/85] EpisodeFileOrganizer: Improve error handling (alternate approach) Previously some methods were just returning null or empty values in case of encountered errors; as a consequence, the actual reason for failure was never written to the auto-organize log. Instead, only a generic message like "Unable to sort xxx because target path could not be determined." was displayed. After this change, the actual reason for failure will be saved to the auto-organize log or displayed in the UI (when completing the organize dialog). This information is very important for the user. Examples are "No permission", "Target folder not available", "Disk full", etc.. --- .../FileOrganization/EpisodeFileOrganizer.cs | 50 +++++++++++++------ .../FileOrganizationService.cs | 14 +++++- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 2109f8d59e..39992b65dd 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -43,13 +43,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _providerManager = providerManager; } - public Task OrganizeEpisodeFile(string path, CancellationToken cancellationToken) - { - var options = _config.GetAutoOrganizeOptions(); - - return OrganizeEpisodeFile(path, options, false, cancellationToken); - } - public async Task OrganizeEpisodeFile(string path, AutoOrganizeOptions options, bool overwriteExisting, CancellationToken cancellationToken) { _logger.Info("Sorting file {0}", path); @@ -63,6 +56,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization FileSize = new FileInfo(path).Length }; + try + { if (_libraryMonitor.IsPathLocked(path)) { result.Status = FileSortingStatus.Failure; @@ -148,6 +143,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + result.Status = FileSortingStatus.Failure; + result.StatusMessage = ex.Message; + } return result; } @@ -156,6 +157,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { var result = _organizationService.GetResult(request.ResultId); + try + { Series series = null; if (request.NewSeriesProviderIds.Count > 0) @@ -207,6 +210,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization cancellationToken).ConfigureAwait(false); await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + result.Status = FileSortingStatus.Failure; + result.StatusMessage = ex.Message; + } return result; } @@ -263,16 +272,15 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var originalExtractedSeriesString = result.ExtractedName; + try + { // Proceed to sort the file var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(newPath)) { var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath); - result.Status = FileSortingStatus.Failure; - result.StatusMessage = msg; - _logger.Warn(msg); - return; + throw new Exception(msg); } _logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath); @@ -347,6 +355,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } } } + } + catch (Exception ex) + { + result.Status = FileSortingStatus.Failure; + result.StatusMessage = ex.Message; + _logger.Warn(ex.Message); + return; + } if (rememberCorrection) { @@ -505,7 +521,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } catch (Exception ex) { - var errorMsg = string.Format("Failed to move file from {0} to {1}", result.OriginalPath, result.TargetPath); + var errorMsg = string.Format("Failed to move file from {0} to {1}: {2}", result.OriginalPath, result.TargetPath, ex.Message); result.Status = FileSortingStatus.Failure; result.StatusMessage = errorMsg; @@ -616,7 +632,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber); _logger.Warn(msg); - return null; + throw new Exception(msg); } var episodeName = episode.Name; @@ -715,6 +731,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var pattern = endingEpisodeNumber.HasValue ? options.MultiEpisodeNamePattern : options.EpisodeNamePattern; + if (string.IsNullOrWhiteSpace(pattern)) + { + throw new Exception("GetEpisodeFileName: Configured episode name pattern is empty!"); + } + var result = pattern.Replace("%sn", seriesName) .Replace("%s.n", seriesName.Replace(" ", ".")) .Replace("%s_n", seriesName.Replace(" ", "_")) @@ -759,8 +780,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization // There may be cases where reducing the title length may still not be sufficient to // stay below maxLength var msg = string.Format("Unable to generate an episode file name shorter than {0} characters to constrain to the max path limit", maxLength); - _logger.Warn(msg); - return string.Empty; + throw new Exception(msg); } return result; diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs index 60d515e120..9e16613e62 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs @@ -112,8 +112,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); - await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeOptions(), true, CancellationToken.None) + var organizeResult = await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeOptions(), true, CancellationToken.None) .ConfigureAwait(false); + + if (organizeResult.Status != FileSortingStatus.Success) + { + throw new Exception(result.StatusMessage); + } } public Task ClearLog() @@ -126,7 +131,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); - await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false); + var result = await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false); + + if (result.Status != FileSortingStatus.Success) + { + throw new Exception(result.StatusMessage); + } } public QueryResult GetSmartMatchInfos(FileOrganizationResultQuery query) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 3d8e7a3d6d..6acb0783eb 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1139,7 +1139,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); - var result = await organize.OrganizeEpisodeFile(path, CancellationToken.None).ConfigureAwait(false); + var result = await organize.OrganizeEpisodeFile(path, _config.GetAutoOrganizeOptions(), false, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { From 9ac5d5417bbc8141c9ce1e8af9e406c65e93119d Mon Sep 17 00:00:00 2001 From: softworkz Date: Tue, 16 Aug 2016 04:43:55 +0200 Subject: [PATCH 76/85] Add accurate bitrate reporting for ffmpeg jobs --- MediaBrowser.Api/ApiEntryPoint.cs | 8 ++++--- .../Playback/BaseStreamingService.cs | 24 ++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index bb9d2b8645..7c5f7cde40 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -192,13 +192,13 @@ namespace MediaBrowser.Api _activeTranscodingJobs.Add(job); - ReportTranscodingProgress(job, state, null, null, null, null); + ReportTranscodingProgress(job, state, null, null, null, null, null); return job; } } - public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded) + public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null; @@ -208,6 +208,7 @@ namespace MediaBrowser.Api job.CompletionPercentage = percentComplete; job.TranscodingPositionTicks = ticks; job.BytesTranscoded = bytesTranscoded; + job.BitRate = bitRate; } var deviceId = state.Request.DeviceId; @@ -219,7 +220,7 @@ namespace MediaBrowser.Api _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo { - Bitrate = state.TotalOutputBitrate, + Bitrate = bitRate ?? state.TotalOutputBitrate, AudioCodec = audioCodec, VideoCodec = videoCodec, Container = state.OutputContainer, @@ -694,6 +695,7 @@ namespace MediaBrowser.Api public long? BytesDownloaded { get; set; } public long? BytesTranscoded { get; set; } + public int? BitRate { get; set; } public long? TranscodingPositionTicks { get; set; } public long? DownloadPositionTicks { get; set; } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index ac967e1949..39fdc98f51 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1172,6 +1172,7 @@ namespace MediaBrowser.Api.Playback double? percent = null; TimeSpan? transcodingPosition = null; long? bytesTranscoded = null; + int? bitRate = null; var parts = line.Split(' '); @@ -1235,11 +1236,32 @@ namespace MediaBrowser.Api.Playback } } } + else if (part.StartsWith("bitrate=", StringComparison.OrdinalIgnoreCase)) + { + var rate = part.Split(new[] { '=' }, 2).Last(); + + int? scale = null; + if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1) + { + scale = 1024; + rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase); + } + + if (scale.HasValue) + { + float val; + + if (float.TryParse(rate, NumberStyles.Any, UsCulture, out val)) + { + bitRate = (int)Math.Ceiling(val * scale.Value); + } + } + } } if (framerate.HasValue || percent.HasValue) { - ApiEntryPoint.Instance.ReportTranscodingProgress(transcodingJob, state, transcodingPosition, framerate, percent, bytesTranscoded); + ApiEntryPoint.Instance.ReportTranscodingProgress(transcodingJob, state, transcodingPosition, framerate, percent, bytesTranscoded, bitRate); } } From eb36b009cab033ab339c2cc521f3aeab0dc744fd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 20:10:10 -0400 Subject: [PATCH 77/85] update stream start events --- .../Playback/BaseStreamingService.cs | 123 +++++++++++++++++- .../Encoder/MediaEncoder.cs | 12 ++ .../Configuration/ServerConfiguration.cs | 2 + .../ApplicationHost.cs | 3 + 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index ac967e1949..a8992ccbb5 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -22,6 +22,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller; namespace MediaBrowser.Api.Playback { @@ -69,6 +71,9 @@ namespace MediaBrowser.Api.Playback protected IZipClient ZipClient { get; private set; } protected IJsonSerializer JsonSerializer { get; private set; } + public static IServerApplicationHost AppHost; + public static IHttpClient HttpClient; + /// /// Initializes a new instance of the class. /// @@ -1112,6 +1117,7 @@ namespace MediaBrowser.Api.Playback } StartThrottler(state, transcodingJob); + ReportUsage(state); return transcodingJob; } @@ -1131,7 +1137,7 @@ namespace MediaBrowser.Api.Playback return state.InputProtocol == MediaProtocol.File && state.RunTimeTicks.HasValue && state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && - state.IsInputVideo && + state.IsInputVideo && state.VideoType == VideoType.VideoFile && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && string.Equals(GetVideoEncoder(state), "libx264", StringComparison.OrdinalIgnoreCase); @@ -2197,6 +2203,121 @@ namespace MediaBrowser.Api.Playback } } + private async void ReportUsage(StreamState state) + { + try + { + await ReportUsageInternal(state).ConfigureAwait(false); + } + catch + { + + } + } + + private Task ReportUsageInternal(StreamState state) + { + if (!ServerConfigurationManager.Configuration.EnableAnonymousUsageReporting) + { + return Task.FromResult(true); + } + + if (!string.Equals(MediaEncoder.EncoderLocationType, "Default", StringComparison.OrdinalIgnoreCase)) + { + return Task.FromResult(true); + } + + var dict = new Dictionary(); + + var outputAudio = GetAudioEncoder(state); + if (!string.IsNullOrWhiteSpace(outputAudio)) + { + dict["outputAudio"] = outputAudio; + } + + var outputVideo = GetVideoEncoder(state); + if (!string.IsNullOrWhiteSpace(outputVideo)) + { + dict["outputVideo"] = outputVideo; + } + + if (ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase) && + ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + { + return Task.FromResult(true); + } + + dict["id"] = AppHost.SystemId; + dict["type"] = state.VideoRequest == null ? "Audio" : "Video"; + + var audioStream = state.AudioStream; + if (audioStream != null && !string.IsNullOrWhiteSpace(audioStream.Codec)) + { + dict["inputAudio"] = audioStream.Codec; + } + + var videoStream = state.VideoStream; + if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec)) + { + dict["inputVideo"] = videoStream.Codec; + } + + var cert = GetType().Assembly.GetModules().First().GetSignerCertificate(); + if (cert != null) + { + dict["assemblySig"] = cert.GetCertHashString(); + dict["certSubject"] = cert.Subject ?? string.Empty; + dict["certIssuer"] = cert.Issuer ?? string.Empty; + } + else + { + return Task.FromResult(true); + } + + if (state.SupportedAudioCodecs.Count > 0) + { + dict["supportedAudioCodecs"] = string.Join(",", state.SupportedAudioCodecs.ToArray()); + } + + var auth = AuthorizationContext.GetAuthorizationInfo(Request); + + dict["appName"] = auth.Client ?? string.Empty; + dict["appVersion"] = auth.Version ?? string.Empty; + dict["device"] = auth.Device ?? string.Empty; + dict["deviceId"] = auth.DeviceId ?? string.Empty; + dict["context"] = "streaming"; + + Logger.Info(JsonSerializer.SerializeToString(dict)); + if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + { + var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); + list.Add(outputAudio); + ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); + } + + if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputVideo ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + { + var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); + list.Add(outputVideo); + ServerConfigurationManager.Configuration.CodecsUsed = list.ToArray(); + } + + ServerConfigurationManager.SaveConfiguration(); + + //Logger.Info(JsonSerializer.SerializeToString(dict)); + var options = new HttpRequestOptions() + { + Url = "https://mb3admin.com/admin/service/transcoding/report", + CancellationToken = CancellationToken.None, + LogRequest = false, + LogErrors = false + }; + options.RequestContent = JsonSerializer.SerializeToString(dict); + options.RequestContentType = "application/json"; + + return HttpClient.Post(options); + } + /// /// Adds the dlna headers. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index e90f6bdc36..f488be11a7 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -123,10 +123,22 @@ namespace MediaBrowser.MediaEncoding.Encoder return "System"; } + if (IsDefaultPath(FFMpegPath)) + { + return "Default"; + } + return "Custom"; } } + private bool IsDefaultPath(string path) + { + var parentPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg", "20160410"); + + return FileSystem.ContainsSubPath(parentPath, path); + } + private bool IsSystemInstalledPath(string path) { if (path.IndexOf("/", StringComparison.Ordinal) == -1 && path.IndexOf("\\", StringComparison.Ordinal) == -1) diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 303ba1acf7..63d452bcee 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -202,6 +202,7 @@ namespace MediaBrowser.Model.Configuration public bool DisplaySpecialsWithinSeasons { get; set; } public bool DisplayCollectionsView { get; set; } public string[] LocalNetworkAddresses { get; set; } + public string[] CodecsUsed { get; set; } /// /// Initializes a new instance of the class. @@ -210,6 +211,7 @@ namespace MediaBrowser.Model.Configuration { LocalNetworkAddresses = new string[] { }; Migrations = new string[] { }; + CodecsUsed = new string[] { }; SqliteCacheSize = 0; EnableLocalizedGuids = true; diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 9eb8a47366..8cb1d4f0db 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -101,6 +101,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Api.Playback; using MediaBrowser.Common.Implementations.Updates; namespace MediaBrowser.Server.Startup.Common @@ -766,6 +767,8 @@ namespace MediaBrowser.Server.Startup.Common BaseItem.CollectionManager = CollectionManager; BaseItem.MediaSourceManager = MediaSourceManager; CollectionFolder.XmlSerializer = XmlSerializer; + BaseStreamingService.AppHost = this; + BaseStreamingService.HttpClient = HttpClient; } /// From dea08933f1e645f364520a01806aaa57e8e61b71 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Aug 2016 23:57:36 -0400 Subject: [PATCH 78/85] update xmltv lib --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- .../MediaBrowser.Server.Implementations.csproj | 2 +- MediaBrowser.Server.Implementations/packages.config | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index fa4be8fc24..f52505c04b 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2309,7 +2309,7 @@ namespace MediaBrowser.Api.Playback dict["deviceId"] = auth.DeviceId ?? string.Empty; dict["context"] = "streaming"; - Logger.Info(JsonSerializer.SerializeToString(dict)); + //Logger.Info(JsonSerializer.SerializeToString(dict)); if (!ServerConfigurationManager.Configuration.CodecsUsed.Contains(outputAudio ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { var list = ServerConfigurationManager.Configuration.CodecsUsed.ToList(); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 442465430d..7fa9ee32c2 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -46,7 +46,7 @@ ..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll - ..\packages\Emby.XmlTv.1.0.0.55\lib\net45\Emby.XmlTv.dll + ..\packages\Emby.XmlTv.1.0.0.56\lib\net45\Emby.XmlTv.dll True diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index bac5a7c5d0..746dc7f62e 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -1,7 +1,7 @@  - + From 719ad3971e2fdf51341f388bb1f3cc572d70219a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Aug 2016 01:58:35 -0400 Subject: [PATCH 79/85] update genre validator --- .../Persistence/IItemRepository.cs | 4 +- .../Encoder/AudioEncoder.cs | 5 ++- .../Validators/GameGenresPostScanTask.cs | 7 +++- .../Library/Validators/GameGenresValidator.cs | 21 +++++----- .../Library/Validators/GenresPostScanTask.cs | 7 +++- .../Library/Validators/GenresValidator.cs | 21 +++++----- .../Validators/MusicGenresPostScanTask.cs | 7 +++- .../Validators/MusicGenresValidator.cs | 21 +++++----- .../Persistence/SqliteItemRepository.cs | 39 +++++++++++++++++-- 9 files changed, 87 insertions(+), 45 deletions(-) diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index edfec902b8..87937869d5 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -171,8 +171,10 @@ namespace MediaBrowser.Controller.Persistence QueryResult> GetAlbumArtists(InternalItemsQuery query); QueryResult> GetAllArtists(InternalItemsQuery query); + List GetGameGenreNames(); + List GetMusicGenreNames(); List GetStudioNames(); - + List GetGenreNames(); List GetAllArtistNames(); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs index cd1575fa58..f42582270f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs @@ -51,7 +51,10 @@ namespace MediaBrowser.MediaEncoding.Encoder var metadata = string.Empty; var vn = string.Empty; - if (!string.IsNullOrWhiteSpace(state.AlbumCoverPath)) + var hasArt = !string.IsNullOrWhiteSpace(state.AlbumCoverPath); + hasArt = false; + + if (hasArt) { albumCoverInput = " -i \"" + state.AlbumCoverPath + "\""; mapArgs = " -map 0:a -map 1:v -c:v copy"; diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs index 8be2e436fe..f3891180e2 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -16,16 +17,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; /// /// Initializes a new instance of the class. /// /// The library manager. /// The logger. - public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger) + public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -36,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public Task Run(IProgress progress, CancellationToken cancellationToken) { - return new GameGenresValidator(_libraryManager, _logger).Run(progress, cancellationToken); + return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs index 72864790b8..b06c0b3b9b 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -19,11 +20,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _logger /// private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - public GameGenresValidator(ILibraryManager libraryManager, ILogger logger) + public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -34,21 +37,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var items = _libraryManager.GetGameGenres(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Game).Name } - }) - .Items - .Select(i => i.Item1) - .ToList(); + var names = _itemRepo.GetGameGenreNames(); var numComplete = 0; - var count = items.Count; + var count = names.Count; - foreach (var item in items) + foreach (var name in names) { try { + var item = _libraryManager.GetGameGenre(name); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -58,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing {0}", ex, item.Name); + _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs index a1c34676c8..ed2429769c 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs @@ -2,6 +2,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Logging; namespace MediaBrowser.Server.Implementations.Library.Validators @@ -13,16 +14,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; /// /// Initializes a new instance of the class. /// /// The library manager. /// The logger. - public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger) + public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -33,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public Task Run(IProgress progress, CancellationToken cancellationToken) { - return new GenresValidator(_libraryManager, _logger).Run(progress, cancellationToken); + return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs index 6a62d7fe47..f35bb51363 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs @@ -6,6 +6,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -15,16 +16,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _library manager /// private readonly ILibraryManager _libraryManager; + private readonly IItemRepository _itemRepo; /// /// The _logger /// private readonly ILogger _logger; - public GenresValidator(ILibraryManager libraryManager, ILogger logger) + public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -35,21 +38,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var items = _libraryManager.GetGenres(new InternalItemsQuery - { - ExcludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(MusicVideo).Name, typeof(Game).Name } - }) - .Items - .Select(i => i.Item1) - .ToList(); + var names = _itemRepo.GetGenreNames(); var numComplete = 0; - var count = items.Count; + var count = names.Count; - foreach (var item in items) + foreach (var name in names) { try { + var item = _libraryManager.GetGenre(name); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -59,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing {0}", ex, item.Name); + _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs index dbcab0832a..777532ff87 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging; using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -16,16 +17,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; /// /// Initializes a new instance of the class. /// /// The library manager. /// The logger. - public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger) + public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -36,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public Task Run(IProgress progress, CancellationToken cancellationToken) { - return new MusicGenresValidator(_libraryManager, _logger).Run(progress, cancellationToken); + return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); } } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs index 2668d84e95..2be99f106e 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Server.Implementations.Library.Validators { @@ -20,11 +21,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// The _logger /// private readonly ILogger _logger; + private readonly IItemRepository _itemRepo; - public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger) + public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; + _itemRepo = itemRepo; } /// @@ -35,21 +38,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var items = _libraryManager.GetMusicGenres(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(MusicVideo).Name } - }) - .Items - .Select(i => i.Item1) - .ToList(); + var names = _itemRepo.GetMusicGenreNames(); var numComplete = 0; - var count = items.Count; + var count = names.Count; - foreach (var item in items) + foreach (var name in names) { try { + var item = _libraryManager.GetMusicGenre(name); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -59,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing {0}", ex, item.Name); + _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 2ac625ebc7..c3eee6d354 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -3882,18 +3882,36 @@ namespace MediaBrowser.Server.Implementations.Persistence public List GetStudioNames() { - return GetItemValueNames(new[] { 3 }); + return GetItemValueNames(new[] { 3 }, new List(), new List()); } public List GetAllArtistNames() { - return GetItemValueNames(new[] { 0, 1 }); + return GetItemValueNames(new[] { 0, 1 }, new List(), new List()); } - private List GetItemValueNames(int[] itemValueTypes) + public List GetMusicGenreNames() + { + return GetItemValueNames(new[] { 2 }, new List { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }, new List()); + } + + public List GetGameGenreNames() + { + return GetItemValueNames(new[] { 2 }, new List { "Game" }, new List()); + } + + public List GetGenreNames() + { + return GetItemValueNames(new[] { 2 }, new List(), new List { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist", "Game", "GameSystem" }); + } + + private List GetItemValueNames(int[] itemValueTypes, List withItemTypes, List excludeItemTypes) { CheckDisposed(); + withItemTypes = withItemTypes.SelectMany(MapIncludeItemTypes).ToList(); + excludeItemTypes = excludeItemTypes.SelectMany(MapIncludeItemTypes).ToList(); + var now = DateTime.UtcNow; var typeClause = itemValueTypes.Length == 1 ? @@ -3904,7 +3922,20 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "Select Value From ItemValues where " + typeClause + " Group By CleanValue"; + cmd.CommandText = "Select Value From ItemValues where " + typeClause; + + if (withItemTypes.Count > 0) + { + var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'").ToArray()); + cmd.CommandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))"; + } + if (excludeItemTypes.Count > 0) + { + var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'").ToArray()); + cmd.CommandText += " AND ItemId not In (select guid from typedbaseitems where type in (" + typeString + "))"; + } + + cmd.CommandText += " Group By CleanValue"; var commandBehavior = CommandBehavior.SequentialAccess | CommandBehavior.SingleResult; From 8f59f39873be3ee54aac1403d561031c459f4845 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Aug 2016 02:22:18 -0400 Subject: [PATCH 80/85] update default dlna profile --- MediaBrowser.Dlna/Profiles/DefaultProfile.cs | 20 +++++++++++++++---- MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs | 2 ++ MediaBrowser.Dlna/Profiles/DirectTvProfile.cs | 2 ++ .../Profiles/Foobar2000Profile.cs | 4 +++- MediaBrowser.Dlna/Profiles/LgTvProfile.cs | 2 ++ .../Profiles/LinksysDMA2100Profile.cs | 2 ++ .../Profiles/MediaMonkeyProfile.cs | 2 ++ .../Profiles/PopcornHourProfile.cs | 2 ++ .../Profiles/SonyBlurayPlayer2013Profile.cs | 2 ++ MediaBrowser.Dlna/Profiles/Xml/Default.xml | 10 +++++++--- 10 files changed, 40 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs index 76797c0e3a..e4f6d337fe 100644 --- a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs @@ -65,14 +65,26 @@ namespace MediaBrowser.Dlna.Profiles { new DirectPlayProfile { - Container = "mp3,wma", - Type = DlnaProfileType.Audio + Container = "m4v,ts,mkv,avi,mpg,mpeg,mp4", + VideoCodec = "h264", + AudioCodec = "aac,mp3,ac3", + Type = DlnaProfileType.Video }, new DirectPlayProfile { - Container = "avi,mp4", - Type = DlnaProfileType.Video + Container = "mp3,wma,aac,wav", + Type = DlnaProfileType.Audio + } + }; + + ResponseProfiles = new[] + { + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; } diff --git a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs index f8451bdfd8..fb498c4ce4 100644 --- a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs @@ -24,6 +24,8 @@ namespace MediaBrowser.Dlna.Profiles Type = DlnaProfileType.Audio }, }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/DirectTvProfile.cs b/MediaBrowser.Dlna/Profiles/DirectTvProfile.cs index 585f8652e6..c2a007a31a 100644 --- a/MediaBrowser.Dlna/Profiles/DirectTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DirectTvProfile.cs @@ -112,6 +112,8 @@ namespace MediaBrowser.Dlna.Profiles } } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs index 45cbbef6cb..2c1919c00e 100644 --- a/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs +++ b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Dlna.Profiles Name = "foobar2000"; SupportedMediaTypes = "Audio"; - + Identification = new DeviceIdentification { FriendlyName = @"foobar", @@ -70,6 +70,8 @@ namespace MediaBrowser.Dlna.Profiles Type = DlnaProfileType.Audio } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs index ab9a6a51ff..af81fabe43 100644 --- a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs @@ -198,6 +198,8 @@ namespace MediaBrowser.Dlna.Profiles Method = SubtitleDeliveryMethod.External } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs index da00d9e86e..2488cf5423 100644 --- a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs +++ b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs @@ -30,6 +30,8 @@ namespace MediaBrowser.Dlna.Profiles Type = DlnaProfileType.Video } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/MediaMonkeyProfile.cs b/MediaBrowser.Dlna/Profiles/MediaMonkeyProfile.cs index 7163252db2..eef847852d 100644 --- a/MediaBrowser.Dlna/Profiles/MediaMonkeyProfile.cs +++ b/MediaBrowser.Dlna/Profiles/MediaMonkeyProfile.cs @@ -70,6 +70,8 @@ namespace MediaBrowser.Dlna.Profiles Type = DlnaProfileType.Audio } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs b/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs index c98609393a..0e1210afbb 100644 --- a/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs +++ b/MediaBrowser.Dlna/Profiles/PopcornHourProfile.cs @@ -200,6 +200,8 @@ namespace MediaBrowser.Dlna.Profiles } } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs index dbade81705..cfc793c01e 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs @@ -181,6 +181,8 @@ namespace MediaBrowser.Dlna.Profiles } } }; + + ResponseProfiles = new ResponseProfile[] { }; } } } diff --git a/MediaBrowser.Dlna/Profiles/Xml/Default.xml b/MediaBrowser.Dlna/Profiles/Xml/Default.xml index 8fae686325..732b5baded 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Default.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Default.xml @@ -29,8 +29,8 @@ false - - + + @@ -39,6 +39,10 @@ - + + + + + \ No newline at end of file From df5450d0b62f7c9c409b35a6268c8fab64b0d403 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Aug 2016 02:23:26 -0400 Subject: [PATCH 81/85] 3.1.113 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 4edf0e251a..d1343f22e4 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.112")] +[assembly: AssemblyVersion("3.1.113")] From 6e01e277d41c9a8505cfdea7f65e95de5a72bf03 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Aug 2016 13:43:16 -0400 Subject: [PATCH 82/85] update new episode creation --- MediaBrowser.Providers/TV/DummySeasonProvider.cs | 4 +++- .../Library/Resolvers/TV/EpisodeResolver.cs | 3 +++ .../Library/Resolvers/TV/SeasonResolver.cs | 6 ++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs index baea0a06d2..fe0ad78be3 100644 --- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs +++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs @@ -112,7 +112,9 @@ namespace MediaBrowser.Providers.TV IndexNumber = seasonNumber, Id = _libraryManager.GetNewItemId((series.Id + (seasonNumber ?? -1).ToString(_usCulture) + seasonName), typeof(Season)), IsVirtualItem = isVirtualItem, - SeriesId = series.Id + SeriesId = series.Id, + SeriesName = series.Name, + SeriesSortName = series.SortName }; season.SetParent(series); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs index 2f940eb1d8..6edc4a009e 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -56,10 +56,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV if (series != null) { episode.SeriesId = series.Id; + episode.SeriesName = series.Name; + episode.SeriesSortName = series.SortName; } if (season != null) { episode.SeasonId = season.Id; + episode.SeasonName = season.Name; } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index eeac1345e8..fc49297482 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -43,9 +43,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV var season = new Season { IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(args.Path, true, true).SeasonNumber, - SeriesId = series.Id + SeriesId = series.Id, + SeriesSortName = series.SortName, + SeriesName = series.Name }; - + if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0) { season.Name = _config.Configuration.SeasonZeroDisplayName; From f5ad9186ec3730b92cfdf06947ae6a85912867dc Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Aug 2016 14:44:58 -0400 Subject: [PATCH 83/85] update boxset resolver --- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 +- .../Library/Resolvers/Movies/MovieResolver.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index caf440a83f..6d5278f1fe 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Movies { if (IsLegacyBoxSet) { - return base.LoadChildren(); + return base.GetNonCachedChildren(directoryService); } return new List(); } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 37d1e163f9..6558407538 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -48,6 +48,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies string collectionType, IDirectoryService directoryService) { + if (parent != null && parent.Path != null && parent.Path.IndexOf("disney", StringComparison.OrdinalIgnoreCase) != -1) + { + var b = true; + var a = b; + } + var result = ResolveMultipleInternal(parent, files, collectionType, directoryService); if (result != null) @@ -197,6 +203,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies /// Video. protected override Video Resolve(ItemResolveArgs args) { + if (args.Path != null && args.Path.IndexOf("disney", StringComparison.OrdinalIgnoreCase) != -1) + { + var b = true; + var a = b; + } + var collectionType = args.GetCollectionType(); if (IsInvalid(args.Parent, collectionType)) From e108e4f23a9c2c7b1930020799ef8577a39ecf54 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Aug 2016 14:46:08 -0400 Subject: [PATCH 84/85] 3.1.114 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index d1343f22e4..5e789de3dd 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.1.*")] -[assembly: AssemblyVersion("3.1.113")] +[assembly: AssemblyVersion("3.1.114")] From d1da8f4449580dd642ae71580e9c40cab8aedbe3 Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 19 Aug 2016 14:51:40 -0400 Subject: [PATCH 85/85] update mac project --- MediaBrowser.Server.Mac/Emby.Server.Mac.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj index 9422b7fa36..104923f8ee 100644 --- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj +++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj @@ -1017,6 +1017,9 @@ Resources\dashboard-ui\bower_components\emby-apiclient\apiclient.js + + Resources\dashboard-ui\bower_components\emby-apiclient\appstorage-cache.js + Resources\dashboard-ui\bower_components\emby-apiclient\appstorage-localstorage.js @@ -3711,6 +3714,9 @@ Resources\dashboard-ui\components\navdrawer\navdrawer.js + + Resources\dashboard-ui\components\syncjoblist\syncjoblist.js + Resources\dashboard-ui\components\tvproviders\schedulesdirect.js