Luke Pulverenti пре 8 година
родитељ
комит
c9be9b4141

+ 27 - 0
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -710,7 +710,34 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                 throw new InvalidOperationException("SeriesId for program not found");
             }
 
+            // If any timers have already been manually created, make sure they don't get cancelled
+            var existingTimers = (await GetTimersAsync(CancellationToken.None).ConfigureAwait(false))
+                .Where(i =>
+                {
+                    if (string.Equals(i.ProgramId, info.ProgramId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(info.ProgramId))
+                    {
+                        return true;
+                    }
+
+                    //if (string.Equals(i.SeriesId, info.SeriesId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(info.SeriesId))
+                    //{
+                    //    return true;
+                    //}
+
+                    return false;
+                })
+                .ToList();
+
             _seriesTimerProvider.Add(info);
+
+            foreach (var timer in existingTimers)
+            {
+                timer.SeriesTimerId = info.Id;
+                timer.IsManual = true;
+
+                _timerProvider.AddOrUpdate(timer);
+            }
+
             await UpdateTimersForSeriesTimer(epgData, info, true, false).ConfigureAwait(false);
 
             return info.Id;

+ 3 - 129
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -289,8 +289,10 @@ namespace MediaBrowser.Api.Playback
             // MUST read both stdout and stderr asynchronously or a deadlock may occurr
             //process.BeginOutputReadLine();
 
+            state.TranscodingJob = transcodingJob;
+
             // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-            var task = Task.Run(() => StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream));
+            new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream);
 
             // Wait for the file to exist before proceeeding
             while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
@@ -340,134 +342,6 @@ namespace MediaBrowser.Api.Playback
             //    string.Equals(GetVideoEncoder(state), "libx264", StringComparison.OrdinalIgnoreCase);
         }
 
-        private async Task StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
-        {
-            try
-            {
-                using (var reader = new StreamReader(source))
-                {
-                    while (!reader.EndOfStream)
-                    {
-                        var line = await reader.ReadLineAsync().ConfigureAwait(false);
-
-                        ParseLogLine(line, transcodingJob, state);
-
-                        var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
-
-                        await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
-                        await target.FlushAsync().ConfigureAwait(false);
-                    }
-                }
-            }
-            catch (ObjectDisposedException)
-            {
-                // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error reading ffmpeg log", ex);
-            }
-        }
-
-        private void ParseLogLine(string line, TranscodingJob transcodingJob, StreamState state)
-        {
-            float? framerate = null;
-            double? percent = null;
-            TimeSpan? transcodingPosition = null;
-            long? bytesTranscoded = null;
-            int? bitRate = null;
-
-            var parts = line.Split(' ');
-
-            var totalMs = state.RunTimeTicks.HasValue
-                ? TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds
-                : 0;
-
-            var startMs = state.Request.StartTimeTicks.HasValue
-                ? TimeSpan.FromTicks(state.Request.StartTimeTicks.Value).TotalMilliseconds
-                : 0;
-
-            for (var i = 0; i < parts.Length; i++)
-            {
-                var part = parts[i];
-
-                if (string.Equals(part, "fps=", StringComparison.OrdinalIgnoreCase) &&
-                    (i + 1 < parts.Length))
-                {
-                    var rate = parts[i + 1];
-                    float val;
-
-                    if (float.TryParse(rate, NumberStyles.Any, UsCulture, out val))
-                    {
-                        framerate = val;
-                    }
-                }
-                else if (state.RunTimeTicks.HasValue &&
-                    part.StartsWith("time=", StringComparison.OrdinalIgnoreCase))
-                {
-                    var time = part.Split(new[] { '=' }, 2).Last();
-                    TimeSpan val;
-
-                    if (TimeSpan.TryParse(time, UsCulture, out val))
-                    {
-                        var currentMs = startMs + val.TotalMilliseconds;
-
-                        var percentVal = currentMs / totalMs;
-                        percent = 100 * percentVal;
-
-                        transcodingPosition = val;
-                    }
-                }
-                else if (part.StartsWith("size=", StringComparison.OrdinalIgnoreCase))
-                {
-                    var size = part.Split(new[] { '=' }, 2).Last();
-
-                    int? scale = null;
-                    if (size.IndexOf("kb", StringComparison.OrdinalIgnoreCase) != -1)
-                    {
-                        scale = 1024;
-                        size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase);
-                    }
-
-                    if (scale.HasValue)
-                    {
-                        long val;
-
-                        if (long.TryParse(size, NumberStyles.Any, UsCulture, out val))
-                        {
-                            bytesTranscoded = val * scale.Value;
-                        }
-                    }
-                }
-                else if (part.StartsWith("bitrate=", StringComparison.OrdinalIgnoreCase))
-                {
-                    var rate = part.Split(new[] { '=' }, 2).Last();
-
-                    int? scale = null;
-                    if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1)
-                    {
-                        scale = 1024;
-                        rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase);
-                    }
-
-                    if (scale.HasValue)
-                    {
-                        float val;
-
-                        if (float.TryParse(rate, NumberStyles.Any, UsCulture, out val))
-                        {
-                            bitRate = (int)Math.Ceiling(val * scale.Value);
-                        }
-                    }
-                }
-            }
-
-            if (framerate.HasValue || percent.HasValue)
-            {
-                ApiEntryPoint.Instance.ReportTranscodingProgress(transcodingJob, state, transcodingPosition, framerate, percent, bytesTranscoded, bitRate);
-            }
-        }
-
         /// <summary>
         /// Processes the exited.
         /// </summary>

