Browse Source

Merge pull request #2240 from MediaBrowser/beta

Beta
Luke 8 years ago
parent
commit
fb9db5c3c3
30 changed files with 228 additions and 85 deletions
  1. 8 0
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  2. 11 5
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  3. 1 0
      MediaBrowser.Api/Playback/StreamRequest.cs
  4. 83 12
      MediaBrowser.Controller/Entities/BaseItem.cs
  5. 1 1
      MediaBrowser.Controller/Entities/InternalItemsQuery.cs
  6. 1 1
      MediaBrowser.Controller/Entities/Movies/Movie.cs
  7. 2 2
      MediaBrowser.Controller/Entities/Video.cs
  8. 5 1
      MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
  9. 5 1
      MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
  10. 2 0
      MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
  11. 5 0
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  12. 1 0
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  13. 2 0
      MediaBrowser.Model/Dlna/StreamInfo.cs
  14. 3 0
      MediaBrowser.Model/Dlna/TranscodingProfile.cs
  15. 13 2
      MediaBrowser.Model/Entities/MediaStream.cs
  16. 32 20
      MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  17. 8 1
      MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
  18. 1 0
      MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
  19. 6 0
      MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
  20. 2 2
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  21. 4 5
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  22. 4 0
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
  23. 1 1
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
  24. 6 7
      MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
  25. 5 2
      MediaBrowser.Server.Implementations/Session/SessionManager.cs
  26. 3 3
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
  27. 8 14
      MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
  28. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  29. 1 1
      Nuget/MediaBrowser.Common.nuspec
  30. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

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

@@ -1735,6 +1735,13 @@ namespace MediaBrowser.Api.Playback
                 {
                     request.Tag = val;
                 }
+                else if (i == 29)
+                {
+                    if (videoRequest != null)
+                    {
+                        videoRequest.EnableSplittingOnNonKeyFrames = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+                    }
+                }
             }
         }
 
@@ -2354,6 +2361,7 @@ namespace MediaBrowser.Api.Playback
                     {
                         state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps;
                         state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
+                        state.VideoRequest.EnableSplittingOnNonKeyFrames = transcodingProfile.EnableSplittingOnNonKeyFrames;
                     }
                 }
             }

+ 11 - 5
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -885,14 +885,17 @@ namespace MediaBrowser.Api.Playback.Hls
             }
 
             var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;
+            var enableSplittingOnNonKeyFrames = state.VideoRequest.EnableSplittingOnNonKeyFrames && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase);
+            enableSplittingOnNonKeyFrames = false;
 
-            var enableGenericSegmenter = false;
+            // TODO: check libavformat version for 57 50.100 and use -hls_flags split_by_time
+            var hlsProtocolSupportsSplittingByTime = false;
 
-            if (enableGenericSegmenter)
+            if (enableSplittingOnNonKeyFrames && !hlsProtocolSupportsSplittingByTime)
             {
                 var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
 
-                return string.Format("{0} {10} {1} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
+                return string.Format("{0} {10} {1} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -break_non_keyframes  1 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
                     inputModifier,
                     GetInputArgument(state),
                     threads,
@@ -907,8 +910,10 @@ 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}\"",
+            var splitByTime = hlsProtocolSupportsSplittingByTime && enableSplittingOnNonKeyFrames;
+            var splitByTimeArg = splitByTime ? " -hls_flags split_by_time" : "";
+
+            return string.Format("{0}{12} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7}{8} -start_number {9} -hls_list_size {10} -y \"{11}\"",
                             inputModifier,
                             GetInputArgument(state),
                             threads,
@@ -917,6 +922,7 @@ namespace MediaBrowser.Api.Playback.Hls
                             timestampOffsetParam,
                             GetAudioArguments(state),
                             state.SegmentLength.ToString(UsCulture),
+                            splitByTimeArg,
                             startNumberParam,
                             state.HlsListSize.ToString(UsCulture),
                             outputPath,

+ 1 - 0
MediaBrowser.Api/Playback/StreamRequest.cs

@@ -194,6 +194,7 @@ namespace MediaBrowser.Api.Playback
         public bool CopyTimestamps { get; set; }
 
         public bool EnableSubtitlesInManifest { get; set; }
+        public bool EnableSplittingOnNonKeyFrames { get; set; }
 
         public VideoStreamRequest()
         {

+ 83 - 12
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -1188,7 +1188,7 @@ namespace MediaBrowser.Controller.Entities
 
             var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
 
-            var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken));
+            var tasks = newItems.Select(i => RefreshMetadataForOwnedItem(i, true, options, cancellationToken));
 
             await Task.WhenAll(tasks).ConfigureAwait(false);
 
@@ -1197,7 +1197,7 @@ namespace MediaBrowser.Controller.Entities
             return itemsChanged;
         }
 
-        private static async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
+        private async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
 
@@ -1215,7 +1215,7 @@ namespace MediaBrowser.Controller.Entities
                     subOptions.ForceSave = true;
                 }
 
