diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-04-25 23:39:21 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-04-25 23:39:21 -0400 |
| commit | 69622a74a8c60f60d9859de8d247bcbe488e68d3 (patch) | |
| tree | f84f8a9ae8dcdc99bac35b7ef4ad2911d669a085 | |
| parent | 54e04dd027f75066981524f7db02664b3afed2ab (diff) | |
faster cleanup of missing episodes
4 files changed, 151 insertions, 27 deletions
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index c8b3d5131..0f6b10b43 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Library /// <param name="fileInfo">The file information.</param> /// <param name="parent">The parent.</param> /// <returns>BaseItem.</returns> - BaseItem ResolvePath(FileSystemMetadata fileInfo, + BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null); /// <summary> @@ -36,9 +36,9 @@ namespace MediaBrowser.Controller.Library /// <param name="parent">The parent.</param> /// <param name="collectionType">Type of the collection.</param> /// <returns>List{``0}.</returns> - IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, + IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, - Folder parent, string + Folder parent, string collectionType = null); /// <summary> @@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.Library /// <param name="path">The path.</param> /// <returns>BaseItem.</returns> BaseItem FindByPath(string path); - + /// <summary> /// Gets the artist. /// </summary> @@ -156,7 +156,7 @@ namespace MediaBrowser.Controller.Library /// <param name="id">The identifier.</param> /// <returns>BaseItem.</returns> BaseItem GetMemoryItemById(Guid id); - + /// <summary> /// Gets the intros. /// </summary> @@ -243,6 +243,8 @@ namespace MediaBrowser.Controller.Library /// <returns>BaseItem.</returns> BaseItem RetrieveItem(Guid id); + bool IsScanRunning { get; } + /// <summary> /// Occurs when [item added]. /// </summary> @@ -290,7 +292,7 @@ namespace MediaBrowser.Controller.Library /// <param name="path">The path.</param> /// <returns>System.String.</returns> string GetConfiguredContentType(string path); - + /// <summary> /// Normalizes the root path list. /// </summary> @@ -332,8 +334,8 @@ namespace MediaBrowser.Controller.Library Task<UserView> GetNamedView(User user, string name, string parentId, - string viewType, - string sortName, + string viewType, + string sortName, CancellationToken cancellationToken); /// <summary> @@ -346,8 +348,8 @@ namespace MediaBrowser.Controller.Library /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<UserView>.</returns> Task<UserView> GetNamedView(User user, - string name, - string viewType, + string name, + string viewType, string sortName, CancellationToken cancellationToken); @@ -393,7 +395,7 @@ namespace MediaBrowser.Controller.Library string viewType, string sortName, CancellationToken cancellationToken); - + /// <summary> /// Determines whether [is video file] [the specified path]. /// </summary> @@ -477,14 +479,14 @@ namespace MediaBrowser.Controller.Library /// <param name="query">The query.</param> /// <returns>List<PersonInfo>.</returns> List<PersonInfo> GetPeople(InternalPeopleQuery query); - + /// <summary> /// Gets the people items. /// </summary> /// <param name="query">The query.</param> /// <returns>List<Person>.</returns> List<Person> GetPeopleItems(InternalPeopleQuery query); - + /// <summary> /// Gets all people names. /// </summary> @@ -559,7 +561,7 @@ namespace MediaBrowser.Controller.Library /// <param name="query">The query.</param> /// <returns>QueryResult<BaseItem>.</returns> QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query); - + /// <summary> /// Ignores the file. /// </summary> diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index ad55c186a..8ae9aa5bb 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -27,6 +27,8 @@ namespace MediaBrowser.Providers.TV private readonly IFileSystem _fileSystem; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private static readonly SemaphoreSlim _resourceLock = new SemaphoreSlim(1, 1); + public static bool IsRunning = false; public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization, IFileSystem fileSystem) { @@ -37,13 +39,16 @@ namespace MediaBrowser.Providers.TV _fileSystem = fileSystem; } - public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken) + public async Task Run(List<IGrouping<string, Series>> series, bool addNewItems, CancellationToken cancellationToken) { + await _resourceLock.WaitAsync(cancellationToken).ConfigureAwait(false); + IsRunning = true; + foreach (var seriesGroup in series) { try { - await Run(seriesGroup, cancellationToken).ConfigureAwait(false); + await Run(seriesGroup, addNewItems, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -58,9 +63,12 @@ namespace MediaBrowser.Providers.TV _logger.ErrorException("Error in missing episode provider for series id {0}", ex, seriesGroup.Key); } } + + IsRunning = false; + _resourceLock.Release(); } - private async Task Run(IGrouping<string, Series> group, CancellationToken cancellationToken) + private async Task Run(IGrouping<string, Series> group, bool addNewItems, CancellationToken cancellationToken) { var tvdbId = group.Key; @@ -110,7 +118,7 @@ namespace MediaBrowser.Providers.TV var hasNewEpisodes = false; - if (_config.Configuration.EnableInternetProviders) + if (_config.Configuration.EnableInternetProviders && addNewItems) { var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase)); @@ -427,7 +435,7 @@ namespace MediaBrowser.Providers.TV await season.AddChild(episode, cancellationToken).ConfigureAwait(false); - await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) + await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { }, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs index 5428e6c92..0fd6fa56f 100644 --- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs @@ -11,6 +11,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Model.Tasks; namespace MediaBrowser.Providers.TV { @@ -46,14 +50,17 @@ namespace MediaBrowser.Providers.TV private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken) { - var seriesList = _libraryManager.RootFolder - .GetRecursiveChildren(i => i is Series) - .Cast<Series>() - .ToList(); + var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true + + }).Cast<Series>().ToList(); var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList(); - await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem).Run(seriesGroups, cancellationToken).ConfigureAwait(false); + await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem) + .Run(seriesGroups, true, cancellationToken).ConfigureAwait(false); var numComplete = 0; @@ -82,7 +89,7 @@ namespace MediaBrowser.Providers.TV } } - private IEnumerable<IGrouping<string, Series>> FindSeriesGroups(List<Series> seriesList) + internal static IEnumerable<IGrouping<string, Series>> FindSeriesGroups(List<Series> seriesList) { var links = seriesList.ToDictionary(s => s, s => seriesList.Where(c => c != s && ShareProviderId(s, c)).ToList()); @@ -102,7 +109,7 @@ namespace MediaBrowser.Providers.TV } } - private void FindAllLinked(Series series, HashSet<Series> visited, IDictionary<Series, List<Series>> linksMap, List<Series> results) + private static void FindAllLinked(Series series, HashSet<Series> visited, IDictionary<Series, List<Series>> linksMap, List<Series> results) { results.Add(series); visited.Add(series); @@ -118,7 +125,7 @@ namespace MediaBrowser.Providers.TV } } - private bool ShareProviderId(Series a, Series b) + private static bool ShareProviderId(Series a, Series b) { return a.ProviderIds.Any(id => { @@ -137,4 +144,108 @@ namespace MediaBrowser.Providers.TV } } + public class CleanMissingEpisodesEntryPoint : IServerEntryPoint + { + private readonly ILibraryManager _libraryManager; + private readonly IServerConfigurationManager _config; + private readonly ILogger _logger; + private readonly ILocalizationManager _localization; + private readonly IFileSystem _fileSystem; + private readonly object _libraryChangedSyncLock = new object(); + private const int LibraryUpdateDuration = 180000; + private readonly ITaskManager _taskManager; + + public CleanMissingEpisodesEntryPoint(ILibraryManager libraryManager, IServerConfigurationManager config, ILogger logger, ILocalizationManager localization, IFileSystem fileSystem, ITaskManager taskManager) + { + _libraryManager = libraryManager; + _config = config; + _logger = logger; + _localization = localization; + _fileSystem = fileSystem; + _taskManager = taskManager; + } + + private Timer LibraryUpdateTimer { get; set; } + + public void Run() + { + _libraryManager.ItemAdded += _libraryManager_ItemAdded; + } + + private void _libraryManager_ItemAdded(object sender, ItemChangeEventArgs e) + { + if (!FilterItem(e.Item)) + { + return; + } + + lock (_libraryChangedSyncLock) + { + if (LibraryUpdateTimer == null) + { + LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, Timeout.Infinite); + } + else + { + LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite); + } + } + } + + private async void LibraryUpdateTimerCallback(object state) + { + if (MissingEpisodeProvider.IsRunning) + { + return; + } + + if (_libraryManager.IsScanRunning) + { + return ; + } + + var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true + + }).Cast<Series>().ToList(); + + var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList(); + + await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem) + .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false); + } + + private bool FilterItem(BaseItem item) + { + return item is Episode && item.LocationType != LocationType.Virtual; + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + if (LibraryUpdateTimer != null) + { + LibraryUpdateTimer.Dispose(); + LibraryUpdateTimer = null; + } + + _libraryManager.ItemAdded -= _libraryManager_ItemAdded; + } + } + } } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index ccba293a3..17c4f59ba 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -143,6 +143,7 @@ namespace MediaBrowser.Server.Implementations.Library private readonly Func<ILibraryMonitor> _libraryMonitorFactory; private readonly Func<IProviderManager> _providerManagerFactory; private readonly Func<IUserViewManager> _userviewManager; + public bool IsScanRunning { get; private set; } /// <summary> /// The _library items cache @@ -1102,6 +1103,7 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>Task.</returns> public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken) { + IsScanRunning = true; _libraryMonitorFactory().Stop(); try @@ -1111,6 +1113,7 @@ namespace MediaBrowser.Server.Implementations.Library finally { _libraryMonitorFactory().Start(); + IsScanRunning = false; } } |
