소스 검색

Merge pull request #2145 from MediaBrowser/dev

Dev
Luke 8 년 전
부모
커밋
51f6cd999f

+ 51 - 26
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -337,9 +337,9 @@ namespace MediaBrowser.Api.Playback
         /// Gets the video bitrate to specify on the command line
         /// </summary>
         /// <param name="state">The state.</param>
-        /// <param name="videoCodec">The video codec.</param>
+        /// <param name="videoEncoder">The video codec.</param>
         /// <returns>System.String.</returns>
-        protected string GetVideoQualityParam(StreamState state, string videoCodec)
+        protected string GetVideoQualityParam(StreamState state, string videoEncoder)
         {
             var param = string.Empty;
 
@@ -348,7 +348,7 @@ namespace MediaBrowser.Api.Playback
 
             var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
 
-            if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+            if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
             {
                 if (!string.IsNullOrWhiteSpace(encodingOptions.H264Preset))
                 {
@@ -369,7 +369,7 @@ namespace MediaBrowser.Api.Playback
                 }
             }
 
-            else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
             {
                 param += "-preset fast";
 
@@ -377,20 +377,20 @@ namespace MediaBrowser.Api.Playback
             }
 
             // h264 (h264_qsv)
-            else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
             {
                 param += "-preset 7 -look_ahead 0";
 
             }
 
             // h264 (h264_nvenc)
-            else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
             {
                 param += "-preset default";
             }
 
             // webm
-            else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
             {
                 // Values 0-3, 0 being highest quality but slower
                 var profileScore = 0;
@@ -417,23 +417,23 @@ namespace MediaBrowser.Api.Playback
                     qmax);
             }
 
-            else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
             {
                 param += "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
             }
 
             // asf/wmv
-            else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
             {
                 param += "-qmin 2";
             }
 
-            else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
             {
                 param += "-mbd 2";
             }
 
-            param += GetVideoBitrateParam(state, videoCodec);
+            param += GetVideoBitrateParam(state, videoEncoder);
 
             var framerate = GetFramerateParam(state);
             if (framerate.HasValue)
@@ -448,8 +448,8 @@ namespace MediaBrowser.Api.Playback
 
             if (!string.IsNullOrEmpty(state.VideoRequest.Profile))
             {
-                if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
-                    !string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+                if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
+                    !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
                 {
                     // not supported by h264_omx
                     param += " -profile:v " + state.VideoRequest.Profile;
@@ -458,11 +458,13 @@ namespace MediaBrowser.Api.Playback
 
             if (!string.IsNullOrEmpty(state.VideoRequest.Level))
             {
+                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
-                if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
-                    string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
+                    string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
                 {
-                    switch (state.VideoRequest.Level)
+                    switch (level)
                     {
                         case "30":
                             param += " -level 3";
@@ -492,20 +494,20 @@ namespace MediaBrowser.Api.Playback
                             param += " -level 5.2";
                             break;
                         default:
-                            param += " -level " + state.VideoRequest.Level;
+                            param += " -level " + level;
                             break;
                     }
                 }
-                else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
+                else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
                 {
-                    param += " -level " + state.VideoRequest.Level;
+                    param += " -level " + level;
                 }
             }
 
-            if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
-                !string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
-                !string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
-                !string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+            if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
+                !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
+                !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
+                !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-pix_fmt yuv420p " + param;
             }
@@ -513,6 +515,25 @@ namespace MediaBrowser.Api.Playback
             return param;
         }
 
+        private string NormalizeTranscodingLevel(string videoCodec, string level)
+        {
+            double requestLevel;
+
+            // Clients may direct play higher than level 41, but there's no reason to transcode higher
+            if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
+            {
+                if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
+                {
+                    if (requestLevel > 41)
+                    {
+                        return "41";
+                    }
+                }
+            }
+
+            return level;
+        }
+
         protected string GetAudioFilterParam(StreamState state, bool isHls)
         {
             var volParam = string.Empty;
@@ -1176,17 +1197,21 @@ namespace MediaBrowser.Api.Playback
                 await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
             }
 
-            if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive)
+            if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
             {
                 await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
 
-                if (state.ReadInputAtNativeFramerate)
+                if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited)
                 {
                     await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
                 }
             }
 
