using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; namespace JellyfinPlugin.Tasks { public class LibraryForceRescanTask : IScheduledTask { private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; public LibraryForceRescanTask(ILogger logger, ILibraryManager libraryManager) { _logger = logger; _libraryManager = libraryManager; } public string Name => "Force Rescan All Black Bars (Black Bar Remover)"; public string Key => "BlackBarForceRescanTask"; public string Description => "Forces a rescan of all files, overwriting any previously saved crop data. Use this if you changed the detection limit."; public string Category => "Library"; public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) { var config = Plugin.Instance!.Configuration; if (!config.IsEnabled) { _logger.LogInformation("Plugin is disabled. Skipping."); return; } var items = _libraryManager.RootFolder.GetRecursiveChildren() .Where(x => x is Movie || x is Episode) .ToList(); int total = items.Count; if (total == 0) return; int processed = 0; int maxParallel = Math.Clamp(config.MaxParallelScans, 1, 16); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = maxParallel, CancellationToken = cancellationToken }; _logger.LogInformation("Starting Force Rescan of {Total} items with {MaxParallel} parallel workers.", total, maxParallel); await Parallel.ForEachAsync(items, parallelOptions, async (item, ct) => { var path = item.Path; if (!string.IsNullOrEmpty(path) && File.Exists(path)) { try { string cropData = await CropHelper.DetectCropAsync(path, config.CropDetectLimit); if (!string.IsNullOrEmpty(cropData)) { if (item.ProviderIds == null) { item.ProviderIds = new Dictionary(); } item.ProviderIds["BlackBarCrop"] = cropData; await _libraryManager.UpdateItemAsync(item, item, ItemUpdateType.MetadataEdit, ct); _logger.LogInformation("Found black bars {Crop} in {Path}", cropData, path); } } catch (Exception ex) { _logger.LogError(ex, "Error scanning file {Path}", path); } } int current = Interlocked.Increment(ref processed); progress.Report((current / (double)total) * 100); }); } public IEnumerable GetDefaultTriggers() { return Array.Empty(); } } }