From 6ea8e7868df95cea54216a5dbf927b3b4069bde5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 3 Jul 2017 13:16:01 -0400 Subject: [PATCH 1/2] add live stream params --- .../Library/MediaSourceManager.cs | 2 +- .../LiveTv/LiveTvManager.cs | 47 ++++++++++++++----- .../Playback/Hls/DynamicHlsService.cs | 5 ++ MediaBrowser.Api/Playback/MediaInfoService.cs | 2 +- MediaBrowser.Model/Dlna/StreamBuilder.cs | 29 ++++++++++-- .../MediaInfo/LiveStreamRequest.cs | 4 +- .../MediaInfo/PlaybackInfoRequest.cs | 4 +- MediaBrowser.Model/Session/TranscodingInfo.cs | 3 +- .../Music/ArtistMetadataService.cs | 23 ++++----- .../Playlists/PlaylistMetadataService.cs | 32 ++++++++++++- 10 files changed, 111 insertions(+), 40 deletions(-) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index e4bc2962b..c1360c887 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -371,7 +371,7 @@ namespace Emby.Server.Implementations.Library var tuple = GetProvider(request.OpenToken); var provider = tuple.Item1; - var mediaSourceTuple = await provider.OpenMediaSource(tuple.Item2, request.AllowMediaProbe, cancellationToken).ConfigureAwait(false); + var mediaSourceTuple = await provider.OpenMediaSource(tuple.Item2, request.EnableMediaProbe, cancellationToken).ConfigureAwait(false); var mediaSource = mediaSourceTuple.Item1; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 24afc03da..bf11b7d3a 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1514,7 +1514,7 @@ namespace Emby.Server.Implementations.LiveTv } private DateTime _lastRecordingRefreshTime; - private async Task RefreshRecordings(CancellationToken cancellationToken) + private async Task RefreshRecordings(Guid internalLiveTvFolderId, CancellationToken cancellationToken) { const int cacheMinutes = 2; @@ -1542,10 +1542,8 @@ namespace Emby.Server.Implementations.LiveTv }); var results = await Task.WhenAll(tasks).ConfigureAwait(false); - var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); - var parentFolderId = folder.Id; - var recordingTasks = results.SelectMany(i => i.ToList()).Select(i => CreateRecordingRecord(i.Item1, i.Item2.Name, parentFolderId, cancellationToken)); + var recordingTasks = results.SelectMany(i => i.ToList()).Select(i => CreateRecordingRecord(i.Item1, i.Item2.Name, internalLiveTvFolderId, cancellationToken)); var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false); @@ -1559,7 +1557,7 @@ namespace Emby.Server.Implementations.LiveTv } } - private QueryResult GetEmbyRecordings(RecordingQuery query, DtoOptions dtoOptions, User user) + private QueryResult GetEmbyRecordings(RecordingQuery query, DtoOptions dtoOptions, Guid internalLiveTvFolderId, User user) { if (user == null) { @@ -1571,21 +1569,31 @@ namespace Emby.Server.Implementations.LiveTv return new QueryResult(); } - var folders = EmbyTV.EmbyTV.Current.GetRecordingFolders() + var folderIds = EmbyTV.EmbyTV.Current.GetRecordingFolders() .SelectMany(i => i.Locations) .Distinct(StringComparer.OrdinalIgnoreCase) .Select(i => _libraryManager.FindByPath(i, true)) .Where(i => i != null) .Where(i => i.IsVisibleStandalone(user)) + .Select(i => i.Id) .ToList(); - if (folders.Count == 0) + var excludeItemTypes = new List(); + + if (!query.IsInProgress.HasValue) + { + folderIds.Add(internalLiveTvFolderId); + + excludeItemTypes.Add(typeof(LiveTvChannel).Name); + excludeItemTypes.Add(typeof(LiveTvProgram).Name); + } + + if (folderIds.Count == 0) { return new QueryResult(); } var includeItemTypes = new List(); - var excludeItemTypes = new List(); var genres = new List(); if (query.IsMovie.HasValue) @@ -1631,7 +1639,7 @@ namespace Emby.Server.Implementations.LiveTv { MediaTypes = new[] { MediaType.Video }, Recursive = true, - AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(), + AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(), IsFolder = false, IsVirtualItem = false, Limit = query.Limit, @@ -1714,12 +1722,24 @@ namespace Emby.Server.Implementations.LiveTv return new QueryResult(); } - if (_services.Count == 1 && !(query.IsInProgress ?? false) && (!query.IsLibraryItem.HasValue || query.IsLibraryItem.Value)) + var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + + if (_services.Count == 1 && (!query.IsInProgress.HasValue || !query.IsInProgress.Value) && (!query.IsLibraryItem.HasValue || query.IsLibraryItem.Value)) { - return GetEmbyRecordings(query, options, user); + if (!query.IsInProgress.HasValue) + { + await RefreshRecordings(folder.Id, cancellationToken).ConfigureAwait(false); + } + + return GetEmbyRecordings(query, options, folder.Id, user); } - await RefreshRecordings(cancellationToken).ConfigureAwait(false); + return await GetInternalRecordingsFromServices(query, user, options, folder.Id, cancellationToken).ConfigureAwait(false); + } + + private async Task> GetInternalRecordingsFromServices(RecordingQuery query, User user, DtoOptions options, Guid internalLiveTvFolderId, CancellationToken cancellationToken) + { + await RefreshRecordings(internalLiveTvFolderId, cancellationToken).ConfigureAwait(false); var internalQuery = new InternalItemsQuery(user) { @@ -2620,7 +2640,8 @@ namespace Emby.Server.Implementations.LiveTv }, new DtoOptions(), cancellationToken).ConfigureAwait(false); - var recordings = recordingResult.Items.OfType().ToList(); + var embyServiceName = EmbyTV.EmbyTV.Current.Name; + var recordings = recordingResult.Items.Where(i => !string.Equals(i.ServiceName, embyServiceName, StringComparison.OrdinalIgnoreCase)).OfType().ToList(); var groups = new List(); diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index c6282bbad..664735dfe 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -848,6 +848,11 @@ namespace MediaBrowser.Api.Playback.Hls { return string.Empty; } + // No known video stream + if (state.VideoStream == null) + { + return string.Empty; + } var codec = EncodingHelper.GetVideoEncoder(state, ApiEntryPoint.Instance.GetEncodingOptions()); diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index ae7271844..536236f5f 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -199,7 +199,7 @@ namespace MediaBrowser.Api.Playback SubtitleStreamIndex = request.SubtitleStreamIndex, UserId = request.UserId, OpenToken = mediaSource.OpenToken, - AllowMediaProbe = request.AllowMediaProbe + EnableMediaProbe = request.EnableMediaProbe }).ConfigureAwait(false); diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index de6cbf4bb..3536b17b2 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -635,8 +635,10 @@ namespace MediaBrowser.Model.Dlna MediaStream videoStream = item.VideoStream; // TODO: This doesn't accout for situation of device being able to handle media bitrate, but wifi connection not fast enough - bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), subtitleStream, options, PlayMethod.DirectPlay)); - bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || IsEligibleForDirectPlay(item, options.GetMaxBitrate(false), subtitleStream, options, PlayMethod.DirectStream)); + var directPlayEligibilityResult = IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), subtitleStream, options, PlayMethod.DirectPlay); + var directStreamEligibilityResult = IsEligibleForDirectPlay(item, options.GetMaxBitrate(false), subtitleStream, options, PlayMethod.DirectStream); + bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || directPlayEligibilityResult.Item1); + bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || directStreamEligibilityResult.Item1); _logger.Info("Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}", options.Profile.Name ?? "Unknown Profile", @@ -669,6 +671,16 @@ namespace MediaBrowser.Model.Dlna transcodeReasons.AddRange(directPlayInfo.Item2); } + if (directPlayEligibilityResult.Item2.HasValue) + { + transcodeReasons.Add(directPlayEligibilityResult.Item2.Value); + } + + if (directStreamEligibilityResult.Item2.HasValue) + { + transcodeReasons.Add(directStreamEligibilityResult.Item2.Value); + } + // Can't direct play, find the transcoding profile TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) @@ -1136,7 +1148,7 @@ namespace MediaBrowser.Model.Dlna mediaSource.Path ?? "Unknown path"); } - private bool IsEligibleForDirectPlay(MediaSourceInfo item, + private Tuple IsEligibleForDirectPlay(MediaSourceInfo item, long? maxBitrate, MediaStream subtitleStream, VideoOptions options, @@ -1149,11 +1161,18 @@ namespace MediaBrowser.Model.Dlna if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed) { _logger.Info("Not eligible for {0} due to unsupported subtitles", playMethod); - return false; + return new Tuple(false, TranscodeReason.SubtitleCodecNotSupported); } } - return IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod); + var result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod); + + if (result) + { + return new Tuple(result, null); + } + + return new Tuple(result, TranscodeReason.ContainerBitrateExceedsLimit); } public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, string transcodingSubProtocol, string transcodingContainer) diff --git a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs index 303340030..dedbb428d 100644 --- a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs +++ b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs @@ -17,13 +17,13 @@ namespace MediaBrowser.Model.MediaInfo public bool EnableDirectPlay { get; set; } public bool EnableDirectStream { get; set; } - public bool AllowMediaProbe { get; set; } + public bool EnableMediaProbe { get; set; } public LiveStreamRequest() { EnableDirectPlay = true; EnableDirectStream = true; - AllowMediaProbe = true; + EnableMediaProbe = true; } public LiveStreamRequest(AudioOptions options) diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs index afffe9b14..df39f0556 100644 --- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs +++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Model.MediaInfo public bool AllowVideoStreamCopy { get; set; } public bool AllowAudioStreamCopy { get; set; } public bool AutoOpenLiveStream { get; set; } - public bool AllowMediaProbe { get; set; } + public bool EnableMediaProbe { get; set; } public PlaybackInfoRequest() { @@ -39,7 +39,7 @@ namespace MediaBrowser.Model.MediaInfo EnableTranscoding = true; AllowVideoStreamCopy = true; AllowAudioStreamCopy = true; - AllowMediaProbe = true; + EnableMediaProbe = true; } } } diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index f1cbacd90..f58e605b2 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -48,6 +48,7 @@ namespace MediaBrowser.Model.Session VideoFramerateNotSupported = 17, VideoLevelNotSupported = 18, VideoProfileNotSupported = 19, - AudioBitDepthNotSupported = 20 + AudioBitDepthNotSupported = 20, + SubtitleCodecNotSupported = 21 } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs index d4e580871..98fe766e0 100644 --- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Music if (isFullRefresh || currentUpdateType > ItemUpdateType.None) { - if (!item.IsLocked) + if (!item.IsLocked && !item.LockedFields.Contains(MetadataFields.Genres)) { var taggedItems = item.IsAccessedByName ? item.GetTaggedItems(new Controller.Entities.InternalItemsQuery() @@ -31,22 +31,19 @@ namespace MediaBrowser.Providers.Music }) : item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder).ToList(); - if (!item.LockedFields.Contains(MetadataFields.Genres)) + var currentList = item.Genres.ToList(); + + item.Genres = taggedItems.SelectMany(i => i.Genres) + .DistinctNames() + .ToList(); + + if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase)) { - var currentList = item.Genres.ToList(); - - item.Genres = taggedItems.SelectMany(i => i.Genres) - .DistinctNames() - .ToList(); - - if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase)) - { - updateType = updateType | ItemUpdateType.MetadataEdit; - } + updateType = updateType | ItemUpdateType.MetadataEdit; } } } - + return updateType; } diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs index 235fd8c8a..c4ea106fb 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; @@ -6,7 +7,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; - +using System.Linq; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -33,6 +34,33 @@ namespace MediaBrowser.Providers.Playlists } } + protected override ItemUpdateType BeforeSave(Playlist item, bool isFullRefresh, ItemUpdateType currentUpdateType) + { + var updateType = base.BeforeSave(item, isFullRefresh, currentUpdateType); + + if (isFullRefresh || currentUpdateType > ItemUpdateType.None) + { + if (!item.IsLocked && !item.LockedFields.Contains(MetadataFields.Genres)) + { + var items = item.GetLinkedChildren() + .ToList(); + + var currentList = item.Genres.ToList(); + + item.Genres = items.SelectMany(i => i.Genres) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase)) + { + updateType = updateType | ItemUpdateType.MetadataEdit; + } + } + } + + return updateType; + } + public PlaylistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) { } From 2bd33ba650351e73006ee6ee08a54e4cf8ce2f39 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 3 Jul 2017 13:16:26 -0400 Subject: [PATCH 2/2] 3.2.22.3 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index ba8659803..957ba736c 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.22.2")] +[assembly: AssemblyVersion("3.2.22.3")]