-                return i.RefreshMetadata(subOptions, cancellationToken);
+                return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
             });
 
             await Task.WhenAll(tasks).ConfigureAwait(false);
@@ -1228,7 +1228,7 @@ namespace MediaBrowser.Controller.Entities
         /// <summary>
         /// Refreshes the theme songs.
         /// </summary>
-        private static async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
+        private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
             var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
@@ -1245,7 +1245,7 @@ namespace MediaBrowser.Controller.Entities
                     subOptions.ForceSave = true;
                 }
 
-                return i.RefreshMetadata(subOptions, cancellationToken);
+                return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
             });
 
             await Task.WhenAll(tasks).ConfigureAwait(false);
@@ -2203,14 +2203,85 @@ namespace MediaBrowser.Controller.Entities
             return Task.FromResult(true);
         }
 
-        protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, string path, CancellationToken cancellationToken)
+        protected Task RefreshMetadataForOwnedItem(BaseItem ownedItem, bool copyTitleMetadata, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
-            var newOptions = new MetadataRefreshOptions(options.DirectoryService)
+            var newOptions = new MetadataRefreshOptions(options);
+            newOptions.SearchResult = null;
+
+            var item = this;
+
+            if (copyTitleMetadata)
             {
-                ImageRefreshMode = options.ImageRefreshMode,
-                MetadataRefreshMode = options.MetadataRefreshMode,
-                ReplaceAllMetadata = options.ReplaceAllMetadata
-            };
+                // Take some data from the main item, for querying purposes
+                if (!item.Genres.SequenceEqual(ownedItem.Genres, StringComparer.Ordinal))
+                {
+                    newOptions.ForceSave = true;
+                    ownedItem.Genres = item.Genres.ToList();
+                }
+                if (!item.Studios.SequenceEqual(ownedItem.Studios, StringComparer.Ordinal))
+                {
+                    newOptions.ForceSave = true;
+                    ownedItem.Studios = item.Studios.ToList();
+                }
+                if (!item.ProductionLocations.SequenceEqual(ownedItem.ProductionLocations, StringComparer.Ordinal))
+                {
+                    newOptions.ForceSave = true;
+                    ownedItem.ProductionLocations = item.ProductionLocations.ToList();
+                }
+                if (!item.Keywords.SequenceEqual(ownedItem.Keywords, StringComparer.Ordinal))
+                {
+                    newOptions.ForceSave = true;
+                    ownedItem.Keywords = item.Keywords.ToList();
+                }
+                if (item.CommunityRating != ownedItem.CommunityRating)
+                {
+                    ownedItem.CommunityRating = item.CommunityRating;
+                    newOptions.ForceSave = true;
+                }
+                if (item.CriticRating != ownedItem.CriticRating)
+                {
+                    ownedItem.CriticRating = item.CriticRating;
+                    newOptions.ForceSave = true;
+                }
+                if (!string.Equals(item.Overview, ownedItem.Overview, StringComparison.Ordinal))
+                {
+                    ownedItem.Overview = item.Overview;
+                    newOptions.ForceSave = true;
+                }
+                if (!string.Equals(item.ShortOverview, ownedItem.ShortOverview, StringComparison.Ordinal))
+                {
+                    ownedItem.ShortOverview = item.ShortOverview;
+                    newOptions.ForceSave = true;
+                }
+                if (!string.Equals(item.OfficialRating, ownedItem.OfficialRating, StringComparison.Ordinal))
+                {
+                    ownedItem.OfficialRating = item.OfficialRating;
+                    newOptions.ForceSave = true;
+                }
+                if (!string.Equals(item.CustomRating, ownedItem.CustomRating, StringComparison.Ordinal))
+                {
+                    ownedItem.CustomRating = item.CustomRating;
+                    newOptions.ForceSave = true;
+                }
+                if (!string.Equals(item.CriticRatingSummary, ownedItem.CriticRatingSummary, StringComparison.Ordinal))
+                {
+                    ownedItem.CriticRatingSummary = item.CriticRatingSummary;
+                    newOptions.ForceSave = true;
+                }
+                if (!string.Equals(item.OfficialRatingDescription, ownedItem.OfficialRatingDescription, StringComparison.Ordinal))
+                {
+                    ownedItem.OfficialRatingDescription = item.OfficialRatingDescription;
+                    newOptions.ForceSave = true;
+                }
+            }
+
+            return ownedItem.RefreshMetadata(newOptions, cancellationToken);
+        }
+
+        protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, bool copyTitleMetadata, string path, CancellationToken cancellationToken)
+        {
+            var newOptions = new MetadataRefreshOptions(options);
+            newOptions.SearchResult = null;
 
             var id = LibraryManager.GetNewItemId(path, typeof(Video));
 
@@ -2229,7 +2300,7 @@ namespace MediaBrowser.Controller.Entities
                 return Task.FromResult(true);
             }
 