-            StartThrottler(state, transcodingJob);
+            if (!transcodingJob.HasExited)
+            {
+                StartThrottler(state, transcodingJob);
+            }
+
             ReportUsage(state);
 
             return transcodingJob;

+ 2 - 0
MediaBrowser.Controller/Channels/IChannelManager.cs

@@ -31,6 +31,8 @@ namespace MediaBrowser.Controller.Channels
         /// <returns>ChannelFeatures.</returns>
         ChannelFeatures GetChannelFeatures(string id);
 
+        bool SupportsSync(string channelId);
+
         /// <summary>
         /// Gets all channel features.
         /// </summary>

+ 11 - 1
MediaBrowser.Controller/Entities/Folder.cs

@@ -1057,10 +1057,20 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>IList{BaseItem}.</returns>
         public IList<BaseItem> GetRecursiveChildren()
         {
-            return GetRecursiveChildren(i => true);
+            return GetRecursiveChildren(true);
+        }
+
+        public IList<BaseItem> GetRecursiveChildren(bool includeLinkedChildren)
+        {
+            return GetRecursiveChildren(i => true, includeLinkedChildren);
         }
 
         public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
+        {
+            return GetRecursiveChildren(filter, true);
+        }
+
+        public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter, bool includeLinkedChildren)
         {
             var result = new Dictionary<Guid, BaseItem>();
 

+ 2 - 0
MediaBrowser.Dlna/PlayTo/Device.cs

@@ -483,7 +483,9 @@ namespace MediaBrowser.Dlna.PlayTo
                 {
                     if (OnDeviceUnavailable != null)
                     {
+                        _logger.Debug("Disposing device due to loss of connection");
                         OnDeviceUnavailable();
+                        return;
                     }
                 }
                 if (_successiveStopCount >= maxSuccessiveStopReturns)

+ 41 - 20
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -595,23 +595,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
         /// Gets the video bitrate to specify on the command line
         /// </summary>
         /// <param name="state">The state.</param>
-        /// <param name="videoCodec">The video codec.</param>
+        /// <param name="videoEncoder">The video codec.</param>
         /// <returns>System.String.</returns>
-        protected string GetVideoQualityParam(EncodingJob state, string videoCodec)
+        protected string GetVideoQualityParam(EncodingJob state, string videoEncoder)
         {
             var param = string.Empty;
 
             var isVc1 = state.VideoStream != null &&
                 string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
 
-            if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+            if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-preset superfast";
 
                 param += " -crf 23";
             }
 
-            else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-preset fast";
 
@@ -619,20 +619,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
 
             // h264 (h264_qsv)
-            else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-preset 7 -look_ahead 0";
 
             }
 
             // h264 (h264_nvenc)
-            else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-preset llhq";
             }
 
             // webm
-            else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
             {
                 // Values 0-3, 0 being highest quality but slower
                 var profileScore = 0;
@@ -659,23 +659,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
                     qmax);
             }
 
-            else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
             }
 
             // asf/wmv
-            else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-qmin 2";
             }
 
-            else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
+            else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-mbd 2";
             }
 
-            param += GetVideoBitrateParam(state, videoCodec);
+            param += GetVideoBitrateParam(state, videoEncoder);
 
             var framerate = GetFramerateParam(state);
             if (framerate.HasValue)