+ 6 - 3
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -268,7 +268,7 @@ namespace MediaBrowser.Api.Playback.Hls
                     "hls/" + Path.GetFileNameWithoutExtension(outputPath));
             }
 
-            var useGenericSegmenter = false;
+            var useGenericSegmenter = true;
             if (useGenericSegmenter)
             {
                 var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
@@ -281,7 +281,9 @@ namespace MediaBrowser.Api.Playback.Hls
                     segmentFormat = "mpegts";
                 }
 
-                return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
+                baseUrlParam = string.Format("\"{0}/\"", "hls/" + Path.GetFileNameWithoutExtension(outputPath));
+
+                return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_entry_prefix {12} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
                     inputModifier,
                     EncodingHelper.GetInputArgument(state, encodingOptions),
                     threads,
@@ -293,7 +295,8 @@ namespace MediaBrowser.Api.Playback.Hls
                     outputPath,
                     outputTsArg,
                     timeDeltaParam,
-                    segmentFormat
+                    segmentFormat,
+                    baseUrlParam
                 ).Trim();
             }
 

+ 8 - 0
MediaBrowser.Api/Playback/StreamState.cs

@@ -154,6 +154,8 @@ namespace MediaBrowser.Api.Playback
             DisposeLiveStream();
             DisposeLogStream();
             DisposeIsoMount();
+
+            TranscodingJob = null;
         }
 
         private void DisposeLogStream()
@@ -476,5 +478,11 @@ namespace MediaBrowser.Api.Playback
                 return true;
             }
         }
+
+        public TranscodingJob TranscodingJob;
+        public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
+        {
+            ApiEntryPoint.Instance.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate);
+        }
     }
 }

+ 1 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -190,6 +190,7 @@
     <Compile Include="MediaEncoding\ImageEncodingOptions.cs" />
     <Compile Include="MediaEncoding\IMediaEncoder.cs" />
     <Compile Include="MediaEncoding\ISubtitleEncoder.cs" />
+    <Compile Include="MediaEncoding\JobLogger.cs" />
     <Compile Include="MediaEncoding\MediaInfoRequest.cs" />
     <Compile Include="MediaEncoding\MediaStreamSelector.cs" />
     <Compile Include="Net\AuthenticatedAttribute.cs" />

+ 3 - 1
MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs

@@ -12,7 +12,7 @@ using MediaBrowser.Model.MediaInfo;
 namespace MediaBrowser.Controller.MediaEncoding
 {
     // For now, a common base class until the API and MediaEncoding classes are unified
-    public class EncodingJobInfo
+    public abstract class EncodingJobInfo
     {
         private readonly ILogger _logger;
 
@@ -115,5 +115,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 IsoMount = null;
             }
         }
+
+        public abstract void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate);
     }
 }

+ 37 - 10
MediaBrowser.MediaEncoding/Encoder/JobLogger.cs → MediaBrowser.Controller/MediaEncoding/JobLogger.cs

@@ -6,7 +6,7 @@ using System.IO;
 using System.Linq;
 using System.Text;
 