-            return video.RefreshMetadata(newOptions, cancellationToken);
+            return RefreshMetadataForOwnedItem(video, copyTitleMetadata, newOptions, cancellationToken);
         }
 
         public string GetEtag(User user)

+ 1 - 1
MediaBrowser.Controller/Entities/InternalItemsQuery.cs

@@ -182,7 +182,7 @@ namespace MediaBrowser.Controller.Entities
                 case ItemFields.HomePageUrl:
                 case ItemFields.VoteCount:
                 case ItemFields.DisplayMediaType:
-                case ItemFields.ServiceName:
+                //case ItemFields.ServiceName:
                 case ItemFields.Genres:
                 case ItemFields.Studios:
                 case ItemFields.Settings:

+ 1 - 1
MediaBrowser.Controller/Entities/Movies/Movie.cs

@@ -103,7 +103,7 @@ namespace MediaBrowser.Controller.Entities.Movies
 
             var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
 
-            var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken));
+            var tasks = newItems.Select(i => RefreshMetadataForOwnedItem(i, false, options, cancellationToken));
 
             await Task.WhenAll(tasks).ConfigureAwait(false);
 

+ 2 - 2
MediaBrowser.Controller/Entities/Video.cs

@@ -427,7 +427,7 @@ namespace MediaBrowser.Controller.Entities
             if (IsStacked)
             {
                 var tasks = AdditionalParts
-                    .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken));
+                    .Select(i => RefreshMetadataForOwnedVideo(options, true, i, cancellationToken));
 
                 await Task.WhenAll(tasks).ConfigureAwait(false);
             }
@@ -442,7 +442,7 @@ namespace MediaBrowser.Controller.Entities
                     RefreshLinkedAlternateVersions();
 
                     var tasks = LocalAlternateVersions
