From 1cf6cfb11c6cc80ede364267e4b7cd49ad8bb688 Mon Sep 17 00:00:00 2001 From: Jan Friedrich Date: Tue, 13 Sep 2016 18:29:53 +0200 Subject: fix graphical subtitle transcoding with vaapi --- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 2ded8a66f..9d8b7fd63 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -487,7 +487,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions); if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + arg = "-hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } } @@ -565,7 +565,20 @@ namespace MediaBrowser.MediaEncoding.Encoder { outputSizeParam = await GetOutputSizeParam(state, outputVideoCodec).ConfigureAwait(false); outputSizeParam = outputSizeParam.TrimEnd('"'); - outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase)); + + if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + { + outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase)); + } + else + { + outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase)); + } + } + + if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && outputSizeParam.Length == 0) + { + outputSizeParam = ",format=nv12|vaapi,hwupload"; } var videoSizeParam = string.Empty; -- cgit v1.2.3 From d94598a75e303c0b4f76392e1e26b819d73e87c1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 21 Sep 2016 13:07:18 -0400 Subject: update recording screens --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 +++- MediaBrowser.Controller/Entities/IHasMetadata.cs | 2 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 21 ------------------- .../LiveTv/EmbyTV/EmbyTV.cs | 18 ++++++++++++++++ .../LiveTv/Listings/SchedulesDirect.cs | 24 ++++++++++++++-------- .../ApplicationHost.cs | 17 +++++++++++++++ 6 files changed, 56 insertions(+), 30 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 9a3659f07..7ef9a1d5b 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -367,6 +367,8 @@ namespace MediaBrowser.Api.Playback { param += " -crf 23"; } + + param += " -tune zerolatency"; } else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) @@ -1232,7 +1234,7 @@ namespace MediaBrowser.Api.Playback private void StartThrottler(StreamState state, TranscodingJob transcodingJob) { - if (EnableThrottling(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EnableThrottling(state)) { transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager); state.TranscodingThrottler.Start(); diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index cf2f7db64..ae73dbeed 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { @@ -62,5 +63,6 @@ namespace MediaBrowser.Controller.Entities int? GetInheritedParentalRatingValue(); int InheritedParentalRatingValue { get; set; } + List GetInheritedTags(); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a2707aace..b2c2b71f8 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -108,11 +108,6 @@ namespace MediaBrowser.MediaEncoding.Encoder { get { - if (_hasExternalEncoder) - { - return "External"; - } - if (string.IsNullOrWhiteSpace(FFMpegPath)) { return null; @@ -177,12 +172,6 @@ namespace MediaBrowser.MediaEncoding.Encoder { ConfigureEncoderPaths(); - if (_hasExternalEncoder) - { - LogPaths(); - return; - } - // If the path was passed in, save it into config now. var encodingOptions = GetEncodingOptions(); var appPath = encodingOptions.EncoderAppPath; @@ -207,11 +196,6 @@ namespace MediaBrowser.MediaEncoding.Encoder public async Task UpdateEncoderPath(string path, string pathType) { - if (_hasExternalEncoder) - { - return; - } - Tuple newPaths; if (string.Equals(pathType, "system", StringComparison.OrdinalIgnoreCase)) @@ -256,11 +240,6 @@ namespace MediaBrowser.MediaEncoding.Encoder private void ConfigureEncoderPaths() { - if (_hasExternalEncoder) - { - return; - } - var appPath = GetEncodingOptions().EncoderAppPath; if (string.IsNullOrWhiteSpace(appPath)) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 2dd23857a..d4b21102d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -843,6 +843,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (recordingEndDate <= DateTime.UtcNow) { _logger.Warn("Recording timer fired for timer {0}, Id: {1}, but the program has already ended.", timer.Name, timer.Id); + _timerProvider.Delete(timer); return; } @@ -1273,6 +1274,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV writer.WriteElementString("rating", timer.CommunityRating.Value.ToString(CultureInfo.InvariantCulture)); } + if (timer.IsSports) + { + AddGenre(timer.Genres, "Sports"); + } + if (timer.IsKids) + { + AddGenre(timer.Genres, "Kids"); + } + foreach (var genre in timer.Genres) { writer.WriteElementString("genre", genre); @@ -1294,6 +1304,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } + private void AddGenre(List genres, string genre) + { + if (!genres.Contains(genre, StringComparer.OrdinalIgnoreCase)) + { + genres.Add(genre); + } + } + private ProgramInfo GetProgramInfoFromCache(string channelId, string programId) { var epgData = GetEpgDataForChannel(channelId); diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 0bc84a2e5..c3907c045 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -339,13 +339,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings channelNumber = channelNumber.TrimStart('0'); _logger.Debug("Found channel: " + channelNumber + " in Schedules Direct"); - if (root.stations != null) + + var schChannel = (root.stations ?? new List()).FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase)); + if (schChannel != null) { - var schChannel = root.stations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase)); - if (schChannel != null) + AddToChannelPairCache(listingsId, channelNumber, schChannel); + } + else + { + AddToChannelPairCache(listingsId, channelNumber, new ScheduleDirect.Station { - AddToChannelPairCache(listingsId, channelNumber, schChannel); - } + stationID = map.stationID + }); } } _logger.Info("Added " + GetChannelPairCacheCount(listingsId) + " channels to the dictionary"); @@ -361,8 +366,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings channel.ImageUrl = station.logo.URL; channel.HasImage = true; } - string channelName = station.name; - channel.Name = channelName; + + if (!string.IsNullOrWhiteSpace(station.name)) + { + channel.Name = station.name; + } } else { @@ -993,7 +1001,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var name = channelNumber; var station = GetStation(listingsId, channelNumber, null); - if (station != null) + if (station != null && !string.IsNullOrWhiteSpace(station.name)) { name = station.name; } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index d8d3614e6..9312e1501 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -870,6 +870,23 @@ namespace MediaBrowser.Server.Startup.Common { CertificatePath = GetCertificatePath(true); + try + { + ServerManager.Start(GetUrlPrefixes(), CertificatePath); + return; + } + catch (Exception ex) + { + Logger.ErrorException("Error starting http server", ex); + + if (HttpPort == 8096) + { + throw; + } + } + + HttpPort = 8096; + try { ServerManager.Start(GetUrlPrefixes(), CertificatePath); -- cgit v1.2.3 From eee9c0e0489087f4a8f611165e547f8f2dd353d5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 22 Sep 2016 02:57:31 -0400 Subject: update recording dialogs --- .../ScheduledTasks/ScheduledTaskWorker.cs | 2 +- .../Encoder/EncoderValidator.cs | 24 ++++++++++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 55 +++++++++------------- MediaBrowser.Providers/Manager/MetadataService.cs | 7 +++ .../Persistence/SqliteItemRepository.cs | 9 +++- 5 files changed, 63 insertions(+), 34 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 446e399bd..ced85780f 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -334,7 +334,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks trigger.Stop(); - TaskManager.QueueScheduledTask(ScheduledTask); + TaskManager.QueueScheduledTask(ScheduledTask, e.Argument); await Task.Delay(1000).ConfigureAwait(false); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index a450097fd..24de4e77e 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -26,6 +26,30 @@ namespace MediaBrowser.MediaEncoding.Encoder return new Tuple, List>(decoders, encoders); } + public bool ValidateVersion(string encoderAppPath) + { + string output = string.Empty; + try + { + output = GetProcessOutput(encoderAppPath, "-version"); + } + catch + { + } + + if (string.IsNullOrWhiteSpace(output)) + { + return false; + } + + if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1) + { + return false; + } + + return true; + } + private List GetDecoders(string encoderAppPath) { string output = string.Empty; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index b2c2b71f8..d3131eb5a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -82,6 +82,8 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly List _runningProcesses = new List(); private readonly bool _hasExternalEncoder; + private string _originalFFMpegPath; + private string _originalFFProbePath; public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager, IHttpClient httpClient, IZipClient zipClient) { @@ -100,6 +102,8 @@ namespace MediaBrowser.MediaEncoding.Encoder _zipClient = zipClient; FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; + _originalFFProbePath = ffProbePath; + _originalFFMpegPath = ffMpegPath; _hasExternalEncoder = hasExternalEncoder; } @@ -231,6 +235,11 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new ResourceNotFoundException("ffprobe not found"); } + if (!ValidateVersion(path)) + { + throw new ResourceNotFoundException("ffmpeg version 3.0 or greater is required."); + } + var config = GetEncodingOptions(); config.EncoderAppPath = path; ConfigurationManager.SaveConfiguration("encoding", config); @@ -238,6 +247,11 @@ namespace MediaBrowser.MediaEncoding.Encoder Init(); } + private bool ValidateVersion(string path) + { + return new EncoderValidator(_logger).ValidateVersion(path); + } + private void ConfigureEncoderPaths() { var appPath = GetEncodingOptions().EncoderAppPath; @@ -287,45 +301,22 @@ namespace MediaBrowser.MediaEncoding.Encoder string encoderPath = null; string probePath = null; - if (TestSystemInstalled("ffmpeg")) + if (_hasExternalEncoder && ValidateVersion(_originalFFMpegPath)) { - encoderPath = "ffmpeg"; + encoderPath = _originalFFMpegPath; + probePath = _originalFFProbePath; } - if (TestSystemInstalled("ffprobe")) - { - probePath = "ffprobe"; - } - - return new Tuple(encoderPath, probePath); - } - private bool TestSystemInstalled(string app) - { - try + if (string.IsNullOrWhiteSpace(encoderPath)) { - var startInfo = new ProcessStartInfo + if (ValidateVersion("ffmpeg") && ValidateVersion("ffprobe")) { - FileName = app, - Arguments = "-v", - UseShellExecute = false, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }; - - using (var process = Process.Start(startInfo)) - { - process.WaitForExit(); + encoderPath = "ffmpeg"; + probePath = "ffprobe"; } - - _logger.Debug("System app installed: " + app); - return true; - } - catch - { - _logger.Debug("System app not installed: " + app); - return false; } + + return new Tuple(encoderPath, probePath); } private Tuple GetPathsFromDirectory(string path) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index e16e76bfc..18405aae9 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -316,6 +316,13 @@ namespace MediaBrowser.Providers.Manager updateType |= ItemUpdateType.MetadataImport; } + var inheritedTags = item.GetInheritedTags(); + if (!inheritedTags.SequenceEqual(item.InheritedTags, StringComparer.Ordinal)) + { + item.InheritedTags = inheritedTags; + updateType |= ItemUpdateType.MetadataImport; + } + return updateType; } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 5ece3dd82..05c282687 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -412,7 +412,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "SeriesId", "SeriesSortName", "PresentationUniqueKey", - "InheritedParentalRatingValue" + "InheritedParentalRatingValue", + "InheritedTags" }; private readonly string[] _mediaStreamSaveColumns = @@ -1459,6 +1460,12 @@ namespace MediaBrowser.Server.Implementations.Persistence } index++; + if (!reader.IsDBNull(index)) + { + item.InheritedTags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + } + index++; + return item; } -- cgit v1.2.3 From 3d260bd13c3e2ea21dd6ca0209e1c7b0f7cf1ae9 Mon Sep 17 00:00:00 2001 From: Jan Friedrich Date: Sat, 24 Sep 2016 17:34:54 +0200 Subject: vaapi: copy decoded frames to main memory only when necessary --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 10 +++++++++- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 371247ecd..fe9869664 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1037,7 +1037,15 @@ namespace MediaBrowser.Api.Playback var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); if (GetVideoEncoder(state).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg = "-hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode; + var hwOutputFormat = "vaapi"; + + if (hasGraphicalSubs) + { + hwOutputFormat = "yuv420p"; + } + + arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 9d8b7fd63..e8121d178 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -487,7 +487,15 @@ namespace MediaBrowser.MediaEncoding.Encoder var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions); if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg = "-hwaccel vaapi -hwaccel_output_format yuv420p -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.Options.SubtitleMethod == SubtitleDeliveryMethod.Encode; + var hwOutputFormat = "vaapi"; + + if (hasGraphicalSubs) + { + hwOutputFormat = "yuv420p"; + } + + arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } } -- cgit v1.2.3 From 76c7bfcb6795771cb06ef354fbf76d6e39de8948 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 29 Sep 2016 08:55:49 -0400 Subject: update closing of streams --- MediaBrowser.Api/ApiEntryPoint.cs | 8 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 46 ++++++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 16 +-- MediaBrowser.Api/Playback/MediaInfoService.cs | 2 +- .../Progressive/BaseProgressiveStreamingService.cs | 2 - MediaBrowser.Api/Playback/StreamState.cs | 2 +- .../Entities/InternalItemsQuery.cs | 2 + .../Library/IMediaSourceManager.cs | 3 +- .../Library/IMediaSourceProvider.cs | 3 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 +- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 5 +- MediaBrowser.Controller/LiveTv/LiveStream.cs | 23 +++- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 53 +++++++- MediaBrowser.Controller/LiveTv/TimerInfo.cs | 1 + MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 2 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 7 +- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 24 ++++ MediaBrowser.Model/LiveTv/ProgramQuery.cs | 7 + .../LiveTv/RecommendedProgramQuery.cs | 6 + MediaBrowser.Model/LiveTv/RecordingQuery.cs | 1 + .../Channels/ChannelDynamicMediaSourceProvider.cs | 2 +- .../Library/MediaSourceManager.cs | 59 +++++---- .../LiveTv/EmbyTV/DirectRecorder.cs | 16 +-- .../LiveTv/EmbyTV/EmbyTV.cs | 143 +++++++++++++-------- .../LiveTv/EmbyTV/EncodedRecorder.cs | 39 +----- .../LiveTv/EmbyTV/RecordingHelper.cs | 1 + .../LiveTv/LiveTvManager.cs | 90 ++++++++----- .../LiveTv/LiveTvMediaSourceProvider.cs | 4 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 4 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 8 -- .../TunerHosts/HdHomerun/HdHomerunLiveStream.cs | 7 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 5 - .../Persistence/SqliteItemRepository.cs | 113 +++++++++++++--- .../Session/SessionManager.cs | 2 +- .../Sync/SyncedMediaSourceProvider.cs | 2 +- MediaBrowser.WebDashboard/Api/DashboardService.cs | 90 +------------ 36 files changed, 475 insertions(+), 326 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 2f5b9e1e0..c6e45c61a 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -567,7 +567,7 @@ namespace MediaBrowser.Api { try { - await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { @@ -789,12 +789,12 @@ namespace MediaBrowser.Api { if (KillTimer == null) { - Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); + //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite); } else { - Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); + //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer.Change(intervalMs, Timeout.Infinite); } } @@ -813,7 +813,7 @@ namespace MediaBrowser.Api { var intervalMs = PingTimeout; - Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); + //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer.Change(intervalMs, Timeout.Infinite); } } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index a5f8fce6e..9c1105082 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -48,6 +48,21 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? StartIndex { get; set; } + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsMovie { get; set; } + + [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSeries { get; set; } + + [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsNews { get; set; } + + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsKids { get; set; } + + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSports { get; set; } + /// /// The maximum number of items to return /// @@ -163,6 +178,7 @@ namespace MediaBrowser.Api.LiveTv public bool? IsSeries { get; set; } public bool? IsKids { get; set; } public bool? IsSports { get; set; } + public bool? IsNews { get; set; } public GetRecordings() { @@ -309,6 +325,12 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsMovie { get; set; } + [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSeries { get; set; } + + [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsNews { get; set; } + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsKids { get; set; } @@ -380,15 +402,21 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? HasAired { get; set; } - [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] - public bool? IsSports { get; set; } + [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSeries { get; set; } - [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsMovie { get; set; } - [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsNews { get; set; } + + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsKids { get; set; } + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSports { 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; } @@ -815,6 +843,11 @@ namespace MediaBrowser.Api.LiveTv IsLiked = request.IsLiked, IsDisliked = request.IsDisliked, EnableFavoriteSorting = request.EnableFavoriteSorting, + IsMovie = request.IsMovie, + IsSeries = request.IsSeries, + IsNews = request.IsNews, + IsKids = request.IsKids, + IsSports = request.IsSports, AddCurrentProgram = request.AddCurrentProgram }, CancellationToken.None).ConfigureAwait(false); @@ -897,7 +930,9 @@ namespace MediaBrowser.Api.LiveTv query.Limit = request.Limit; query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.SortOrder = request.SortOrder; + query.IsNews = request.IsNews; query.IsMovie = request.IsMovie; + query.IsSeries = request.IsSeries; query.IsKids = request.IsKids; query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); @@ -915,8 +950,10 @@ namespace MediaBrowser.Api.LiveTv IsAiring = request.IsAiring, Limit = request.Limit, HasAired = request.HasAired, + IsSeries = request.IsSeries, IsMovie = request.IsMovie, IsKids = request.IsKids, + IsNews = request.IsNews, IsSports = request.IsSports, EnableTotalRecordCount = request.EnableTotalRecordCount }; @@ -948,6 +985,7 @@ namespace MediaBrowser.Api.LiveTv IsInProgress = request.IsInProgress, EnableTotalRecordCount = request.EnableTotalRecordCount, IsMovie = request.IsMovie, + IsNews = request.IsNews, IsSeries = request.IsSeries, IsKids = request.IsKids, IsSports = request.IsSports diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index fe9869664..8e57650b4 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1861,14 +1861,14 @@ namespace MediaBrowser.Api.Playback MediaSourceInfo mediaSource = null; if (string.IsNullOrWhiteSpace(request.LiveStreamId)) { - //TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? - // ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) - // : null; - - //if (currentJob != null) - //{ - // mediaSource = currentJob.MediaSource; - //} + TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? + ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) + : null; + + if (currentJob != null) + { + mediaSource = currentJob.MediaSource; + } if (mediaSource == null) { diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 656b2ee08..761538c83 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback public void Post(CloseMediaSource request) { - var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId, CancellationToken.None); + var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId); Task.WaitAll(task); } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index a68319109..4bb62f47f 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -27,12 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive public abstract class BaseProgressiveStreamingService : BaseStreamingService { protected readonly IImageProcessor ImageProcessor; - protected readonly IHttpClient HttpClient; protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer) { ImageProcessor = imageProcessor; - HttpClient = httpClient; } /// diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index ef0282abc..019f378c5 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -225,7 +225,7 @@ namespace MediaBrowser.Api.Playback { try { - await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index deea63112..d917b7d6d 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -101,6 +101,8 @@ namespace MediaBrowser.Controller.Entities public bool? IsMovie { get; set; } public bool? IsSports { get; set; } public bool? IsKids { get; set; } + public bool? IsNews { get; set; } + public bool? IsSeries { get; set; } public int? MinPlayers { get; set; } public int? MaxPlayers { get; set; } diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 1df77cdc9..c06470c5e 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -92,8 +92,7 @@ namespace MediaBrowser.Controller.Library /// Closes the media source. /// /// The live stream identifier. - /// The cancellation token. /// Task. - Task CloseLiveStream(string id, CancellationToken cancellationToken); + Task CloseLiveStream(string id); } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs index 5b033af4a..56366e5a8 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs @@ -28,8 +28,7 @@ namespace MediaBrowser.Controller.Library /// Closes the media source. /// /// The live stream identifier. - /// The cancellation token. /// Task. - Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken); + Task CloseMediaSource(string liveStreamId); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 41c5dbdbb..d65d1ae30 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -220,9 +220,8 @@ namespace MediaBrowser.Controller.LiveTv /// Closes the live stream. /// /// The identifier. - /// The cancellation token. /// Task. - Task CloseLiveStream(string id, CancellationToken cancellationToken); + Task CloseLiveStream(string id); /// /// Gets the guide information. diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 3c8b964a2..89d035649 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -22,9 +22,8 @@ namespace MediaBrowser.Controller.LiveTv /// /// Gets the channels. /// - /// The cancellation token. /// Task<IEnumerable<ChannelInfo>>. - Task> GetChannels(CancellationToken cancellationToken); + Task> GetChannels(bool enableCache, CancellationToken cancellationToken); /// /// Gets the tuner infos. /// @@ -46,8 +45,6 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// Task<List<MediaSourceInfo>>. Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); - - string ApplyDuration(string streamPath, TimeSpan duration); } public interface IConfigurableTunerHost { diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs index 15d09d857..1bb198632 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dto; @@ -7,17 +8,27 @@ namespace MediaBrowser.Controller.LiveTv public class LiveStream { public MediaSourceInfo OriginalMediaSource { get; set; } - public MediaSourceInfo PublicMediaSource { get; set; } - public string Id { get; set; } + public MediaSourceInfo OpenedMediaSource { get; set; } + public DateTime DateOpened { get; set; } + public int ConsumerCount { get; set; } + public ITunerHost TunerHost { get; set; } + public string OriginalStreamId { get; set; } public LiveStream(MediaSourceInfo mediaSource) { OriginalMediaSource = mediaSource; - PublicMediaSource = mediaSource; - Id = mediaSource.Id; + OpenedMediaSource = mediaSource; } - public virtual Task Open(CancellationToken cancellationToken) + public async Task Open(CancellationToken cancellationToken) + { + await OpenInternal(cancellationToken).ConfigureAwait(false); + DateOpened = DateTime.UtcNow; + + OpenedMediaSource.DateLiveStreamOpened = DateOpened; + } + + protected virtual Task OpenInternal(CancellationToken cancellationToken) { return Task.FromResult(true); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 50aeed27d..69a1c24ea 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -9,7 +9,7 @@ using System.Runtime.Serialization; namespace MediaBrowser.Controller.LiveTv { - public class LiveTvChannel : BaseItem, IHasMediaSources + public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes { public override List GetUserDataKeys() { @@ -137,5 +137,56 @@ namespace MediaBrowser.Controller.LiveTv { return false; } + + [IgnoreDataMember] + public bool IsMovie { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is sports. + /// + /// true if this instance is sports; otherwise, false. + [IgnoreDataMember] + public bool IsSports { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is series. + /// + /// true if this instance is series; otherwise, false. + [IgnoreDataMember] + public bool IsSeries { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is live. + /// + /// true if this instance is live; otherwise, false. + [IgnoreDataMember] + public bool IsLive { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is news. + /// + /// true if this instance is news; otherwise, false. + [IgnoreDataMember] + public bool IsNews { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is kids. + /// + /// true if this instance is kids; otherwise, false. + [IgnoreDataMember] + public bool IsKids { get; set; } + + [IgnoreDataMember] + public bool IsPremiere { get; set; } + + [IgnoreDataMember] + public bool IsRepeat { get; set; } + + /// + /// Gets or sets the episode title. + /// + /// The episode title. + [IgnoreDataMember] + public string EpisodeTitle { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index 42c3480ce..978e9e1a8 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -101,6 +101,7 @@ namespace MediaBrowser.Controller.LiveTv public bool IsMovie { get; set; } public bool IsKids { get; set; } public bool IsSports { get; set; } + public bool IsNews { get; set; } public int? ProductionYear { get; set; } public string EpisodeTitle { get; set; } public DateTime? OriginalAirDate { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index 490a51128..d3738d903 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { try { - await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index bb07d9cb6..2be69c8e4 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using System; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.MediaInfo; using System.Collections.Generic; @@ -52,7 +53,9 @@ namespace MediaBrowser.Model.Dto public string TranscodingUrl { get; set; } public string TranscodingSubProtocol { get; set; } public string TranscodingContainer { get; set; } - + + public DateTime? DateLiveStreamOpened { get; set; } + public MediaSourceInfo() { Formats = new List(); diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 0ece1e4a0..f76368a7b 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -61,6 +61,30 @@ namespace MediaBrowser.Model.LiveTv public bool AddCurrentProgram { get; set; } public bool EnableUserData { get; set; } + /// + /// Used to specific whether to return news or not + /// + /// If set to null, all programs will be returned + public bool? IsNews { get; set; } + + /// + /// Used to specific whether to return movies or not + /// + /// If set to null, all programs will be returned + public bool? IsMovie { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is kids. + /// + /// null if [is kids] contains no value, true if [is kids]; otherwise, false. + public bool? IsKids { get; set; } + /// + /// Gets or sets a value indicating whether this instance is sports. + /// + /// null if [is sports] contains no value, true if [is sports]; otherwise, false. + public bool? IsSports { get; set; } + public bool? IsSeries { get; set; } + public LiveTvChannelQuery() { EnableUserData = true; diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index bf459237a..7886342e7 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -62,6 +62,12 @@ namespace MediaBrowser.Model.LiveTv /// public DateTime? MaxEndDate { get; set; } + /// + /// Used to specific whether to return news or not + /// + /// If set to null, all programs will be returned + public bool? IsNews { get; set; } + /// /// Used to specific whether to return movies or not /// @@ -83,6 +89,7 @@ namespace MediaBrowser.Model.LiveTv /// Skips over a given number of items within the results. Use for paging. /// public int? StartIndex { get; set; } + public bool? IsSeries { get; set; } /// /// Gets or sets a value indicating whether this instance has aired. diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 0e6d081a1..4bc506bf6 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -45,11 +45,17 @@ namespace MediaBrowser.Model.LiveTv /// The limit. public int? Limit { get; set; } + /// + /// Gets or sets a value indicating whether this instance is movie. + /// + /// null if [is movie] contains no value, true if [is movie]; otherwise, false. + public bool? IsNews { get; set; } /// /// Gets or sets a value indicating whether this instance is movie. /// /// null if [is movie] contains no value, true if [is movie]; otherwise, false. public bool? IsMovie { get; set; } + public bool? IsSeries { get; set; } /// /// Gets or sets a value indicating whether this instance is kids. /// diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index 0ba5f1779..265aad335 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -68,6 +68,7 @@ namespace MediaBrowser.Model.LiveTv /// The fields. public ItemFields[] Fields { get; set; } public bool? EnableImages { get; set; } + public bool? IsNews { get; set; } public bool? IsMovie { get; set; } public bool? IsSeries { get; set; } public bool? IsKids { get; set; } diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs index 3239b20b2..6cba1b441 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Channels throw new NotImplementedException(); } - public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken) + public Task CloseMediaSource(string liveStreamId) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index c20245a6e..c7650102f 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -355,7 +355,7 @@ namespace MediaBrowser.Server.Implementations.Library .ToList(); } - private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _openStreams = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); public async Task OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken) @@ -383,7 +383,7 @@ namespace MediaBrowser.Server.Implementations.Library Id = mediaSource.LiveStreamId, MediaSource = mediaSource }; - _openStreams.AddOrUpdate(mediaSource.LiveStreamId, info, (key, i) => info); + _openStreams[mediaSource.LiveStreamId] = info; if (enableAutoClose) { @@ -421,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("id"); } - _logger.Debug("Getting live stream {0}", id); + _logger.Debug("Getting already opened live stream {0}", id); await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -465,17 +465,16 @@ namespace MediaBrowser.Server.Implementations.Library } } - private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId, CancellationToken cancellationToken) + private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId) { _logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name); try { - await provider.CloseMediaSource(streamId, cancellationToken).ConfigureAwait(false); + await provider.CloseMediaSource(streamId).ConfigureAwait(false); } catch (NotImplementedException) { - } catch (Exception ex) { @@ -483,37 +482,35 @@ namespace MediaBrowser.Server.Implementations.Library } } - public async Task CloseLiveStream(string id, CancellationToken cancellationToken) + public async Task CloseLiveStream(string id) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException("id"); } - await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false); try { LiveStreamInfo current; + if (_openStreams.TryGetValue(id, out current)) { + _openStreams.Remove(id); + current.Closed = true; + if (current.MediaSource.RequiresClosing) { var tuple = GetProvider(id); - await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false); + await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false); } - } - LiveStreamInfo removed; - if (_openStreams.TryRemove(id, out removed)) - { - removed.Closed = true; - } - - if (_openStreams.Count == 0) - { - StopCloseTimer(); + if (_openStreams.Count == 0) + { + StopCloseTimer(); + } } } finally @@ -565,10 +562,20 @@ namespace MediaBrowser.Server.Implementations.Library private async void CloseTimerCallback(object state) { - var infos = _openStreams - .Values - .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge) - .ToList(); + List infos; + await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false); + + try + { + infos = _openStreams + .Values + .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge) + .ToList(); + } + finally + { + _liveStreamSemaphore.Release(); + } foreach (var info in infos) { @@ -576,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Library { try { - await CloseLiveStream(info.Id, CancellationToken.None).ConfigureAwait(false); + await CloseLiveStream(info.Id).ConfigureAwait(false); } catch (Exception ex) { @@ -608,12 +615,10 @@ namespace MediaBrowser.Server.Implementations.Library { foreach (var key in _openStreams.Keys.ToList()) { - var task = CloseLiveStream(key, CancellationToken.None); + var task = CloseLiveStream(key); Task.WaitAll(task); } - - _openStreams.Clear(); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 0d043669a..0f8c15e71 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -47,19 +47,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _logger.Info("Copying recording stream to file {0}", targetFile); - if (mediaSource.RunTimeTicks.HasValue) - { - // The media source already has a fixed duration - // But add another stop 1 minute later just in case the recording gets stuck for any reason - var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1))); - cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; - } - else - { - // The media source if infinite so we need to handle stopping ourselves - var durationToken = new CancellationTokenSource(duration); - cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; - } + // The media source if infinite so we need to handle stopping ourselves + var durationToken = new CancellationTokenSource(duration); + cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; await CopyUntilCancelled(response.Content, output, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index f53ec3ee8..ef19dcbc9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -340,22 +340,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _timerProvider.Delete(timer); } - private List _channelCache = null; private async Task> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken) { - if (enableCache && _channelCache != null) - { - - return _channelCache.ToList(); - } - var list = new List(); foreach (var hostInstance in _liveTvManager.TunerHosts) { try { - var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.GetChannels(enableCache, cancellationToken).ConfigureAwait(false); list.AddRange(channels); } @@ -388,7 +381,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - _channelCache = list.ToList(); return list; } @@ -400,7 +392,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { try { - var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.GetChannels(false, cancellationToken).ConfigureAwait(false); list.AddRange(channels); } @@ -632,6 +624,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV existingTimer.Genres = updatedTimer.Genres; existingTimer.HomePageUrl = updatedTimer.HomePageUrl; existingTimer.IsKids = updatedTimer.IsKids; + existingTimer.IsNews = updatedTimer.IsNews; existingTimer.IsMovie = updatedTimer.IsMovie; existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries; existingTimer.IsSports = updatedTimer.IsSports; @@ -836,33 +829,68 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var result = await GetChannelStreamInternal(channelId, streamId, cancellationToken).ConfigureAwait(false); - return result.Item1.PublicMediaSource; + return result.Item2; + } + + private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId) + { + var json = _jsonSerializer.SerializeToString(mediaSource); + mediaSource = _jsonSerializer.DeserializeFromString(json); + + mediaSource.Id = consumerId.ToString(CultureInfo.InvariantCulture) + "_" + mediaSource.Id; + + return mediaSource; } - private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) + private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) { _logger.Info("Streaming Channel " + channelId); - foreach (var hostInstance in _liveTvManager.TunerHosts) + await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + var result = _liveStreams.Values.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase)); + + if (result != null) { - try - { - var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); + //result.ConsumerCount++; - await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false); - _liveStreams[result.Id] = result; - _liveStreamsSemaphore.Release(); + //_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); - return new Tuple(result, hostInstance); - } - catch (FileNotFoundException) - { - } - catch (Exception e) + //_liveStreamsSemaphore.Release(); + //return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1), result.TunerHost); + } + + try + { + foreach (var hostInstance in _liveTvManager.TunerHosts) { - _logger.ErrorException("Error getting channel stream", e); + try + { + result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); + + _liveStreams[result.OpenedMediaSource.Id] = result; + + result.ConsumerCount++; + result.TunerHost = hostInstance; + result.OriginalStreamId = streamId; + + _logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}", + streamId, result.OpenedMediaSource.Id, result.OpenedMediaSource.LiveStreamId); + + return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, 0), hostInstance); + } + catch (FileNotFoundException) + { + } + catch (OperationCanceledException) + { + } } } + finally + { + _liveStreamsSemaphore.Release(); + } throw new ApplicationException("Tuner not found."); } @@ -896,25 +924,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public async Task CloseLiveStream(string id, CancellationToken cancellationToken) { - await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false); + // Ignore the consumer id + id = id.Substring(id.IndexOf('_') + 1); + + await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { LiveStream stream; if (_liveStreams.TryGetValue(id, out stream)) { - _liveStreams.Remove(id); + stream.ConsumerCount--; - try + _logger.Info("Live stream {0} consumer count is now {1}", id, stream.ConsumerCount); + + if (stream.ConsumerCount <= 0) { + _liveStreams.Remove(id); + + _logger.Info("Closing live stream {0}", id); + await stream.Close().ConfigureAwait(false); _logger.Info("Live stream {0} closed successfully", id); } - catch (Exception ex) - { - _logger.ErrorException("Error closing live stream", ex); - } } + else + { + _logger.Warn("Live stream not found: {0}, unable to close", id); + } + } + catch (OperationCanceledException) + { + } + catch (Exception ex) + { + _logger.ErrorException("Error closing live stream", ex); } finally { @@ -1095,20 +1139,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var recordPath = GetRecordingPath(timer, out seriesPath); var recordingStatus = RecordingStatus.New; - LiveStream liveStream = null; + string liveStreamId = null; try { var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); - var liveStreamInfo = - await - GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) + var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) .ConfigureAwait(false); - liveStream = liveStreamInfo.Item1; - var mediaStreamInfo = liveStreamInfo.Item1.PublicMediaSource; - var tunerHost = liveStreamInfo.Item2; + + var mediaStreamInfo = liveStreamInfo.Item2; + liveStreamId = mediaStreamInfo.Id; // HDHR doesn't seem to release the tuner right away after first probing with ffmpeg //await Task.Delay(3000, cancellationToken).ConfigureAwait(false); @@ -1140,15 +1182,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV EnforceKeepUpTo(timer); }; - var pathWithDuration = tunerHost.ApplyDuration(mediaStreamInfo.Path, duration); - - // If it supports supplying duration via url - if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase)) - { - mediaStreamInfo.Path = pathWithDuration; - mediaStreamInfo.RunTimeTicks = duration.Ticks; - } - await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken) .ConfigureAwait(false); @@ -1166,11 +1199,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recordingStatus = RecordingStatus.Error; } - if (liveStream != null) + if (!string.IsNullOrWhiteSpace(liveStreamId)) { try { - await CloseLiveStream(liveStream.Id, CancellationToken.None).ConfigureAwait(false); + await CloseLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -1251,7 +1284,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1,1); + private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1, 1); private async Task DeleteLibraryItemsForTimers(List timers) { foreach (var timer in timers) @@ -1295,7 +1328,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } catch (FileNotFoundException) { - + } } @@ -1492,6 +1525,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { AddGenre(timer.Genres, "Kids"); } + if (timer.IsNews) + { + AddGenre(timer.Genres, "News"); + } foreach (var genre in timer.Genres) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index f74a76e3f..ce5f14f4b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -71,38 +71,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var durationToken = new CancellationTokenSource(duration); cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; - await RecordFromFile(mediaSource, mediaSource.Path, targetFile, false, duration, onStarted, cancellationToken).ConfigureAwait(false); + await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false); _logger.Info("Recording completed to file {0}", targetFile); } - private async void DeleteTempFile(string path) - { - for (var i = 0; i < 10; i++) - { - try - { - File.Delete(path); - return; - } - catch (FileNotFoundException) - { - return; - } - catch (DirectoryNotFoundException) - { - return; - } - catch (Exception ex) - { - _logger.ErrorException("Error deleting recording temp file", ex); - } - - await Task.Delay(1000).ConfigureAwait(false); - } - } - - private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, bool deleteInputFileAfterCompletion, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) + private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { _targetPath = targetFile; _fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile)); @@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length); - process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile, deleteInputFileAfterCompletion); + process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile); process.Start(); @@ -252,7 +226,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV /// /// Processes the exited. /// - private void OnFfMpegProcessExited(Process process, string inputFile, bool deleteInputFileAfterCompletion) + private void OnFfMpegProcessExited(Process process, string inputFile) { _hasExited = true; @@ -278,11 +252,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _logger.Error("FFMpeg recording exited with an error for {0}.", _targetPath); _taskCompletionSource.TrySetException(new Exception(string.Format("Recording for {0} failed", _targetPath))); } - - if (deleteInputFileAfterCompletion) - { - DeleteTempFile(inputFile); - } } private void DisposeLogStream() diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index f9c04abc5..bb6935e8e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV timerInfo.EpisodeNumber = programInfo.EpisodeNumber; timerInfo.IsMovie = programInfo.IsMovie; timerInfo.IsKids = programInfo.IsKids; + timerInfo.IsNews = programInfo.IsNews; timerInfo.IsSports = programInfo.IsSports; timerInfo.ProductionYear = programInfo.ProductionYear; timerInfo.EpisodeTitle = programInfo.EpisodeTitle; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 8a4572813..7c61d2396 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -62,9 +62,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly List _services = new List(); - private readonly ConcurrentDictionary _openStreams = - new ConcurrentDictionary(); - private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1); private readonly List _tunerHosts = new List(); @@ -153,6 +150,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv var channels = _libraryManager.GetItemList(new InternalItemsQuery { + IsMovie = query.IsMovie, + IsNews = query.IsNews, + IsKids = query.IsKids, + IsSports = query.IsSports, + IsSeries = query.IsSeries, IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }, SortBy = new[] { ItemSortBy.SortName }, TopParentIds = new[] { topFolder.Id.ToString("N") } @@ -407,15 +409,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info)); Normalize(info, service, isVideo); - var data = new LiveStreamData - { - Info = info, - IsChannel = isChannel, - ItemId = id - }; - - _openStreams.AddOrUpdate(info.Id, data, (key, i) => data); - return info; } catch (Exception ex) @@ -937,8 +930,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv MaxStartDate = query.MaxStartDate, ChannelIds = query.ChannelIds, IsMovie = query.IsMovie, + IsSeries = query.IsSeries, IsSports = query.IsSports, IsKids = query.IsKids, + IsNews = query.IsNews, Genres = query.Genres, StartIndex = query.StartIndex, Limit = query.Limit, @@ -985,7 +980,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, IsAiring = query.IsAiring, + IsNews = query.IsNews, IsMovie = query.IsMovie, + IsSeries = query.IsSeries, IsSports = query.IsSports, IsKids = query.IsKids, EnableTotalRecordCount = query.EnableTotalRecordCount, @@ -1014,7 +1011,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var programList = programs.ToList(); - var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false); + var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false) || (query.IsNews ?? false) || (query.IsSeries ?? false); programs = programList.OrderBy(i => i.StartDate.Date) .ThenByDescending(i => GetRecommendationScore(i, user.Id, factorChannelWatchCount)) @@ -1305,6 +1302,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv var start = DateTime.UtcNow.AddHours(-1); var end = start.AddDays(guideDays); + var isMovie = false; + var isSports = false; + var isNews = false; + var isKids = false; + var iSSeries = false; + var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false); foreach (var program in channelPrograms) @@ -1312,7 +1315,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv var programItem = await GetProgram(program, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false); programs.Add(programItem.Id); + + if (program.IsMovie) + { + isMovie = true; + } + + if (program.IsSeries) + { + iSSeries = true; + } + + if (program.IsSports) + { + isSports = true; + } + + if (program.IsNews) + { + isNews = true; + } + + if (program.IsKids) + { + isKids = true; + } } + + currentChannel.IsMovie = isMovie; + currentChannel.IsNews = isNews; + currentChannel.IsSports = isSports; + currentChannel.IsKids = isKids; + currentChannel.IsSeries = iSSeries; + + await currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -1647,6 +1683,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv recordings = recordings.Where(i => i.IsMovie == val); } + if (query.IsNews.HasValue) + { + var val = query.IsNews.Value; + recordings = recordings.Where(i => i.IsNews == val); + } + if (query.IsSeries.HasValue) { var val = query.IsSeries.Value; @@ -2444,9 +2486,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv internal bool IsChannel; } - public async Task CloseLiveStream(string id, CancellationToken cancellationToken) + public async Task CloseLiveStream(string id) { - await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false); try { @@ -2461,12 +2503,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv id = parts[1]; - LiveStreamData data; - _openStreams.TryRemove(id, out data); - _logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id); - await service.CloseLiveStream(id, cancellationToken).ConfigureAwait(false); + await service.CloseLiveStream(id, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -2500,7 +2539,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv Dispose(true); } - private readonly object _disposeLock = new object(); private bool _isDisposed = false; /// /// Releases unmanaged and - optionally - managed resources. @@ -2511,18 +2549,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (dispose) { _isDisposed = true; - - lock (_disposeLock) - { - foreach (var stream in _openStreams.Values.ToList()) - { - var task = CloseLiveStream(stream.Info.Id, CancellationToken.None); - - Task.WaitAll(task); - } - - _openStreams.Clear(); - } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index cdba1873e..aacc0c22b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -204,9 +204,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken) + public Task CloseMediaSource(string liveStreamId) { - return _liveTvManager.CloseLiveStream(liveStreamId, cancellationToken); + return _liveTvManager.CloseLiveStream(liveStreamId); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 6beea352a..a4236763f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts .ToList(); } - public async Task> GetChannels(CancellationToken cancellationToken) + public async Task> GetChannels(bool enableCache, CancellationToken cancellationToken) { var list = new List(); @@ -83,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { try { - var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false); + var channels = await GetChannels(host, enableCache, cancellationToken).ConfigureAwait(false); var newChannels = channels.Where(i => !list.Any(l => string.Equals(i.Id, l.Id, StringComparison.OrdinalIgnoreCase))).ToList(); list.AddRange(newChannels); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index b40b74436..9f71940e1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -67,14 +67,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return id; } - public string ApplyDuration(string streamPath, TimeSpan duration) - { - streamPath += streamPath.IndexOf('?') == -1 ? "?" : "&"; - streamPath += "duration=" + Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture); - - return streamPath; - } - private async Task> GetLineup(TunerHostInfo info, CancellationToken cancellationToken) { var options = new HttpRequestOptions diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs index d3540d180..d6574db22 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun _appHost = appHost; } - public override async Task Open(CancellationToken openCancellationToken) + protected override async Task OpenInternal(CancellationToken openCancellationToken) { _liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested(); @@ -54,13 +54,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun await taskCompletionSource.Task.ConfigureAwait(false); - PublicMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts"; + OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts"; - PublicMediaSource.Protocol = MediaProtocol.Http; + OpenedMediaSource.Protocol = MediaProtocol.Http; } public override Task Close() { + _logger.Info("Closing HDHR live stream"); _liveStreamCancellationTokenSource.Cancel(); return _liveStreamTaskCompletionSource.Task; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index d9c0bb8bf..e5d6102b1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -153,10 +153,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { return Task.FromResult(true); } - - public string ApplyDuration(string streamPath, TimeSpan duration) - { - return streamPath; - } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 05c282687..097118418 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2530,38 +2530,111 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("IsOffline=@IsOffline"); cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline; } - if (query.IsMovie.HasValue) + + var exclusiveProgramAttribtues = !(query.IsMovie ?? true) || + !(query.IsSports ?? true) || + !(query.IsKids ?? true) || + !(query.IsNews ?? true) || + !(query.IsSeries ?? true); + + if (exclusiveProgramAttribtues) { - var alternateTypes = new List(); - if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name)) + if (query.IsMovie.HasValue) + { + var alternateTypes = new List(); + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name)) + { + alternateTypes.Add(typeof(Movie).FullName); + } + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + { + alternateTypes.Add(typeof(Trailer).FullName); + } + + if (alternateTypes.Count == 0) + { + whereClauses.Add("IsMovie=@IsMovie"); + cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie; + } + else + { + whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)"); + cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie; + } + } + if (query.IsSeries.HasValue) { - alternateTypes.Add(typeof(Movie).FullName); + whereClauses.Add("IsSeries=@IsSeries"); + cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = query.IsSeries; } - if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + if (query.IsNews.HasValue) { - alternateTypes.Add(typeof(Trailer).FullName); + whereClauses.Add("IsNews=@IsNews"); + cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = query.IsNews; } - - if (alternateTypes.Count == 0) + if (query.IsKids.HasValue) { - whereClauses.Add("IsMovie=@IsMovie"); + whereClauses.Add("IsKids=@IsKids"); + cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids; } - else + if (query.IsSports.HasValue) { - whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)"); + whereClauses.Add("IsSports=@IsSports"); + cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports; } - cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie; } - if (query.IsKids.HasValue) - { - whereClauses.Add("IsKids=@IsKids"); - cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids; - } - if (query.IsSports.HasValue) + else { - whereClauses.Add("IsSports=@IsSports"); - cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports; + var programAttribtues = new List(); + if (query.IsMovie ?? false) + { + var alternateTypes = new List(); + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name)) + { + alternateTypes.Add(typeof(Movie).FullName); + } + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + { + alternateTypes.Add(typeof(Trailer).FullName); + } + + if (alternateTypes.Count == 0) + { + programAttribtues.Add("IsMovie=@IsMovie"); + } + else + { + programAttribtues.Add("(IsMovie is null OR IsMovie=@IsMovie)"); + } + + cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = true; + } + if (query.IsSports ?? false) + { + programAttribtues.Add("IsSports=@IsSports"); + cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = true; + } + if (query.IsNews ?? false) + { + programAttribtues.Add("IsNews=@IsNews"); + cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = true; + } + if (query.IsSeries ?? false) + { + programAttribtues.Add("IsSeries=@IsSeries"); + cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = true; + } + if (query.IsKids ?? false) + { + programAttribtues.Add("IsKids=@IsKids"); + cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = true; + } + if (programAttribtues.Count > 0) + { + whereClauses.Add("("+string.Join(" OR ", programAttribtues.ToArray())+")"); + } } + if (query.IsFolder.HasValue) { whereClauses.Add("IsFolder=@IsFolder"); diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 48f48cdcc..5857e9dbc 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -818,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.Session { try { - await _mediaSourceManager.CloseLiveStream(info.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(info.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs index a2b5851ac..cb666b6ac 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Sync } } - public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken) + public Task CloseMediaSource(string liveStreamId) { throw new NotImplementedException(); } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 2f8b34879..4850b6fe0 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -289,7 +289,7 @@ namespace MediaBrowser.WebDashboard.Api return list; } - private List> GetDeployIgnoreFilenames() + private List> GetDeployIgnoreFilenames() { var list = new List>(); @@ -313,8 +313,11 @@ namespace MediaBrowser.WebDashboard.Api public async Task Get(GetDashboardPackage request) { - var path = Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath, - "webclient-dump"); + var mode = request.Mode; + + var path = string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? + Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath, "webclient-dump") + : "C:\\dev\\emby-web-mobile\\src"; try { @@ -333,8 +336,6 @@ namespace MediaBrowser.WebDashboard.Api var appVersion = _appHost.ApplicationVersion.ToString(); - var mode = request.Mode; - // Try to trim the output size a bit var bowerPath = Path.Combine(path, "bower_components"); @@ -372,11 +373,6 @@ namespace MediaBrowser.WebDashboard.Api // 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); } - else - { - MinifyCssDirectory(path); - MinifyJsDirectory(path); - } await DumpHtml(creator.DashboardUIPath, path, mode, culture, appVersion); @@ -444,78 +440,6 @@ namespace MediaBrowser.WebDashboard.Api } } - private void MinifyCssDirectory(string path) - { - foreach (var file in Directory.GetFiles(path, "*.css", SearchOption.AllDirectories)) - { - if (file.IndexOf(".min.", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - if (file.IndexOf("bower_", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - - try - { - var text = _fileSystem.ReadAllText(file, Encoding.UTF8); - - var result = new KristensenCssMinifier().Minify(text, false, Encoding.UTF8); - - if (result.Errors.Count > 0) - { - Logger.Error("Error minifying css: " + result.Errors[0].Message); - } - else - { - text = result.MinifiedContent; - _fileSystem.WriteAllText(file, text, Encoding.UTF8); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error minifying css", ex); - } - } - } - - private void MinifyJsDirectory(string path) - { - foreach (var file in Directory.GetFiles(path, "*.js", SearchOption.AllDirectories)) - { - if (file.IndexOf(".min.", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - if (file.IndexOf("bower_", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - - try - { - var text = _fileSystem.ReadAllText(file, Encoding.UTF8); - - var result = new CrockfordJsMinifier().Minify(text, false, Encoding.UTF8); - - if (result.Errors.Count > 0) - { - Logger.Error("Error minifying javascript: " + result.Errors[0].Message); - } - else - { - text = result.MinifiedContent; - _fileSystem.WriteAllText(file, text, Encoding.UTF8); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error minifying css", ex); - } - } - } - private async Task DumpHtml(string source, string destination, string mode, string culture, string appVersion) { foreach (var file in Directory.GetFiles(source, "*", SearchOption.TopDirectoryOnly)) @@ -528,7 +452,7 @@ namespace MediaBrowser.WebDashboard.Api private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion) { - using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, true).ConfigureAwait(false)) + using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, false).ConfigureAwait(false)) { using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read)) { -- cgit v1.2.3 From 6a7fabc3bd4ab8496a90bd04e9decf48bf16edc2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Sep 2016 02:50:06 -0400 Subject: add new guide settings --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 52 +++++++++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 1 + .../Entities/InternalItemsQuery.cs | 3 + MediaBrowser.Controller/LiveTv/LiveStream.cs | 2 + MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 + MediaBrowser.Model/Dlna/StreamInfo.cs | 17 +++- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 12 ++- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 - .../LiveTv/EmbyTV/EmbyTV.cs | 38 ++++--- .../LiveTv/EmbyTV/EncodedRecorder.cs | 25 ++++- .../LiveTv/LiveTvManager.cs | 109 +++------------------ .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 70 ++++++++++--- .../TunerHosts/HdHomerun/HdHomerunLiveStream.cs | 9 +- .../Persistence/SqliteItemRepository.cs | 81 ++++++++------- 14 files changed, 256 insertions(+), 166 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 9c1105082..5b821df0b 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -104,6 +104,26 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableUserData { get; set; } + public string SortBy { get; set; } + + public SortOrder? SortOrder { get; set; } + + /// + /// Gets the order by. + /// + /// IEnumerable{ItemSortBy}. + public string[] GetOrderBy() + { + var val = SortBy; + + if (string.IsNullOrEmpty(val)) + { + return new string[] { }; + } + + return val.Split(','); + } + public GetChannels() { AddCurrentProgram = true; @@ -650,6 +670,8 @@ namespace MediaBrowser.Api.LiveTv { public string Id { get; set; } public string Container { get; set; } + public long T { get; set; } + public long S { get; set; } } public class LiveTvService : BaseApiService @@ -681,9 +703,35 @@ namespace MediaBrowser.Api.LiveTv outputHeaders["Content-Type"] = MimeTypes.GetMimeType(filePath); + long startPosition = 0; + + if (request.T > 0) + { + var now = DateTime.UtcNow; + + var totalTicks = now.Ticks - request.S; + + if (totalTicks > 0) + { + double requestedOffset = request.T; + requestedOffset = Math.Max(0, requestedOffset - TimeSpan.FromSeconds(10).Ticks); + + var pct = requestedOffset / totalTicks; + + Logger.Info("Live stream offset pct {0}", pct); + + var bytes = new FileInfo(filePath).Length; + Logger.Info("Live stream total bytes {0}", bytes); + startPosition = Convert.ToInt64(pct * bytes); + } + } + + Logger.Info("Live stream starting byte position {0}", startPosition); + var streamSource = new ProgressiveFileCopier(_fileSystem, filePath, outputHeaders, null, Logger, CancellationToken.None) { - AllowEndOfFile = false + AllowEndOfFile = false, + StartPosition = startPosition }; return ResultFactory.GetAsyncStreamWriter(streamSource); @@ -848,6 +896,8 @@ namespace MediaBrowser.Api.LiveTv IsNews = request.IsNews, IsKids = request.IsKids, IsSports = request.IsSports, + SortBy = request.GetOrderBy(), + SortOrder = request.SortOrder ?? SortOrder.Ascending, AddCurrentProgram = request.AddCurrentProgram }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 8e57650b4..fb4bd9244 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2602,6 +2602,7 @@ namespace MediaBrowser.Api.Playback inputModifier += " " + GetFastSeekCommandLineParameter(state.Request); inputModifier = inputModifier.Trim(); + //inputModifier += " -fflags +genpts+ignidx+igndts"; if (state.VideoRequest != null && genPts) { inputModifier += " -fflags +genpts"; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index d917b7d6d..5e70cd587 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -151,6 +151,8 @@ namespace MediaBrowser.Controller.Entities public Dictionary ExcludeProviderIds { get; set; } public bool EnableGroupByMetadataKey { get; set; } + public List> OrderBy { get; set; } + public InternalItemsQuery() { GroupByPresentationUniqueKey = true; @@ -193,6 +195,7 @@ namespace MediaBrowser.Controller.Entities TrailerTypes = new TrailerType[] { }; AirDays = new DayOfWeek[] { }; SeriesStatuses = new SeriesStatus[] { }; + OrderBy = new List>(); } public InternalItemsQuery(User user) diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs index 1bb198632..7d44fbd90 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs @@ -13,11 +13,13 @@ namespace MediaBrowser.Controller.LiveTv public int ConsumerCount { get; set; } public ITunerHost TunerHost { get; set; } public string OriginalStreamId { get; set; } + public bool EnableStreamSharing { get; set; } public LiveStream(MediaSourceInfo mediaSource) { OriginalMediaSource = mediaSource; OpenedMediaSource = mediaSource; + EnableStreamSharing = true; } public async Task Open(CancellationToken cancellationToken) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index d3131eb5a..44103e720 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -235,6 +235,8 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new ResourceNotFoundException("ffprobe not found"); } + path = newPaths.Item1; + if (!ValidateVersion(path)) { throw new ResourceNotFoundException("ffmpeg version 3.0 or greater is required."); diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index ac024f00b..f7dc893c8 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -215,13 +215,26 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty)); list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty)); - if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls")) + var forceStartPosition = false; + long startPositionTicks = item.StartPositionTicks; + //if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0) + //{ + // var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value; + // elapsed -= TimeSpan.FromSeconds(20); + // if (elapsed.TotalSeconds >= 0) + // { + // startPositionTicks = elapsed.Ticks + startPositionTicks; + // forceStartPosition = true; + // } + //} + + if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls") && !forceStartPosition) { list.Add(new NameValuePair("StartTimeTicks", string.Empty)); } else { - list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(item.StartPositionTicks))); + list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(startPositionTicks))); } list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty)); diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index f76368a7b..4505b80a0 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -1,4 +1,5 @@ - +using MediaBrowser.Model.Entities; + namespace MediaBrowser.Model.LiveTv { /// @@ -85,9 +86,18 @@ namespace MediaBrowser.Model.LiveTv public bool? IsSports { get; set; } public bool? IsSeries { get; set; } + public string[] SortBy { get; set; } + + /// + /// The sort order to return results with + /// + /// The sort order. + public SortOrder? SortOrder { get; set; } + public LiveTvChannelQuery() { EnableUserData = true; + SortBy = new string[] { }; } } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index ee7dd8b98..a6240afe6 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -60,7 +60,6 @@ namespace MediaBrowser.Model.LiveTv public TunerHostInfo() { IsEnabled = true; - AllowHWTranscoding = true; } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index ef19dcbc9..3db764ae1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -483,7 +483,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (existingTimer != null) { - if (existingTimer.Status == RecordingStatus.Cancelled) + if (existingTimer.Status == RecordingStatus.Cancelled || + existingTimer.Status == RecordingStatus.Completed) { existingTimer.Status = RecordingStatus.New; _timerProvider.Update(existingTimer); @@ -832,12 +833,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return result.Item2; } - private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId) + private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId, bool enableStreamSharing) { var json = _jsonSerializer.SerializeToString(mediaSource); mediaSource = _jsonSerializer.DeserializeFromString(json); - mediaSource.Id = consumerId.ToString(CultureInfo.InvariantCulture) + "_" + mediaSource.Id; + mediaSource.Id = Guid.NewGuid().ToString("N") + "_" + mediaSource.Id; + + if (mediaSource.DateLiveStreamOpened.HasValue && enableStreamSharing) + { + var ticks = (DateTime.UtcNow - mediaSource.DateLiveStreamOpened.Value).Ticks - TimeSpan.FromSeconds(10).Ticks; + ticks = Math.Max(0, ticks); + mediaSource.Path += "?t=" + ticks.ToString(CultureInfo.InvariantCulture) + "&s=" + mediaSource.DateLiveStreamOpened.Value.Ticks.ToString(CultureInfo.InvariantCulture); + } return mediaSource; } @@ -850,14 +858,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var result = _liveStreams.Values.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase)); - if (result != null) + if (result != null && result.EnableStreamSharing) { - //result.ConsumerCount++; + result.ConsumerCount++; - //_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); + _logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); - //_liveStreamsSemaphore.Release(); - //return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1), result.TunerHost); + var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1, result.EnableStreamSharing); + _liveStreamsSemaphore.Release(); + return new Tuple(result, openedMediaSource, result.TunerHost); } try @@ -868,16 +877,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); - _liveStreams[result.OpenedMediaSource.Id] = result; + var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, 0, result.EnableStreamSharing); + + _liveStreams[openedMediaSource.Id] = result; result.ConsumerCount++; result.TunerHost = hostInstance; result.OriginalStreamId = streamId; _logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}", - streamId, result.OpenedMediaSource.Id, result.OpenedMediaSource.LiveStreamId); + streamId, openedMediaSource.Id, openedMediaSource.LiveStreamId); - return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, 0), hostInstance); + return new Tuple(result, openedMediaSource, hostInstance); } catch (FileNotFoundException) { @@ -925,7 +936,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public async Task CloseLiveStream(string id, CancellationToken cancellationToken) { // Ignore the consumer id - id = id.Substring(id.IndexOf('_') + 1); + //id = id.Substring(id.IndexOf('_') + 1); await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -1143,8 +1154,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV try { - var allMediaSources = - await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); + var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) .ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index ce5f14f4b..65e653551 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -141,7 +141,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var maxBitrate = 25000000; videoArgs = string.Format( - "-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41", + "-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41 -tune zerolatency", GetOutputSizeParam(), maxBitrate.ToString(CultureInfo.InvariantCulture)); } @@ -151,16 +151,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks); - var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\""; + var inputModifiers = "-fflags +genpts -async 1 -vsync -1"; + var commandLineArgs = "-i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\""; + + long startTimeTicks = 0; + //if (mediaSource.DateLiveStreamOpened.HasValue) + //{ + // var elapsed = DateTime.UtcNow - mediaSource.DateLiveStreamOpened.Value; + // elapsed -= TimeSpan.FromSeconds(10); + // if (elapsed.TotalSeconds >= 0) + // { + // startTimeTicks = elapsed.Ticks + startTimeTicks; + // } + //} if (mediaSource.ReadAtNativeFramerate) { - commandLineArgs = "-re " + commandLineArgs; + inputModifiers += " -re"; + } + + if (startTimeTicks > 0) + { + inputModifiers = "-ss " + _mediaEncoder.GetTimeParameter(startTimeTicks) + " " + inputModifiers; } commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), durationParam); - return commandLineArgs; + return inputModifiers + " " + commandLineArgs; } private string GetAudioArgs(MediaSourceInfo mediaSource) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 7c61d2396..f736307f0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); - var channels = _libraryManager.GetItemList(new InternalItemsQuery + var internalQuery = new InternalItemsQuery(user) { IsMovie = query.IsMovie, IsNews = query.IsNews, @@ -156,109 +156,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv IsSports = query.IsSports, IsSeries = query.IsSeries, IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }, - SortBy = new[] { ItemSortBy.SortName }, - TopParentIds = new[] { topFolder.Id.ToString("N") } + SortOrder = query.SortOrder ?? SortOrder.Ascending, + TopParentIds = new[] { topFolder.Id.ToString("N") }, + IsFavorite = query.IsFavorite, + IsLiked = query.IsLiked, + StartIndex = query.StartIndex, + Limit = query.Limit + }; - }).Cast(); + internalQuery.OrderBy.AddRange(query.SortBy.Select(i => new Tuple(i, query.SortOrder ?? SortOrder.Ascending))); - if (user != null) + if (query.EnableFavoriteSorting) { - // Avoid implicitly captured closure - var currentUser = user; - - channels = channels - .Where(i => i.IsVisible(currentUser)) - .OrderBy(i => - { - double number = 0; - - if (!string.IsNullOrEmpty(i.Number)) - { - double.TryParse(i.Number, out number); - } - - return number; - - }); - - if (query.IsFavorite.HasValue) - { - var val = query.IsFavorite.Value; - - channels = channels - .Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val); - } - - if (query.IsLiked.HasValue) - { - var val = query.IsLiked.Value; - - channels = channels - .Where(i => - { - var likes = _userDataManager.GetUserData(user, i).Likes; - - return likes.HasValue && likes.Value == val; - }); - } - - if (query.IsDisliked.HasValue) - { - var val = query.IsDisliked.Value; - - channels = channels - .Where(i => - { - var likes = _userDataManager.GetUserData(user, i).Likes; - - return likes.HasValue && likes.Value != val; - }); - } + internalQuery.OrderBy.Insert(0, new Tuple(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending)); } - var enableFavoriteSorting = query.EnableFavoriteSorting; - - channels = channels.OrderBy(i => - { - if (enableFavoriteSorting) - { - var userData = _userDataManager.GetUserData(user, i); - - if (userData.IsFavorite) - { - return 0; - } - if (userData.Likes.HasValue) - { - if (!userData.Likes.Value) - { - return 3; - } - - return 1; - } - } - - return 2; - }); - - var allChannels = channels.ToList(); - IEnumerable allEnumerable = allChannels; - - if (query.StartIndex.HasValue) + if (!internalQuery.OrderBy.Any(i => string.Equals(i.Item1, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase))) { - allEnumerable = allEnumerable.Skip(query.StartIndex.Value); + internalQuery.OrderBy.Add(new Tuple(ItemSortBy.SortName, SortOrder.Ascending)); } - if (query.Limit.HasValue) - { - allEnumerable = allEnumerable.Take(query.Limit.Value); - } + var channelResult = _libraryManager.GetItemsResult(internalQuery); var result = new QueryResult { - Items = allEnumerable.ToArray(), - TotalRecordCount = allChannels.Count + Items = channelResult.Items.Cast().ToArray(), + TotalRecordCount = channelResult.TotalRecordCount }; return result; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 68450105e..14ae45228 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -104,8 +104,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun }); } + private Dictionary _modelCache = new Dictionary(); private async Task GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken) { + lock (_modelCache) + { + DiscoverResponse response; + if (_modelCache.TryGetValue(info.Url, out response)) + { + return response.ModelNumber; + } + } + try { using (var stream = await _httpClient.Get(new HttpRequestOptions() @@ -119,6 +129,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var response = JsonSerializer.DeserializeFromStream(stream); + lock (_modelCache) + { + _modelCache[info.Id] = response; + } + return response.ModelNumber; } } @@ -126,8 +141,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound) { + var defaultValue = "HDHR"; // HDHR4 doesn't have this api - return "HDHR"; + lock (_modelCache) + { + _modelCache[info.Id] = new DiscoverResponse + { + ModelNumber = defaultValue + }; + } + return defaultValue; } throw; @@ -427,18 +450,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun try { - string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); - model = model ?? string.Empty; - - if (info.AllowHWTranscoding && (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)) + if (info.AllowHWTranscoding) { - list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false)); + string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + model = model ?? string.Empty; + + if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)) + { + list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false)); - list.Add(await GetMediaSource(info, hdhrId, "internet540").ConfigureAwait(false)); - list.Add(await GetMediaSource(info, hdhrId, "internet480").ConfigureAwait(false)); - list.Add(await GetMediaSource(info, hdhrId, "internet360").ConfigureAwait(false)); - list.Add(await GetMediaSource(info, hdhrId, "internet240").ConfigureAwait(false)); - list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false)); + list.Add(await GetMediaSource(info, hdhrId, "internet540").ConfigureAwait(false)); + list.Add(await GetMediaSource(info, hdhrId, "internet480").ConfigureAwait(false)); + list.Add(await GetMediaSource(info, hdhrId, "internet360").ConfigureAwait(false)); + list.Add(await GetMediaSource(info, hdhrId, "internet240").ConfigureAwait(false)); + list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false)); + } } } catch @@ -474,6 +500,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun var mediaSource = await GetMediaSource(info, hdhrId, profile).ConfigureAwait(false); var liveStream = new HdHomerunLiveStream(mediaSource, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost); + if (info.AllowHWTranscoding) + { + var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + + if ((model ?? string.Empty).IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) + { + liveStream.EnableStreamSharing = !info.AllowHWTranscoding; + } + else + { + liveStream.EnableStreamSharing = true; + } + } + else + { + liveStream.EnableStreamSharing = true; + } return liveStream; } @@ -484,6 +527,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return; } + lock (_modelCache) + { + _modelCache.Clear(); + } + try { // Test it by pulling down the lineup diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs index d6574db22..57722881d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs @@ -52,11 +52,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun StartStreamingToTempFile(output, tempFile, url, taskCompletionSource, _liveStreamCancellationTokenSource.Token); - await taskCompletionSource.Task.ConfigureAwait(false); + //OpenedMediaSource.Protocol = MediaProtocol.File; + //OpenedMediaSource.Path = tempFile; + //OpenedMediaSource.ReadAtNativeFramerate = true; OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts"; - OpenedMediaSource.Protocol = MediaProtocol.Http; + + await taskCompletionSource.Task.ConfigureAwait(false); + + //await Task.Delay(5000).ConfigureAwait(false); } public override Task Close() diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 097118418..672cd1bc2 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -1730,28 +1730,28 @@ namespace MediaBrowser.Server.Implementations.Persistence return true; } - if (query.SortBy != null && query.SortBy.Length > 0) + var sortingFields = query.SortBy.ToList(); + sortingFields.AddRange(query.OrderBy.Select(i => i.Item1)); + + if (sortingFields.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase)) { - if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase)) - { - return true; - } - if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase)) - { - return true; - } - if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase)) - { - return true; - } - if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase)) - { - return true; - } - if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase)) - { - return true; - } + return true; + } + if (sortingFields.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (sortingFields.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (sortingFields.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (sortingFields.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase)) + { + return true; } if (query.IsFavoriteOrLiked.HasValue) @@ -2151,34 +2151,41 @@ namespace MediaBrowser.Server.Implementations.Persistence private string GetOrderByText(InternalItemsQuery query) { + var orderBy = query.OrderBy.ToList(); + var enableOrderInversion = true; + + if (orderBy.Count == 0) + { + orderBy.AddRange(query.SortBy.Select(i => new Tuple(i, query.SortOrder))); + } + else + { + enableOrderInversion = false; + } + if (query.SimilarTo != null) { - if (query.SortBy == null || query.SortBy.Length == 0) + if (orderBy.Count == 0) { - if (query.User != null) - { - query.SortBy = new[] { "SimilarityScore", ItemSortBy.Random }; - } - else - { - query.SortBy = new[] { "SimilarityScore", ItemSortBy.Random }; - } + orderBy.Add(new Tuple("SimilarityScore", SortOrder.Descending)); + orderBy.Add(new Tuple(ItemSortBy.Random, SortOrder.Ascending)); query.SortOrder = SortOrder.Descending; + enableOrderInversion = false; } } - if (query.SortBy == null || query.SortBy.Length == 0) + query.OrderBy = orderBy; + + if (orderBy.Count == 0) { return string.Empty; } - var isAscending = query.SortOrder != SortOrder.Descending; - - return " ORDER BY " + string.Join(",", query.SortBy.Select(i => + return " ORDER BY " + string.Join(",", orderBy.Select(i => { - var columnMap = MapOrderByField(i, query); - var columnAscending = isAscending; - if (columnMap.Item2) + var columnMap = MapOrderByField(i.Item1, query); + var columnAscending = i.Item2 == SortOrder.Ascending; + if (columnMap.Item2 && enableOrderInversion) { columnAscending = !columnAscending; } -- cgit v1.2.3 From 229172da500d8fd11676144779d004172f3d41a1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 30 Sep 2016 14:43:59 -0400 Subject: update series recording editor --- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 1 + .../MediaEncoding/IMediaEncoder.cs | 4 ++-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 23 ++++++++++++---------- .../MediaInfo/VideoImageProvider.cs | 4 ++-- .../LiveTv/EmbyTV/EncodedRecorder.cs | 4 +++- .../MediaEncoder/EncodingManager.cs | 4 +++- 6 files changed, 24 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index d4ddbd7c5..51455c141 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -907,6 +907,7 @@ namespace MediaBrowser.Api.Playback.Hls ).Trim(); } + // TODO: check libavformat version for 57 50.100 and use -hls_flags split_by_time return string.Format("{0}{11} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"", inputModifier, GetInputArgument(state), diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 7fdbf020c..f97fe9560 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -45,9 +45,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// The offset. /// The cancellation token. /// Task{Stream}. - Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); - Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video images on interval. diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 44103e720..06867969e 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -771,20 +771,20 @@ namespace MediaBrowser.MediaEncoding.Encoder public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(new[] { path }, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); + return ExtractImage(new[] { path }, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, null, protocol, false, threedFormat, offset, cancellationToken); + return ExtractImage(inputFiles, container, null, protocol, false, threedFormat, offset, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, imageStreamIndex, protocol, false, null, null, cancellationToken); + return ExtractImage(inputFiles, container, imageStreamIndex, protocol, false, null, null, cancellationToken); } - private async Task ExtractImage(string[] inputFiles, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, + private async Task ExtractImage(string[] inputFiles, string container, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool; @@ -803,7 +803,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { try { - return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false); } catch (ArgumentException) { @@ -815,10 +815,10 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false); } - private async Task ExtractImageInternal(string inputPath, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + private async Task ExtractImageInternal(string inputPath, string container, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { @@ -859,8 +859,11 @@ namespace MediaBrowser.MediaEncoding.Encoder var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; + var enableThumbnail = !new List { "wtv" }.Contains(container ?? string.Empty, StringComparer.OrdinalIgnoreCase); + var thumbnail = enableThumbnail ? ",thumbnail=30" : 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 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg) : + var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) : 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); diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index 2ad02da2e..6a934240a 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -134,7 +134,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, videoIndex, cancellationToken).ConfigureAwait(false); + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoIndex, cancellationToken).ConfigureAwait(false); } else { @@ -145,7 +145,7 @@ namespace MediaBrowser.Providers.MediaInfo ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1)) : TimeSpan.FromSeconds(10); - extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); } return new DynamicImageResponse diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 65e653551..3e9d186e3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -131,6 +131,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback StartStreamingLog(process.StandardError.BaseStream, _logFileStream); + _logger.Info("ffmpeg recording process started for {0}", _targetPath); + return _taskCompletionSource.Task; } @@ -141,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var maxBitrate = 25000000; videoArgs = string.Format( - "-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41 -tune zerolatency", + "-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41", GetOutputSizeParam(), maxBitrate.ToString(CultureInfo.InvariantCulture)); } diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs index 7d0841fa6..06c109dfc 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -160,7 +160,9 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); - var tempFile = await _encoder.ExtractVideoImage(inputPath, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); + var container = video.Container; + + var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); File.Copy(tempFile, path, true); try -- cgit v1.2.3 From d3583c14605dbf31aed7dd921fb2085c1c0b7be1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 3 Oct 2016 02:28:45 -0400 Subject: update lists --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 6 ++++-- MediaBrowser.Api/Playback/StreamState.cs | 13 +++++++++++++ MediaBrowser.Controller/Entities/InternalItemsQuery.cs | 3 +++ MediaBrowser.Dlna/Didl/DidlBuilder.cs | 6 ++++-- MediaBrowser.Dlna/PlayTo/PlayToController.cs | 3 ++- MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 13 +++++++++++++ MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs | 3 ++- MediaBrowser.Model/Dlna/ConditionProcessor.cs | 5 ++++- MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs | 6 ++++-- MediaBrowser.Model/Dlna/DeviceProfile.cs | 5 +++-- MediaBrowser.Model/Dlna/ProfileConditionValue.cs | 3 ++- MediaBrowser.Model/Dlna/StreamBuilder.cs | 10 ++++++---- MediaBrowser.Model/Dlna/StreamInfo.cs | 13 +++++++++++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 14 ++++++++++++++ .../LiveTv/EmbyTV/EmbyTV.cs | 13 +++++++------ .../LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs | 12 +++++++++++- .../Persistence/SqliteItemRepository.cs | 12 ++++++++++++ 17 files changed, 117 insertions(+), 23 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index fb4bd9244..7f41cb059 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2329,7 +2329,8 @@ namespace MediaBrowser.Api.Playback state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, - state.TargetVideoCodecTag); + state.TargetVideoCodecTag, + state.IsTargetAVC); if (mediaProfile != null) { @@ -2547,7 +2548,8 @@ namespace MediaBrowser.Api.Playback state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, - state.TargetVideoCodecTag + state.TargetVideoCodecTag, + state.IsTargetAVC ).FirstOrDefault() ?? string.Empty; } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 019f378c5..863bc0193 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -516,5 +516,18 @@ namespace MediaBrowser.Api.Playback return false; } } + + public bool? IsTargetAVC + { + get + { + if (Request.Static) + { + return VideoStream == null ? null : VideoStream.IsAVC; + } + + return true; + } + } } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 60af2c56a..89fe71d3c 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -154,6 +154,9 @@ namespace MediaBrowser.Controller.Entities public List> OrderBy { get; set; } + public DateTime? MinDateCreated { get; set; } + public DateTime? MinDateLastSaved { get; set; } + public InternalItemsQuery() { GroupByPresentationUniqueKey = true; diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 84c1b3bde..f53dec3bf 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -177,7 +177,8 @@ namespace MediaBrowser.Dlna.Didl streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, - streamInfo.TargetVideoCodecTag); + streamInfo.TargetVideoCodecTag, + streamInfo.IsTargetAVC); foreach (var contentFeature in contentFeatureList) { @@ -322,7 +323,8 @@ namespace MediaBrowser.Dlna.Didl streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, - streamInfo.TargetVideoCodecTag); + streamInfo.TargetVideoCodecTag, + streamInfo.IsTargetAVC); var filename = url.Substring(0, url.IndexOf('?')); diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index 6345e2105..f6b24e615 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -540,7 +540,8 @@ namespace MediaBrowser.Dlna.PlayTo streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, - streamInfo.TargetVideoCodecTag); + streamInfo.TargetVideoCodecTag, + streamInfo.IsTargetAVC); return list.FirstOrDefault(); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index d3738d903..0c7ff1b76 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -392,6 +392,19 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + public bool? IsTargetAVC + { + get + { + if (Options.Static) + { + return VideoStream == null ? null : VideoStream.IsAVC; + } + + return false; + } + } + public int? TargetVideoStreamCount { get diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index c72532669..b66a3ed96 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -823,7 +823,8 @@ namespace MediaBrowser.MediaEncoding.Encoder state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, - state.TargetVideoCodecTag); + state.TargetVideoCodecTag, + state.IsTargetAVC); if (mediaProfile != null) { diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 69f1369dc..ec13cacfa 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -20,12 +20,15 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag) + string videoCodecTag, + bool? isAvc) { switch (condition.Property) { case ProfileConditionValue.IsAnamorphic: return IsConditionSatisfied(condition, isAnamorphic); + case ProfileConditionValue.IsAvc: + return IsConditionSatisfied(condition, isAvc); case ProfileConditionValue.VideoFramerate: return IsConditionSatisfied(condition, videoFramerate); case ProfileConditionValue.VideoLevel: diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index c4b3383a2..4a16a2780 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -118,7 +118,8 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag) + string videoCodecTag, + bool? isAvc) { // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo); @@ -159,7 +160,8 @@ namespace MediaBrowser.Model.Dlna refFrames, numVideoStreams, numAudioStreams, - videoCodecTag); + videoCodecTag, + isAvc); List orgPnValues = new List(); diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index d6a322322..884a9f29d 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -285,7 +285,8 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag) + string videoCodecTag, + bool? isAvc) { container = StringHelper.TrimStart(container ?? string.Empty, '.'); @@ -319,7 +320,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index c17a09c3f..7e2002f17 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -20,6 +20,7 @@ NumAudioStreams = 16, NumVideoStreams = 17, IsSecondaryAudio = 18, - VideoCodecTag = 19 + VideoCodecTag = 19, + IsAvc = 20 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 30d1498bf..52b7fd43a 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -541,6 +541,7 @@ namespace MediaBrowser.Model.Dlna float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate; bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic; string videoCodecTag = videoStream == null ? null : videoStream.CodecTag; + bool? isAvc = videoStream == null ? null : videoStream.IsAVC; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp; int? packetLength = videoStream == null ? null : videoStream.PacketLength; @@ -549,7 +550,7 @@ namespace MediaBrowser.Model.Dlna int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); - if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item); applyConditions = false; @@ -718,6 +719,7 @@ namespace MediaBrowser.Model.Dlna float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate; bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic; string videoCodecTag = videoStream == null ? null : videoStream.CodecTag; + bool? isAvc = videoStream == null ? null : videoStream.IsAVC; int? audioBitrate = audioStream == null ? null : audioStream.BitRate; int? audioChannels = audioStream == null ? null : audioStream.Channels; @@ -733,7 +735,7 @@ namespace MediaBrowser.Model.Dlna // Check container conditions foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource); @@ -760,7 +762,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(profile, "VideoCodecProfile", applyCondition, mediaSource); applyConditions = false; @@ -780,7 +782,7 @@ namespace MediaBrowser.Model.Dlna foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource); diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index f7dc893c8..c9cb873e1 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -676,6 +676,19 @@ namespace MediaBrowser.Model.Dlna } } + public bool? IsTargetAVC + { + get + { + if (IsDirectStream) + { + return TargetVideoStream == null ? null : TargetVideoStream.IsAVC; + } + + return true; + } + } + public int? TargetWidth { get diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3de330557..36b5987a0 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -211,6 +211,20 @@ namespace MediaBrowser.Providers.Manager throw; } } + catch (IOException ex) + { + var retry = !string.IsNullOrWhiteSpace(retryPath) && + !string.Equals(path, retryPath, StringComparison.OrdinalIgnoreCase); + + if (retry) + { + _logger.Error("IOException saving to {0}. {2}. Will retry saving to {1}", path, retryPath, ex.Message); + } + else + { + throw; + } + } source.Position = 0; await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 3db764ae1..4530bfcb6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -606,15 +606,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV ActiveRecordingInfo activeRecordingInfo; if (!_activeRecordings.TryGetValue(updatedTimer.Id, out activeRecordingInfo)) { - UpdateExistingTimerWithNewData(existingTimer, updatedTimer); - - _timerProvider.Update(existingTimer); + existingTimer.PrePaddingSeconds = updatedTimer.PrePaddingSeconds; + existingTimer.PostPaddingSeconds = updatedTimer.PostPaddingSeconds; + existingTimer.IsPostPaddingRequired = updatedTimer.IsPostPaddingRequired; + existingTimer.IsPrePaddingRequired = updatedTimer.IsPrePaddingRequired; } return Task.FromResult(true); } - private void UpdateExistingTimerWithNewData(TimerInfo existingTimer, TimerInfo updatedTimer) + private void UpdateExistingTimerWithNewMetadata(TimerInfo existingTimer, TimerInfo updatedTimer) { // Update the program info but retain the status existingTimer.ChannelId = updatedTimer.ChannelId; @@ -1430,7 +1431,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { SaveSeriesNfo(timer, recordingPath, seriesPath); } - else if (!timer.IsMovie || timer.IsSports) + else if (!timer.IsMovie || timer.IsSports || timer.IsNews) { SaveVideoNfo(timer, recordingPath); } @@ -1620,7 +1621,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV ActiveRecordingInfo activeRecordingInfo; if (!_activeRecordings.TryGetValue(timer.Id, out activeRecordingInfo)) { - UpdateExistingTimerWithNewData(existingTimer, timer); + UpdateExistingTimerWithNewMetadata(existingTimer, timer); if (ShouldCancelTimerForSeriesTimer(seriesTimer, timer)) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs index 2cdd0571b..d49e3f258 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun Action onStarted = null; if (isFirstAttempt) { - onStarted = () => openTaskCompletionSource.TrySetResult(true); + onStarted = () => ResolveWhenExists(openTaskCompletionSource, tempFilePath, cancellationToken); } await DirectRecorder.CopyUntilCancelled(response.Content, outputStream, onStarted, cancellationToken).ConfigureAwait(false); } @@ -137,6 +137,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun }).ConfigureAwait(false); } + private async void ResolveWhenExists(TaskCompletionSource taskCompletionSource, string file, CancellationToken cancellationToken) + { + while (!File.Exists(file) && !cancellationToken.IsCancellationRequested) + { + await Task.Delay(50).ConfigureAwait(false); + } + + taskCompletionSource.TrySetResult(true); + } + private async void DeleteTempFile(string path) { for (var i = 0; i < 10; i++) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index c843ab596..5a11742dc 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2724,6 +2724,18 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@MinIndexNumber", DbType.Int32).Value = query.MinIndexNumber.Value; } + if (query.MinDateCreated.HasValue) + { + whereClauses.Add("DateCreated>=@MinDateCreated"); + cmd.Parameters.Add(cmd, "@MinDateCreated", DbType.DateTime).Value = query.MinDateCreated.Value; + } + + if (query.MinDateLastSaved.HasValue) + { + whereClauses.Add("DateLastSaved>=@MinDateLastSaved"); + cmd.Parameters.Add(cmd, "@MinDateLastSaved", DbType.DateTime).Value = query.MinDateLastSaved.Value; + } + //if (query.MinPlayers.HasValue) //{ // whereClauses.Add("Players>=@MinPlayers"); -- cgit v1.2.3 From c4e137e6cf7a52937e1169d1f170da4b8e72ba6a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 4 Oct 2016 01:15:39 -0400 Subject: update timer listings --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 5 ++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 10 +++-- MediaBrowser.Controller/LiveTv/TimerInfo.cs | 1 + MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 10 +++-- MediaBrowser.Model/Dto/BaseItemDto.cs | 1 + MediaBrowser.Model/LiveTv/TimerQuery.cs | 2 + .../LiveTv/EmbyTV/EmbyTV.cs | 44 ++++++++++++---------- .../LiveTv/EmbyTV/RecordingHelper.cs | 20 +++++----- .../LiveTv/LiveTvDtoService.cs | 1 + .../LiveTv/LiveTvManager.cs | 14 +++++++ 10 files changed, 71 insertions(+), 37 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ecc17374f..4baae031f 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -315,6 +315,8 @@ namespace MediaBrowser.Api.LiveTv public string SeriesTimerId { get; set; } public bool? IsActive { get; set; } + + public bool? IsScheduled { get; set; } } [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] @@ -1095,7 +1097,8 @@ namespace MediaBrowser.Api.LiveTv { ChannelId = request.ChannelId, SeriesTimerId = request.SeriesTimerId, - IsActive = request.IsActive + IsActive = request.IsActive, + IsScheduled = request.IsScheduled }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7f41cb059..bcf3bd28e 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -463,13 +463,15 @@ namespace MediaBrowser.Api.Playback var level = NormalizeTranscodingLevel(state.OutputVideoCodec, state.VideoRequest.Level); // h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format + // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307 if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) + string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) { switch (level) { case "30": - param += " -level 3"; + param += " -level 3.0"; break; case "31": param += " -level 3.1"; @@ -478,7 +480,7 @@ namespace MediaBrowser.Api.Playback param += " -level 3.2"; break; case "40": - param += " -level 4"; + param += " -level 4.0"; break; case "41": param += " -level 4.1"; @@ -487,7 +489,7 @@ namespace MediaBrowser.Api.Playback param += " -level 4.2"; break; case "50": - param += " -level 5"; + param += " -level 5.0"; break; case "51": param += " -level 5.1"; diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index 978e9e1a8..fd614253a 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -106,6 +106,7 @@ namespace MediaBrowser.Controller.LiveTv public string EpisodeTitle { get; set; } public DateTime? OriginalAirDate { get; set; } public bool IsProgramSeries { get; set; } + public bool IsRepeat { get; set; } public string HomePageUrl { get; set; } public float? CommunityRating { get; set; } public string ShortOverview { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index e8121d178..f1e2f7241 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -726,13 +726,15 @@ namespace MediaBrowser.MediaEncoding.Encoder levelString = NormalizeTranscodingLevel(state.OutputVideoCodec, levelString); // h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format + // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307 if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) + string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)) { switch (levelString) { case "30": - param += " -level 3"; + param += " -level 3.0"; break; case "31": param += " -level 3.1"; @@ -741,7 +743,7 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -level 3.2"; break; case "40": - param += " -level 4"; + param += " -level 4.0"; break; case "41": param += " -level 4.1"; @@ -750,7 +752,7 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -level 4.2"; break; case "50": - param += " -level 5"; + param += " -level 5.0"; break; case "51": param += " -level 5.1"; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 9434ab03a..19853fd2b 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1215,6 +1215,7 @@ namespace MediaBrowser.Model.Dto /// /// The timer identifier. public string TimerId { get; set; } + public RecordingStatus TimerStatus { get; set; } /// /// Gets or sets the current program. /// diff --git a/MediaBrowser.Model/LiveTv/TimerQuery.cs b/MediaBrowser.Model/LiveTv/TimerQuery.cs index 87b6b89ac..310dc486f 100644 --- a/MediaBrowser.Model/LiveTv/TimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/TimerQuery.cs @@ -15,5 +15,7 @@ public string SeriesTimerId { get; set; } public bool? IsActive { get; set; } + + public bool? IsScheduled { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 4530bfcb6..a3ba2c6f8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -629,6 +629,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV existingTimer.IsNews = updatedTimer.IsNews; existingTimer.IsMovie = updatedTimer.IsMovie; existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries; + existingTimer.IsRepeat = updatedTimer.IsRepeat; existingTimer.IsSports = updatedTimer.IsSports; existingTimer.Name = updatedTimer.Name; existingTimer.OfficialRating = updatedTimer.OfficialRating; @@ -665,8 +666,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var excludeStatues = new List { - RecordingStatus.Completed, - RecordingStatus.Cancelled + RecordingStatus.Completed }; var timers = _timerProvider.GetAll() @@ -1591,6 +1591,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private bool ShouldCancelTimerForSeriesTimer(SeriesTimerInfo seriesTimer, TimerInfo timer) { + if (!seriesTimer.RecordAnyTime) + { + if (Math.Abs(seriesTimer.StartDate.TimeOfDay.Ticks - timer.StartDate.TimeOfDay.Ticks) >= TimeSpan.FromMinutes(5).Ticks) + { + return true; + } + + if (!seriesTimer.Days.Contains(timer.StartDate.ToLocalTime().DayOfWeek)) + { + return true; + } + } + + if (seriesTimer.RecordNewOnly && timer.IsRepeat) + { + return true; + } + + if (!seriesTimer.RecordAnyChannel && !string.Equals(timer.ChannelId, seriesTimer.ChannelId, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + return seriesTimer.SkipEpisodesInLibrary && IsProgramAlreadyInLibrary(timer); } @@ -1734,23 +1757,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private IEnumerable GetProgramsForSeries(SeriesTimerInfo seriesTimer, IEnumerable allPrograms) { - if (!seriesTimer.RecordAnyTime) - { - allPrograms = allPrograms.Where(epg => Math.Abs(seriesTimer.StartDate.TimeOfDay.Ticks - epg.StartDate.TimeOfDay.Ticks) < TimeSpan.FromMinutes(5).Ticks); - - allPrograms = allPrograms.Where(i => seriesTimer.Days.Contains(i.StartDate.ToLocalTime().DayOfWeek)); - } - - if (seriesTimer.RecordNewOnly) - { - allPrograms = allPrograms.Where(epg => !epg.IsRepeat); - } - - if (!seriesTimer.RecordAnyChannel) - { - allPrograms = allPrograms.Where(epg => string.Equals(epg.ChannelId, seriesTimer.ChannelId, StringComparison.OrdinalIgnoreCase)); - } - if (string.IsNullOrWhiteSpace(seriesTimer.SeriesId)) { _logger.Error("seriesTimer.SeriesId is null. Cannot find programs for series"); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index bb6935e8e..f7b4b3fde 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.LiveTv; using System; using System.Globalization; +using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { @@ -12,24 +13,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds); } - public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo series) + public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo seriesTimer) { var timer = new TimerInfo(); timer.ChannelId = parent.ChannelId; - timer.Id = (series.Id + parent.Id).GetMD5().ToString("N"); + timer.Id = (seriesTimer.Id + parent.Id).GetMD5().ToString("N"); timer.StartDate = parent.StartDate; timer.EndDate = parent.EndDate; timer.ProgramId = parent.Id; - timer.PrePaddingSeconds = series.PrePaddingSeconds; - timer.PostPaddingSeconds = series.PostPaddingSeconds; - timer.IsPostPaddingRequired = series.IsPostPaddingRequired; - timer.IsPrePaddingRequired = series.IsPrePaddingRequired; - timer.KeepUntil = series.KeepUntil; - timer.Priority = series.Priority; + timer.PrePaddingSeconds = seriesTimer.PrePaddingSeconds; + timer.PostPaddingSeconds = seriesTimer.PostPaddingSeconds; + timer.IsPostPaddingRequired = seriesTimer.IsPostPaddingRequired; + timer.IsPrePaddingRequired = seriesTimer.IsPrePaddingRequired; + timer.KeepUntil = seriesTimer.KeepUntil; + timer.Priority = seriesTimer.Priority; timer.Name = parent.Name; timer.Overview = parent.Overview; - timer.SeriesTimerId = series.Id; + timer.SeriesTimerId = seriesTimer.Id; CopyProgramInfoToTimerInfo(parent, timer); @@ -53,6 +54,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV timerInfo.CommunityRating = programInfo.CommunityRating; timerInfo.ShortOverview = programInfo.ShortOverview; timerInfo.OfficialRating = programInfo.OfficialRating; + timerInfo.IsRepeat = programInfo.IsRepeat; } public static string GetRecordingName(TimerInfo info) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 348bcd97b..2189cf627 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -72,6 +72,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv dto.ProgramInfo = _dtoService.GetBaseItemDto(program, new DtoOptions()); dto.ProgramInfo.TimerId = dto.Id; + dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index e34868428..84b162286 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1087,6 +1087,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv program.TimerId = _tvDtoService.GetInternalTimerId(serviceName, timer.Id) .ToString("N"); + program.TimerStatus = timer.Status; + if (!string.IsNullOrEmpty(timer.SeriesTimerId)) { program.SeriesTimerId = _tvDtoService.GetInternalSeriesTimerId(serviceName, timer.SeriesTimerId) @@ -1875,6 +1877,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + if (query.IsScheduled.HasValue) + { + if (query.IsScheduled.Value) + { + timers = timers.Where(i => i.Item1.Status == RecordingStatus.New || i.Item1.Status == RecordingStatus.Scheduled); + } + else + { + timers = timers.Where(i => !(i.Item1.Status == RecordingStatus.New || i.Item1.Status == RecordingStatus.Scheduled)); + } + } + if (!string.IsNullOrEmpty(query.ChannelId)) { var guid = new Guid(query.ChannelId); -- cgit v1.2.3 From a69ca6c55bb7183d247c2c3b25203dbed99fd5d9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 6 Oct 2016 14:55:01 -0400 Subject: avoid buffering http responses --- MediaBrowser.Api/Dlna/DlnaServerService.cs | 8 ++- MediaBrowser.Api/Images/RemoteImageService.cs | 3 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 3 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 3 +- .../BaseApplicationHost.cs | 8 ++- .../HttpClientManager/HttpClientManager.cs | 15 ++-- .../IO/MemoryStreamProvider.cs | 31 ++++++++ .../Logging/NLogger.cs | 10 +++ .../MediaBrowser.Common.Implementations.csproj | 5 ++ .../Security/PluginSecurityManager.cs | 6 +- .../Updates/GithubUpdater.cs | 6 +- .../packages.config | 1 + MediaBrowser.Common/IO/IMemoryStreamProvider.cs | 11 +++ MediaBrowser.Common/MediaBrowser.Common.csproj | 1 + MediaBrowser.Controller/LiveTv/ILiveTvService.cs | 5 ++ .../Net/BasePeriodicWebSocketListener.cs | 4 +- .../ContentDirectory/ContentDirectoryBrowser.cs | 3 +- MediaBrowser.Dlna/Eventing/EventManager.cs | 3 +- MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 1 - MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs | 9 ++- MediaBrowser.Dlna/Ssdp/SsdpHelper.cs | 45 ------------ .../Encoder/EncodingUtils.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 7 +- .../Probing/ProbeResultNormalizer.cs | 11 +-- .../Subtitles/SubtitleEncoder.cs | 10 ++- MediaBrowser.Model/System/SystemInfo.cs | 2 + .../GameGenres/GameGenreImageProvider.cs | 4 +- .../Genres/GenreImageProvider.cs | 6 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 6 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 11 +-- .../Studios/StudiosImageProvider.cs | 4 +- .../TV/TheTVDB/TvdbSeriesProvider.cs | 4 +- .../Connect/ConnectEntryPoint.cs | 3 +- .../Connect/ConnectManager.cs | 27 ++++--- .../Dto/DtoService.cs | 6 ++ .../EntryPoints/UsageReporter.cs | 6 +- .../HttpServer/HttpListenerHost.cs | 8 ++- .../HttpServer/ServerFactory.cs | 10 +-- .../HttpServer/SocketSharp/RequestMono.cs | 8 +-- .../SocketSharp/WebSocketSharpListener.cs | 7 +- .../SocketSharp/WebSocketSharpRequest.cs | 9 ++- .../HttpServer/StreamWriter.cs | 37 ++++++++-- .../LiveTv/Listings/SchedulesDirect.cs | 3 +- .../LiveTv/LiveTvManager.cs | 47 ++++++++++--- .../LiveTv/LiveTvMediaSourceProvider.cs | 82 +++++++++++++++++++++- .../LiveTv/TunerHosts/BaseTunerHost.cs | 78 -------------------- .../TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 3 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 12 ++-- .../TunerHosts/HdHomerun/HdHomerunLiveStream.cs | 8 ++- .../News/NewsEntryPoint.cs | 3 +- .../Persistence/DataExtensions.cs | 13 ++-- .../SqliteDisplayPreferencesRepository.cs | 14 ++-- .../Persistence/SqliteItemRepository.cs | 9 ++- .../Persistence/SqliteUserRepository.cs | 9 ++- .../Playlists/ManualPlaylistsFolder.cs | 2 +- .../ServerManager/ServerManager.cs | 7 +- .../ServerManager/WebSocketConnection.cs | 9 ++- .../Session/HttpSessionController.cs | 3 +- .../Sync/SyncManager.cs | 7 +- .../Sync/TargetDataProvider.cs | 7 +- .../ApplicationHost.cs | 24 ++++--- MediaBrowser.sln | 3 + OpenSubtitlesHandler/Utilities.cs | 3 +- 63 files changed, 448 insertions(+), 267 deletions(-) create mode 100644 MediaBrowser.Common.Implementations/IO/MemoryStreamProvider.cs create mode 100644 MediaBrowser.Common/IO/IMemoryStreamProvider.cs delete mode 100644 MediaBrowser.Dlna/Ssdp/SsdpHelper.cs (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs index 4e7b1a7d5..b2c7e5532 100644 --- a/MediaBrowser.Api/Dlna/DlnaServerService.cs +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -7,6 +7,8 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; namespace MediaBrowser.Api.Dlna { @@ -109,13 +111,15 @@ namespace MediaBrowser.Api.Dlna private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar; private const string XMLContentType = "text/xml; charset=UTF-8"; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar) + public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar, IMemoryStreamProvider memoryStreamProvider) { _dlnaManager = dlnaManager; _contentDirectory = contentDirectory; _connectionManager = connectionManager; _mediaReceiverRegistrar = mediaReceiverRegistrar; + _memoryStreamProvider = memoryStreamProvider; } public object Get(GetDescriptionXml request) @@ -201,7 +205,7 @@ namespace MediaBrowser.Api.Dlna { using (var response = _dlnaManager.GetIcon(request.Filename)) { - using (var ms = new MemoryStream()) + using (var ms = _memoryStreamProvider.CreateNew()) { response.Stream.CopyTo(ms); diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index b21e54495..25d7639c6 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -273,7 +273,8 @@ namespace MediaBrowser.Api.Images { var result = await _httpClient.GetResponse(new HttpRequestOptions { - Url = url + Url = url, + BufferContent = false }).ConfigureAwait(false); diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ed7a0990f..8b5e7075d 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -811,7 +811,8 @@ namespace MediaBrowser.Api.LiveTv var response = await _httpClient.Get(new HttpRequestOptions { - Url = "https://json.schedulesdirect.org/20141201/available/countries" + Url = "https://json.schedulesdirect.org/20141201/available/countries", + BufferContent = false }).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 0b2fad580..056c1d7ae 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2469,7 +2469,8 @@ namespace MediaBrowser.Api.Playback Url = "https://mb3admin.com/admin/service/transcoding/report", CancellationToken = CancellationToken.None, LogRequest = false, - LogErrors = false + LogErrors = false, + BufferContent = false }; options.RequestContent = JsonSerializer.SerializeToString(dict); options.RequestContentType = "application/json"; diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index baf5afc1b..4099c9c56 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -30,6 +30,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.IO; namespace MediaBrowser.Common.Implementations { @@ -192,6 +193,8 @@ namespace MediaBrowser.Common.Implementations get { return Environment.OSVersion.VersionString; } } + public IMemoryStreamProvider MemoryStreamProvider { get; set; } + /// /// Initializes a new instance of the class. /// @@ -231,6 +234,8 @@ namespace MediaBrowser.Common.Implementations JsonSerializer = CreateJsonSerializer(); + MemoryStreamProvider = new MemoryStreamProvider(); + OnLoggerLoaded(true); LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false); @@ -456,6 +461,7 @@ namespace MediaBrowser.Common.Implementations RegisterSingleInstance(JsonSerializer); RegisterSingleInstance(XmlSerializer); + RegisterSingleInstance(MemoryStreamProvider); RegisterSingleInstance(LogManager); RegisterSingleInstance(Logger); @@ -464,7 +470,7 @@ namespace MediaBrowser.Common.Implementations RegisterSingleInstance(FileSystemManager); - HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager); + HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamProvider); RegisterSingleInstance(HttpClient); NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager")); diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index ba5964be5..eec18e985 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; + private readonly IMemoryStreamProvider _memoryStreamProvider; /// /// Initializes a new instance of the class. @@ -52,7 +53,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// appPaths /// or /// logger - public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem) + public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamProvider memoryStreamProvider) { if (appPaths == null) { @@ -65,6 +66,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager _logger = logger; _fileSystem = fileSystem; + _memoryStreamProvider = memoryStreamProvider; _appPaths = appPaths; // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c @@ -269,6 +271,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager Url = url, ResourcePool = resourcePool, CancellationToken = cancellationToken, + BufferContent = resourcePool != null }); } @@ -329,7 +332,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { using (var stream = _fileSystem.GetFileStream(responseCachePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { - var memoryStream = new MemoryStream(); + var memoryStream = _memoryStreamProvider.CreateNew(); await stream.CopyToAsync(memoryStream).ConfigureAwait(false); memoryStream.Position = 0; @@ -363,7 +366,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager using (var responseStream = response.Content) { - var memoryStream = new MemoryStream(); + var memoryStream = _memoryStreamProvider.CreateNew(); await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false); memoryStream.Position = 0; @@ -455,7 +458,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager using (var stream = httpResponse.GetResponseStream()) { - var memoryStream = new MemoryStream(); + var memoryStream = _memoryStreamProvider.CreateNew(); await stream.CopyToAsync(memoryStream).ConfigureAwait(false); @@ -550,7 +553,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { Url = url, ResourcePool = resourcePool, - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + BufferContent = resourcePool != null }, postData); } @@ -560,7 +564,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// /// The options. /// Task{System.String}. - /// progress public async Task GetTempFile(HttpRequestOptions options) { var response = await GetTempFileResponse(options).ConfigureAwait(false); diff --git a/MediaBrowser.Common.Implementations/IO/MemoryStreamProvider.cs b/MediaBrowser.Common.Implementations/IO/MemoryStreamProvider.cs new file mode 100644 index 000000000..364055283 --- /dev/null +++ b/MediaBrowser.Common.Implementations/IO/MemoryStreamProvider.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using Microsoft.IO; + +namespace MediaBrowser.Common.Implementations.IO +{ + public class MemoryStreamProvider : IMemoryStreamProvider + { + readonly RecyclableMemoryStreamManager _manager = new RecyclableMemoryStreamManager(); + + public MemoryStream CreateNew() + { + return _manager.GetStream(); + } + + public MemoryStream CreateNew(int capacity) + { + return _manager.GetStream("RecyclableMemoryStream", capacity); + } + + public MemoryStream CreateNew(byte[] buffer) + { + return _manager.GetStream("RecyclableMemoryStream", buffer, 0, buffer.Length); + } + } +} diff --git a/MediaBrowser.Common.Implementations/Logging/NLogger.cs b/MediaBrowser.Common.Implementations/Logging/NLogger.cs index 29b618890..97bc437a0 100644 --- a/MediaBrowser.Common.Implementations/Logging/NLogger.cs +++ b/MediaBrowser.Common.Implementations/Logging/NLogger.cs @@ -72,6 +72,11 @@ namespace MediaBrowser.Common.Implementations.Logging /// The param list. public void Debug(string message, params object[] paramList) { + if (_logManager.LogSeverity == LogSeverity.Info) + { + return; + } + _logger.Debug(message, paramList); } @@ -137,6 +142,11 @@ namespace MediaBrowser.Common.Implementations.Logging /// Content of the additional. public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent) { + if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info) + { + return; + } + additionalContent.Insert(0, message + Environment.NewLine); const char tabChar = '\t'; diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 7e8823bc0..718e6b9f6 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -51,6 +51,10 @@ False ..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll + + ..\packages\Microsoft.IO.RecyclableMemoryStream.1.1.0.0\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll + True + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll @@ -93,6 +97,7 @@ + diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs index 10c0f8fc9..5d440609e 100644 --- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs +++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs @@ -169,7 +169,8 @@ namespace MediaBrowser.Common.Implementations.Security var options = new HttpRequestOptions() { Url = AppstoreRegUrl, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; options.RequestHeaders.Add("X-Emby-Token", _appHost.SystemId); options.RequestContent = parameters; @@ -269,7 +270,8 @@ namespace MediaBrowser.Common.Implementations.Security Url = MBValidateUrl, // Seeing block length errors - EnableHttpCompression = false + EnableHttpCompression = false, + BufferContent = false }; options.SetPostData(data); diff --git a/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs index 84c08439e..371c2ea11 100644 --- a/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs +++ b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs @@ -30,7 +30,8 @@ namespace MediaBrowser.Common.Implementations.Updates Url = url, EnableKeepAlive = false, CancellationToken = cancellationToken, - UserAgent = "Emby/3.0" + UserAgent = "Emby/3.0", + BufferContent = false }; if (cacheLength.Ticks > 0) @@ -105,7 +106,8 @@ namespace MediaBrowser.Common.Implementations.Updates Url = url, EnableKeepAlive = false, CancellationToken = cancellationToken, - UserAgent = "Emby/3.0" + UserAgent = "Emby/3.0", + BufferContent = false }; using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index f444a3a05..40c727a06 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -1,6 +1,7 @@  + diff --git a/MediaBrowser.Common/IO/IMemoryStreamProvider.cs b/MediaBrowser.Common/IO/IMemoryStreamProvider.cs new file mode 100644 index 000000000..1c0e98018 --- /dev/null +++ b/MediaBrowser.Common/IO/IMemoryStreamProvider.cs @@ -0,0 +1,11 @@ +using System.IO; + +namespace MediaBrowser.Common.IO +{ + public interface IMemoryStreamProvider + { + MemoryStream CreateNew(); + MemoryStream CreateNew(int capacity); + MemoryStream CreateNew(byte[] buffer); + } +} diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 17f211d84..a46aaf9f7 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -60,6 +60,7 @@ + diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index 94082b42e..cea2d6e21 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -251,4 +251,9 @@ namespace MediaBrowser.Controller.LiveTv { Task> GetChannelStreamWithDirectStreamProvider(string channelId, string streamId, CancellationToken cancellationToken); } + + public interface ISupportsUpdatingDefaults + { + Task UpdateTimerDefaults(SeriesTimerInfo info, CancellationToken cancellationToken); + } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 3756f1d93..be177cb02 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -120,7 +120,7 @@ namespace MediaBrowser.Controller.Net var cancellationTokenSource = new CancellationTokenSource(); - Logger.Info("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); + Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); var timer = SendOnTimer ? new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : @@ -267,7 +267,7 @@ namespace MediaBrowser.Controller.Net /// The connection. private void DisposeConnection(Tuple connection) { - Logger.Info("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); + Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); var timer = connection.Item3; diff --git a/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryBrowser.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryBrowser.cs index 77b0a70fd..261887366 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryBrowser.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryBrowser.cs @@ -34,7 +34,8 @@ namespace MediaBrowser.Dlna.ContentDirectory UserAgent = "Emby", RequestContentType = "text/xml; charset=\"utf-8\"", LogErrorResponseBody = true, - Url = request.ContentDirectoryUrl + Url = request.ContentDirectoryUrl, + BufferContent = false }; options.RequestHeaders["SOAPACTION"] = "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"; diff --git a/MediaBrowser.Dlna/Eventing/EventManager.cs b/MediaBrowser.Dlna/Eventing/EventManager.cs index 65e742d49..68f012c3a 100644 --- a/MediaBrowser.Dlna/Eventing/EventManager.cs +++ b/MediaBrowser.Dlna/Eventing/EventManager.cs @@ -141,7 +141,8 @@ namespace MediaBrowser.Dlna.Eventing { RequestContent = builder.ToString(), RequestContentType = "text/xml", - Url = subscription.CallbackUrl + Url = subscription.CallbackUrl, + BufferContent = false }; options.RequestHeaders.Add("NT", subscription.NotificationType); diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index ae2e43a4f..ef60be227 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -133,7 +133,6 @@ - diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs index ff4223c72..a1eb19d9a 100644 --- a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs +++ b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs @@ -70,7 +70,8 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url, UserAgent = USERAGENT, - LogErrorResponseBody = true + LogErrorResponseBody = true, + BufferContent = false }; options.RequestHeaders["HOST"] = ip + ":" + port.ToString(_usCulture); @@ -87,7 +88,8 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url, UserAgent = USERAGENT, - LogErrorResponseBody = true + LogErrorResponseBody = true, + BufferContent = false }; options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName; @@ -115,7 +117,8 @@ namespace MediaBrowser.Dlna.PlayTo Url = url, UserAgent = USERAGENT, LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLog, - LogErrorResponseBody = true + LogErrorResponseBody = true, + BufferContent = false }; options.RequestHeaders["SOAPAction"] = soapAction; diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs b/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs deleted file mode 100644 index d196e9851..000000000 --- a/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MediaBrowser.Controller.Dlna; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace MediaBrowser.Dlna.Ssdp -{ - public class SsdpHelper - { - public static SsdpMessageEventArgs ParseSsdpResponse(byte[] data) - { - using (var ms = new MemoryStream(data)) - { - using (var reader = new StreamReader(ms, Encoding.ASCII)) - { - var proto = (reader.ReadLine() ?? string.Empty).Trim(); - var method = proto.Split(new[] { ' ' }, 2)[0]; - var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); - for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) - { - line = line.Trim(); - if (string.IsNullOrEmpty(line)) - { - break; - } - var parts = line.Split(new[] { ':' }, 2); - - if (parts.Length >= 2) - { - headers[parts[0]] = parts[1].Trim(); - } - } - - return new SsdpMessageEventArgs - { - Method = method, - Headers = headers, - Message = data - }; - } - } - } - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index b34a4cd38..33e90743a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -76,7 +76,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public static string GetProbeSizeArgument(bool isDvd) { - return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty; + return isDvd ? "-probesize 1G -analyzeduration 200M" : " -analyzeduration 2M"; } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 06867969e..25ad14fe8 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -24,6 +24,7 @@ using CommonIO; using MediaBrowser.Model.Configuration; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; namespace MediaBrowser.MediaEncoding.Encoder @@ -79,13 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder protected readonly Func MediaSourceManager; private readonly IHttpClient _httpClient; private readonly IZipClient _zipClient; + private readonly IMemoryStreamProvider _memoryStreamProvider; private readonly List _runningProcesses = new List(); private readonly bool _hasExternalEncoder; private string _originalFFMpegPath; private string _originalFFProbePath; - public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager, IHttpClient httpClient, IZipClient zipClient) + public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamProvider memoryStreamProvider) { _logger = logger; _jsonSerializer = jsonSerializer; @@ -100,6 +102,7 @@ namespace MediaBrowser.MediaEncoding.Encoder MediaSourceManager = mediaSourceManager; _httpClient = httpClient; _zipClient = zipClient; + _memoryStreamProvider = memoryStreamProvider; FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; _originalFFProbePath = ffProbePath; @@ -544,7 +547,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); + var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem, _memoryStreamProvider).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 5805127e6..9f51dcf66 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Text; using System.Xml; using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -20,11 +22,13 @@ namespace MediaBrowser.MediaEncoding.Probing private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly ILogger _logger; private readonly IFileSystem _fileSystem; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public ProbeResultNormalizer(ILogger logger, IFileSystem fileSystem) + public ProbeResultNormalizer(ILogger logger, IFileSystem fileSystem, IMemoryStreamProvider memoryStreamProvider) { _logger = logger; _fileSystem = fileSystem; + _memoryStreamProvider = memoryStreamProvider; } public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol) @@ -187,7 +191,7 @@ namespace MediaBrowser.MediaEncoding.Probing xml = "" + xml; // \n\n\n\n\tcast\n\t\n\t\t\n\t\t\tname\n\t\t\tBlender Foundation\n\t\t\n\t\t\n\t\t\tname\n\t\t\tJanus Bager Kristensen\n\t\t\n\t\n\tdirectors\n\t\n\t\t\n\t\t\tname\n\t\t\tSacha Goedegebure\n\t\t\n\t\n\tstudio\n\tBlender Foundation\n\n\n - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) + using (var stream = _memoryStreamProvider.CreateNew(Encoding.UTF8.GetBytes(xml))) { using (var streamReader = new StreamReader(stream)) { @@ -573,8 +577,7 @@ namespace MediaBrowser.MediaEncoding.Probing private void NormalizeStreamTitle(MediaStream stream) { - if (string.Equals(stream.Title, "sdh", StringComparison.OrdinalIgnoreCase) || - string.Equals(stream.Title, "cc", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(stream.Title, "cc", StringComparison.OrdinalIgnoreCase)) { stream.Title = null; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index dc5e69283..6dda49a55 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -18,6 +18,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; using UniversalDetector; namespace MediaBrowser.MediaEncoding.Subtitles @@ -32,8 +34,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles private readonly IJsonSerializer _json; private readonly IHttpClient _httpClient; private readonly IMediaSourceManager _mediaSourceManager; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json, IHttpClient httpClient, IMediaSourceManager mediaSourceManager) + public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json, IHttpClient httpClient, IMediaSourceManager mediaSourceManager, IMemoryStreamProvider memoryStreamProvider) { _libraryManager = libraryManager; _logger = logger; @@ -43,6 +46,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _json = json; _httpClient = httpClient; _mediaSourceManager = mediaSourceManager; + _memoryStreamProvider = memoryStreamProvider; } private string SubtitleCachePath @@ -61,7 +65,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles bool preserveOriginalTimestamps, CancellationToken cancellationToken) { - var ms = new MemoryStream(); + var ms = _memoryStreamProvider.CreateNew(); try { @@ -202,7 +206,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var bytes = Encoding.UTF8.GetBytes(text); - return new MemoryStream(bytes); + return _memoryStreamProvider.CreateNew(bytes); } } } diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index c4d056a61..022e03baf 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -34,6 +34,8 @@ namespace MediaBrowser.Model.System /// The mac address. public string MacAddress { get; set; } + public string PackageName { get; set; } + /// /// Gets or sets a value indicating whether this instance has pending restart. /// diff --git a/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs b/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs index 3a532257f..b26f23715 100644 --- a/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs +++ b/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.GameGenres public static string ProviderName { - get { return "Media Browser Designs"; } + get { return "Emby Designs"; } } public bool Supports(IHasImages item) @@ -137,7 +137,7 @@ namespace MediaBrowser.Providers.GameGenres { CancellationToken = cancellationToken, Url = url, - ResourcePool = GenreImageProvider.ImageDownloadResourcePool + BufferContent = false }); } } diff --git a/MediaBrowser.Providers/Genres/GenreImageProvider.cs b/MediaBrowser.Providers/Genres/GenreImageProvider.cs index 7c2ed00a6..954cd008e 100644 --- a/MediaBrowser.Providers/Genres/GenreImageProvider.cs +++ b/MediaBrowser.Providers/Genres/GenreImageProvider.cs @@ -22,8 +22,6 @@ namespace MediaBrowser.Providers.Genres private readonly SemaphoreSlim _listResourcePool = new SemaphoreSlim(1, 1); - public static SemaphoreSlim ImageDownloadResourcePool = new SemaphoreSlim(5, 5); - public GenreImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) { _config = config; @@ -38,7 +36,7 @@ namespace MediaBrowser.Providers.Genres public static string ProviderName { - get { return "Media Browser Designs"; } + get { return "Emby Designs"; } } public bool Supports(IHasImages item) @@ -138,7 +136,7 @@ namespace MediaBrowser.Providers.Genres { CancellationToken = cancellationToken, Url = url, - ResourcePool = ImageDownloadResourcePool + BufferContent = false }); } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 36b5987a0..c9b3f22c5 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -38,6 +38,7 @@ namespace MediaBrowser.Providers.Manager private readonly ILibraryMonitor _libraryMonitor; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; + private readonly IMemoryStreamProvider _memoryStreamProvider; /// /// Initializes a new instance of the class. @@ -46,12 +47,13 @@ namespace MediaBrowser.Providers.Manager /// The directory watchers. /// The file system. /// The logger. - public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger) + public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger, IMemoryStreamProvider memoryStreamProvider) { _config = config; _libraryMonitor = libraryMonitor; _fileSystem = fileSystem; _logger = logger; + _memoryStreamProvider = memoryStreamProvider; } /// @@ -124,7 +126,7 @@ namespace MediaBrowser.Providers.Manager var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false); // If there are more than one output paths, the stream will need to be seekable - var memoryStream = new MemoryStream(); + var memoryStream = _memoryStreamProvider.CreateNew(); using (source) { await source.CopyToAsync(memoryStream).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 25b9b4fd5..7e28254b0 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -20,6 +20,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.IO; using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.Manager @@ -64,6 +65,7 @@ namespace MediaBrowser.Providers.Manager private IExternalId[] _externalIds; private readonly Func _libraryManagerFactory; + private readonly IMemoryStreamProvider _memoryStreamProvider; /// /// Initializes a new instance of the class. @@ -73,7 +75,7 @@ namespace MediaBrowser.Providers.Manager /// The directory watchers. /// The log manager. /// The file system. - public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func libraryManagerFactory, IJsonSerializer json) + public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func libraryManagerFactory, IJsonSerializer json, IMemoryStreamProvider memoryStreamProvider) { _logger = logManager.GetLogger("ProviderManager"); _httpClient = httpClient; @@ -83,6 +85,7 @@ namespace MediaBrowser.Providers.Manager _appPaths = appPaths; _libraryManagerFactory = libraryManagerFactory; _json = json; + _memoryStreamProvider = memoryStreamProvider; } /// @@ -142,12 +145,12 @@ namespace MediaBrowser.Providers.Manager public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) { - return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken); + return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken); } public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken) { - return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken); + return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken); } public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken) @@ -159,7 +162,7 @@ namespace MediaBrowser.Providers.Manager var fileStream = _fileSystem.GetFileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); - return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken); + return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken); } public async Task> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 62109243d..bfb7eb8fd 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Studios public static string ProviderName { - get { return "Media Browser Designs"; } + get { return "Emby Designs"; } } public bool Supports(IHasImages item) @@ -137,7 +137,7 @@ namespace MediaBrowser.Providers.Studios { CancellationToken = cancellationToken, Url = url, - ResourcePool = GenreImageProvider.ImageDownloadResourcePool + BufferContent = false }); } } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index 4ac9e6836..ca4f1b956 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -21,6 +21,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; using CommonIO; +using MediaBrowser.Common.IO; namespace MediaBrowser.Providers.TV { @@ -38,6 +39,7 @@ namespace MediaBrowser.Providers.TV private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; + private readonly IMemoryStreamProvider _memoryStreamProvider; public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager) { @@ -238,7 +240,7 @@ namespace MediaBrowser.Providers.TV DeleteXmlFiles(seriesDataPath); // Copy to memory stream because we need a seekable stream - using (var ms = new MemoryStream()) + using (var ms = _memoryStreamProvider.CreateNew()) { await zipStream.CopyToAsync(ms).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs index 2b2373a47..f9eff3c92 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs @@ -127,7 +127,8 @@ namespace MediaBrowser.Server.Implementations.Connect // Seeing block length errors with our server EnableHttpCompression = false, - PreferIpv4 = preferIpv4 + PreferIpv4 = preferIpv4, + BufferContent = false }).ConfigureAwait(false)) { diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index b2dd8ec86..d7c1b0da0 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -266,7 +266,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; options.SetPostData(postData); @@ -314,7 +315,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; options.SetPostData(postData); @@ -464,7 +466,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; var accessToken = Guid.NewGuid().ToString("N"); @@ -599,7 +602,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; var accessToken = Guid.NewGuid().ToString("N"); @@ -652,7 +656,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; var postData = new Dictionary @@ -726,7 +731,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { CancellationToken = cancellationToken, - Url = url + Url = url, + BufferContent = false }; SetServerAccessToken(options); @@ -790,7 +796,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + BufferContent = false }; SetServerAccessToken(options); @@ -1078,7 +1085,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { Url = url, - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false }; var postData = new Dictionary @@ -1126,7 +1134,8 @@ namespace MediaBrowser.Server.Implementations.Connect var options = new HttpRequestOptions { - Url = GetConnectUrl("user/authenticate") + Url = GetConnectUrl("user/authenticate"), + BufferContent = false }; options.SetPostData(new Dictionary diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index e4f1460c6..46ee29b63 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1176,6 +1176,12 @@ namespace MediaBrowser.Server.Implementations.Dto .Except(foundArtists, new DistinctNameComparer()) .Select(i => { + // This should not be necessary but we're seeing some cases of it + if (string.IsNullOrWhiteSpace(i)) + { + return null; + } + var artist = _libraryManager.GetArtist(i); if (artist != null) { diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs index 7b3a7a30d..e445300e4 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs @@ -64,7 +64,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints EnableHttpCompression = false, LogRequest = false, - LogErrors = logErrors + LogErrors = logErrors, + BufferContent = false }; options.SetPostData(data); @@ -114,7 +115,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints EnableHttpCompression = false, LogRequest = false, - LogErrors = logErrors + LogErrors = logErrors, + BufferContent = false }; options.SetPostData(data); diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 8e46f8f03..7dc6fbb25 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -19,6 +19,7 @@ using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Security; using MediaBrowser.Model.Extensions; @@ -45,16 +46,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer private readonly IServerConfigurationManager _config; private readonly INetworkManager _networkManager; + private readonly IMemoryStreamProvider _memoryStreamProvider; public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, IServerConfigurationManager config, string serviceName, - string defaultRedirectPath, INetworkManager networkManager, params Assembly[] assembliesWithServices) + string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamProvider memoryStreamProvider, params Assembly[] assembliesWithServices) : base(serviceName, assembliesWithServices) { DefaultRedirectPath = defaultRedirectPath; _networkManager = networkManager; + _memoryStreamProvider = memoryStreamProvider; _config = config; _logger = logManager.GetLogger("HttpServer"); @@ -95,6 +98,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer container.Adapter = _containerAdapter; + Plugins.RemoveAll(x => x is NativeTypesFeature); Plugins.Add(new SwaggerFeature()); Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization")); @@ -179,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private IHttpListener GetListener() { - return new WebSocketSharpListener(_logger, CertificatePath); + return new WebSocketSharpListener(_logger, CertificatePath, _memoryStreamProvider); } private void OnWebSocketConnecting(WebSocketConnectingEventArgs args) diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs index cc351f6b3..8a7c14eb6 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; @@ -15,23 +16,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// /// Creates the server. /// - /// The application host. - /// The log manager. - /// The configuration. - /// The _networkmanager. - /// Name of the server. - /// The default redirectpath. /// IHttpServer. public static IHttpServer CreateServer(IApplicationHost applicationHost, ILogManager logManager, IServerConfigurationManager config, INetworkManager _networkmanager, + IMemoryStreamProvider streamProvider, string serverName, string defaultRedirectpath) { LogManager.LogFactory = new ServerLogFactory(logManager); - return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager); + return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager, streamProvider); } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs index bfa65ac6b..d20dd7ec0 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs @@ -39,11 +39,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp if (boundary == null) return; - using (var requestStream = GetSubStream(InputStream)) + using (var requestStream = GetSubStream(InputStream, _memoryStreamProvider)) { //DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request //Not ending with \r\n? - var ms = new MemoryStream(32 * 1024); + var ms = _memoryStreamProvider.CreateNew(32 * 1024); await requestStream.CopyToAsync(ms).ConfigureAwait(false); var input = ms; @@ -229,9 +229,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp async Task LoadWwwForm() { - using (Stream input = GetSubStream(InputStream)) + using (Stream input = GetSubStream(InputStream, _memoryStreamProvider)) { - using (var ms = new MemoryStream()) + using (var ms = _memoryStreamProvider.CreateNew()) { await input.CopyToAsync(ms).ConfigureAwait(false); ms.Position = 0; diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index bcc081eb1..b090c97c6 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { @@ -18,11 +19,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp private readonly ILogger _logger; private readonly string _certificatePath; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public WebSocketSharpListener(ILogger logger, string certificatePath) + public WebSocketSharpListener(ILogger logger, string certificatePath, IMemoryStreamProvider memoryStreamProvider) { _logger = logger; _certificatePath = certificatePath; + _memoryStreamProvider = memoryStreamProvider; } public Action ErrorHandler { get; set; } @@ -148,7 +151,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { var operationName = httpContext.Request.GetOperationName(); - var req = new WebSocketSharpRequest(httpContext, operationName, RequestAttributes.None, _logger); + var req = new WebSocketSharpRequest(httpContext, operationName, RequestAttributes.None, _logger, _memoryStreamProvider); req.RequestAttributes = req.GetAttributes(); return req; diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs index dc2aec3e1..405b3114b 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using Funq; +using MediaBrowser.Common.IO; using MediaBrowser.Model.Logging; using ServiceStack; using ServiceStack.Host; @@ -16,11 +17,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp public Container Container { get; set; } private readonly HttpListenerRequest request; private readonly IHttpResponse response; + private IMemoryStreamProvider _memoryStreamProvider; - public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger) + public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger, IMemoryStreamProvider memoryStreamProvider) { this.OperationName = operationName; this.RequestAttributes = requestAttributes; + _memoryStreamProvider = memoryStreamProvider; this.request = httpContext.Request; this.response = new WebSocketSharpResponse(logger, httpContext.Response, this); @@ -403,7 +406,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp set { bufferedStream = value - ? bufferedStream ?? new MemoryStream(request.InputStream.ReadFully()) + ? bufferedStream ?? _memoryStreamProvider.CreateNew(request.InputStream.ReadFully()) : null; } } @@ -447,7 +450,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp } } - static Stream GetSubStream(Stream stream) + static Stream GetSubStream(Stream stream, IMemoryStreamProvider streamProvider) { if (stream is MemoryStream) { diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index ae408f8d6..5f122fb96 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading.Tasks; +using MediaBrowser.Common.IO; using ServiceStack; namespace MediaBrowser.Server.Implementations.HttpServer @@ -17,7 +18,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private ILogger Logger { get; set; } private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - + /// /// Gets or sets the source stream. /// @@ -39,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public Action OnComplete { get; set; } public Action OnError { get; set; } + private readonly byte[] _bytes; /// /// Initializes a new instance of the class. @@ -73,6 +75,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer public StreamWriter(byte[] source, string contentType, ILogger logger) : this(new MemoryStream(source), contentType, logger) { + if (string.IsNullOrEmpty(contentType)) + { + throw new ArgumentNullException("contentType"); + } + + _bytes = source; + Logger = logger; + + Options["Content-Type"] = contentType; + + Options["Content-Length"] = source.Length.ToString(UsCulture); } private const int BufferSize = 81920; @@ -85,9 +98,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer { try { - using (var src = SourceStream) + if (_bytes != null) { - src.CopyTo(responseStream, BufferSize); + responseStream.Write(_bytes, 0, _bytes.Length); + } + else + { + using (var src = SourceStream) + { + src.CopyTo(responseStream, BufferSize); + } } } catch (Exception ex) @@ -114,9 +134,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer { try { - using (var src = SourceStream) + if (_bytes != null) + { + await responseStream.WriteAsync(_bytes, 0, _bytes.Length); + } + else { - await src.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); + using (var src = SourceStream) + { + await src.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); + } } } catch (Exception ex) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index b98919282..7574eb485 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -846,7 +846,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings Url = ApiUrl + "/lineups/" + info.ListingsId, UserAgent = UserAgent, CancellationToken = cancellationToken, - LogErrorResponseBody = true + LogErrorResponseBody = true, + BufferContent = false }; httpOptions.RequestHeaders["token"] = token; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 546525fd1..72287f32d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -558,7 +558,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return item; } - private async Task GetProgram(ProgramInfo info, Dictionary allExistingPrograms, LiveTvChannel channel, ChannelType channelType, string serviceName, CancellationToken cancellationToken) + private Tuple GetProgram(ProgramInfo info, Dictionary allExistingPrograms, LiveTvChannel channel, ChannelType channelType, string serviceName, CancellationToken cancellationToken) { var id = _tvDtoService.GetInternalProgramId(serviceName, info.Id); @@ -671,13 +671,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + var isUpdated = false; if (isNew) { - await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); } else if (forceUpdate || string.IsNullOrWhiteSpace(info.Etag)) { - await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + isUpdated = true; } else { @@ -687,13 +687,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (!string.Equals(etag, item.ExternalEtag, StringComparison.OrdinalIgnoreCase)) { item.ExternalEtag = etag; - await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + isUpdated = true; } } - _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)); - - return item; + return new Tuple(item, isNew, isUpdated); } private async Task CreateRecordingRecord(RecordingInfo info, string serviceName, Guid parentFolderId, CancellationToken cancellationToken) @@ -1289,9 +1287,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv }).Cast().ToDictionary(i => i.Id); + var newPrograms = new List(); + var updatedPrograms = new List(); + foreach (var program in channelPrograms) { - var programItem = await GetProgram(program, existingPrograms, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false); + var programTuple = GetProgram(program, existingPrograms, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken); + var programItem = programTuple.Item1; + + if (programTuple.Item2) + { + newPrograms.Add(programItem); + } + else if (programTuple.Item3) + { + updatedPrograms.Add(programItem); + } programs.Add(programItem.Id); @@ -1321,6 +1332,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + if (newPrograms.Count > 0) + { + await _libraryManager.CreateItems(newPrograms, cancellationToken).ConfigureAwait(false); + } + + // TODO: Do this in bulk + foreach (var program in updatedPrograms) + { + await _libraryManager.UpdateItem(program, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + } + + foreach (var program in newPrograms) + { + _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem)); + } + foreach (var program in updatedPrograms) + { + _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem)); + } + currentChannel.IsMovie = isMovie; currentChannel.IsNews = isNews; currentChannel.IsSports = isSports; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 1861b79eb..1ca664ee2 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Dlna; namespace MediaBrowser.Server.Implementations.LiveTv { @@ -138,7 +139,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv try { - await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false); + await AddMediaInfoInternal(stream, isAudio, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -207,6 +208,85 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) + { + var originalRuntime = mediaSource.RunTimeTicks; + + var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest + { + InputPath = mediaSource.Path, + Protocol = mediaSource.Protocol, + MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, + ExtractChapters = false + + }, cancellationToken).ConfigureAwait(false); + + mediaSource.Bitrate = info.Bitrate; + mediaSource.Container = info.Container; + mediaSource.Formats = info.Formats; + mediaSource.MediaStreams = info.MediaStreams; + mediaSource.RunTimeTicks = info.RunTimeTicks; + mediaSource.Size = info.Size; + mediaSource.Timestamp = info.Timestamp; + mediaSource.Video3DFormat = info.Video3DFormat; + mediaSource.VideoType = info.VideoType; + + mediaSource.DefaultSubtitleStreamIndex = null; + + // Null this out so that it will be treated like a live stream + if (!originalRuntime.HasValue) + { + mediaSource.RunTimeTicks = null; + } + + var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio); + + if (audioStream == null || audioStream.Index == -1) + { + mediaSource.DefaultAudioStreamIndex = null; + } + else + { + mediaSource.DefaultAudioStreamIndex = audioStream.Index; + } + + var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video); + if (videoStream != null) + { + if (!videoStream.BitRate.HasValue) + { + var width = videoStream.Width ?? 1920; + + if (width >= 1900) + { + videoStream.BitRate = 8000000; + } + + else if (width >= 1260) + { + videoStream.BitRate = 3000000; + } + + else if (width >= 700) + { + videoStream.BitRate = 1000000; + } + } + } + + // Try to estimate this + if (!mediaSource.Bitrate.HasValue) + { + var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); + + if (total > 0) + { + mediaSource.Bitrate = total; + } + } + } + + public Task CloseMediaSource(string liveStreamId) { return _liveTvManager.CloseLiveStream(liveStreamId); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index a4236763f..84ba15e49 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -252,84 +252,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts //} } - private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) - { - var originalRuntime = mediaSource.RunTimeTicks; - - var info = await MediaEncoder.GetMediaInfo(new MediaInfoRequest - { - InputPath = mediaSource.Path, - Protocol = mediaSource.Protocol, - MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, - ExtractChapters = false - - }, cancellationToken).ConfigureAwait(false); - - mediaSource.Bitrate = info.Bitrate; - mediaSource.Container = info.Container; - mediaSource.Formats = info.Formats; - mediaSource.MediaStreams = info.MediaStreams; - mediaSource.RunTimeTicks = info.RunTimeTicks; - mediaSource.Size = info.Size; - mediaSource.Timestamp = info.Timestamp; - mediaSource.Video3DFormat = info.Video3DFormat; - mediaSource.VideoType = info.VideoType; - - mediaSource.DefaultSubtitleStreamIndex = null; - - // Null this out so that it will be treated like a live stream - if (!originalRuntime.HasValue) - { - mediaSource.RunTimeTicks = null; - } - - var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio); - - if (audioStream == null || audioStream.Index == -1) - { - mediaSource.DefaultAudioStreamIndex = null; - } - else - { - mediaSource.DefaultAudioStreamIndex = audioStream.Index; - } - - var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video); - if (videoStream != null) - { - if (!videoStream.BitRate.HasValue) - { - var width = videoStream.Width ?? 1920; - - if (width >= 1900) - { - videoStream.BitRate = 8000000; - } - - else if (width >= 1260) - { - videoStream.BitRate = 3000000; - } - - else if (width >= 700) - { - videoStream.BitRate = 1000000; - } - } - } - - // Try to estimate this - if (!mediaSource.Bitrate.HasValue) - { - var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); - - if (total > 0) - { - mediaSource.Bitrate = total; - } - } - } - protected abstract bool IsValidChannelId(string channelId); protected LiveTvOptions GetConfiguration() diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index ef37e3b35..cd168ba58 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -88,7 +88,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions { Url = string.Format("{0}/discover.json", url), - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false })) { var response = _json.DeserializeFromStream(stream); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 14ae45228..101b9ba84 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -72,7 +72,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun var options = new HttpRequestOptions { Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)), - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + BufferContent = false }; using (var stream = await _httpClient.Get(options)) { @@ -124,7 +125,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun CancellationToken = cancellationToken, CacheLength = TimeSpan.FromDays(1), CacheMode = CacheMode.Unconditional, - TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds) + TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds), + BufferContent = false })) { var response = JsonSerializer.DeserializeFromStream(stream); @@ -165,7 +167,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)), CancellationToken = cancellationToken, - TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds) + TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds), + BufferContent = false })) { var tuners = new List(); @@ -538,7 +541,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions { Url = string.Format("{0}/discover.json", GetApiUrl(info, false)), - CancellationToken = CancellationToken.None + CancellationToken = CancellationToken.None, + BufferContent = false })) { var response = JsonSerializer.DeserializeFromStream(stream); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs index dd635bd55..dd7726be0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs @@ -12,6 +12,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; using System.Collections.Generic; +using System.Linq; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { @@ -139,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun }).ConfigureAwait(false); } - private List>> _additionalStreams = new List>>(); + private readonly List>> _additionalStreams = new List>>(); public Task CopyToAsync(Stream stream, CancellationToken cancellationToken) { @@ -186,7 +187,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); - foreach (var additionalStream in _additionalStreams) + var additionalStreams = _additionalStreams.ToList(); + foreach (var additionalStream in additionalStreams) { cancellationToken.ThrowIfCancellationRequested(); @@ -196,6 +198,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } catch (Exception ex) { + _logger.ErrorException("Error writing HDHR data to stream", ex); + PopAdditionalStream(additionalStream, ex); } } diff --git a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs index 969541fbc..c15af6f70 100644 --- a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs @@ -81,7 +81,8 @@ namespace MediaBrowser.Server.Implementations.News { Url = "http://emby.media/community/index.php?/blog/rss/1-media-browser-developers-blog", Progress = new Progress(), - UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36" + UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36", + BufferContent = false }; using (var stream = await _httpClient.Get(requestOptions).ConfigureAwait(false)) diff --git a/MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs index a16d23700..028465354 100644 --- a/MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Serialization; using System; using System.Data; using System.IO; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Persistence { @@ -51,18 +52,16 @@ namespace MediaBrowser.Server.Implementations.Persistence /// /// Gets a stream from a DataReader at a given ordinal /// - /// The reader. - /// The ordinal. /// Stream. /// reader - public static Stream GetMemoryStream(this IDataReader reader, int ordinal) + public static Stream GetMemoryStream(this IDataReader reader, int ordinal, IMemoryStreamProvider streamProvider) { if (reader == null) { throw new ArgumentNullException("reader"); } - var memoryStream = new MemoryStream(); + var memoryStream = streamProvider.CreateNew(); var num = 0L; var array = new byte[4096]; long bytes; @@ -132,18 +131,16 @@ namespace MediaBrowser.Server.Implementations.Persistence /// /// Serializes to bytes. /// - /// The json. - /// The obj. /// System.Byte[][]. /// obj - public static byte[] SerializeToBytes(this IJsonSerializer json, object obj) + public static byte[] SerializeToBytes(this IJsonSerializer json, object obj, IMemoryStreamProvider streamProvider) { if (obj == null) { throw new ArgumentNullException("obj"); } - using (var stream = new MemoryStream()) + using (var stream = streamProvider.CreateNew()) { json.SerializeToStream(obj, stream); return stream.ToArray(); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs index 40970dbe4..1726a77a6 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs @@ -10,6 +10,7 @@ using System.Data; using System.IO; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Persistence { @@ -18,10 +19,13 @@ namespace MediaBrowser.Server.Implementations.Persistence /// public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository { - public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IDbConnector dbConnector) + private readonly IMemoryStreamProvider _memoryStreamProvider; + + public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IDbConnector dbConnector, IMemoryStreamProvider memoryStreamProvider) : base(logManager, dbConnector) { _jsonSerializer = jsonSerializer; + _memoryStreamProvider = memoryStreamProvider; DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); } @@ -82,7 +86,7 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - var serialized = _jsonSerializer.SerializeToBytes(displayPreferences); + var serialized = _jsonSerializer.SerializeToBytes(displayPreferences, _memoryStreamProvider); using (var connection = await CreateConnection().ConfigureAwait(false)) { @@ -166,7 +170,7 @@ namespace MediaBrowser.Server.Implementations.Persistence foreach (var displayPreference in displayPreferences) { - var serialized = _jsonSerializer.SerializeToBytes(displayPreference); + var serialized = _jsonSerializer.SerializeToBytes(displayPreference, _memoryStreamProvider); using (var cmd = connection.CreateCommand()) { @@ -246,7 +250,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { if (reader.Read()) { - using (var stream = reader.GetMemoryStream(0)) + using (var stream = reader.GetMemoryStream(0, _memoryStreamProvider)) { return _jsonSerializer.DeserializeFromStream(stream); } @@ -283,7 +287,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { while (reader.Read()) { - using (var stream = reader.GetMemoryStream(0)) + using (var stream = reader.GetMemoryStream(0, _memoryStreamProvider)) { list.Add(_jsonSerializer.DeserializeFromStream(stream)); } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 5a11742dc..e8c1ce3fb 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -19,6 +19,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Playlists; @@ -95,11 +96,12 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedTagsCommand; public const int LatestSchemaVersion = 109; + private readonly IMemoryStreamProvider _memoryStreamProvider; /// /// Initializes a new instance of the class. /// - public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager, IDbConnector connector) + public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager, IDbConnector connector, IMemoryStreamProvider memoryStreamProvider) : base(logManager, connector) { if (config == null) @@ -113,6 +115,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _config = config; _jsonSerializer = jsonSerializer; + _memoryStreamProvider = memoryStreamProvider; _criticReviewsPath = Path.Combine(_config.ApplicationPaths.DataPath, "critic-reviews"); DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); @@ -724,7 +727,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = item.Id; _saveItemCommand.GetParameter(index++).Value = item.GetType().FullName; - _saveItemCommand.GetParameter(index++).Value = _jsonSerializer.SerializeToBytes(item); + _saveItemCommand.GetParameter(index++).Value = _jsonSerializer.SerializeToBytes(item, _memoryStreamProvider); _saveItemCommand.GetParameter(index++).Value = item.Path; @@ -1075,7 +1078,7 @@ namespace MediaBrowser.Server.Implementations.Persistence BaseItem item = null; - using (var stream = reader.GetMemoryStream(1)) + using (var stream = reader.GetMemoryStream(1, _memoryStreamProvider)) { try { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs index 25ab60ca5..31fa78806 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs @@ -9,6 +9,7 @@ using System.Data; using System.IO; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Persistence { @@ -18,10 +19,12 @@ namespace MediaBrowser.Server.Implementations.Persistence public class SqliteUserRepository : BaseSqliteRepository, IUserRepository { private readonly IJsonSerializer _jsonSerializer; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer, IDbConnector dbConnector) : base(logManager, dbConnector) + public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer, IDbConnector dbConnector, IMemoryStreamProvider memoryStreamProvider) : base(logManager, dbConnector) { _jsonSerializer = jsonSerializer; + _memoryStreamProvider = memoryStreamProvider; DbFilePath = Path.Combine(appPaths.DataPath, "users.db"); } @@ -75,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - var serialized = _jsonSerializer.SerializeToBytes(user); + var serialized = _jsonSerializer.SerializeToBytes(user, _memoryStreamProvider); cancellationToken.ThrowIfCancellationRequested(); @@ -150,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { var id = reader.GetGuid(0); - using (var stream = reader.GetMemoryStream(1)) + using (var stream = reader.GetMemoryStream(1, _memoryStreamProvider)) { var user = _jsonSerializer.DeserializeFromStream(stream); user.Id = id; diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index ff0e4a0e0..07b63718c 100644 --- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Playlists public override bool IsVisible(User user) { - return base.IsVisible(user) && GetChildren(user, false).Any(); + return base.IsVisible(user); } protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs index 33d106916..893592fa3 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.ServerManager { @@ -72,6 +73,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager private readonly List _webSocketListeners = new List(); private bool _disposed; + private readonly IMemoryStreamProvider _memoryStreamProvider; /// /// Initializes a new instance of the class. @@ -81,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager /// The logger. /// The configuration manager. /// applicationHost - public ServerManager(IServerApplicationHost applicationHost, IJsonSerializer jsonSerializer, ILogger logger, IServerConfigurationManager configurationManager) + public ServerManager(IServerApplicationHost applicationHost, IJsonSerializer jsonSerializer, ILogger logger, IServerConfigurationManager configurationManager, IMemoryStreamProvider memoryStreamProvider) { if (applicationHost == null) { @@ -100,6 +102,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager _jsonSerializer = jsonSerializer; _applicationHost = applicationHost; ConfigurationManager = configurationManager; + _memoryStreamProvider = memoryStreamProvider; } /// @@ -150,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager return; } - var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger) + var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger, _memoryStreamProvider) { OnReceive = ProcessWebSocketMessageReceived, Url = e.Url, diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs index 2adf3e86a..af0699834 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs @@ -9,6 +9,7 @@ using System.Collections.Specialized; using System.IO; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.IO; using UniversalDetector; namespace MediaBrowser.Server.Implementations.ServerManager @@ -78,7 +79,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager /// /// The query string. public NameValueCollection QueryString { get; set; } - + private readonly IMemoryStreamProvider _memoryStreamProvider; + /// /// Initializes a new instance of the class. /// @@ -87,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager /// The json serializer. /// The logger. /// socket - public WebSocketConnection(IWebSocket socket, string remoteEndPoint, IJsonSerializer jsonSerializer, ILogger logger) + public WebSocketConnection(IWebSocket socket, string remoteEndPoint, IJsonSerializer jsonSerializer, ILogger logger, IMemoryStreamProvider memoryStreamProvider) { if (socket == null) { @@ -113,6 +115,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager _socket.OnReceive = OnReceiveInternal; RemoteEndPoint = remoteEndPoint; _logger = logger; + _memoryStreamProvider = memoryStreamProvider; socket.Closed += socket_Closed; } @@ -149,7 +152,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager { try { - using (var ms = new MemoryStream(bytes)) + using (var ms = _memoryStreamProvider.CreateNew(bytes)) { var detector = new CharsetDetector(); detector.Feed(ms); diff --git a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs index b841f0216..f54c452cc 100644 --- a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs +++ b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs @@ -75,7 +75,8 @@ namespace MediaBrowser.Server.Implementations.Session await _httpClient.Post(new HttpRequestOptions { Url = url, - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + BufferContent = false }).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 1278a40a4..c523ec7bd 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -30,6 +30,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Sync { @@ -51,6 +52,7 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly Func _mediaSourceManager; private readonly IJsonSerializer _json; private readonly ITaskManager _taskManager; + private readonly IMemoryStreamProvider _memoryStreamProvider; private ISyncProvider[] _providers = { }; @@ -60,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.Sync public event EventHandler> SyncJobItemUpdated; public event EventHandler> SyncJobItemCreated; - public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func dtoService, IServerApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func mediaEncoder, IFileSystem fileSystem, Func subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager, Func mediaSourceManager, IJsonSerializer json, ITaskManager taskManager) + public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func dtoService, IServerApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func mediaEncoder, IFileSystem fileSystem, Func subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager, Func mediaSourceManager, IJsonSerializer json, ITaskManager taskManager, IMemoryStreamProvider memoryStreamProvider) { _libraryManager = libraryManager; _repo = repo; @@ -78,6 +80,7 @@ namespace MediaBrowser.Server.Implementations.Sync _mediaSourceManager = mediaSourceManager; _json = json; _taskManager = taskManager; + _memoryStreamProvider = memoryStreamProvider; } public void AddParts(IEnumerable providers) @@ -95,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.Sync public ISyncDataProvider GetDataProvider(IServerSyncProvider provider, SyncTarget target) { - return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost, _logger, _json, _fileSystem, _config.CommonApplicationPaths)); + return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost, _logger, _json, _fileSystem, _config.CommonApplicationPaths, _memoryStreamProvider)); } public async Task CreateJob(SyncJobRequest request) diff --git a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs index 106dc9115..32a600371 100644 --- a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using CommonIO; using Interfaces.IO; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Sync { @@ -28,8 +29,9 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly IFileSystem _fileSystem; private readonly IApplicationPaths _appPaths; private readonly IServerApplicationHost _appHost; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths) + public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths, IMemoryStreamProvider memoryStreamProvider) { _logger = logger; _json = json; @@ -37,6 +39,7 @@ namespace MediaBrowser.Server.Implementations.Sync _target = target; _fileSystem = fileSystem; _appPaths = appPaths; + _memoryStreamProvider = memoryStreamProvider; _appHost = appHost; } @@ -90,7 +93,7 @@ namespace MediaBrowser.Server.Implementations.Sync private async Task SaveData(List items, CancellationToken cancellationToken) { - using (var stream = new MemoryStream()) + using (var stream = _memoryStreamProvider.CreateNew()) { _json.SerializeToStream(items, stream); diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index a72231893..18b340709 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -436,11 +436,11 @@ namespace MediaBrowser.Server.Startup.Common UserRepository = await GetUserRepository().ConfigureAwait(false); - var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths, NativeApp.GetDbConnector()); + var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths, NativeApp.GetDbConnector(), MemoryStreamProvider); DisplayPreferencesRepository = displayPreferencesRepo; RegisterSingleInstance(DisplayPreferencesRepository); - var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager, NativeApp.GetDbConnector()); + var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager, NativeApp.GetDbConnector(), MemoryStreamProvider); ItemRepository = itemRepo; RegisterSingleInstance(ItemRepository); @@ -465,17 +465,17 @@ namespace MediaBrowser.Server.Startup.Common LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, this); RegisterSingleInstance(LibraryMonitor); - ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer); + ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer, MemoryStreamProvider); RegisterSingleInstance(ProviderManager); RegisterSingleInstance(() => new SearchEngine(LogManager, LibraryManager, UserManager)); - HttpServer = ServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, "Emby", "web/index.html"); + HttpServer = ServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, MemoryStreamProvider, "Emby", "web/index.html"); HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); RegisterSingleInstance(HttpServer, false); progress.Report(10); - ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager); + ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamProvider); RegisterSingleInstance(ServerManager); var innerProgress = new ActionableProgress(); @@ -487,7 +487,7 @@ namespace MediaBrowser.Server.Startup.Common TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager); RegisterSingleInstance(TVSeriesManager); - SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager, () => MediaSourceManager, JsonSerializer, TaskManager); + SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager, () => MediaSourceManager, JsonSerializer, TaskManager, MemoryStreamProvider); RegisterSingleInstance(SyncManager); DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager, () => LiveTvManager); @@ -573,7 +573,7 @@ namespace MediaBrowser.Server.Startup.Common RegisterSingleInstance(new SessionContext(UserManager, authContext, SessionManager)); RegisterSingleInstance(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager)); - SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager); + SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamProvider); RegisterSingleInstance(SubtitleEncoder); await displayPreferencesRepo.Initialize().ConfigureAwait(false); @@ -665,7 +665,7 @@ namespace MediaBrowser.Server.Startup.Common () => SubtitleEncoder, () => MediaSourceManager, HttpClient, - ZipClient); + ZipClient, MemoryStreamProvider); MediaEncoder = mediaEncoder; RegisterSingleInstance(MediaEncoder); @@ -679,7 +679,7 @@ namespace MediaBrowser.Server.Startup.Common { try { - var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector()); + var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector(), MemoryStreamProvider); await repo.Initialize().ConfigureAwait(false); @@ -1132,7 +1132,8 @@ namespace MediaBrowser.Server.Startup.Common SupportsLibraryMonitor = SupportsLibraryMonitor, EncoderLocationType = MediaEncoder.EncoderLocationType, SystemArchitecture = NativeApp.Environment.SystemArchitecture, - SystemUpdateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel + SystemUpdateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel, + PackageName = _startupOptions.GetOption("package") }; } @@ -1237,7 +1238,8 @@ namespace MediaBrowser.Server.Startup.Common LogErrorResponseBody = false, LogErrors = false, LogRequest = false, - TimeoutMs = 30000 + TimeoutMs = 30000, + BufferContent = false }, "POST").ConfigureAwait(false)) { diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 22e990e8b..7e0d834fa 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -67,6 +67,9 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Nat", "Mono.Nat\Mono.Nat.csproj", "{D7453B88-2266-4805-B39B-2B5A2A33E1BA}" EndProject Global + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|Mixed Platforms = Debug|Mixed Platforms diff --git a/OpenSubtitlesHandler/Utilities.cs b/OpenSubtitlesHandler/Utilities.cs index d26c76b7c..9a90462f6 100644 --- a/OpenSubtitlesHandler/Utilities.cs +++ b/OpenSubtitlesHandler/Utilities.cs @@ -201,7 +201,8 @@ namespace OpenSubtitlesHandler // Response parsing will fail with this enabled EnableHttpCompression = false, - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + BufferContent = false }; if (string.IsNullOrEmpty(options.UserAgent)) -- cgit v1.2.3 From 50e66869872579d2cbd8337c4b114cf68dff814a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Oct 2016 11:08:13 -0400 Subject: update live stream management --- Emby.Drawing/ImageProcessor.cs | 13 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 4 + MediaBrowser.Api/StartupWizardService.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 28 ++- MediaBrowser.Controller/Entities/Game.cs | 2 +- MediaBrowser.Controller/Entities/IHasImages.cs | 6 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 6 +- MediaBrowser.Controller/Entities/MusicVideo.cs | 11 +- MediaBrowser.Controller/Entities/Trailer.cs | 4 +- MediaBrowser.Controller/Entities/Video.cs | 2 +- MediaBrowser.Controller/LiveTv/LiveStream.cs | 1 + .../MediaBrowser.Controller.csproj | 2 - MediaBrowser.Controller/Net/IHttpResultFactory.cs | 8 - .../Providers/IImageFileSaver.cs | 20 -- MediaBrowser.Controller/Providers/IImageSaver.cs | 11 - .../Providers/IProviderManager.cs | 7 - MediaBrowser.Controller/Providers/ItemInfo.cs | 2 +- MediaBrowser.Dlna/Eventing/EventManager.cs | 1 - .../Images/LocalImageProvider.cs | 2 +- MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs | 2 +- .../Encoder/EncodingUtils.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 +- .../Configuration/ServerConfiguration.cs | 1 + .../Notifications/NotificationType.cs | 1 - MediaBrowser.Providers/Manager/ImageSaver.cs | 10 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 10 +- .../TV/TheTVDB/TvdbSeriesProvider.cs | 3 +- .../EntryPoints/Notifications/Notifications.cs | 17 +- .../HttpServer/HttpListenerHost.cs | 10 +- .../HttpServer/HttpResultFactory.cs | 23 -- .../HttpServer/NativeWebSocket.cs | 240 ------------------ .../HttpServer/RangeRequestWriter.cs | 18 -- .../SocketSharp/WebSocketSharpResponse.cs | 18 +- .../Library/LibraryManager.cs | 2 +- .../Library/Resolvers/Audio/MusicArtistResolver.cs | 18 +- .../Library/Resolvers/Movies/MovieResolver.cs | 30 +-- .../Library/UserDataManager.cs | 24 +- .../LiveTv/EmbyTV/EmbyTV.cs | 33 ++- .../LiveTv/LiveTvManager.cs | 132 ++++------ .../LiveTv/LiveTvMediaSourceProvider.cs | 19 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 19 -- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 38 ++- .../TunerHosts/HdHomerun/HdHomerunLiveStream.cs | 196 ++++----------- .../LiveTv/TunerHosts/MulticastStream.cs | 96 ++++++++ .../LiveTv/TunerHosts/QueueStream.cs | 93 +++++++ .../Localization/Core/en-US.json | 1 - .../MediaBrowser.Server.Implementations.csproj | 3 +- .../Notifications/CoreNotificationTypes.cs | 7 - .../Persistence/SqliteItemRepository.cs | 7 +- .../ServerManager/WebSocketConnection.cs | 63 +---- .../ApplicationHost.cs | 15 +- MediaBrowser.XbmcMetadata/Images/XbmcImageSaver.cs | 272 --------------------- .../MediaBrowser.XbmcMetadata.csproj | 1 - 53 files changed, 484 insertions(+), 1075 deletions(-) delete mode 100644 MediaBrowser.Controller/Providers/IImageFileSaver.cs delete mode 100644 MediaBrowser.Controller/Providers/IImageSaver.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs delete mode 100644 MediaBrowser.XbmcMetadata/Images/XbmcImageSaver.cs (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 80ebbb719..e9f8f81f3 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -829,18 +829,7 @@ namespace Emby.Drawing // Run the enhancers sequentially in order of priority foreach (var enhancer in imageEnhancers) { - var typeName = enhancer.GetType().Name; - - try - { - await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("{0} failed enhancing {1}", ex, typeName, item.Name); - - throw; - } + await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false); // Feed the output into the next enhancer as input inputPath = outputPath; diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index a98637650..96d7874f0 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -197,6 +197,10 @@ {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model + + {2e781478-814d-4a48-9d80-bff206441a65} + MediaBrowser.Server.Implementations + diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index ebb3204a4..4c5abc996 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -116,6 +116,7 @@ namespace MediaBrowser.Api config.EnableCaseSensitiveItemIds = true; //config.EnableFolderView = true; config.SchemaVersion = 109; + config.EnableSimpleArtistDetection = true; } public void Post(UpdateStartupConfiguration request) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index be88c535e..90a22b217 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -115,6 +115,22 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public bool IsInMixedFolder { get; set; } + [IgnoreDataMember] + protected virtual bool SupportsIsInMixedFolderDetection + { + get { return false; } + } + + public bool DetectIsInMixedFolder() + { + if (SupportsIsInMixedFolderDetection) + { + + } + + return IsInMixedFolder; + } + [IgnoreDataMember] public virtual bool SupportsRemoteImageDownloading { @@ -1116,7 +1132,7 @@ namespace MediaBrowser.Controller.Entities var hasThemeMedia = this as IHasThemeMedia; if (hasThemeMedia != null) { - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { themeSongsChanged = await RefreshThemeSongs(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); @@ -1266,7 +1282,15 @@ namespace MediaBrowser.Controller.Entities { var current = this; - return current.IsInMixedFolder == newItem.IsInMixedFolder; + if (!SupportsIsInMixedFolderDetection) + { + if (current.IsInMixedFolder != newItem.IsInMixedFolder) + { + return false; + } + } + + return true; } public void AfterMetadataRefresh() diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index 24910498f..a48b9f564 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -98,7 +98,7 @@ namespace MediaBrowser.Controller.Entities public override IEnumerable GetDeletePaths() { - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { return new[] { System.IO.Path.GetDirectoryName(Path) }; } diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index a38b7394d..1ab0566e0 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -150,11 +150,7 @@ namespace MediaBrowser.Controller.Entities /// true if [supports local metadata]; otherwise, false. bool SupportsLocalMetadata { get; } - /// - /// Gets a value indicating whether this instance is in mixed folder. - /// - /// true if this instance is in mixed folder; otherwise, false. - bool IsInMixedFolder { get; } + bool DetectIsInMixedFolder(); /// /// Gets a value indicating whether this instance is locked. diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index f0270497c..e1e336147 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Entities.Movies // Must have a parent to have special features // In other words, it must be part of the Parent/Child tree - if (LocationType == LocationType.FileSystem && GetParent() != null && !IsInMixedFolder) + if (LocationType == LocationType.FileSystem && GetParent() != null && !DetectIsInMixedFolder()) { var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); @@ -119,7 +119,7 @@ namespace MediaBrowser.Controller.Entities.Movies { var info = GetItemLookupInfo(); - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { info.Name = System.IO.Path.GetFileName(ContainingFolderPath); } @@ -145,7 +145,7 @@ namespace MediaBrowser.Controller.Entities.Movies else { // Try to get the year from the folder name - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 8b749b7a5..9254802dd 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -37,6 +37,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + protected override bool SupportsIsInMixedFolderDetection + { + get + { + return true; + } + } + public override UnratedItem GetBlockUnratedType() { return UnratedItem.Music; @@ -65,7 +74,7 @@ namespace MediaBrowser.Controller.Entities else { // Try to get the year from the folder name - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 7a987a68e..f68cd2c85 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -64,7 +64,7 @@ namespace MediaBrowser.Controller.Entities info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer); - if (!IsInMixedFolder && LocationType == LocationType.FileSystem) + if (!DetectIsInMixedFolder() && LocationType == LocationType.FileSystem) { info.Name = System.IO.Path.GetFileName(ContainingFolderPath); } @@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities else { // Try to get the year from the folder name - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 1406a05ce..c64cdf57d 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -480,7 +480,7 @@ namespace MediaBrowser.Controller.Entities public override IEnumerable GetDeletePaths() { - if (!IsInMixedFolder) + if (!DetectIsInMixedFolder()) { return new[] { ContainingFolderPath }; } diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs index 7d44fbd90..a5d432a54 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs @@ -14,6 +14,7 @@ namespace MediaBrowser.Controller.LiveTv public ITunerHost TunerHost { get; set; } public string OriginalStreamId { get; set; } public bool EnableStreamSharing { get; set; } + public string UniqueId = Guid.NewGuid().ToString("N"); public LiveStream(MediaSourceInfo mediaSource) { diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index e9d2054da..7c1114e22 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -287,9 +287,7 @@ - - diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index 8fdb1ce37..ca453840f 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -11,14 +11,6 @@ namespace MediaBrowser.Controller.Net /// public interface IHttpResultFactory { - /// - /// Throws the error. - /// - /// The status code. - /// The error message. - /// The response headers. - void ThrowError(int statusCode, string errorMessage, IDictionary responseHeaders = null); - /// /// Gets the result. /// diff --git a/MediaBrowser.Controller/Providers/IImageFileSaver.cs b/MediaBrowser.Controller/Providers/IImageFileSaver.cs deleted file mode 100644 index 3e11d8bf8..000000000 --- a/MediaBrowser.Controller/Providers/IImageFileSaver.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public interface IImageFileSaver : IImageSaver - { - /// - /// Gets the save paths. - /// - /// The item. - /// The type. - /// The format. - /// The index. - /// IEnumerable{System.String}. - IEnumerable GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index); - } -} \ No newline at end of file diff --git a/MediaBrowser.Controller/Providers/IImageSaver.cs b/MediaBrowser.Controller/Providers/IImageSaver.cs deleted file mode 100644 index 62017160f..000000000 --- a/MediaBrowser.Controller/Providers/IImageSaver.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MediaBrowser.Controller.Providers -{ - public interface IImageSaver - { - /// - /// Gets the name. - /// - /// The name. - string Name { get; } - } -} diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 3eefa9647..d3e5685bb 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -95,15 +95,8 @@ namespace MediaBrowser.Controller.Providers /// /// Adds the metadata providers. /// - /// The image providers. - /// The metadata services. - /// The metadata providers. - /// The savers. - /// The image savers. - /// The external ids. void AddParts(IEnumerable imageProviders, IEnumerable metadataServices, IEnumerable metadataProviders, IEnumerable savers, - IEnumerable imageSavers, IEnumerable externalIds); /// diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs index 63cc48058..8de11b743 100644 --- a/MediaBrowser.Controller/Providers/ItemInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemInfo.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Providers { Path = item.Path; ContainingFolderPath = item.ContainingFolderPath; - IsInMixedFolder = item.IsInMixedFolder; + IsInMixedFolder = item.DetectIsInMixedFolder(); var video = item as Video; if (video != null) diff --git a/MediaBrowser.Dlna/Eventing/EventManager.cs b/MediaBrowser.Dlna/Eventing/EventManager.cs index 68f012c3a..51c8d2d91 100644 --- a/MediaBrowser.Dlna/Eventing/EventManager.cs +++ b/MediaBrowser.Dlna/Eventing/EventManager.cs @@ -156,7 +156,6 @@ namespace MediaBrowser.Dlna.Eventing } catch (OperationCanceledException) { - throw; } catch { diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index fe61a7a46..ef9160b70 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -132,7 +132,7 @@ namespace MediaBrowser.LocalMetadata.Images } var imagePrefix = item.FileNameWithoutExtension + "-"; - var isInMixedFolder = item.IsInMixedFolder; + var isInMixedFolder = item.DetectIsInMixedFolder(); PopulatePrimaryImages(item, images, files, imagePrefix, isInMixedFolder); diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs index a90789a3e..5592c068c 100644 --- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs @@ -99,7 +99,7 @@ namespace MediaBrowser.LocalMetadata.Savers public static string GetGameSavePath(Game item) { - if (item.IsInMixedFolder) + if (item.DetectIsInMixedFolder()) { return Path.ChangeExtension(item.Path, ".xml"); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 33e90743a..5d0f1f075 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -76,7 +76,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public static string GetProbeSizeArgument(bool isDvd) { - return isDvd ? "-probesize 1G -analyzeduration 200M" : " -analyzeduration 2M"; + return isDvd ? "-probesize 1G -analyzeduration 200M" : ""; } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 25ad14fe8..5c3345008 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -426,8 +426,10 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames); + var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol); + return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, - GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); + probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); } /// diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 1d2928f67..e7f8e6548 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -203,6 +203,7 @@ namespace MediaBrowser.Model.Configuration public string[] CodecsUsed { get; set; } public bool EnableChannelView { get; set; } public bool EnableExternalContentInSuggestions { get; set; } + public bool EnableSimpleArtistDetection { get; set; } public int ImageExtractionTimeoutMs { get; set; } /// diff --git a/MediaBrowser.Model/Notifications/NotificationType.cs b/MediaBrowser.Model/Notifications/NotificationType.cs index f5e3624f0..eefd15808 100644 --- a/MediaBrowser.Model/Notifications/NotificationType.cs +++ b/MediaBrowser.Model/Notifications/NotificationType.cs @@ -16,7 +16,6 @@ namespace MediaBrowser.Model.Notifications PluginUpdateInstalled, PluginUninstalled, NewLibraryContent, - NewLibraryContentMultiple, ServerRestartRequired, TaskFailed, CameraImageUploaded, diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index c9b3f22c5..5203adc9d 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -371,7 +371,7 @@ namespace MediaBrowser.Providers.Manager return Path.Combine(seriesFolder, imageFilename); } - if (item.IsInMixedFolder) + if (item.DetectIsInMixedFolder()) { return GetSavePathForItemInMixedFolder(item, type, "landscape", extension); } @@ -447,7 +447,7 @@ namespace MediaBrowser.Providers.Manager path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension); } - else if (item.IsInMixedFolder) + else if (item.DetectIsInMixedFolder()) { path = GetSavePathForItemInMixedFolder(item, type, filename, extension); } @@ -514,7 +514,7 @@ namespace MediaBrowser.Providers.Manager if (imageIndex.Value == 0) { - if (item.IsInMixedFolder) + if (item.DetectIsInMixedFolder()) { return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) }; } @@ -540,7 +540,7 @@ namespace MediaBrowser.Providers.Manager var outputIndex = imageIndex.Value; - if (item.IsInMixedFolder) + if (item.DetectIsInMixedFolder()) { return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) }; } @@ -583,7 +583,7 @@ namespace MediaBrowser.Providers.Manager return new[] { Path.Combine(seasonFolder, imageFilename) }; } - if (item.IsInMixedFolder || item is MusicVideo) + if (item.DetectIsInMixedFolder() || item is MusicVideo) { return new[] { GetSavePathForItemInMixedFolder(item, type, string.Empty, extension) }; } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 7e28254b0..ae1d60eb9 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -58,7 +58,6 @@ namespace MediaBrowser.Providers.Manager private IMetadataService[] _metadataServices = { }; private IMetadataProvider[] _metadataProviders = { }; private IEnumerable _savers; - private IImageSaver[] _imageSavers; private readonly IServerApplicationPaths _appPaths; private readonly IJsonSerializer _json; @@ -91,21 +90,14 @@ namespace MediaBrowser.Providers.Manager /// /// Adds the metadata providers. /// - /// The image providers. - /// The metadata services. - /// The metadata providers. - /// The metadata savers. - /// The image savers. - /// The external ids. public void AddParts(IEnumerable imageProviders, IEnumerable metadataServices, IEnumerable metadataProviders, IEnumerable metadataSavers, - IEnumerable imageSavers, IEnumerable externalIds) + IEnumerable externalIds) { ImageProviders = imageProviders.ToArray(); _metadataServices = metadataServices.OrderBy(i => i.Order).ToArray(); _metadataProviders = metadataProviders.ToArray(); - _imageSavers = imageSavers.ToArray(); _externalIds = externalIds.OrderBy(i => i.Name).ToArray(); _savers = metadataSavers.Where(i => diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index ca4f1b956..2572a4f58 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.TV private readonly ILibraryManager _libraryManager; private readonly IMemoryStreamProvider _memoryStreamProvider; - public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager) + public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IMemoryStreamProvider memoryStreamProvider) { _zipClient = zipClient; _httpClient = httpClient; @@ -49,6 +49,7 @@ namespace MediaBrowser.Providers.TV _config = config; _logger = logger; _libraryManager = libraryManager; + _memoryStreamProvider = memoryStreamProvider; Current = this; } diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs index e84b66c5a..f7fe707da 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs @@ -377,10 +377,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications DisposeLibraryUpdateTimer(); } - if (items.Count == 1) - { - var item = items.First(); + items = items.Take(10).ToList(); + foreach (var item in items) + { var notification = new NotificationRequest { NotificationType = NotificationType.NewLibraryContent.ToString() @@ -388,17 +388,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications notification.Variables["Name"] = GetItemName(item); - await SendNotification(notification).ConfigureAwait(false); - } - else - { - var notification = new NotificationRequest - { - NotificationType = NotificationType.NewLibraryContentMultiple.ToString() - }; - - notification.Variables["ItemCount"] = items.Count.ToString(CultureInfo.InvariantCulture); - await SendNotification(notification).ConfigureAwait(false); } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 7dc6fbb25..2ebeb0d44 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -94,12 +94,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer // The Markdown feature causes slow startup times (5 mins+) on cold boots for some users // Custom format allows images - HostConfig.Instance.EnableFeatures = Feature.Csv | Feature.Html | Feature.Json | Feature.Jsv | Feature.Metadata | Feature.Xml | Feature.CustomFormat; + HostConfig.Instance.EnableFeatures = Feature.Html | Feature.Json | Feature.CustomFormat; container.Adapter = _containerAdapter; Plugins.RemoveAll(x => x is NativeTypesFeature); - Plugins.Add(new SwaggerFeature()); + //Plugins.Add(new SwaggerFeature()); Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization")); //Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { @@ -546,8 +546,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - - throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo); + else + { + httpRes.Close(); + } } /// diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index 04085d3c7..10d6f7493 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -683,29 +683,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } - /// - /// Gets the error result. - /// - /// The status code. - /// The error message. - /// The response headers. - /// System.Object. - public void ThrowError(int statusCode, string errorMessage, IDictionary responseHeaders = null) - { - var error = new HttpError - { - Status = statusCode, - ErrorCode = errorMessage - }; - - if (responseHeaders != null) - { - AddResponseHeaders(error, responseHeaders); - } - - throw error; - } - public object GetAsyncStreamWriter(IAsyncStreamSource streamSource) { return new AsyncStreamWriter(streamSource); diff --git a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs deleted file mode 100644 index cac2f8e09..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs +++ /dev/null @@ -1,240 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WebSocketMessageType = MediaBrowser.Model.Net.WebSocketMessageType; -using WebSocketState = MediaBrowser.Model.Net.WebSocketState; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// - /// Class NativeWebSocket - /// - public class NativeWebSocket : IWebSocket - { - /// - /// The logger - /// - private readonly ILogger _logger; - - public event EventHandler Closed; - - /// - /// Gets or sets the web socket. - /// - /// The web socket. - private System.Net.WebSockets.WebSocket WebSocket { get; set; } - - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - /// - /// Initializes a new instance of the class. - /// - /// The socket. - /// The logger. - /// socket - public NativeWebSocket(WebSocket socket, ILogger logger) - { - if (socket == null) - { - throw new ArgumentNullException("socket"); - } - - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - _logger = logger; - WebSocket = socket; - - Receive(); - } - - /// - /// Gets or sets the state. - /// - /// The state. - public WebSocketState State - { - get - { - WebSocketState commonState; - - if (!Enum.TryParse(WebSocket.State.ToString(), true, out commonState)) - { - _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.State.ToString()); - } - - return commonState; - } - } - - /// - /// Receives this instance. - /// - private async void Receive() - { - while (true) - { - byte[] bytes; - - try - { - bytes = await ReceiveBytesAsync(_cancellationTokenSource.Token).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - break; - } - catch (WebSocketException ex) - { - _logger.ErrorException("Error receiving web socket message", ex); - - break; - } - - if (bytes == null) - { - // Connection closed - EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); - break; - } - - if (OnReceiveBytes != null) - { - OnReceiveBytes(bytes); - } - } - } - - /// - /// Receives the async. - /// - /// The cancellation token. - /// Task{WebSocketMessageInfo}. - /// Connection closed - private async Task ReceiveBytesAsync(CancellationToken cancellationToken) - { - var bytes = new byte[4096]; - var buffer = new ArraySegment(bytes); - - var result = await WebSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); - - if (result.CloseStatus.HasValue) - { - _logger.Info("Web socket connection closed by client. Reason: {0}", result.CloseStatus.Value); - return null; - } - - return buffer.Array; - } - - /// - /// Sends the async. - /// - /// The bytes. - /// The type. - /// if set to true [end of message]. - /// The cancellation token. - /// Task. - public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) - { - System.Net.WebSockets.WebSocketMessageType nativeType; - - if (!Enum.TryParse(type.ToString(), true, out nativeType)) - { - _logger.Warn("Unrecognized WebSocketMessageType: {0}", type.ToString()); - } - - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); - - return WebSocket.SendAsync(new ArraySegment(bytes), nativeType, true, linkedTokenSource.Token); - } - - public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) - { - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); - - return WebSocket.SendAsync(new ArraySegment(bytes), System.Net.WebSockets.WebSocketMessageType.Binary, true, linkedTokenSource.Token); - } - - public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) - { - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); - - var bytes = Encoding.UTF8.GetBytes(text); - - return WebSocket.SendAsync(new ArraySegment(bytes), System.Net.WebSockets.WebSocketMessageType.Text, true, linkedTokenSource.Token); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _cancellationTokenSource.Cancel(); - - WebSocket.Dispose(); - } - } - - /// - /// Gets or sets the receive action. - /// - /// The receive action. - public Action OnReceiveBytes { get; set; } - - /// - /// Gets or sets the on receive. - /// - /// The on receive. - public Action OnReceive { get; set; } - - /// - /// The _supports native web socket - /// - private static bool? _supportsNativeWebSocket; - - /// - /// Gets a value indicating whether [supports web sockets]. - /// - /// true if [supports web sockets]; otherwise, false. - public static bool IsSupported - { - get - { - if (!_supportsNativeWebSocket.HasValue) - { - try - { - new ClientWebSocket(); - - _supportsNativeWebSocket = true; - } - catch (PlatformNotSupportedException) - { - _supportsNativeWebSocket = false; - } - } - - return _supportsNativeWebSocket.Value; - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index 488c630fe..4b94095f5 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -191,15 +191,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - catch (IOException) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error in range request writer", ex); - throw; - } finally { if (OnComplete != null) @@ -251,15 +242,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - catch (IOException ex) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error in range request writer", ex); - throw; - } finally { if (OnComplete != null) diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index e08be8bd1..a58645ec5 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs @@ -81,20 +81,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp public void Write(string text) { - try - { - var bOutput = System.Text.Encoding.UTF8.GetBytes(text); - response.ContentLength64 = bOutput.Length; + var bOutput = System.Text.Encoding.UTF8.GetBytes(text); + response.ContentLength64 = bOutput.Length; - var outputStream = response.OutputStream; - outputStream.Write(bOutput, 0, bOutput.Length); - Close(); - } - catch (Exception ex) - { - _logger.ErrorException("Could not WriteTextToResponse: " + ex.Message, ex); - throw; - } + var outputStream = response.OutputStream; + outputStream.Write(bOutput, 0, bOutput.Length); + Close(); } public void Close() diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index b2bddc70d..f7661f55b 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -2463,7 +2463,7 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable