Procházet zdrojové kódy

Merge pull request #2182 from MediaBrowser/dev

Dev
Luke před 8 roky
rodič
revize
d61258f290

+ 2 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -1453,7 +1453,8 @@ namespace MediaBrowser.Api.Playback
                 // Make sure we don't request a bitrate higher than the source
                 // Make sure we don't request a bitrate higher than the source
                 var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value;
                 var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value;
 
 
-                return request.AudioBitRate.Value;
+                // Don't encode any higher than this
+                return Math.Min(384000, request.AudioBitRate.Value);
                 //return Math.Min(currentBitrate, request.AudioBitRate.Value);
                 //return Math.Min(currentBitrate, request.AudioBitRate.Value);
             }
             }
 
 

+ 2 - 0
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -113,6 +113,8 @@ namespace MediaBrowser.Api.Playback.Hls
                 args += GetGraphicalSubtitleParam(state, codec);
                 args += GetGraphicalSubtitleParam(state, codec);
             }
             }
 
 
+            args += " -flags -global_header";
+
             return args;
             return args;
         }
         }
 
 

+ 14 - 3
MediaBrowser.Controller/LiveTv/TimerInfo.cs

@@ -1,10 +1,16 @@
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.LiveTv;
 using System;
 using System;
+using System.Collections.Generic;
 
 
 namespace MediaBrowser.Controller.LiveTv
 namespace MediaBrowser.Controller.LiveTv
 {
 {
     public class TimerInfo
     public class TimerInfo
     {
     {
+        public TimerInfo()
+        {
+            Genres = new List<string>();
+        }
+
         /// <summary>
         /// <summary>
         /// Id of the recording.
         /// Id of the recording.
         /// </summary>
         /// </summary>
@@ -15,7 +21,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// </summary>
         /// </summary>
         /// <value>The series timer identifier.</value>
         /// <value>The series timer identifier.</value>
         public string SeriesTimerId { get; set; }
         public string SeriesTimerId { get; set; }
-        
+
         /// <summary>
         /// <summary>
         /// ChannelId of the recording.
         /// ChannelId of the recording.
         /// </summary>
         /// </summary>
@@ -26,7 +32,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// </summary>
         /// </summary>
         /// <value>The program identifier.</value>
         /// <value>The program identifier.</value>
         public string ProgramId { get; set; }
         public string ProgramId { get; set; }
-        
+
         /// <summary>
         /// <summary>
         /// Name of the recording.
         /// Name of the recording.
         /// </summary>
         /// </summary>
@@ -76,7 +82,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
         public bool IsPostPaddingRequired { get; set; }
         public bool IsPostPaddingRequired { get; set; }
-        
+
         /// <summary>
         /// <summary>
         /// Gets or sets the priority.
         /// Gets or sets the priority.
         /// </summary>
         /// </summary>
@@ -98,5 +104,10 @@ namespace MediaBrowser.Controller.LiveTv
         public string EpisodeTitle { get; set; }
         public string EpisodeTitle { get; set; }
         public DateTime? OriginalAirDate { get; set; }
         public DateTime? OriginalAirDate { get; set; }
         public bool IsProgramSeries { get; set; }
         public bool IsProgramSeries { get; set; }
+        public string HomePageUrl { get; set; }
+        public float? CommunityRating { get; set; }
+        public string ShortOverview { get; set; }
+        public string OfficialRating { get; set; }
+        public List<string> Genres { get; set; }
     }
     }
 }
 }

+ 15 - 0
MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs

@@ -393,6 +393,20 @@ namespace MediaBrowser.MediaEncoding.Probing
             };
             };
         }
         }
 
 