-                        .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken));
+                        .Select(i => RefreshMetadataForOwnedVideo(options, false, i, cancellationToken));
 
                     await Task.WhenAll(tasks).ConfigureAwait(false);
                 }

+ 5 - 1
MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs

@@ -113,7 +113,11 @@ namespace MediaBrowser.Controller.LiveTv
 
         public override bool CanDelete()
         {
-            return Status == RecordingStatus.Completed;
+            if (string.Equals(ServiceName, "Emby", StringComparison.OrdinalIgnoreCase))
+            {
+                return Status == RecordingStatus.Completed;
+            }
+            return true;
         }
 
         public override bool IsAuthorizedToDelete(User user)

+ 5 - 1
MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs

@@ -130,7 +130,11 @@ namespace MediaBrowser.Controller.LiveTv
 
         public override bool CanDelete()
         {
-            return Status == RecordingStatus.Completed;
+            if (string.Equals(ServiceName, "Emby", StringComparison.OrdinalIgnoreCase))
+            {
+                return Status == RecordingStatus.Completed;
+            }
+            return true;
         }
 
         public override bool IsAuthorizedToDelete(User user)

+ 2 - 0
MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs

@@ -154,6 +154,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 }
             };
 
+            _logger.Info("Running {0} {1}", path, arguments);
+
             using (process)
             {
                 process.Start();

+ 5 - 0
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -610,6 +610,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
         {
             if (video.Protocol != MediaProtocol.File)
             {
+                // If it's mpeg based, assume true
+                if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1)
+                {
+                    return true;
+                }
                 return false;
             }
 

+ 1 - 0
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -478,6 +478,7 @@ namespace MediaBrowser.Model.Dlna
                 playlistItem.VideoCodec = transcodingProfile.VideoCodec;
                 playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps;
                 playlistItem.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
+                playlistItem.EnableSplittingOnNonKeyFrames = transcodingProfile.EnableSplittingOnNonKeyFrames;
 
                 if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels))
                 {

+ 2 - 0
MediaBrowser.Model/Dlna/StreamInfo.cs

@@ -37,6 +37,7 @@ namespace MediaBrowser.Model.Dlna
 
         public bool CopyTimestamps { get; set; }
         public bool EnableSubtitlesInManifest { get; set; }
+        public bool EnableSplittingOnNonKeyFrames { get; set; }
         public string[] AudioCodecs { get; set; }
 
         public int? AudioStreamIndex { get; set; }
@@ -264,6 +265,7 @@ namespace MediaBrowser.Model.Dlna
             list.Add(new NameValuePair("EnableSubtitlesInManifest", item.EnableSubtitlesInManifest.ToString().ToLower()));
 
             list.Add(new NameValuePair("Tag", item.MediaSource.ETag ?? string.Empty));
+            list.Add(new NameValuePair("EnableSplittingOnNonKeyFrames", item.EnableSplittingOnNonKeyFrames.ToString().ToLower()));
 
             return list;
         }

+ 3 - 0
MediaBrowser.Model/Dlna/TranscodingProfile.cs

@@ -38,6 +38,9 @@ namespace MediaBrowser.Model.Dlna
         [XmlAttribute("enableSubtitlesInManifest")]
         public bool EnableSubtitlesInManifest { get; set; }
 
+        [XmlAttribute("enableSplittingOnNonKeyFrames")]
+        public bool EnableSplittingOnNonKeyFrames { get; set; }
+
         [XmlAttribute("maxAudioChannels")]
         public string MaxAudioChannels { get; set; }
 

+ 13 - 2
MediaBrowser.Model/Entities/MediaStream.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Extensions;
 using System.Diagnostics;
@@ -47,7 +48,7 @@ namespace MediaBrowser.Model.Entities
             {
                 if (!string.IsNullOrEmpty(Title))
                 {
-                    return Title;
+                    return AddLanguageIfNeeded(Title);
                 }
 
                 if (Type == MediaStreamType.Audio)
@@ -115,6 +116,16 @@ namespace MediaBrowser.Model.Entities
             }
         }
 