-namespace MediaBrowser.MediaEncoding.Encoder
+namespace MediaBrowser.Controller.MediaEncoding
 {
     public class JobLogger
     {
@@ -18,7 +18,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             _logger = logger;
         }
 
-        public async void StartStreamingLog(EncodingJob transcodingJob, Stream source, Stream target)
+        public async void StartStreamingLog(EncodingJobInfo state, Stream source, Stream target)
         {
             try
             {
@@ -28,35 +28,41 @@ namespace MediaBrowser.MediaEncoding.Encoder
                     {
                         var line = await reader.ReadLineAsync().ConfigureAwait(false);
 
-                        ParseLogLine(line, transcodingJob);
+                        ParseLogLine(line, state);
 
                         var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
 
                         await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+                        await target.FlushAsync().ConfigureAwait(false);
                     }
                 }
             }
+            catch (ObjectDisposedException)
+            {
+                // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
+            }
             catch (Exception ex)
             {
                 _logger.ErrorException("Error reading ffmpeg log", ex);
             }
         }
 
-        private void ParseLogLine(string line, EncodingJob transcodingJob)
+        private void ParseLogLine(string line, EncodingJobInfo state)
         {
             float? framerate = null;
             double? percent = null;
             TimeSpan? transcodingPosition = null;
             long? bytesTranscoded = null;
+            int? bitRate = null;
 
             var parts = line.Split(' ');
 
-            var totalMs = transcodingJob.RunTimeTicks.HasValue
-                ? TimeSpan.FromTicks(transcodingJob.RunTimeTicks.Value).TotalMilliseconds
+            var totalMs = state.RunTimeTicks.HasValue
+                ? TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds
                 : 0;
 
-            var startMs = transcodingJob.Options.StartTimeTicks.HasValue
-                ? TimeSpan.FromTicks(transcodingJob.Options.StartTimeTicks.Value).TotalMilliseconds
+            var startMs = state.BaseRequest.StartTimeTicks.HasValue
+                ? TimeSpan.FromTicks(state.BaseRequest.StartTimeTicks.Value).TotalMilliseconds
                 : 0;
 
             for (var i = 0; i < parts.Length; i++)
@@ -74,7 +80,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                         framerate = val;
                     }
                 }
-                else if (transcodingJob.RunTimeTicks.HasValue &&
+                else if (state.RunTimeTicks.HasValue &&
                     part.StartsWith("time=", StringComparison.OrdinalIgnoreCase))
                 {
                     var time = part.Split(new[] { '=' }, 2).Last();
@@ -111,11 +117,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
                         }
                     }
                 }
+                else if (part.StartsWith("bitrate=", StringComparison.OrdinalIgnoreCase))
+                {
+                    var rate = part.Split(new[] { '=' }, 2).Last();
+
+                    int? scale = null;
+                    if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1)
+                    {
+                        scale = 1024;
+                        rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase);
+                    }
+
+                    if (scale.HasValue)
+                    {
+                        float val;
+
+                        if (float.TryParse(rate, NumberStyles.Any, _usCulture, out val))
+                        {
+                            bitRate = (int)Math.Ceiling(val * scale.Value);
+                        }
+                    }
+                }
             }
 
             if (framerate.HasValue || percent.HasValue)
             {
-                transcodingJob.ReportTranscodingProgress(transcodingPosition, framerate, percent, bytesTranscoded);
+                state.ReportTranscodingProgress(transcodingPosition, framerate, percent, bytesTranscoded, bitRate);
             }
         }
     }

+ 1 - 1
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -242,7 +242,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
         private void OnTranscodeBeginning(EncodingJob job)
         {
-            job.ReportTranscodingProgress(null, null, null, null);
+            job.ReportTranscodingProgress(null, null, null, null, null);
         }
 
         private void OnTranscodeFailedToStart(string path, EncodingJob job)

+ 3 - 3
MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs

@@ -377,7 +377,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return count;
         }
 
-        public void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded)
+        public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
         {
             var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
 
@@ -385,8 +385,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             if (!percentComplete.HasValue && ticks.HasValue && RunTimeTicks.HasValue)
             {
-                var pct = ticks.Value/RunTimeTicks.Value;
-                percentComplete = pct*100;
+                var pct = ticks.Value / RunTimeTicks.Value;
+                percentComplete = pct * 100;
             }
 
             if (percentComplete.HasValue)

+ 0 - 1
MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj

@@ -55,7 +55,6 @@
     <Compile Include="Encoder\EncodingUtils.cs" />
     <Compile Include="Encoder\EncoderValidator.cs" />
     <Compile Include="Encoder\FontConfigLoader.cs" />
-    <Compile Include="Encoder\JobLogger.cs" />
     <Compile Include="Encoder\MediaEncoder.cs" />
     <Compile Include="Encoder\VideoEncoder.cs" />
     <Compile Include="Probing\FFProbeHelpers.cs" />

+ 7 - 7
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -324,7 +324,7 @@ namespace MediaBrowser.Model.Dlna
             if (directPlayProfile != null)
             {
                 // While options takes the network and other factors into account. Only applies to direct stream
-                if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true)) && options.EnableDirectStream)
+                if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream) && options.EnableDirectStream)
                 {
                     playMethods.Add(PlayMethod.DirectStream);
                 }