+        private string NormalizeSubtitleCodec(string codec)
+        {
+            if ((codec ?? string.Empty).IndexOf("PGS", StringComparison.OrdinalIgnoreCase) != -1)
+            {
+                codec = "PGSSUB";
+            }
+            else if ((codec ?? string.Empty).IndexOf("DVD", StringComparison.OrdinalIgnoreCase) != -1)
+            {
+                codec = "DVDSUB";
+            }
+
+            return codec;
+        }
+
         /// <summary>
         /// <summary>
         /// Converts ffprobe stream info to our MediaStream class
         /// Converts ffprobe stream info to our MediaStream class
         /// </summary>
         /// </summary>
@@ -474,6 +488,7 @@ namespace MediaBrowser.MediaEncoding.Probing
             else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
             else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
             {
             {
                 stream.Type = MediaStreamType.Subtitle;
                 stream.Type = MediaStreamType.Subtitle;
+                stream.Codec = NormalizeSubtitleCodec(stream.Codec);
             }
             }
             else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
             else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
             {
             {

+ 14 - 19
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -609,26 +609,13 @@ namespace MediaBrowser.Model.Dlna
                 defaultBitrate = StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3") ? 192000 : 128000;
                 defaultBitrate = StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3") ? 192000 : 128000;
             }
             }
 
 
-            if (targetAudioChannels.HasValue)
+            if (StringHelper.EqualsIgnoreCase(subProtocol, "hls"))
             {
             {
-                if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 1200000)
-                {
-                    if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3"))
-                    {
-                        if (StringHelper.EqualsIgnoreCase(subProtocol, "hls"))
-                        {
-                            defaultBitrate = Math.Max(384000, defaultBitrate);
-                        }
-                        else
-                        {
-                            defaultBitrate = Math.Max(448000, defaultBitrate);
-                        }
-                    }
-                    else
-                    {
-                        defaultBitrate = Math.Max(320000, defaultBitrate);
-                    }
-                }
+                defaultBitrate = Math.Min(384000, defaultBitrate);
+            }
+            else
+            {
+                defaultBitrate = Math.Min(448000, defaultBitrate);
             }
             }
 
 
             int encoderAudioBitrateLimit = int.MaxValue;
             int encoderAudioBitrateLimit = int.MaxValue;
@@ -647,6 +634,14 @@ namespace MediaBrowser.Model.Dlna
                 }
                 }
             }
             }
 
 
+            if (maxTotalBitrate.HasValue)
+            {
+                if (maxTotalBitrate.Value < 640000)
+                {
+                    defaultBitrate = Math.Min(128000, defaultBitrate);
+                }
+            }
+
             return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
             return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
         }
         }
 
 

+ 3 - 1
MediaBrowser.Server.Implementations/IO/FileRefresher.cs

@@ -12,6 +12,7 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Server.Implementations.ScheduledTasks;
 using MediaBrowser.Server.Implementations.ScheduledTasks;