+        private string AddLanguageIfNeeded(string title)
+        {
+            if (!string.IsNullOrEmpty(Language) && title.IndexOf(Language, StringComparison.OrdinalIgnoreCase) == -1)
+            {
+                title = StringHelper.FirstToUpper(Language) + " " + title;
+            }
+
+            return title;
+        }
+
         public string NalLengthSize { get; set; }
 
         /// <summary>

+ 32 - 20
MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -122,43 +122,55 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
             var identifier = string.IsNullOrWhiteSpace(usn) ? nt : usn;
 
-            if (info.Location != null && !_usnsHandled.Contains(identifier))
+            if (info.Location == null)
             {
+                return;
+            }
+
+            lock (_usnsHandled)
+            {
+                if (_usnsHandled.Contains(identifier))
+                {
+                    return;
+                }
                 _usnsHandled.Add(identifier);
+            }
 
-                _logger.Debug("Calling Nat.Handle on " + identifier);
+            _logger.Debug("Calling Nat.Handle on " + identifier);
 
-                IPAddress address;
-                if (IPAddress.TryParse(info.Location.Host, out address))
-                {
-                    // The Handle method doesn't need the port
-                    var endpoint = new IPEndPoint(address, info.Location.Port);
+            IPAddress address;
+            if (IPAddress.TryParse(info.Location.Host, out address))
+            {
+                // The Handle method doesn't need the port
+                var endpoint = new IPEndPoint(address, info.Location.Port);
 
-                    IPAddress localAddress = null;
+                IPAddress localAddress = null;
 
-                    try
-                    {
-                        var localAddressString = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
+                try
+                {
+                    var localAddressString = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
 
-                        if (!IPAddress.TryParse(localAddressString, out localAddress))
-                        {
-                            return;
-                        }
-                    }
-                    catch
+                    if (!IPAddress.TryParse(localAddressString, out localAddress))
                     {
                         return;
                     }
-
-                    NatUtility.Handle(localAddress, info, endpoint, NatProtocol.Upnp);
                 }
+                catch
+                {
+                    return;
+                }
+
+                NatUtility.Handle(localAddress, info, endpoint, NatProtocol.Upnp);
             }
         }
 
         private void ClearCreatedRules(object state)
         {
             _createdRules = new List<string>();
-            _usnsHandled = new List<string>();
+            lock (_usnsHandled)
+            {
+                _usnsHandled.Clear();
+            }
         }
 
         void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)

+ 8 - 1
MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs

@@ -66,10 +66,12 @@ namespace MediaBrowser.Server.Implementations.Intros
             var candidates = new List<ItemWithTrailer>();
 
             var trailerTypes = new List<TrailerType>();
+            var sourceTypes = new List<SourceType>();
 
             if (config.EnableIntrosFromMoviesInLibrary)
             {
                 trailerTypes.Add(TrailerType.LocalTrailer);
+                sourceTypes.Add(SourceType.Library);
             }
 
             if (IsSupporter)
@@ -77,18 +79,22 @@ namespace MediaBrowser.Server.Implementations.Intros
                 if (config.EnableIntrosFromUpcomingTrailers)
                 {
                     trailerTypes.Add(TrailerType.ComingSoonToTheaters);
+                    sourceTypes.Clear();
                 }
                 if (config.EnableIntrosFromUpcomingDvdMovies)
                 {
                     trailerTypes.Add(TrailerType.ComingSoonToDvd);
+                    sourceTypes.Clear();
                 }
                 if (config.EnableIntrosFromUpcomingStreamingMovies)
                 {
                     trailerTypes.Add(TrailerType.ComingSoonToStreaming);
+                    sourceTypes.Clear();
                 }
                 if (config.EnableIntrosFromSimilarMovies)
                 {
                     trailerTypes.Add(TrailerType.Archive);
+                    sourceTypes.Clear();
                 }
             }
 