@@ -332,7 +332,7 @@ namespace MediaBrowser.Model.Dlna
                 // The profile describes what the device supports
                 // If device requirements are satisfied then allow both direct stream and direct play
                 if (item.SupportsDirectPlay &&
-                    IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true)) && options.EnableDirectPlay)
+                    IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay) && options.EnableDirectPlay)
                 {
                     playMethods.Add(PlayMethod.DirectPlay);
                 }
@@ -905,7 +905,7 @@ namespace MediaBrowser.Model.Dlna
                 }
             }
 
-            return IsAudioEligibleForDirectPlay(item, maxBitrate);
+            return IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
         }
 
         public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, string transcodingSubProtocol, string transcodingContainer)
@@ -1035,7 +1035,7 @@ namespace MediaBrowser.Model.Dlna
             return null;
         }
 
-        private bool IsAudioEligibleForDirectPlay(MediaSourceInfo item, long? maxBitrate)
+        private bool IsAudioEligibleForDirectPlay(MediaSourceInfo item, long? maxBitrate, PlayMethod playMethod)
         {
             // Don't restrict by bitrate if coming from an external domain
             if (item.IsRemote)
@@ -1045,19 +1045,19 @@ namespace MediaBrowser.Model.Dlna
 
             if (!maxBitrate.HasValue)
             {
-                _logger.Info("Cannot direct play due to unknown supported bitrate");
+                _logger.Info("Cannot "+ playMethod + " due to unknown supported bitrate");
                 return false;
             }
 
             if (!item.Bitrate.HasValue)
             {
-                _logger.Info("Cannot direct play due to unknown content bitrate");
+                _logger.Info("Cannot " + playMethod + " due to unknown content bitrate");
                 return false;
             }
 
             if (item.Bitrate.Value > maxBitrate.Value)
             {
-                _logger.Info("Bitrate exceeds DirectPlay limit: media bitrate: {0}, max bitrate: {1}", item.Bitrate.Value.ToString(CultureInfo.InvariantCulture), maxBitrate.Value.ToString(CultureInfo.InvariantCulture));
+                _logger.Info("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", item.Bitrate.Value.ToString(CultureInfo.InvariantCulture), maxBitrate.Value.ToString(CultureInfo.InvariantCulture));
                 return false;
             }
 

+ 5 - 12
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -172,18 +172,11 @@ namespace MediaBrowser.Providers.Manager
 
                 try
                 {
-                    var currentFile = _fileSystem.GetFileInfo(currentPath);
-
-                    // This will fail if the file is hidden
-                    if (currentFile.Exists)
-                    {
-                        if (currentFile.IsHidden)
-                        {
-                            _fileSystem.SetHidden(currentFile.FullName, false);
-                        }
-
-                        _fileSystem.DeleteFile(currentFile.FullName);
-                    }
+                    _fileSystem.DeleteFile(currentPath);
+                }
+                catch (FileNotFoundException)
+                {
+                    
                 }
                 finally
                 {

+ 6 - 11
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -373,20 +373,15 @@ namespace MediaBrowser.Providers.Manager
                     continue;
                 }
 
-                // Delete the source file
-                var currentFile = _fileSystem.GetFileInfo(image.Path);
-
-                // Deletion will fail if the file is hidden so remove the attribute first
-                if (currentFile.Exists)
+                try
                 {
-                    if (currentFile.IsHidden)
-                    {
-                        _fileSystem.SetHidden(currentFile.FullName, false);
-                    }
-
-                    _fileSystem.DeleteFile(currentFile.FullName);
+                    _fileSystem.DeleteFile(image.Path);
                     deleted = true;
                 }
+                catch (FileNotFoundException)
+                {
+                    
+                }
             }
 
             foreach (var image in deletedImages)