+using MoreLinq;
 
 
 namespace MediaBrowser.Server.Implementations.IO
 namespace MediaBrowser.Server.Implementations.IO
 {
 {
@@ -136,9 +137,10 @@ namespace MediaBrowser.Server.Implementations.IO
         private async Task ProcessPathChanges(List<string> paths)
         private async Task ProcessPathChanges(List<string> paths)
         {
         {
             var itemsToRefresh = paths
             var itemsToRefresh = paths
+                .Distinct(StringComparer.OrdinalIgnoreCase)
                 .Select(GetAffectedBaseItem)
                 .Select(GetAffectedBaseItem)
                 .Where(item => item != null)
                 .Where(item => item != null)
-                .Distinct()
+                .DistinctBy(i => i.Id)
                 .ToList();
                 .ToList();
 
 
             foreach (var p in paths)
             foreach (var p in paths)

+ 14 - 1
MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs

@@ -404,7 +404,20 @@ namespace MediaBrowser.Server.Implementations.IO
             {
             {
                 Logger.Debug("Changed detected of type " + e.ChangeType + " to " + e.FullPath);
                 Logger.Debug("Changed detected of type " + e.ChangeType + " to " + e.FullPath);
 
 
-                ReportFileSystemChanged(e.FullPath);
+                var path = e.FullPath;
+
+                // For deletes, use the parent path
+                if (e.ChangeType == WatcherChangeTypes.Deleted)
+                {
+                    var parentPath = Path.GetDirectoryName(path);
+
+                    if (!string.IsNullOrWhiteSpace(parentPath))
+                    {
+                        path = parentPath;
+                    }
+                }
+
+                ReportFileSystemChanged(path);
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {

+ 1 - 1
MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs

@@ -89,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
                 return false;
                 return false;
             }
             }
 
 
-            if (IgnoreFiles.Any(i => filename.IndexOf("-" + i, StringComparison.OrdinalIgnoreCase) != -1))
+            if (IgnoreFiles.Any(i => filename.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
             {
             {
                 return false;
                 return false;
             }
             }

+ 91 - 6
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -27,6 +27,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Xml;
 using System.Xml;
 using CommonIO;
 using CommonIO;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
@@ -1026,6 +1027,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
 
                     result.Item3.Release();
                     result.Item3.Release();
                     isResourceOpen = false;
                     isResourceOpen = false;
+
+                    SaveNfo(timer, recordPath, seriesPath);
                 };
                 };
 
 
                 var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);
                 var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);
@@ -1071,7 +1074,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                 timer.Status = RecordingStatus.Completed;
                 timer.Status = RecordingStatus.Completed;
                 _timerProvider.Delete(timer);
                 _timerProvider.Delete(timer);
 
 
-                OnSuccessfulRecording(timer, recordPath, seriesPath);
+                OnSuccessfulRecording(timer, recordPath);
             }
             }
             else if (DateTime.UtcNow < timer.EndDate)
             else if (DateTime.UtcNow < timer.EndDate)
             {
             {
@@ -1139,7 +1142,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             return new DirectRecorder(_logger, _httpClient, _fileSystem);
             return new DirectRecorder(_logger, _httpClient, _fileSystem);
         }
         }
 
 
-        private async void OnSuccessfulRecording(TimerInfo timer, string path, string seriesPath)
+        private async void OnSuccessfulRecording(TimerInfo timer, string path)
         {
         {
             if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
             if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
             {
             {
@@ -1163,15 +1166,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                     _logger.ErrorException("Error processing new recording", ex);
                     _logger.ErrorException("Error processing new recording", ex);
                 }
                 }
             }
             }
-
-            SaveNfo(timer, path, seriesPath);
         }
         }
 
 
         private void SaveNfo(TimerInfo timer, string recordingPath, string seriesPath)
         private void SaveNfo(TimerInfo timer, string recordingPath, string seriesPath)
         {
         {
-            if (timer.IsProgramSeries)
+            try
+            {
+                if (timer.IsProgramSeries)
+                {
+                    SaveSeriesNfo(timer, recordingPath, seriesPath);
+                }
+                else if (!timer.IsMovie || timer.IsSports)
+                {
+                    SaveVideoNfo(timer, recordingPath);
+                }
+            }
+            catch (Exception ex)
             {
             {
-                SaveSeriesNfo(timer, recordingPath, seriesPath);
+                _logger.ErrorException("Error saving nfo", ex);
             }
             }
         }
         }
 
 
@@ -1209,6 +1221,79 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             }
             }
         }
         }
 
 