@@ -102,7 +108,8 @@ namespace MediaBrowser.Server.Implementations.Intros
                     IsPlayed = config.EnableIntrosForWatchedContent ? (bool?)null : false,
                     MaxParentalRating = config.EnableIntrosParentalControl ? ratingLevel : null,
                     BlockUnratedItems = config.EnableIntrosParentalControl ? new[] { UnratedItem.Trailer } : new UnratedItem[] { },
-                    Limit = config.TrailerLimit
+                    Limit = config.TrailerLimit,
+                    SourceTypes = sourceTypes.ToArray()
                 });
 
                 candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer

+ 1 - 0
MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs

@@ -360,6 +360,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
         public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
         {
+            enableAutoClose = false;
             await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
             try

+ 6 - 0
MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs

@@ -85,6 +85,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
                 {
                     if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
                     {
+                        if (args.Parent.IsRoot)
+                        {
+                            // For now, return null, but if we want to allow this in the future then add some additional checks to guard against a misplaced tvshow.nfo
+                            return null;
+                        }
+
                         return new Series
                         {
                             Path = args.Path,

+ 2 - 2
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -741,7 +741,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 PostPaddingSeconds = Math.Max(config.PostPaddingSeconds, 0),
                 PrePaddingSeconds = Math.Max(config.PrePaddingSeconds, 0),
-                RecordAnyChannel = true,
+                RecordAnyChannel = false,
                 RecordAnyTime = true,
                 RecordNewOnly = true,
 
@@ -764,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                 defaults.RecordNewOnly = !program.IsRepeat;
             }
 
-            defaults.SkipEpisodesInLibrary = true;
+            defaults.SkipEpisodesInLibrary = defaults.RecordNewOnly;
             defaults.KeepUntil = KeepUntil.UntilDeleted;
 
             return Task.FromResult(defaults);

+ 4 - 5
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -1752,7 +1752,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
         {
-            var recordingTuples = new List<Tuple<BaseItemDto, string, string, string>>();
+            var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
 
             foreach (var tuple in tuples)
             {
@@ -1812,18 +1812,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                     }
                 }
 
-                var service = GetService(program);
-                var serviceName = service == null ? null : service.Name;
+                var serviceName = program.ServiceName;
 
                 if (fields.Contains(ItemFields.ServiceName))
                 {
                     dto.ServiceName = serviceName;
                 }
 
-                recordingTuples.Add(new Tuple<BaseItemDto, string, string, string>(dto, serviceName, program.ExternalId, program.ExternalSeriesIdLegacy));
+                programTuples.Add(new Tuple<BaseItemDto, string, string, string>(dto, serviceName, program.ExternalId, program.ExternalSeriesIdLegacy));
             }
 
-            await AddRecordingInfo(recordingTuples, CancellationToken.None).ConfigureAwait(false);
+            await AddRecordingInfo(programTuples, CancellationToken.None).ConfigureAwait(false);
         }
 
         public void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, User user = null)

+ 4 - 0
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -114,6 +114,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
                 {
                     protocol = MediaProtocol.Rtsp;
                 }
+                else if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
+                {
+                    protocol = MediaProtocol.Udp;
+                }
 
                 var mediaSource = new MediaSourceInfo
                 {

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

@@ -114,8 +114,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
             channel.ImageUrl = FindProperty("tvg-logo", extInf, null);
             channel.Number = FindProperty("channel-id", extInf, channel.Number);
             channel.Number = FindProperty("tvg-id", extInf, channel.Number);
-            channel.Name = FindProperty("tvg-name", extInf, channel.Name);
             channel.Name = FindProperty("tvg-id", extInf, channel.Name);
+            channel.Name = FindProperty("tvg-name", extInf, channel.Name);
             return channel;
 
         }

