diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 2cd9007544..2a72854fb4 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -250,6 +250,14 @@ namespace MediaBrowser.Api return GetTranscodingJob(path, type) != null; } + public TranscodingJob GetTranscodingJobByPlaySessionId(string playSessionId) + { + lock (_activeTranscodingJobs) + { + return _activeTranscodingJobs.FirstOrDefault(j => j.PlaySessionId.Equals(playSessionId, StringComparison.OrdinalIgnoreCase)); + } + } + public TranscodingJob GetTranscodingJob(string path, TranscodingJobType type) { lock (_activeTranscodingJobs) @@ -258,14 +266,6 @@ namespace MediaBrowser.Api } } - public TranscodingJob GetTranscodingJob(string id) - { - lock (_activeTranscodingJobs) - { - return _activeTranscodingJobs.FirstOrDefault(j => j.Id.Equals(id, StringComparison.OrdinalIgnoreCase)); - } - } - /// /// Called when [transcode begin request]. /// diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index d3241a4436..a33a7df8d3 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -148,6 +148,7 @@ namespace MediaBrowser.Api.Playback } protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + private readonly long _slowSeekTicks = TimeSpan.FromSeconds(2).Ticks; /// /// Gets the fast seek command line parameter. @@ -157,16 +158,41 @@ namespace MediaBrowser.Api.Playback /// The fast seek command line parameter. protected string GetFastSeekCommandLineParameter(StreamRequest request) { - var time = request.StartTimeTicks; + var time = request.StartTimeTicks ?? 0; - if (time.HasValue && time.Value > 0) + if (time > 0) { - return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time.Value)); + if (time > _slowSeekTicks && EnableSlowSeek) + { + time -= _slowSeekTicks; + } + + return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time)); } return string.Empty; } + protected string GetSlowSeekCommandLineParameter(StreamRequest request) + { + var time = request.StartTimeTicks ?? 0; + + if (time > _slowSeekTicks) + { + return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(_slowSeekTicks)); + } + + return string.Empty; + } + + protected virtual bool EnableSlowSeek + { + get + { + return false; + } + } + /// /// Gets the map args. /// @@ -1060,7 +1086,7 @@ namespace MediaBrowser.Api.Playback private void StartThrottler(StreamState state, TranscodingJob transcodingJob) { - if (state.InputProtocol == MediaProtocol.File && + if (EnableThrottling && state.InputProtocol == MediaProtocol.File && state.RunTimeTicks.HasValue && state.VideoType == VideoType.VideoFile && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) @@ -1073,6 +1099,14 @@ namespace MediaBrowser.Api.Playback } } + protected virtual bool EnableThrottling + { + get + { + return true; + } + } + private async void StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target) { try @@ -1695,6 +1729,11 @@ namespace MediaBrowser.Api.Playback private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest) { + if (!EnableStreamCopy) + { + return; + } + if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream)) { state.OutputVideoCodec = "copy"; @@ -1706,6 +1745,14 @@ namespace MediaBrowser.Api.Playback } } + protected virtual bool EnableStreamCopy + { + get + { + return true; + } + } + private void AttachMediaSourceInfo(StreamState state, MediaSourceInfo mediaSource, VideoStreamRequest videoRequest, diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 1f6bc242df..f5345df723 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -62,7 +62,8 @@ namespace MediaBrowser.Api.Playback.Hls public class DynamicHlsService : BaseHlsService { - public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer) + public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) + : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer) { NetworkManager = networkManager; } @@ -130,7 +131,7 @@ namespace MediaBrowser.Api.Playback.Hls { var startTranscoding = false; - var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension); + var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, request.PlaySessionId, segmentExtension); var segmentGapRequiringTranscodingChange = 24 / state.SegmentLength; if (currentTranscodingIndex == null) @@ -206,9 +207,11 @@ namespace MediaBrowser.Api.Playback.Hls return position; } - public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension) + public int? GetCurrentTranscodingIndex(string playlist, string playSessionId, string segmentExtension) { - var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType); + var job = string.IsNullOrWhiteSpace(playSessionId) ? + ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType) : + ApiEntryPoint.Instance.GetTranscodingJobByPlaySessionId(playSessionId); if (job == null || job.HasExited) { @@ -720,11 +723,31 @@ namespace MediaBrowser.Api.Playback.Hls // If isEncoding is true we're actually starting ffmpeg var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0"; + var toTimeParam = string.Empty; + if (state.RunTimeTicks.HasValue) + { + var startTime = state.Request.StartTimeTicks ?? 0; + var durationSeconds = ApiEntryPoint.Instance.GetEncodingOptions().ThrottleThresholdInSeconds; + var endTime = startTime + TimeSpan.FromSeconds(durationSeconds).Ticks; + endTime = Math.Min(endTime, state.RunTimeTicks.Value); + + if (endTime < state.RunTimeTicks.Value) + { + toTimeParam = " -to " + MediaEncoder.GetTimeParameter(endTime); + } + } + + var slowSeekParam = GetSlowSeekCommandLineParameter(state.Request); + if (!string.IsNullOrWhiteSpace(slowSeekParam)) + { + slowSeekParam = " " + slowSeekParam; + } + if (state.EnableGenericHlsSegmenter) { var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d.ts"; - return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -flags -global_header -sc_threshold 0 {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"", + return string.Format("{0} {1}{10}{11} -map_metadata -1 -threads {2} {3} {4} -flags -global_header -sc_threshold 0 {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"", inputModifier, GetInputArgument(state), threads, @@ -734,11 +757,13 @@ namespace MediaBrowser.Api.Playback.Hls state.SegmentLength.ToString(UsCulture), startNumberParam, outputPath, - outputTsArg + outputTsArg, + slowSeekParam, + toTimeParam ).Trim(); } - return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -flags -global_header -copyts -sc_threshold 0 {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"", + return string.Format("{0} {1}{10}{11} -map_metadata -1 -threads {2} {3} {4} -flags -global_header -copyts -sc_threshold 0 {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"", inputModifier, GetInputArgument(state), threads, @@ -748,10 +773,36 @@ namespace MediaBrowser.Api.Playback.Hls state.SegmentLength.ToString(UsCulture), startNumberParam, state.HlsListSize.ToString(UsCulture), - outputPath + outputPath, + slowSeekParam, + toTimeParam ).Trim(); } + protected override bool EnableThrottling + { + get + { + return false; + } + } + + protected override bool EnableStreamCopy + { + get + { + return false; + } + } + + protected override bool EnableSlowSeek + { + get + { + return true; + } + } + /// /// Gets the segment file extension. /// diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs index ece4550095..fec3dda869 100644 --- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs +++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback var options = GetOptions(); - if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) + if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdInSeconds)) { PauseTranscoding(); } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 7f16072173..ae714a84ee 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Model.Configuration public string H264Encoder { get; set; } public bool EnableDebugLogging { get; set; } public bool EnableThrottling { get; set; } - public int ThrottleThresholdSeconds { get; set; } + public int ThrottleThresholdInSeconds { get; set; } public EncodingOptions() { @@ -17,7 +17,7 @@ namespace MediaBrowser.Model.Configuration DownMixAudioBoost = 2; EncodingQuality = EncodingQuality.Auto; EnableThrottling = true; - ThrottleThresholdSeconds = 110; + ThrottleThresholdInSeconds = 120; } } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 8400b204f9..3c1c7ea6d4 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -485,7 +485,7 @@ namespace MediaBrowser.Model.Dlna if (targetAudioChannels.HasValue) { - if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 1500000) + if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 2000000) { defaultBitrate = 320000; } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index f2999ea027..8f90f1aca6 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1424,13 +1424,6 @@ "OptionEnableFullSpeedConversionHelp": "By default, sync conversion is performed at a low speed to minimize resource consumption.", "HeaderPlaylists": "Playlists", "HeaderSelectDate": "Select Date", - "HeaderWelcomeExclamation": "Welcome!", - "HeaderMyPreferences": "My Preferences", - "ButtonMyPreferencesWelcomeYes": "Yes, I'd like to set my preferences now.", - "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.", - "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.", - "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?", - "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.", "HeaderViewStyles": "View Styles", "LabelSelectViewStyles": "Enable enhanced presentations for:", "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.", diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 0e4a3bcf13..d47135c65c 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -286,6 +286,13 @@ namespace MediaBrowser.Server.Implementations.Sync private async Task FillMetadata(SyncJob job) { + var user = _userManager.GetUserById(job.UserId); + + if (user == null) + { + return; + } + var target = GetSyncTargets(job.UserId) .FirstOrDefault(i => string.Equals(i.Id, job.TargetId, StringComparison.OrdinalIgnoreCase)); @@ -302,8 +309,6 @@ namespace MediaBrowser.Server.Implementations.Sync { var processor = GetSyncJobProcessor(); - var user = _userManager.GetUserById(job.UserId); - item = (await processor .GetItemsForSync(job.Category, job.ParentId, job.RequestedItemIds, user, job.UnwatchedOnly).ConfigureAwait(false)) .FirstOrDefault(); diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index bbdb733c15..6b8c17002a 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -474,11 +474,6 @@ namespace MediaBrowser.WebDashboard.Api } apiClientFiles.Add("thirdparty/apiclient/connectionmanager.js"); - if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) - { - apiClientFiles.Add("thirdparty/cordova/remotecontrols.js"); - } - foreach (var file in apiClientFiles) { using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) @@ -561,13 +556,9 @@ namespace MediaBrowser.WebDashboard.Api "alphapicker.js", "addpluginpage.js", - "metadataadvanced.js", "autoorganizetv.js", "autoorganizelog.js", - "channelslatest.js", - "channelitems.js", "channelsettings.js", - "connectlogin.js", "dashboardgeneral.js", "dashboardpage.js", "devicesupload.js", @@ -585,16 +576,13 @@ namespace MediaBrowser.WebDashboard.Api "encodingsettings.js", "externalplayer.js", - "favorites.js", "forgotpassword.js", "forgotpasswordpin.js", - "homelatest.js", "indexpage.js", "itembynamedetailpage.js", "itemdetailpage.js", "kids.js", "librarypathmapping.js", - "reports.js", "librarysettings.js", "livetvchannel.js", "livetvguide.js", @@ -607,7 +595,6 @@ namespace MediaBrowser.WebDashboard.Api "livetvsettings.js", "livetvstatus.js", - "loginpage.js", "medialibrarypage.js", "metadataconfigurationpage.js", "metadataimagespage.js", @@ -632,7 +619,6 @@ namespace MediaBrowser.WebDashboard.Api "scheduledtaskpage.js", "scheduledtaskspage.js", "search.js", - "selectserver.js", "supporterkeypage.js", "syncactivity.js", "syncsettings.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 215fb5e5ea..b7ecd58a50 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -222,15 +222,13 @@ PreserveNewest - - PreserveNewest - PreserveNewest PreserveNewest + PreserveNewest