+        public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
+        private void SaveVideoNfo(TimerInfo timer, string recordingPath)
+        {
+            var nfoPath = Path.ChangeExtension(recordingPath, ".nfo");
+
+            if (File.Exists(nfoPath))
+            {
+                return;
+            }
+
+            using (var stream = _fileSystem.GetFileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+            {
+                var settings = new XmlWriterSettings
+                {
+                    Indent = true,
+                    Encoding = Encoding.UTF8,
+                    CloseOutput = false
+                };
+
+                using (XmlWriter writer = XmlWriter.Create(stream, settings))
+                {
+                    writer.WriteStartDocument(true);
+                    writer.WriteStartElement("movie");
+
+                    if (!string.IsNullOrWhiteSpace(timer.Name))
+                    {
+                        writer.WriteElementString("title", timer.Name);
+                    }
+
+                    writer.WriteElementString("dateadded", DateTime.UtcNow.ToLocalTime().ToString(DateAddedFormat));
+
+                    if (timer.ProductionYear.HasValue)
+                    {
+                        writer.WriteElementString("year", timer.ProductionYear.Value.ToString(CultureInfo.InvariantCulture));
+                    }
+                    if (!string.IsNullOrEmpty(timer.OfficialRating))
+                    {
+                        writer.WriteElementString("mpaa", timer.OfficialRating);
+                    }
+
+                    var overview = (timer.Overview ?? string.Empty)
+                        .StripHtml()
+                        .Replace("&quot;", "'");
+
+                    writer.WriteElementString("plot", overview);
+                    writer.WriteElementString("lockdata", true.ToString().ToLower());
+
+                    if (timer.CommunityRating.HasValue)
+                    {
+                        writer.WriteElementString("rating", timer.CommunityRating.Value.ToString(CultureInfo.InvariantCulture));
+                    }
+
+                    foreach (var genre in timer.Genres)
+                    {
+                        writer.WriteElementString("genre", genre);
+                    }
+
+                    if (!string.IsNullOrWhiteSpace(timer.ShortOverview))
+                    {
+                        writer.WriteElementString("outline", timer.ShortOverview);
+                    }
+
+                    if (!string.IsNullOrWhiteSpace(timer.HomePageUrl))
+                    {
+                        writer.WriteElementString("website", timer.HomePageUrl);
+                    }
+
+                    writer.WriteEndElement();
+                    writer.WriteEndDocument();
+                }
+            }
+        }
+
         private ProgramInfo GetProgramInfoFromCache(string channelId, string programId)
         private ProgramInfo GetProgramInfoFromCache(string channelId, string programId)
         {
         {
             var epgData = GetEpgDataForChannel(channelId);
             var epgData = GetEpgDataForChannel(channelId);

+ 5 - 0
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs

@@ -46,6 +46,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             timerInfo.EpisodeTitle = programInfo.EpisodeTitle;
             timerInfo.EpisodeTitle = programInfo.EpisodeTitle;
             timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
             timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
             timerInfo.IsProgramSeries = programInfo.IsSeries;
             timerInfo.IsProgramSeries = programInfo.IsSeries;
+
+            timerInfo.HomePageUrl = programInfo.HomePageUrl;
+            timerInfo.CommunityRating = programInfo.CommunityRating;
+            timerInfo.ShortOverview = programInfo.ShortOverview;
+            timerInfo.OfficialRating = programInfo.OfficialRating;
         }
         }
 
 
         public static string GetRecordingName(TimerInfo info)
         public static string GetRecordingName(TimerInfo info)

+ 15 - 2
MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -171,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
                                 var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
                                 var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
                                 data = data.OrderByDescending(GetSizeOrder).ToList();
                                 data = data.OrderByDescending(GetSizeOrder).ToList();
 
 
-                                programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 1280);
+                                programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 800);
                                 //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
                                 //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
                                 //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
                                 //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
                                 //    GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
                                 //    GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
@@ -536,7 +536,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
                 }
                 }
 
 
                 return false;
                 return false;
-            }) ?? matches.FirstOrDefault();
+            });
+
+            if (match == null)
+            {
+                // Get the second lowest quality image, when possible
+                if (matches.Count > 1)
+                {
+                    match = matches[matches.Count - 2];
+                }
+                else
+                {
+                    match = matches.FirstOrDefault();
+                }
+            }
 
 
             if (match == null)
             if (match == null)
             {
             {