+ 6 - 7
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -1188,7 +1188,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
         public ItemImageInfo ItemImageInfoFromValueString(string value)
         {
-            var parts = value.Split(new[] { '*' }, StringSplitOptions.RemoveEmptyEntries);
+            var parts = value.Split(new[] { '*' }, StringSplitOptions.None);
 
             var image = new ItemImageInfo();
 
@@ -1633,14 +1633,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             index++;
 
-            if (query.HasField(ItemFields.ServiceName))
+            // TODO: Even if not needed by apps, the server needs it internally
+            // But get this excluded from contexts where it is not needed
+            if (!reader.IsDBNull(index))
             {
-                if (!reader.IsDBNull(index))
-                {
-                    item.ServiceName = reader.GetString(index);
-                }
-                index++;
+                item.ServiceName = reader.GetString(index);
             }
+            index++;
 
             if (!reader.IsDBNull(index))
             {

+ 5 - 2
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -633,9 +633,12 @@ namespace MediaBrowser.Server.Implementations.Session
             data.PlayCount++;
             data.LastPlayedDate = DateTime.UtcNow;
 
-            if (!(item is Video) && item.SupportsPlayedStatus)
+            if (item.SupportsPlayedStatus)
             {
-                data.Played = true;
+                if (!(item is Video))
+                {
+                    data.Played = true;
+                }
             }
             else
             {

+ 3 - 3
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -164,6 +164,9 @@
     <Content Include="dashboard-ui\components\guestinviter\guestinviter.template.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\components\iap.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\components\libraryoptionseditor\libraryoptionseditor.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -515,9 +518,6 @@
     <Content Include="dashboard-ui\scripts\photos.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\scripts\registrationservices.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\scripts\reports.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>

+ 8 - 14
MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs

@@ -449,10 +449,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 writer.WriteElementString("plot", overview);
             }
 
-            var hasShortOverview = item as IHasShortOverview;
-            if (hasShortOverview != null)
+            if (item is Video)
             {
-                var outline = (hasShortOverview.ShortOverview ?? string.Empty)
+                var outline = (item.ShortOverview ?? string.Empty)
                     .StripHtml()
                     .Replace("&quot;", "'");
 
@@ -658,19 +657,14 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 }
             }
 
-            var hasCriticRating = item as IHasCriticRating;
-
-            if (hasCriticRating != null)
+            if (item.CriticRating.HasValue)
             {
-                if (hasCriticRating.CriticRating.HasValue)
-                {
-                    writer.WriteElementString("criticrating", hasCriticRating.CriticRating.Value.ToString(UsCulture));
-                }
+                writer.WriteElementString("criticrating", item.CriticRating.Value.ToString(UsCulture));
+            }
 
-                if (!string.IsNullOrEmpty(hasCriticRating.CriticRatingSummary))
-                {
-                    writer.WriteElementString("criticratingsummary", hasCriticRating.CriticRatingSummary);
-                }
+            if (!string.IsNullOrEmpty(item.CriticRatingSummary))
+            {
+                writer.WriteElementString("criticratingsummary", item.CriticRatingSummary);
             }
 
             var hasDisplayOrder = item as IHasDisplayOrder;

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.662</version>
+        <version>3.0.663</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.662" />
+            <dependency id="MediaBrowser.Common" version="3.0.663" />
             <dependency id="NLog" version="4.3.8" />
             <dependency id="SimpleInjector" version="3.2.2" />
         </dependencies>

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.662</version>
+        <version>3.0.663</version>
         <title>MediaBrowser.Common</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.662</version>
+        <version>3.0.663</version>
         <title>Media Browser.Server.Core</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Emby Server.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.662" />
+            <dependency id="MediaBrowser.Common" version="3.0.663" />
 			<dependency id="Interfaces.IO" version="1.0.0.5" />
         </dependencies>
     </metadata>