@@ -690,8 +690,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             if (!string.IsNullOrEmpty(state.Options.Profile))
             {
-                if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
-                    !string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+                if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
+                    !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
                 {
                     // not supported by h264_omx
                     param += " -profile:v " + state.Options.Profile;
@@ -702,9 +702,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             if (!string.IsNullOrEmpty(levelString))
             {
+                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
-                if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
-                    string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
+                    string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
                 {
                     switch (levelString)
                     {
@@ -740,16 +742,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
                             break;
                     }
                 }
-                else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
+                else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
                 {
                     param += " -level " + levelString;
                 }
             }
 
-            if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
-                !string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
-                !string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
-                !string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+            if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
+                !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
+                !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
+                !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
             {
                 param = "-pix_fmt yuv420p " + param;
             }
@@ -757,6 +759,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return param;
         }
 
+        private string NormalizeTranscodingLevel(string videoCodec, string level)
+        {
+            double requestLevel;
+
+            // Clients may direct play higher than level 41, but there's no reason to transcode higher
+            if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
+            {
+                if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
+                {
+                    if (requestLevel > 41)
+                    {
+                        return "41";
+                    }
+                }
+            }
+
+            return level;
+        }
+
         protected string GetVideoBitrateParam(EncodingJob state, string videoCodec)
         {
             var bitrate = state.OutputVideoBitrate;

+ 2 - 0
MediaBrowser.Model/LiveTv/LiveTvOptions.cs

@@ -13,6 +13,7 @@ namespace MediaBrowser.Model.LiveTv
         public string SeriesRecordingPath { get; set; }
         public bool EnableAutoOrganize { get; set; }
         public bool EnableRecordingEncoding { get; set; }
+        public string RecordingEncodingFormat { get; set; }
         public bool EnableRecordingSubfolders { get; set; }
         public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
 
@@ -31,6 +32,7 @@ namespace MediaBrowser.Model.LiveTv
             TunerHosts = new List<TunerHostInfo>();
             ListingProviders = new List<ListingsProviderInfo>();
             MediaLocationsCreated = new string[] { };
+            RecordingEncodingFormat = "mp4";
         }
     }
 

+ 31 - 0
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -530,6 +530,19 @@ namespace MediaBrowser.Server.Implementations.Channels
             return GetChannelFeaturesDto(channel, channelProvider, channelProvider.GetChannelFeatures());
         }
 
+        public bool SupportsSync(string channelId)
+        {
+            if (string.IsNullOrWhiteSpace(channelId))
+            {
+                throw new ArgumentNullException("channelId");
+            }
+
+            //var channel = GetChannel(channelId);
+            var channelProvider = GetChannelProvider(channelId);
+
+            return channelProvider.GetChannelFeatures().SupportsContentDownloading;
+        }
+
         public ChannelFeatures GetChannelFeaturesDto(Channel channel,
             IChannel provider,
             InternalChannelFeatures features)
@@ -1450,6 +1463,24 @@ namespace MediaBrowser.Server.Implementations.Channels
             return result;
         }
 
+        internal IChannel GetChannelProvider(string internalChannelId)
+        {
+            if (internalChannelId == null)
+            {
+                throw new ArgumentNullException("internalChannelId");
+            }
+
+            var result = GetAllChannels()
+                .FirstOrDefault(i => string.Equals(GetInternalChannelId(i.Name).ToString("N"), internalChannelId, StringComparison.OrdinalIgnoreCase));
+
+            if (result == null)
+            {
+                throw new ResourceNotFoundException("No channel provider found for channel id " + internalChannelId);
+            }
+
+            return result;
+        }
+
         private IEnumerable<BaseItem> ApplyFilters(IEnumerable<BaseItem> items, IEnumerable<ItemFilter> filters, User user)
         {
             foreach (var filter in filters.OrderByDescending(f => (int)f))

+ 1 - 1
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.Library
             var locationType = item.LocationType;
 
             var children = item.IsFolder
-                ? ((Folder)item).GetRecursiveChildren().ToList()
+                ? ((Folder)item).GetRecursiveChildren(false).ToList()
                 : new List<BaseItem>();
 
             foreach (var metadataPath in GetMetadataPaths(item, children))

+ 17 - 7
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs

@@ -46,9 +46,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             _httpClient = httpClient;
         }
 
+        private string OutputFormat
+        {
+            get
+            {
+                var format = _liveTvOptions.RecordingEncodingFormat;
+
+                if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "mkv";
+                }
+
+                return "mp4";
+            }
+        }
+
         public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
         {
-            return Path.ChangeExtension(targetFile, ".mp4");
+            return Path.ChangeExtension(targetFile, "." + OutputFormat);
         }
 
         public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
@@ -233,15 +248,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         private string GetAudioArgs(MediaSourceInfo mediaSource)
         {
-            // do not copy aac because many players have difficulty with aac_latm
-            var copyAudio = new[] { "mp3" };
             var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
             var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty;
 
-            if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase))
-            {
-                return "-codec:a:0 copy";
-            }
+            // do not copy aac because many players have difficulty with aac_latm
             if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
             {
                 return "-codec:a:0 copy";

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

@@ -785,9 +785,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
             get { return "Schedules Direct"; }
         }
 
