From 9f0e6d17c8653328316cde3a1b0b3ce63b5960ff Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 12 Jun 2017 03:11:54 -0400 Subject: add hevc cuvid --- MediaBrowser.Controller/Entities/Folder.cs | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 48c9b83aa2..727b7dbebe 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -211,33 +211,6 @@ namespace MediaBrowser.Controller.Entities item.SetParent(null); } - /// - /// Returns the valid set of index by options for this folder type. - /// Override or extend to modify. - /// - /// Dictionary{System.StringFunc{UserIEnumerable{BaseItem}}}. - protected virtual IEnumerable GetIndexByOptions() - { - return new List { - {"None"}, - {"Performer"}, - {"Genre"}, - {"Director"}, - {"Year"}, - {"Studio"} - }; - } - - /// - /// Get the list of indexy by choices for this folder (localized). - /// - /// The index by option strings. - [IgnoreDataMember] - public IEnumerable IndexByOptionStrings - { - get { return GetIndexByOptions(); } - } - /// /// Gets the actual children. /// -- cgit v1.2.3 From 1e5c3db9eba730fe8b52995e5c699c22983fa62a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 23 Jun 2017 12:04:45 -0400 Subject: support individual library refreshing --- .../ScheduledTasks/ScheduledTaskWorker.cs | 3 +- Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs | 4 +- Emby.Drawing.Skia/PlayedIndicatorDrawer.cs | 3 +- .../Channels/ChannelManager.cs | 4 +- .../Channels/ChannelPostScanTask.cs | 2 +- .../Channels/RefreshChannelsScheduledTask.cs | 3 +- .../Emby.Server.Implementations.csproj | 1 - .../EntryPoints/LibraryChangedNotifier.cs | 116 +++++++++++- Emby.Server.Implementations/IO/FileRefresher.cs | 4 +- .../Library/LibraryManager.cs | 40 +++-- .../Library/Validators/PeopleValidator.cs | 4 - .../Library/Validators/YearsPostScanTask.cs | 57 ------ .../LiveTv/EmbyTV/EmbyTV.cs | 4 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 3 +- .../LiveTv/LiveTvManager.cs | 6 +- Emby.Server.Implementations/News/NewsEntryPoint.cs | 3 +- .../Notifications/WebSocketNotifier.cs | 1 - .../ScheduledTasks/PluginUpdateTask.cs | 3 +- .../ScheduledTasks/SystemUpdateTask.cs | 5 +- .../Updates/InstallationManager.cs | 2 +- MediaBrowser.Api/ItemRefreshService.cs | 7 +- MediaBrowser.Api/Library/LibraryService.cs | 7 +- .../Library/LibraryStructureService.cs | 10 +- MediaBrowser.Api/PackageService.cs | 5 +- MediaBrowser.Common/Progress/ActionableProgress.cs | 46 +++-- MediaBrowser.Controller/Channels/Channel.cs | 3 +- MediaBrowser.Controller/Dto/DtoOptions.cs | 3 +- .../Entities/Audio/MusicAlbum.cs | 2 - .../Entities/Audio/MusicArtist.cs | 2 - MediaBrowser.Controller/Entities/BaseItem.cs | 38 +++- .../Entities/CollectionFolder.cs | 30 ++++ MediaBrowser.Controller/Entities/Folder.cs | 196 +++++++++++++-------- MediaBrowser.Controller/Entities/TV/Series.cs | 2 - MediaBrowser.Controller/Library/ILibraryManager.cs | 4 +- .../MediaBrowser.Controller.csproj | 1 - .../Providers/IProviderManager.cs | 19 +- .../Providers/ProviderRefreshStatus.cs | 22 --- .../Encoder/FontConfigLoader.cs | 3 +- MediaBrowser.Model/Entities/VirtualFolderInfo.cs | 3 + MediaBrowser.Model/Querying/ItemFields.cs | 3 +- MediaBrowser.Providers/ImagesByName/ImageUtils.cs | 3 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 99 ++++++++++- MediaBrowser.Providers/TV/DummySeasonProvider.cs | 2 +- .../TV/MissingEpisodeProvider.cs | 4 +- 44 files changed, 522 insertions(+), 260 deletions(-) delete mode 100644 Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs delete mode 100644 MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index ac1c55b6b3..c373ffddb9 100644 --- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -402,7 +403,7 @@ namespace Emby.Common.Implementations.ScheduledTasks throw new InvalidOperationException("Cannot execute a Task that is already running"); } - var progress = new Progress(); + var progress = new SimpleProgress(); CurrentCancellationTokenSource = new CancellationTokenSource(); diff --git a/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs b/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs index 2ec58ff288..4dccca0c3d 100644 --- a/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs +++ b/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Drawing; using System; using System.IO; using System.Threading.Tasks; - +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -104,7 +104,7 @@ namespace Emby.Drawing.ImageMagick var tempPath = await httpClient.GetTempFile(new HttpRequestOptions { Url = url, - Progress = new Progress() + Progress = new SimpleProgress() }).ConfigureAwait(false); diff --git a/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs b/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs index ad3b5226ca..48f2da62bc 100644 --- a/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs +++ b/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using System.Reflection; +using MediaBrowser.Common.Progress; namespace Emby.Drawing.Skia { @@ -99,7 +100,7 @@ namespace Emby.Drawing.Skia var tempPath = await httpClient.GetTempFile(new HttpRequestOptions { Url = url, - Progress = new Progress() + Progress = new SimpleProgress() }).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 73878160c9..85f6c66673 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -23,7 +23,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; - +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; @@ -980,7 +980,7 @@ namespace Emby.Server.Implementations.Channels ? null : _userManager.GetUserById(query.UserId); - var internalResult = await GetChannelItemsInternal(query, new Progress(), cancellationToken).ConfigureAwait(false); + var internalResult = await GetChannelItemsInternal(query, new SimpleProgress(), cancellationToken).ConfigureAwait(false); var dtoOptions = new DtoOptions() { diff --git a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs index aef06bd1d6..ae31fcf3f5 100644 --- a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs +++ b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs @@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Channels StartIndex = totalRetrieved, FolderId = folderId - }, new Progress(), cancellationToken); + }, new SimpleProgress(), cancellationToken); folderItems.AddRange(result.Items.Where(i => i.IsFolder).Select(i => i.Id.ToString("N"))); diff --git a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs index d5ec86445d..4a33012529 100644 --- a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.Channels @@ -42,7 +43,7 @@ namespace Emby.Server.Implementations.Channels { var manager = (ChannelManager)_channelManager; - await manager.RefreshChannels(new Progress(), cancellationToken).ConfigureAwait(false); + await manager.RefreshChannels(new SimpleProgress(), cancellationToken).ConfigureAwait(false); await new ChannelPostScanTask(_channelManager, _userManager, _logger, _libraryManager).Run(progress, cancellationToken) .ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 58d44d2614..231ffe7913 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -148,7 +148,6 @@ - diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 91142f9284..23ae4cee9e 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -6,9 +6,14 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Threading; @@ -49,13 +54,16 @@ namespace Emby.Server.Implementations.EntryPoints /// private const int LibraryUpdateDuration = 5000; - public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, ITimerFactory timerFactory) + private readonly IProviderManager _providerManager; + + public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, ITimerFactory timerFactory, IProviderManager providerManager) { _libraryManager = libraryManager; _sessionManager = sessionManager; _userManager = userManager; _logger = logger; _timerFactory = timerFactory; + _providerManager = providerManager; } public void Run() @@ -64,6 +72,108 @@ namespace Emby.Server.Implementations.EntryPoints _libraryManager.ItemUpdated += libraryManager_ItemUpdated; _libraryManager.ItemRemoved += libraryManager_ItemRemoved; + _providerManager.RefreshCompleted += _providerManager_RefreshCompleted; + _providerManager.RefreshStarted += _providerManager_RefreshStarted; + _providerManager.RefreshProgress += _providerManager_RefreshProgress; + } + + private Dictionary _lastProgressMessageTimes = new Dictionary(); + + private void _providerManager_RefreshProgress(object sender, GenericEventArgs> e) + { + var item = e.Argument.Item1; + + if (!EnableRefreshMessage(item)) + { + return; + } + + var progress = e.Argument.Item2; + + DateTime lastMessageSendTime; + if (_lastProgressMessageTimes.TryGetValue(item.Id, out lastMessageSendTime)) + { + if (progress > 0 && progress < 100 && (DateTime.UtcNow - lastMessageSendTime).TotalMilliseconds < 1000) + { + return; + } + } + + _lastProgressMessageTimes[item.Id] = DateTime.UtcNow; + + var dict = new Dictionary(); + dict["ItemId"] = item.Id.ToString("N"); + dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture); + + try + { + _sessionManager.SendMessageToAdminSessions("RefreshProgress", dict, CancellationToken.None); + + _logger.Info("Sending refresh progress {0} {1}", item.Id.ToString("N"), progress); + } + catch + { + } + + var collectionFolders = _libraryManager.GetCollectionFolders(item).ToList(); + + foreach (var collectionFolder in collectionFolders) + { + var collectionFolderDict = new Dictionary(); + collectionFolderDict["ItemId"] = collectionFolder.Id.ToString("N"); + collectionFolderDict["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture); + + try + { + _sessionManager.SendMessageToAdminSessions("RefreshProgress", collectionFolderDict, CancellationToken.None); + } + catch + { + + } + } + } + + private void _providerManager_RefreshStarted(object sender, GenericEventArgs e) + { + _providerManager_RefreshProgress(sender, new GenericEventArgs>(new Tuple(e.Argument, 0))); + } + + private void _providerManager_RefreshCompleted(object sender, GenericEventArgs e) + { + _providerManager_RefreshProgress(sender, new GenericEventArgs>(new Tuple(e.Argument, 100))); + } + + private bool EnableRefreshMessage(BaseItem item) + { + var folder = item as Folder; + + if (folder == null) + { + return false; + } + + if (folder.IsRoot) + { + return false; + } + + if (folder is AggregateFolder || folder is UserRootFolder) + { + return false; + } + + if (folder is UserView || folder is Channel) + { + return false; + } + + if (!folder.IsTopParent) + { + return false; + } + + return true; } /// @@ -218,8 +328,8 @@ namespace Emby.Server.Implementations.EntryPoints try { - info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, - foldersRemovedFrom, id); + info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, + foldersRemovedFrom, id); } catch (Exception ex) { diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 9606b60b80..d4914e734e 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; - +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; @@ -170,7 +170,7 @@ namespace Emby.Server.Implementations.IO // If the root folder changed, run the library task so the user can see it if (itemsToRefresh.Any(i => i is AggregateFolder)) { - LibraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + LibraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); return; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 15efd3d39c..1a909549e7 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -462,7 +462,7 @@ namespace Emby.Server.Implementations.Library if (parent != null) { - await parent.ValidateChildren(new Progress(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false); + await parent.ValidateChildren(new SimpleProgress(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false); } } else if (parent != null) @@ -1113,13 +1113,13 @@ namespace Emby.Server.Implementations.Library progress.Report(.5); // Start by just validating the children of the root, but go no further - await RootFolder.ValidateChildren(new Progress(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false); + await RootFolder.ValidateChildren(new SimpleProgress(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false); progress.Report(1); await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false); - await GetUserRootFolder().ValidateChildren(new Progress(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false); + await GetUserRootFolder().ValidateChildren(new SimpleProgress(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false); progress.Report(2); // Quickly scan CollectionFolders for changes @@ -1204,25 +1204,24 @@ namespace Emby.Server.Implementations.Library /// Gets the default view. /// /// IEnumerable{VirtualFolderInfo}. - public IEnumerable GetVirtualFolders() + public List GetVirtualFolders() { - return GetView(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath); + return GetVirtualFolders(false); } - /// - /// Gets the view. - /// - /// The path. - /// IEnumerable{VirtualFolderInfo}. - private IEnumerable GetView(string path) + public List GetVirtualFolders(bool includeRefreshState) { var topLibraryFolders = GetUserRootFolder().Children.ToList(); - return _fileSystem.GetDirectoryPaths(path) - .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders)); + var refreshQueue = includeRefreshState ? _providerManagerFactory().GetRefreshQueue() : null; + + return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath) + .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue)) + .OrderBy(i => i.Name) + .ToList(); } - private VirtualFolderInfo GetVirtualFolderInfo(string dir, List allCollectionFolders) + private VirtualFolderInfo GetVirtualFolderInfo(string dir, List allCollectionFolders, Dictionary refreshQueue) { var info = new VirtualFolderInfo { @@ -1248,6 +1247,13 @@ namespace Emby.Server.Implementations.Library { info.ItemId = libraryFolder.Id.ToString("N"); info.LibraryOptions = GetLibraryOptions(libraryFolder); + + if (refreshQueue != null) + { + info.RefreshProgress = libraryFolder.GetRefreshProgress(); + + info.RefreshStatus = info.RefreshProgress.HasValue ? "Active" : refreshQueue.ContainsKey(libraryFolder.Id) ? "Queued" : "Idle"; + } } return info; @@ -2947,7 +2953,7 @@ namespace Emby.Server.Implementations.Library // No need to start if scanning the library because it will handle it if (refreshLibrary) { - ValidateMediaLibrary(new Progress(), CancellationToken.None); + ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } else { @@ -3075,7 +3081,7 @@ namespace Emby.Server.Implementations.Library private void SyncLibraryOptionsToLocations(string virtualFolderPath, LibraryOptions options) { var topLibraryFolders = GetUserRootFolder().Children.ToList(); - var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders); + var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders, null); if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length) { @@ -3125,7 +3131,7 @@ namespace Emby.Server.Implementations.Library // No need to start if scanning the library because it will handle it if (refreshLibrary) { - ValidateMediaLibrary(new Progress(), CancellationToken.None); + ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } else { diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index ef3b86abf7..c2eb30ee41 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -55,10 +55,6 @@ namespace Emby.Server.Implementations.Library.Validators /// Task. public async Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) { - var innerProgress = new ActionableProgress(); - - innerProgress.RegisterAction(pct => progress.Report(pct * .15)); - var people = _libraryManager.GetPeople(new InternalPeopleQuery()); var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs deleted file mode 100644 index 4afb4c04a7..0000000000 --- a/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs +++ /dev/null @@ -1,57 +0,0 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Emby.Server.Implementations.Library.Validators -{ - public class YearsPostScanTask : ILibraryPostScanTask - { - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - - public YearsPostScanTask(ILibraryManager libraryManager, ILogger logger) - { - _libraryManager = libraryManager; - _logger = logger; - } - - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var yearNumber = 1900; - var maxYear = DateTime.UtcNow.Year + 3; - var count = maxYear - yearNumber + 1; - var numComplete = 0; - - while (yearNumber < maxYear) - { - cancellationToken.ThrowIfCancellationRequested(); - - try - { - var year = _libraryManager.GetYear(yearNumber); - - await year.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error refreshing year {0}", ex, yearNumber); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); - yearNumber++; - } - } - } -} diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index a4c5b338e2..b55e4412be 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -28,7 +28,7 @@ using System.Xml; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; - +using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -240,7 +240,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (requiresRefresh) { - _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index b50f5ac926..9bf9f140d4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -15,6 +15,7 @@ using Emby.XmlTv.Classes; using Emby.XmlTv.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -75,7 +76,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { CancellationToken = cancellationToken, Url = path, - Progress = new Progress(), + Progress = new SimpleProgress(), DecompressionMethod = CompressionMethod.Gzip, // It's going to come back gzipped regardless of this value diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 69def362b2..24afc03daf 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1273,8 +1273,8 @@ namespace Emby.Server.Implementations.LiveTv if (coreService != null) { - await coreService.RefreshSeriesTimers(cancellationToken, new Progress()).ConfigureAwait(false); - await coreService.RefreshTimers(cancellationToken, new Progress()).ConfigureAwait(false); + await coreService.RefreshSeriesTimers(cancellationToken, new SimpleProgress()).ConfigureAwait(false); + await coreService.RefreshTimers(cancellationToken, new SimpleProgress()).ConfigureAwait(false); } // Load these now which will prefetch metadata @@ -1549,7 +1549,7 @@ namespace Emby.Server.Implementations.LiveTv var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false); - await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new Progress(), cancellationToken).ConfigureAwait(false); + await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress(), cancellationToken).ConfigureAwait(false); _lastRecordingRefreshTime = DateTime.UtcNow; } diff --git a/Emby.Server.Implementations/News/NewsEntryPoint.cs b/Emby.Server.Implementations/News/NewsEntryPoint.cs index 53c862d470..3c9a3bbf1d 100644 --- a/Emby.Server.Implementations/News/NewsEntryPoint.cs +++ b/Emby.Server.Implementations/News/NewsEntryPoint.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Model.Threading; @@ -82,7 +83,7 @@ namespace Emby.Server.Implementations.News var requestOptions = new HttpRequestOptions { Url = "http://emby.media/community/index.php?/blog/rss/1-media-browser-developers-blog", - Progress = new Progress(), + Progress = new SimpleProgress(), UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36", BufferContent = false }; diff --git a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs index 8b3367217c..0239ee3365 100644 --- a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs +++ b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs @@ -23,7 +23,6 @@ namespace Emby.Server.Implementations.Notifications public void Run() { _notificationsRepo.NotificationAdded += _notificationsRepo_NotificationAdded; - _notificationsRepo.NotificationsMarkedRead += _notificationsRepo_NotificationsMarkedRead; } diff --git a/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs index e619b68649..9f887ba030 100644 --- a/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.ScheduledTasks @@ -77,7 +78,7 @@ namespace Emby.Server.Implementations.ScheduledTasks try { - await _installationManager.InstallPackage(i, true, new Progress(), cancellationToken).ConfigureAwait(false); + await _installationManager.InstallPackage(i, true, new SimpleProgress(), cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs index 28fd8b68cb..a41e21a4b7 100644 --- a/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.ScheduledTasks @@ -70,7 +71,7 @@ namespace Emby.Server.Implementations.ScheduledTasks EventHandler innerProgressHandler = (sender, e) => progress.Report(e * .1); // Create a progress object for the update check - var innerProgress = new Progress(); + var innerProgress = new SimpleProgress(); innerProgress.ProgressChanged += innerProgressHandler; var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false); @@ -97,7 +98,7 @@ namespace Emby.Server.Implementations.ScheduledTasks innerProgressHandler = (sender, e) => progress.Report(e * .9 + .1); - innerProgress = new Progress(); + innerProgress = new SimpleProgress(); innerProgress.ProgressChanged += innerProgressHandler; await _appHost.UpdateApplication(updateInfo.Package, cancellationToken, innerProgress).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index eed17fb66d..717416da1b 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -246,7 +246,7 @@ namespace Emby.Server.Implementations.Updates { Url = "https://www.mb3admin.com/admin/service/MB3Packages.json", CancellationToken = cancellationToken, - Progress = new Progress() + Progress = new SimpleProgress() }).ConfigureAwait(false); diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs index 534089848e..d26fb768a3 100644 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ b/MediaBrowser.Api/ItemRefreshService.cs @@ -65,7 +65,7 @@ namespace MediaBrowser.Api _providerManager.QueueRefresh(item.Id, options, RefreshPriority.High); } - private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request) + private MetadataRefreshOptions GetRefreshOptions(RefreshItem request) { return new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) { @@ -73,8 +73,9 @@ namespace MediaBrowser.Api ImageRefreshMode = request.ImageRefreshMode, ReplaceAllImages = request.ReplaceAllImages, ReplaceAllMetadata = request.ReplaceAllMetadata, - ForceSave = true, - IsAutomated = false + ForceSave = request.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || request.ImageRefreshMode == ImageRefreshMode.FullRefresh || request.ReplaceAllImages || request.ReplaceAllMetadata, + IsAutomated = false, + ValidateChildren = request.Recursive }; } } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index d9fc7143f9..80d8c072ee 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -28,6 +28,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Services; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Progress; namespace MediaBrowser.Api.Library { @@ -445,7 +446,7 @@ namespace MediaBrowser.Api.Library } else { - Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None)); + Task.Run(() => _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None)); } } @@ -483,7 +484,7 @@ namespace MediaBrowser.Api.Library } else { - Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None)); + Task.Run(() => _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None)); } } @@ -696,7 +697,7 @@ namespace MediaBrowser.Api.Library { try { - _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } catch (Exception ex) { diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 8e396ff57a..ae488f066c 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; - +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -208,7 +208,7 @@ namespace MediaBrowser.Api.Library /// System.Object. public object Get(GetVirtualFolders request) { - var result = _libraryManager.GetVirtualFolders().OrderBy(i => i.Name).ToList(); + var result = _libraryManager.GetVirtualFolders(true); return ToOptimizedSerializedResultUsingCache(result); } @@ -290,7 +290,7 @@ namespace MediaBrowser.Api.Library // No need to start if scanning the library because it will handle it if (request.RefreshLibrary) { - _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } else { @@ -347,7 +347,7 @@ namespace MediaBrowser.Api.Library // No need to start if scanning the library because it will handle it if (request.RefreshLibrary) { - _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } else { @@ -400,7 +400,7 @@ namespace MediaBrowser.Api.Library // No need to start if scanning the library because it will handle it if (request.RefreshLibrary) { - _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); } else { diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 125cec681b..64424795fc 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Services; namespace MediaBrowser.Api @@ -156,7 +157,7 @@ namespace MediaBrowser.Api else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase)) { - var updateCheckResult = _appHost.CheckForApplicationUpdate(CancellationToken.None, new Progress()).Result; + var updateCheckResult = _appHost.CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress()).Result; if (updateCheckResult.IsUpdateAvailable) { @@ -233,7 +234,7 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name)); } - Task.Run(() => _installationManager.InstallPackage(package, true, new Progress(), CancellationToken.None)); + Task.Run(() => _installationManager.InstallPackage(package, true, new SimpleProgress(), CancellationToken.None)); } /// diff --git a/MediaBrowser.Common/Progress/ActionableProgress.cs b/MediaBrowser.Common/Progress/ActionableProgress.cs index 39f46ce057..503f3f407a 100644 --- a/MediaBrowser.Common/Progress/ActionableProgress.cs +++ b/MediaBrowser.Common/Progress/ActionableProgress.cs @@ -7,12 +7,13 @@ namespace MediaBrowser.Common.Progress /// Class ActionableProgress /// /// - public class ActionableProgress : Progress, IDisposable + public class ActionableProgress : IProgress, IDisposable { /// /// The _actions /// private readonly List> _actions = new List>(); + public event EventHandler ProgressChanged; /// /// Registers the action. @@ -21,22 +22,6 @@ namespace MediaBrowser.Common.Progress public void RegisterAction(Action action) { _actions.Add(action); - - ProgressChanged -= ActionableProgress_ProgressChanged; - ProgressChanged += ActionableProgress_ProgressChanged; - } - - /// - /// Actionables the progress_ progress changed. - /// - /// The sender. - /// The e. - void ActionableProgress_ProgressChanged(object sender, T e) - { - foreach (var action in _actions) - { - action(e); - } } /// @@ -55,9 +40,34 @@ namespace MediaBrowser.Common.Progress { if (disposing) { - ProgressChanged -= ActionableProgress_ProgressChanged; _actions.Clear(); } } + + public void Report(T value) + { + if (ProgressChanged != null) + { + ProgressChanged(this, value); + } + + foreach (var action in _actions) + { + action(value); + } + } + } + + public class SimpleProgress : IProgress + { + public event EventHandler ProgressChanged; + + public void Report(T value) + { + if (ProgressChanged != null) + { + ProgressChanged(this, value); + } + } } } diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 862c8e5ace..8e2faa20e2 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -6,6 +6,7 @@ using System.Linq; using MediaBrowser.Model.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; namespace MediaBrowser.Controller.Channels { @@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.Channels SortBy = query.SortBy, SortOrder = query.SortOrder - }, new Progress(), CancellationToken.None).Result; + }, new SimpleProgress(), CancellationToken.None).Result; } catch { diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index b9d9d7ddad..098ba558f8 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -10,7 +10,8 @@ namespace MediaBrowser.Controller.Dto { private static readonly List DefaultExcludedFields = new List { - ItemFields.SeasonUserData + ItemFields.SeasonUserData, + ItemFields.RefreshState }; public List Fields { get; set; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index e9eca19cf7..516ab50530 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -235,8 +235,6 @@ namespace MediaBrowser.Controller.Entities.Audio { await RefreshArtists(refreshOptions, cancellationToken).ConfigureAwait(false); } - - progress.Report(100); } private async Task RefreshArtists(MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 4b232de499..ebd83205e5 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -250,8 +250,6 @@ namespace MediaBrowser.Controller.Entities.Audio percent /= totalItems; progress.Report(percent * 100); } - - progress.Report(100); } public ArtistInfo GetLookupInfo() diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 4efea94d8e..b4a3d89eac 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1058,6 +1058,16 @@ namespace MediaBrowser.Controller.Entities return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken); } + protected virtual void TriggerOnRefreshStart() + { + + } + + protected virtual void TriggerOnRefreshComplete() + { + + } + /// /// Overrides the base implementation to refresh metadata for local trailers /// @@ -1066,6 +1076,8 @@ namespace MediaBrowser.Controller.Entities /// true if a provider reports we changed public async Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) { + TriggerOnRefreshStart(); + var locationType = LocationType; var requiresSave = false; @@ -1091,14 +1103,21 @@ namespace MediaBrowser.Controller.Entities } } - var refreshOptions = requiresSave - ? new MetadataRefreshOptions(options) - { - ForceSave = true - } - : options; + try + { + var refreshOptions = requiresSave + ? new MetadataRefreshOptions(options) + { + ForceSave = true + } + : options; - return await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false); + return await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false); + } + finally + { + TriggerOnRefreshComplete(); + } } [IgnoreDataMember] @@ -2421,5 +2440,10 @@ namespace MediaBrowser.Controller.Entities { return new List(); } + + public virtual double? GetRefreshProgress() + { + return null; + } } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 8bc23a5819..0bd8606b96 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; @@ -199,6 +200,30 @@ namespace MediaBrowser.Controller.Entities return changed; } + public override double? GetRefreshProgress() + { + var folders = GetPhysicalFolders(true).ToList(); + double totalProgresses = 0; + var foldersWithProgress = 0; + + foreach (var folder in folders) + { + var progress = ProviderManager.GetRefreshProgress(folder.Id); + if (progress.HasValue) + { + totalProgresses += progress.Value; + foldersWithProgress++; + } + } + + if (foldersWithProgress == 0) + { + return null; + } + + return (totalProgresses / foldersWithProgress); + } + protected override bool RefreshLinkedChildren(IEnumerable fileSystemChildren) { return RefreshLinkedChildrenInternal(true); @@ -321,6 +346,11 @@ namespace MediaBrowser.Controller.Entities return GetPhysicalFolders(true).SelectMany(c => c.Children); } + public IEnumerable GetPhysicalFolders() + { + return GetPhysicalFolders(true); + } + private IEnumerable GetPhysicalFolders(bool enableCache) { if (enableCache) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 727b7dbebe..34b33fde0d 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -271,6 +271,11 @@ namespace MediaBrowser.Controller.Entities return GetCachedChildren(); } + public override double? GetRefreshProgress() + { + return ProviderManager.GetRefreshProgress(Id); + } + public Task ValidateChildren(IProgress progress, CancellationToken cancellationToken) { return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))); @@ -318,6 +323,14 @@ namespace MediaBrowser.Controller.Entities return current.IsValidFromResolver(newItem); } + protected override void TriggerOnRefreshStart() + { + } + + protected override void TriggerOnRefreshComplete() + { + } + /// /// Validates the children internal. /// @@ -328,7 +341,27 @@ namespace MediaBrowser.Controller.Entities /// The refresh options. /// The directory service. /// Task. - protected async virtual Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected virtual async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + { + if (recursive) + { + ProviderManager.OnRefreshStart(this); + } + + try + { + await ValidateChildrenInternal2(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService).ConfigureAwait(false); + } + finally + { + if (recursive) + { + ProviderManager.OnRefreshComplete(this); + } + } + } + + private async Task ValidateChildrenInternal2(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { var locationType = LocationType; @@ -360,6 +393,11 @@ namespace MediaBrowser.Controller.Entities progress.Report(5); + if (recursive) + { + ProviderManager.OnRefreshProgress(this, 5); + } + //build a dictionary of the current children we have now by Id so we can compare quickly and easily var currentChildren = GetActualChildrenDictionary(); @@ -424,76 +462,99 @@ namespace MediaBrowser.Controller.Entities await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false); } } + else + { + if (recursive || refreshChildMetadata) + { + // used below + validChildren = Children.ToList(); + } + } progress.Report(10); - cancellationToken.ThrowIfCancellationRequested(); - if (recursive) { - await ValidateSubFolders(Children.ToList().OfType().ToList(), directoryService, progress, cancellationToken).ConfigureAwait(false); + ProviderManager.OnRefreshProgress(this, 10); } - progress.Report(20); + cancellationToken.ThrowIfCancellationRequested(); - if (refreshChildMetadata) + if (recursive) { - var container = this as IMetadataContainer; + using (var innerProgress = new ActionableProgress()) + { + var folder = this; + innerProgress.RegisterAction(p => + { + double newPct = .70 * p + 10; + progress.Report(newPct); + ProviderManager.OnRefreshProgress(folder, newPct); + }); - var innerProgress = new ActionableProgress(); + await ValidateSubFolders(validChildren.OfType().ToList(), directoryService, innerProgress, cancellationToken).ConfigureAwait(false); + } + } - innerProgress.RegisterAction(p => progress.Report(.80 * p + 20)); + if (refreshChildMetadata) + { + progress.Report(80); - if (container != null) + if (recursive) { - await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false); + ProviderManager.OnRefreshProgress(this, 80); } - else + + var container = this as IMetadataContainer; + + using (var innerProgress = new ActionableProgress()) { - await RefreshMetadataRecursive(refreshOptions, recursive, innerProgress, cancellationToken); + var folder = this; + innerProgress.RegisterAction(p => + { + double newPct = .20 * p + 80; + progress.Report(newPct); + if (recursive) + { + ProviderManager.OnRefreshProgress(folder, newPct); + } + }); + + if (container != null) + { + await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false); + } + else + { + await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken); + } } } - - progress.Report(100); } - private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress progress, CancellationToken cancellationToken) + private async Task RefreshMetadataRecursive(List children, MetadataRefreshOptions refreshOptions, bool recursive, IProgress progress, CancellationToken cancellationToken) { - var children = Children.ToList(); - - var percentages = new Dictionary(children.Count); var numComplete = 0; var count = children.Count; + double currentPercent = 0; foreach (var child in children) { cancellationToken.ThrowIfCancellationRequested(); - if (child.IsFolder) + using (var innerProgress = new ActionableProgress()) { - var innerProgress = new ActionableProgress(); - // Avoid implicitly captured closure - var currentChild = child; + var currentInnerPercent = currentPercent; + innerProgress.RegisterAction(p => { - lock (percentages) - { - percentages[currentChild.Id] = p / 100; - - var innerPercent = percentages.Values.Sum(); - innerPercent /= count; - innerPercent *= 100; - progress.Report(innerPercent); - } + double innerPercent = currentInnerPercent; + innerPercent += p / (count); + progress.Report(innerPercent); }); - await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) - .ConfigureAwait(false); - } - else - { - await RefreshChildMetadata(child, refreshOptions, false, new Progress(), cancellationToken) + await RefreshChildMetadata(child, refreshOptions, recursive && child.IsFolder, innerProgress, cancellationToken) .ConfigureAwait(false); } @@ -501,11 +562,10 @@ namespace MediaBrowser.Controller.Entities double percent = numComplete; percent /= count; percent *= 100; + currentPercent = percent; progress.Report(percent); } - - progress.Report(100); } private async Task RefreshChildMetadata(BaseItem child, MetadataRefreshOptions refreshOptions, bool recursive, IProgress progress, CancellationToken cancellationToken) @@ -526,11 +586,10 @@ namespace MediaBrowser.Controller.Entities if (folder != null) { - await folder.RefreshMetadataRecursive(refreshOptions, true, progress, cancellationToken); + await folder.RefreshMetadataRecursive(folder.Children.ToList(), refreshOptions, true, progress, cancellationToken); } } } - progress.Report(100); } /// @@ -543,47 +602,40 @@ namespace MediaBrowser.Controller.Entities /// Task. private async Task ValidateSubFolders(IList children, IDirectoryService directoryService, IProgress progress, CancellationToken cancellationToken) { - var list = children; - var childCount = list.Count; - - var percentages = new Dictionary(list.Count); + var numComplete = 0; + var count = children.Count; + double currentPercent = 0; - foreach (var item in list) + foreach (var child in children) { cancellationToken.ThrowIfCancellationRequested(); - var child = item; - - var innerProgress = new ActionableProgress(); - - innerProgress.RegisterAction(p => + using (var innerProgress = new ActionableProgress()) { - lock (percentages) + // Avoid implicitly captured closure + var currentInnerPercent = currentPercent; + + innerProgress.RegisterAction(p => { - percentages[child.Id] = p / 100; + double innerPercent = currentInnerPercent; + innerPercent += p / (count); + progress.Report(innerPercent); + }); - var percent = percentages.Values.Sum(); - percent /= childCount; + await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService) + .ConfigureAwait(false); + } - progress.Report(10 * percent + 10); - } - }); + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + currentPercent = percent; - await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService) - .ConfigureAwait(false); + progress.Report(percent); } } - /// - /// Determines whether the specified path is offline. - /// - /// The path. - /// true if the specified path is offline; otherwise, false. - public static bool IsPathOffline(string path) - { - return IsPathOffline(path, LibraryManager.GetVirtualFolders().SelectMany(i => i.Locations).ToList()); - } - public static bool IsPathOffline(string path, List allLibraryPaths) { if (FileSystem.FileExists(path)) @@ -926,7 +978,7 @@ namespace MediaBrowser.Controller.Entities SortBy = query.SortBy, SortOrder = query.SortOrder - }, new Progress(), CancellationToken.None).Result; + }, new SimpleProgress(), CancellationToken.None).Result; } catch { diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 0b96624505..1e4b3fdad3 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -414,8 +414,6 @@ namespace MediaBrowser.Controller.Entities.TV refreshOptions = new MetadataRefreshOptions(refreshOptions); refreshOptions.IsPostRecursiveRefresh = true; await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false); - - progress.Report(100); } public IEnumerable GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options) diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 5a702b4f08..b726c267c6 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -132,7 +132,9 @@ namespace MediaBrowser.Controller.Library /// Gets the default view. /// /// IEnumerable{VirtualFolderInfo}. - IEnumerable GetVirtualFolders(); + List GetVirtualFolders(); + + List GetVirtualFolders(bool includeRefreshState); /// /// Gets the item by id. diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 348cfd343f..22f94695d8 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -320,7 +320,6 @@ - diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index c0bc902140..0ba573da8b 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Events; namespace MediaBrowser.Controller.Providers { @@ -30,7 +31,7 @@ namespace MediaBrowser.Controller.Providers /// The cancellation token. /// Task. Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken); - + /// /// Refreshes the metadata. /// @@ -68,7 +69,7 @@ namespace MediaBrowser.Controller.Providers /// /// Task. Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken); - + /// /// Adds the metadata providers. /// @@ -128,7 +129,7 @@ namespace MediaBrowser.Controller.Providers /// The savers. /// Task. Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable savers); - + /// /// Gets the metadata options. /// @@ -158,6 +159,18 @@ namespace MediaBrowser.Controller.Providers /// The cancellation token. /// Task{HttpResponseInfo}. Task GetSearchImage(string providerName, string url, CancellationToken cancellationToken); + + Dictionary GetRefreshQueue(); + + void OnRefreshStart(BaseItem item); + void OnRefreshProgress(BaseItem item, double progress); + void OnRefreshComplete(BaseItem item); + + double? GetRefreshProgress(Guid id); + + event EventHandler> RefreshStarted; + event EventHandler> RefreshCompleted; + event EventHandler>> RefreshProgress; } public enum RefreshPriority diff --git a/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs b/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs deleted file mode 100644 index 6523dc4173..0000000000 --- a/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs +++ /dev/null @@ -1,22 +0,0 @@ - -namespace MediaBrowser.Controller.Providers -{ - /// - /// Enum ProviderRefreshStatus - /// - public enum ProviderRefreshStatus - { - /// - /// The success - /// - Success = 0, - /// - /// The completed with errors - /// - CompletedWithErrors = 1, - /// - /// The failure - /// - Failure = 2 - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs index 1b5b4b4e41..e21292cbd7 100644 --- a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs +++ b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs @@ -7,6 +7,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -62,7 +63,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // Kick this off, but no need to wait on it var task = Task.Run(async () => { - await DownloadFontFile(fontsDirectory, fontFilename, new Progress()).ConfigureAwait(false); + await DownloadFontFile(fontsDirectory, fontFilename, new SimpleProgress()).ConfigureAwait(false); await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false); }); diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index d8ec04ff64..374d8d028d 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -47,5 +47,8 @@ namespace MediaBrowser.Model.Entities /// /// The primary image item identifier. public string PrimaryImageItemId { get; set; } + + public double? RefreshProgress { get; set; } + public string RefreshStatus { get; set; } } } diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index 5873293f72..c6f34d58a6 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -228,6 +228,7 @@ ExternalSeriesId, SeriesPresentationUniqueKey, DateLastRefreshed, - DateLastSaved + DateLastSaved, + RefreshState } } diff --git a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs index 566378dd02..499fd2e0b3 100644 --- a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs +++ b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.ImagesByName @@ -30,7 +31,7 @@ namespace MediaBrowser.Providers.ImagesByName var temp = await httpClient.GetTempFile(new HttpRequestOptions { CancellationToken = cancellationToken, - Progress = new Progress(), + Progress = new SimpleProgress(), Url = url }).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 3cdda2cbb8..ce995fe647 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -18,8 +18,10 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Dto; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Serialization; using Priority_Queue; @@ -67,6 +69,10 @@ namespace MediaBrowser.Providers.Manager private readonly IMemoryStreamFactory _memoryStreamProvider; private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); + public event EventHandler> RefreshStarted; + public event EventHandler> RefreshCompleted; + public event EventHandler>> RefreshProgress; + /// /// Initializes a new instance of the class. /// @@ -849,6 +855,89 @@ namespace MediaBrowser.Providers.Manager }); } + private Dictionary _activeRefreshes = new Dictionary(); + + public Dictionary GetRefreshQueue() + { + lock (_refreshQueueLock) + { + var dict = new Dictionary(); + + foreach (var item in _refreshQueue) + { + dict[item.Item1] = item.Item1; + } + return dict; + } + } + + public void OnRefreshStart(BaseItem item) + { + //_logger.Info("OnRefreshStart {0}", item.Id.ToString("N")); + var id = item.Id; + + lock (_activeRefreshes) + { + _activeRefreshes[id] = 0; + } + + if (RefreshStarted != null) + { + RefreshStarted(this, new GenericEventArgs(item)); + } + } + + public void OnRefreshComplete(BaseItem item) + { + //_logger.Info("OnRefreshComplete {0}", item.Id.ToString("N")); + lock (_activeRefreshes) + { + _activeRefreshes.Remove(item.Id); + } + + if (RefreshCompleted != null) + { + RefreshCompleted(this, new GenericEventArgs(item)); + } + } + + public double? GetRefreshProgress(Guid id) + { + lock (_activeRefreshes) + { + double value; + if (_activeRefreshes.TryGetValue(id, out value)) + { + return value; + } + + return null; + } + } + + public void OnRefreshProgress(BaseItem item, double progress) + { + //_logger.Info("OnRefreshProgress {0} {1}", item.Id.ToString("N"), progress); + var id = item.Id; + + lock (_activeRefreshes) + { + if (_activeRefreshes.ContainsKey(id)) + { + _activeRefreshes[id] = progress; + + if (RefreshProgress != null) + { + RefreshProgress(this, new GenericEventArgs>(new Tuple(item, progress))); + } + } + else + { + throw new Exception(string.Format("Refresh for item {0} {1} is not in progress", item.GetType().Name, item.Id.ToString("N"))); + } + } + } + private readonly SimplePriorityQueue> _refreshQueue = new SimplePriorityQueue>(); @@ -906,7 +995,7 @@ namespace MediaBrowser.Providers.Manager var folder = item as Folder; if (folder != null) { - await folder.ValidateChildren(new Progress(), cancellationToken).ConfigureAwait(false); + await folder.ValidateChildren(new SimpleProgress(), cancellationToken).ConfigureAwait(false); } } @@ -951,14 +1040,14 @@ namespace MediaBrowser.Providers.Manager if (folder != null) { - await folder.ValidateChildren(new Progress(), cancellationToken, options).ConfigureAwait(false); + await folder.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); } } } private async Task RefreshCollectionFolderChildren(MetadataRefreshOptions options, CollectionFolder collectionFolder, CancellationToken cancellationToken) { - foreach (var child in collectionFolder.Children.ToList()) + foreach (var child in collectionFolder.GetPhysicalFolders().ToList()) { await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); @@ -966,7 +1055,7 @@ namespace MediaBrowser.Providers.Manager { var folder = (Folder)child; - await folder.ValidateChildren(new Progress(), cancellationToken, options, true).ConfigureAwait(false); + await folder.ValidateChildren(new SimpleProgress(), cancellationToken, options, true).ConfigureAwait(false); } } } @@ -991,7 +1080,7 @@ namespace MediaBrowser.Providers.Manager .Where(i => i != null) .ToList(); - var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress(), cancellationToken, options, true)); + var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new SimpleProgress(), cancellationToken, options, true)); await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs index 3b2d674a66..aef29abbea 100644 --- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs +++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.TV //await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false); - //await series.ValidateChildren(new Progress(), cancellationToken, new MetadataRefreshOptions(directoryService)) + //await series.ValidateChildren(new SimpleProgress(), cancellationToken, new MetadataRefreshOptions(directoryService)) // .ConfigureAwait(false); } } diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index da5a1f2d1e..51ad12364c 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -13,7 +13,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; - +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; @@ -162,7 +162,7 @@ namespace MediaBrowser.Providers.TV await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false); - await series.ValidateChildren(new Progress(), cancellationToken, new MetadataRefreshOptions(directoryService), true) + await series.ValidateChildren(new SimpleProgress(), cancellationToken, new MetadataRefreshOptions(directoryService), true) .ConfigureAwait(false); } } -- cgit v1.2.3 From a107ff0369e5cade3dc2848f190a95b5be302a0b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 24 Jun 2017 14:33:19 -0400 Subject: capture more transcoding info --- MediaBrowser.Api/ApiEntryPoint.cs | 3 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 + MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 5 + MediaBrowser.Api/Playback/MediaInfoService.cs | 2 + MediaBrowser.Api/Playback/UniversalAudioService.cs | 7 +- MediaBrowser.Controller/Entities/Folder.cs | 8 +- .../MediaEncoding/EncodingJobInfo.cs | 22 +- .../MediaEncoding/EncodingJobOptions.cs | 2 + .../Configuration/UserConfiguration.cs | 1 - MediaBrowser.Model/Dlna/ProfileCondition.cs | 1 - MediaBrowser.Model/Dlna/StreamBuilder.cs | 271 +++++++++++++++++++-- MediaBrowser.Model/Dlna/StreamInfo.cs | 20 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 4 + MediaBrowser.Model/Session/TranscodingInfo.cs | 33 +++ 14 files changed, 338 insertions(+), 45 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index e4abe96f3a..34d0bd413a 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -265,7 +265,8 @@ namespace MediaBrowser.Api Height = state.OutputHeight, AudioChannels = state.OutputAudioChannels, IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase), - IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) + IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase), + TranscodeReasons = state.TranscodeReasons }); } } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bbee361995..e4ef294d17 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -583,6 +583,10 @@ namespace MediaBrowser.Api.Playback videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); } } + else if (i == 33) + { + request.TranscodeReasons = val; + } } } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index ddd2d8cd29..c6282bbad5 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -541,6 +541,11 @@ namespace MediaBrowser.Api.Playback.Hls { queryString += "&SegmentContainer=" + state.Request.SegmentContainer; } + // from universal audio service + if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1) + { + queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons; + } // Main stream var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8"; diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index bba8094b64..6853ddbebf 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -513,6 +513,8 @@ namespace MediaBrowser.Api.Playback var profiles = info.GetSubtitleProfiles(false, "-", accessToken); mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex; + mediaSource.TranscodeReasons = info.TranscodeReasons; + foreach (var profile in profiles) { foreach (var stream in mediaSource.MediaStreams) diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs index fffec69489..b9bcd106e1 100644 --- a/MediaBrowser.Api/Playback/UniversalAudioService.cs +++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Threading.Tasks; using MediaBrowser.Api.Playback.Hls; using MediaBrowser.Api.Playback.Progressive; @@ -265,7 +266,8 @@ namespace MediaBrowser.Api.Playback Static = isStatic, SegmentContainer = request.TranscodingContainer, AudioSampleRate = request.MaxAudioSampleRate, - BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames + BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames, + TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()) }; if (isHeadRequest) @@ -307,7 +309,8 @@ namespace MediaBrowser.Api.Playback PlaySessionId = playbackInfoResult.PlaySessionId, StartTimeTicks = request.StartTimeTicks, Static = isStatic, - AudioSampleRate = request.MaxAudioSampleRate + AudioSampleRate = request.MaxAudioSampleRate, + TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()) }; if (isHeadRequest) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 34b33fde0d..ea442ba1ec 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -487,7 +487,7 @@ namespace MediaBrowser.Controller.Entities var folder = this; innerProgress.RegisterAction(p => { - double newPct = .70 * p + 10; + double newPct = .80 * p + 10; progress.Report(newPct); ProviderManager.OnRefreshProgress(folder, newPct); }); @@ -498,11 +498,11 @@ namespace MediaBrowser.Controller.Entities if (refreshChildMetadata) { - progress.Report(80); + progress.Report(90); if (recursive) { - ProviderManager.OnRefreshProgress(this, 80); + ProviderManager.OnRefreshProgress(this, 90); } var container = this as IMetadataContainer; @@ -512,7 +512,7 @@ namespace MediaBrowser.Controller.Entities var folder = this; innerProgress.RegisterAction(p => { - double newPct = .20 * p + 80; + double newPct = .10 * p + 90; progress.Report(newPct); if (recursive) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 57c81ddf76..a83a6a15ea 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; @@ -9,6 +10,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.MediaEncoding { @@ -40,6 +42,24 @@ namespace MediaBrowser.Controller.MediaEncoding public bool ReadInputAtNativeFramerate { get; set; } + private List _transcodeReasons = null; + public List TranscodeReasons + { + get + { + if (_transcodeReasons == null) + { + _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty) + .Split(',') + .Where(i => !string.IsNullOrWhiteSpace(i)) + .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true)) + .ToList(); + } + + return _transcodeReasons; + } + } + public bool IgnoreInputDts { get @@ -251,7 +271,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return AudioStream.SampleRate; } - } + } else if (BaseRequest.AudioSampleRate.HasValue) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 632c350ad0..28ef665669 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -204,6 +204,8 @@ namespace MediaBrowser.Controller.MediaEncoding public string SubtitleCodec { get; set; } + public string TranscodeReasons { get; set; } + /// /// Gets or sets the index of the audio stream. /// diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 5567063fe3..30b5f384fb 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -55,7 +55,6 @@ namespace MediaBrowser.Model.Configuration HidePlayedInLatest = true; PlayDefaultAudioTrack = true; - DisplayMissingEpisodes = true; LatestItemsExcludes = new string[] { }; OrderedViews = new string[] { }; diff --git a/MediaBrowser.Model/Dlna/ProfileCondition.cs b/MediaBrowser.Model/Dlna/ProfileCondition.cs index 3d104f9c41..9234a27136 100644 --- a/MediaBrowser.Model/Dlna/ProfileCondition.cs +++ b/MediaBrowser.Model/Dlna/ProfileCondition.cs @@ -1,5 +1,4 @@ using System.Xml.Serialization; -using MediaBrowser.Model.Dlna; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 0ecc413f24..b758d5ed53 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -105,8 +105,99 @@ namespace MediaBrowser.Model.Dlna return null; } + private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition) + { + switch (condition.Property) + { + case ProfileConditionValue.AudioBitrate: + if (condition.Condition == ProfileConditionType.LessThanEqual) + { + return TranscodeReason.AudioBitrateNotSupported; + } + return TranscodeReason.AudioBitrateNotSupported; + + case ProfileConditionValue.AudioChannels: + if (condition.Condition == ProfileConditionType.LessThanEqual) + { + return TranscodeReason.AudioChannelsNotSupported; + } + return TranscodeReason.AudioChannelsNotSupported; + + case ProfileConditionValue.AudioProfile: + return TranscodeReason.AudioProfileNotSupported; + + case ProfileConditionValue.AudioSampleRate: + return TranscodeReason.AudioSampleRateNotSupported; + + case ProfileConditionValue.Has64BitOffsets: + // TODO + return null; + + case ProfileConditionValue.Height: + return TranscodeReason.VideoResolutionNotSupported; + + case ProfileConditionValue.IsAnamorphic: + return TranscodeReason.AnamorphicVideoNotSupported; + + case ProfileConditionValue.IsAvc: + // TODO + return null; + + case ProfileConditionValue.IsInterlaced: + return TranscodeReason.InterlacedVideoNotSupported; + + case ProfileConditionValue.IsSecondaryAudio: + return TranscodeReason.SecondaryAudioNotSupported; + + case ProfileConditionValue.NumAudioStreams: + // TODO + return null; + + case ProfileConditionValue.NumVideoStreams: + // TODO + return null; + + case ProfileConditionValue.PacketLength: + // TODO + return null; + + case ProfileConditionValue.RefFrames: + return TranscodeReason.RefFramesNotSupported; + + case ProfileConditionValue.VideoBitDepth: + return TranscodeReason.VideoBitDepthNotSupported; + + case ProfileConditionValue.VideoBitrate: + return TranscodeReason.VideoBitrateNotSupported; + + case ProfileConditionValue.VideoCodecTag: + return TranscodeReason.VideoCodecNotSupported; + + case ProfileConditionValue.VideoFramerate: + return TranscodeReason.VideoFramerateNotSupported; + + case ProfileConditionValue.VideoLevel: + return TranscodeReason.VideoLevelNotSupported; + + case ProfileConditionValue.VideoProfile: + return TranscodeReason.VideoProfileNotSupported; + + case ProfileConditionValue.VideoTimestamp: + // TODO + return null; + + case ProfileConditionValue.Width: + return TranscodeReason.VideoResolutionNotSupported; + + default: + return null; + } + } + private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { + List transcodeReasons = new List(); + StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, @@ -133,7 +224,10 @@ namespace MediaBrowser.Model.Dlna MediaStream audioStream = item.GetDefaultAudioStream(null); - List directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options); + var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options); + + List directPlayMethods = directPlayInfo.Item1; + transcodeReasons.AddRange(directPlayInfo.Item2); ConditionProcessor conditionProcessor = new ConditionProcessor(); @@ -180,6 +274,11 @@ namespace MediaBrowser.Model.Dlna if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) { LogConditionFailure(options.Profile, "AudioCodecProfile", c, item); + var transcodeReason = GetTranscodeReasonForFailedCondition(c); + if (transcodeReason.HasValue) + { + transcodeReasons.Add(transcodeReason.Value); + } all = false; break; } @@ -292,9 +391,9 @@ namespace MediaBrowser.Model.Dlna var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate); playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate); - } + playlistItem.TranscodeReasons = transcodeReasons; return playlistItem; } @@ -308,8 +407,10 @@ namespace MediaBrowser.Model.Dlna return options.GetMaxBitrate(isAudio); } - private List GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) + private Tuple, List> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) { + List transcodeReasons = new List(); + DirectPlayProfile directPlayProfile = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { @@ -325,27 +426,134 @@ namespace MediaBrowser.Model.Dlna if (directPlayProfile != null) { // While options takes the network and other factors into account. Only applies to direct stream - if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream) && options.EnableDirectStream) + if (item.SupportsDirectStream) { - playMethods.Add(PlayMethod.DirectStream); + if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream)) + { + if (options.EnableDirectStream) + { + playMethods.Add(PlayMethod.DirectStream); + } + } + else + { + transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit); + } } // The profile describes what the device supports // If device requirements are satisfied then allow both direct stream and direct play - if (item.SupportsDirectPlay && - IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay) && options.EnableDirectPlay) + if (item.SupportsDirectPlay) { - playMethods.Add(PlayMethod.DirectPlay); + if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay)) + { + if (options.EnableDirectPlay) + { + playMethods.Add(PlayMethod.DirectPlay); + } + } + else + { + transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit); + } } } else { + transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles)); + _logger.Info("Profile: {0}, No direct play profiles found for Path: {1}", options.Profile.Name ?? "Unknown Profile", item.Path ?? "Unknown path"); } - return playMethods; + if (playMethods.Count > 0) + { + transcodeReasons.Clear(); + } + else + { + transcodeReasons = transcodeReasons.Distinct().ToList(); + } + + return new Tuple, List>(playMethods, transcodeReasons); + } + + private List GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable directPlayProfiles) + { + var list = new List(); + var containerSupported = false; + var audioSupported = false; + var videoSupported = false; + + foreach (var profile in directPlayProfiles) + { + if (profile.Container.Length > 0) + { + // Check container type + string mediaContainer = item.Container ?? string.Empty; + foreach (string i in profile.GetContainers()) + { + if (StringHelper.EqualsIgnoreCase(i, mediaContainer)) + { + containerSupported = true; + + if (videoStream != null) + { + // Check video codec + List videoCodecs = profile.GetVideoCodecs(); + if (videoCodecs.Count > 0) + { + string videoCodec = videoStream.Codec; + if (!string.IsNullOrEmpty(videoCodec) && ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec)) + { + videoSupported = true; + } + } + else + { + videoSupported = true; + } + } + + if (audioStream != null) + { + // Check audio codec + List audioCodecs = profile.GetAudioCodecs(); + if (audioCodecs.Count > 0) + { + string audioCodec = audioStream.Codec; + if (!string.IsNullOrEmpty(audioCodec) && ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec)) + { + audioSupported = true; + } + } + else + { + audioSupported = true; + } + } + } + } + } + } + + if (!containerSupported) + { + list.Add(TranscodeReason.ContainerNotSupported); + } + + if (videoStream != null && !videoSupported) + { + list.Add(TranscodeReason.VideoCodecNotSupported); + } + + if (audioStream != null && !audioSupported) + { + list.Add(TranscodeReason.VideoCodecNotSupported); + } + + return list; } private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles) @@ -393,6 +601,8 @@ namespace MediaBrowser.Model.Dlna private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options) { + List transcodeReasons = new List(); + StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, @@ -428,7 +638,8 @@ namespace MediaBrowser.Model.Dlna if (isEligibleForDirectPlay || isEligibleForDirectStream) { // See if it can be direct played - PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); + var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); + var directPlay = directPlayInfo.Item1; if (directPlay != null) { @@ -445,6 +656,8 @@ namespace MediaBrowser.Model.Dlna return playlistItem; } + + transcodeReasons.AddRange(directPlayInfo.Item2); } // Can't direct play, find the transcoding profile @@ -618,6 +831,8 @@ namespace MediaBrowser.Model.Dlna } } + playlistItem.TranscodeReasons = transcodeReasons; + return playlistItem; } @@ -677,7 +892,7 @@ namespace MediaBrowser.Model.Dlna return Math.Min(defaultBitrate, encoderAudioBitrateLimit); } - private PlayMethod? GetVideoDirectPlayProfile(VideoOptions options, + private Tuple> GetVideoDirectPlayProfile(VideoOptions options, MediaSourceInfo mediaSource, MediaStream videoStream, MediaStream audioStream, @@ -688,11 +903,11 @@ namespace MediaBrowser.Model.Dlna if (options.ForceDirectPlay) { - return PlayMethod.DirectPlay; + return new Tuple>(PlayMethod.DirectPlay, new List()); } if (options.ForceDirectStream) { - return PlayMethod.DirectStream; + return new Tuple>(PlayMethod.DirectStream, new List()); } if (videoStream == null) @@ -701,7 +916,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple>(null, new List { TranscodeReason.UnknownVideoStreamInfo }); } // See if it can be direct played @@ -721,7 +936,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles)); } string container = mediaSource.Container; @@ -784,7 +999,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple>(null, new List { TranscodeReason.UnknownVideoStreamInfo }); } conditions = new List(); @@ -819,7 +1034,12 @@ namespace MediaBrowser.Model.Dlna { LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource); - return null; + var transcodeReason = GetTranscodeReasonForFailedCondition(i); + var transcodeReasons = transcodeReason.HasValue + ? new List { transcodeReason.Value } + : new List { }; + + return new Tuple>(null, transcodeReasons); } } @@ -833,7 +1053,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple>(null, new List { TranscodeReason.UnknownAudioStreamInfo }); } conditions = new List(); @@ -870,17 +1090,22 @@ namespace MediaBrowser.Model.Dlna { LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource); - return null; + var transcodeReason = GetTranscodeReasonForFailedCondition(i); + var transcodeReasons = transcodeReason.HasValue + ? new List { transcodeReason.Value } + : new List { }; + + return new Tuple>(null, transcodeReasons); } } } if (isEligibleForDirectStream && mediaSource.SupportsDirectStream) { - return PlayMethod.DirectStream; + return new Tuple>(PlayMethod.DirectStream, new List()); } - return null; + return new Tuple>(null, new List { TranscodeReason.ContainerBitrateExceedsLimit }); } private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource) @@ -1047,12 +1272,12 @@ namespace MediaBrowser.Model.Dlna // Don't restrict by bitrate if coming from an external domain if (item.IsRemote) { - return true; + return true; } if (!maxBitrate.HasValue) { - _logger.Info("Cannot "+ playMethod + " due to unknown supported bitrate"); + _logger.Info("Cannot " + playMethod + " due to unknown supported bitrate"); return false; } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index ba5251e8c9..d70d89cf75 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -21,6 +21,7 @@ namespace MediaBrowser.Model.Dlna AudioCodecs = new string[] { }; VideoCodecs = new string[] { }; SubtitleCodecs = new string[] { }; + TranscodeReasons = new List(); } public string ItemId { get; set; } @@ -89,6 +90,7 @@ namespace MediaBrowser.Model.Dlna public string PlaySessionId { get; set; } public List AllMediaSources { get; set; } + public List TranscodeReasons { get; set; } public string MediaSourceId { @@ -231,22 +233,11 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty)); list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty)); - var forceStartPosition = false; long startPositionTicks = item.StartPositionTicks; - //if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0) - //{ - // var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value; - // elapsed -= TimeSpan.FromSeconds(20); - // if (elapsed.TotalSeconds >= 0) - // { - // startPositionTicks = elapsed.Ticks + startPositionTicks; - // forceStartPosition = true; - // } - //} var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls"); - if (isHls && !forceStartPosition) + if (isHls) { list.Add(new NameValuePair("StartTimeTicks", string.Empty)); } @@ -310,6 +301,11 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString())); } + if (isDlna || !item.IsDirectStream) + { + list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray()))); + } + return list; } diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index c93eca0e79..08824913f8 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.MediaInfo; using System.Collections.Generic; using System.Linq; using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Session; namespace MediaBrowser.Model.Dto { @@ -110,6 +111,9 @@ namespace MediaBrowser.Model.Dto } } + [IgnoreDataMember] + public List TranscodeReasons { get; set; } + public int? DefaultAudioStreamIndex { get; set; } public int? DefaultSubtitleStreamIndex { get; set; } diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index e646d80d35..67eac6fd57 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace MediaBrowser.Model.Session { public class TranscodingInfo @@ -15,5 +17,36 @@ namespace MediaBrowser.Model.Session public int? Width { get; set; } public int? Height { get; set; } public int? AudioChannels { get; set; } + + public List TranscodeReasons { get; set; } + + public TranscodingInfo() + { + TranscodeReasons = new List(); + } + } + + public enum TranscodeReason + { + ContainerNotSupported = 0, + VideoCodecNotSupported = 1, + AudioCodecNotSupported = 2, + ContainerBitrateExceedsLimit = 3, + AudioBitrateNotSupported = 4, + AudioChannelsNotSupported = 5, + VideoResolutionNotSupported = 6, + UnknownVideoStreamInfo = 7, + UnknownAudioStreamInfo = 8, + AudioProfileNotSupported = 9, + AudioSampleRateNotSupported = 10, + AnamorphicVideoNotSupported = 11, + InterlacedVideoNotSupported = 12, + SecondaryAudioNotSupported = 13, + RefFramesNotSupported = 14, + VideoBitDepthNotSupported = 15, + VideoBitrateNotSupported = 16, + VideoFramerateNotSupported = 17, + VideoLevelNotSupported = 18, + VideoProfileNotSupported = 19 } } \ No newline at end of file -- cgit v1.2.3 From dcaf8356e6400543e10ff2ee89fc9b3bdf97ef77 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 29 Jun 2017 15:10:58 -0400 Subject: update inherited images --- .../Data/SqliteItemRepository.cs | 4 ++-- Emby.Server.Implementations/Dto/DtoService.cs | 17 ++++++++++++----- Emby.Server.Implementations/Session/SessionManager.cs | 2 ++ MediaBrowser.Controller/Channels/Channel.cs | 9 +++++++++ .../Collections/ManualCollectionsFolder.cs | 11 +++++++++++ MediaBrowser.Controller/Entities/Audio/MusicArtist.cs | 9 +++++++++ MediaBrowser.Controller/Entities/BasePluginFolder.cs | 10 ++++++++++ MediaBrowser.Controller/Entities/CollectionFolder.cs | 9 +++++++++ MediaBrowser.Controller/Entities/Folder.cs | 9 +++++++++ MediaBrowser.Controller/Entities/GameSystem.cs | 9 +++++++++ MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 10 ++++++++++ MediaBrowser.Controller/Entities/PhotoAlbum.cs | 9 +++++++++ MediaBrowser.Controller/Entities/TV/Series.cs | 9 +++++++++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 9 +++++++++ MediaBrowser.Controller/Entities/UserView.cs | 9 +++++++++ MediaBrowser.Controller/Entities/Video.cs | 9 +++++++++ MediaBrowser.Controller/LiveTv/RecordingGroup.cs | 9 +++++++++ MediaBrowser.Controller/Playlists/Playlist.cs | 9 +++++++++ MediaBrowser.Model/Session/PlaystateCommand.cs | 3 ++- MediaBrowser.Model/Session/SessionInfoDto.cs | 2 ++ .../Devices/CameraUploadsFolder.cs | 9 +++++++++ .../Playlists/ManualPlaylistsFolder.cs | 9 +++++++++ SharedVersion.cs | 2 +- 23 files changed, 178 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 1144bd3c66..52abbae3e2 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -3758,10 +3758,10 @@ namespace Emby.Server.Implementations.Data if (query.MinDateLastSavedForUser.HasValue) { - whereClauses.Add("DateLastSaved>=@MinDateLastSaved"); + whereClauses.Add("DateLastSaved>=@MinDateLastSavedForUser"); if (statement != null) { - statement.TryBind("@MinDateLastSaved", query.MinDateLastSavedForUser.Value); + statement.TryBind("@MinDateLastSavedForUser", query.MinDateLastSavedForUser.Value); } } diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 52ebd5e308..9767de9e0a 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1464,9 +1464,9 @@ namespace Emby.Server.Implementations.Dto } } - private BaseItem GetImageDisplayParent(BaseItem item) + private BaseItem GetImageDisplayParent(BaseItem currentItem, BaseItem originalItem) { - var musicAlbum = item as MusicAlbum; + var musicAlbum = currentItem as MusicAlbum; if (musicAlbum != null) { var artist = musicAlbum.GetMusicArtist(new DtoOptions(false)); @@ -1476,7 +1476,14 @@ namespace Emby.Server.Implementations.Dto } } - return item.DisplayParent ?? item.GetParent(); + var parent = currentItem.DisplayParent ?? currentItem.GetParent(); + + if (parent == null && !(originalItem is UserRootFolder) && !(originalItem is UserView) && !(originalItem is AggregateFolder) && !(originalItem is ICollectionFolder) && !(originalItem is Channel)) + { + parent = _libraryManager.GetCollectionFolders(originalItem).FirstOrDefault(); + } + + return parent; } private void AddInheritedImages(BaseItemDto dto, BaseItem item, DtoOptions options, BaseItem owner) @@ -1503,7 +1510,7 @@ namespace Emby.Server.Implementations.Dto var isFirst = true; while (((!dto.HasLogo && logoLimit > 0) || (!dto.HasArtImage && artLimit > 0) || (!dto.HasThumb && thumbLimit > 0) || parent is Series) && - (parent = parent ?? (isFirst ? GetImageDisplayParent(item) ?? owner : parent)) != null) + (parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null) { if (parent == null) { @@ -1560,7 +1567,7 @@ namespace Emby.Server.Implementations.Dto break; } - parent = GetImageDisplayParent(parent); + parent = GetImageDisplayParent(parent, item); } } diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 6bfa90498f..68ab259470 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1622,6 +1622,8 @@ namespace Emby.Server.Implementations.Session TranscodingInfo = session.NowPlayingItem == null ? null : session.TranscodingInfo }; + dto.ServerId = _appHost.SystemId; + if (session.UserId.HasValue) { dto.UserId = session.UserId.Value.ToString("N"); diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 8e2faa20e2..c6e750a0c0 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -32,6 +32,15 @@ namespace MediaBrowser.Controller.Channels return base.IsVisible(user); } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override SourceType SourceType { diff --git a/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs index d2d28e5047..160a788f1c 100644 --- a/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs +++ b/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Controller.Collections { @@ -18,11 +19,21 @@ namespace MediaBrowser.Controller.Collections } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + public bool IsHiddenFromUser(User user) { return !ConfigurationManager.Configuration.DisplayCollectionsView; } + [IgnoreDataMember] public override string CollectionType { get { return Model.Entities.CollectionType.BoxSets; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index ebd83205e5..7a37b2e02e 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -35,6 +35,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsCumulativeRunTimeTicks { diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index 7dbea317c8..a61862f280 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -9,6 +9,7 @@ namespace MediaBrowser.Controller.Entities /// public abstract class BasePluginFolder : Folder, ICollectionFolder { + [IgnoreDataMember] public virtual string CollectionType { get { return null; } @@ -24,6 +25,15 @@ namespace MediaBrowser.Controller.Entities return true; } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsPeople { diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 0bd8606b96..d88b7da346 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -49,6 +49,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + public override bool CanDelete() { return false; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ea442ba1ec..5d74cf218b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -65,6 +65,15 @@ namespace MediaBrowser.Controller.Entities get { return false; } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return true; + } + } + [IgnoreDataMember] public override bool SupportsPlayedStatus { diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index d8879155af..bbaec14a15 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -35,6 +35,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + /// /// Gets or sets the game system. /// diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 8d440e51b8..071ed405f1 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Entities.Movies Shares = new List(); } + [IgnoreDataMember] protected override bool FilterLinkedChildrenPerUser { get @@ -37,6 +38,15 @@ namespace MediaBrowser.Controller.Entities.Movies } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + public List LocalTrailerIds { get; set; } public List RemoteTrailerIds { get; set; } diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index dd3cd98fb9..af9d8c801d 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -21,5 +21,14 @@ namespace MediaBrowser.Controller.Entities return false; } } + + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 1e4b3fdad3..8b73b80b02 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -53,6 +53,15 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + public List LocalTrailerIds { get; set; } public List RemoteTrailerIds { get; set; } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 3e4931e774..d351563450 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsPlayedStatus { diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 27be696ebd..0d2d69c949 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -40,6 +40,15 @@ namespace MediaBrowser.Controller.Entities return list; } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsPlayedStatus { diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index b6887940ed..7978f47613 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -43,6 +43,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return true; + } + } + [IgnoreDataMember] public override bool SupportsPositionTicksResume { diff --git a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs index b54ca89747..3ee0613605 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs @@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override SourceType SourceType { diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 854f8d7a2f..c992ac56a7 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -32,6 +32,15 @@ namespace MediaBrowser.Controller.Playlists } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsPlayedStatus { diff --git a/MediaBrowser.Model/Session/PlaystateCommand.cs b/MediaBrowser.Model/Session/PlaystateCommand.cs index 2af4f26e37..3b70d54542 100644 --- a/MediaBrowser.Model/Session/PlaystateCommand.cs +++ b/MediaBrowser.Model/Session/PlaystateCommand.cs @@ -37,6 +37,7 @@ namespace MediaBrowser.Model.Session /// /// The fast forward /// - FastForward + FastForward, + PlayPause } } \ No newline at end of file diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs index b21a089aab..3081d7ee3b 100644 --- a/MediaBrowser.Model/Session/SessionInfoDto.cs +++ b/MediaBrowser.Model/Session/SessionInfoDto.cs @@ -26,6 +26,8 @@ namespace MediaBrowser.Model.Session /// The id. public string Id { get; set; } + public string ServerId { get; set; } + /// /// Gets or sets the user id. /// diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs index 57254eed49..ae700e250f 100644 --- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs +++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs @@ -33,6 +33,15 @@ namespace MediaBrowser.Server.Implementations.Devices get { return Model.Entities.CollectionType.Photos; } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + public override string GetClientTypeName() { return typeof(CollectionFolder).Name; diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index bd16dc2e9e..236dbde9cc 100644 --- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -37,6 +37,15 @@ namespace MediaBrowser.Server.Implementations.Playlists } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get + { + return false; + } + } + [IgnoreDataMember] public override string CollectionType { diff --git a/SharedVersion.cs b/SharedVersion.cs index d713641489..1af2abc27f 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.20.16")] +[assembly: AssemblyVersion("3.2.20.17")] -- cgit v1.2.3