+        public static string TypeName = "SchedulesDirect";
         public string Type
         {
-            get { return "SchedulesDirect"; }
+            get { return TypeName; }
         }
 
         private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)

+ 13 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -35,6 +35,7 @@ using MediaBrowser.Common.Security;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Model.Events;
+using MediaBrowser.Server.Implementations.LiveTv.Listings;
 
 namespace MediaBrowser.Server.Implementations.LiveTv
 {
@@ -1436,7 +1437,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             {
                 if (query.IsMovie.Value)
                 {
-                    includeItemTypes.Add(typeof (Movie).Name);
+                    includeItemTypes.Add(typeof(Movie).Name);
                 }
                 else
                 {
@@ -2802,6 +2803,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 feature = "embytvseriesrecordings";
             }
 
+            var config = GetConfiguration();
+            if (config.TunerHosts.Count(i => i.IsEnabled) > 0 &&
+                config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
+            {
+                return Task.FromResult(new MBRegistrationRecord
+                {
+                    IsRegistered = true,
+                    IsValid = true
+                });
+            }
+
             return _security.GetRegistrationStatus(feature);
         }
 

+ 5 - 0
MediaBrowser.Server.Implementations/Sync/SyncManager.cs

@@ -541,6 +541,11 @@ namespace MediaBrowser.Server.Implementations.Sync
                 return true;
             }
 
+            if (item.SourceType == SourceType.Channel)
+            {
+                return BaseItem.ChannelManager.SupportsSync(item.ChannelId);
+            }
+
             return item.LocationType == LocationType.FileSystem || item is Season;
         }
 

+ 5 - 3
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -363,7 +363,10 @@ namespace MediaBrowser.Server.Startup.Common
 
         private void PerformPreInitMigrations()
         {
-            var migrations = new List<IVersionMigration>();
+            var migrations = new List<IVersionMigration>
+            {
+                new UpdateLevelMigration(ServerConfigurationManager, this, HttpClient, JsonSerializer, _releaseAssetFilename)
+            };
 
             foreach (var task in migrations)
             {
@@ -383,8 +386,7 @@ namespace MediaBrowser.Server.Startup.Common
             var migrations = new List<IVersionMigration>
             {
                 new MovieDbEpisodeProviderMigration(ServerConfigurationManager),
-                new DbMigration(ServerConfigurationManager, TaskManager),
-                new UpdateLevelMigration(ServerConfigurationManager, this, HttpClient, JsonSerializer, _releaseAssetFilename)
+                new DbMigration(ServerConfigurationManager, TaskManager)
             };
 
             foreach (var task in migrations)

+ 1 - 1
MediaBrowser.ServerApplication/MainStartup.cs

@@ -331,7 +331,7 @@ namespace MediaBrowser.ServerApplication
             Application.Run();
         }
 
-        private static SplashForm _splash;
+        internal static SplashForm _splash;
         private static Thread _splashThread;
         private static void ShowSplashScreen(Version appVersion, Progress<double> progress, ILogger logger)
         {

+ 7 - 2
MediaBrowser.ServerApplication/Native/WindowsApp.cs

@@ -212,7 +212,12 @@ namespace MediaBrowser.ServerApplication.Native
 
         private bool Confirm()
         {
-            return MessageBox.Show("Emby has detected that Windows Firewall has been configured in a way that may prevent your other devices from accessing Emby Server. Click OK to remove this rule, or cancel to proceed anyway.", "Windows Firewall", MessageBoxButtons.OKCancel) == DialogResult.OK;
+            if (MainStartup._splash == null)
+            {
+                return false;
+            }
+
+            return MessageBox.Show(MainStartup._splash, "Emby has detected that Windows Firewall has been configured in a way that may prevent your other devices from accessing Emby Server. Click OK to remove this rule, or cancel to proceed anyway.", "Windows Firewall", MessageBoxButtons.OKCancel) == DialogResult.OK;
         }
 
         public bool PortsRequireAuthorization(string applicationPath)
@@ -242,7 +247,7 @@ namespace MediaBrowser.ServerApplication.Native
 
                     if (data.IndexOf("Block", StringComparison.OrdinalIgnoreCase) != -1)
                     {
-                        _logger.Info("Found windows firewall rule: " + data);
+                        _logger.Info("Found potential windows firewall rule blocking Emby Server: " + data);
                         return Confirm();
                     }