Files
blackBarRemover/JellyfinPlugin/LibraryMonitor.cs
T

103 lines
3.5 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
namespace JellyfinPlugin
{
public class LibraryMonitor : IHostedService, IDisposable
{
private readonly ILibraryManager _libraryManager;
private readonly ILogger<LibraryMonitor> _logger;
private readonly SemaphoreSlim _ffmpegSemaphore = new SemaphoreSlim(2, 2);
public LibraryMonitor(ILibraryManager libraryManager, ILogger<LibraryMonitor> logger)
{
_libraryManager = libraryManager;
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_libraryManager.ItemAdded += OnItemAddedOrUpdated;
_libraryManager.ItemUpdated += OnItemAddedOrUpdated;
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
private void OnItemAddedOrUpdated(object? sender, ItemChangeEventArgs e)
{
if (e.Item is Video video && (video is Movie || video is Episode))
{
if (!Plugin.Instance!.Configuration.IsEnabled) return;
// Fire and forget, don't block library scan
_ = Task.Run(() => ProcessVideoAsync(video));
}
}
private async Task ProcessVideoAsync(Video video)
{
try
{
if (video.ProviderIds != null && video.ProviderIds.ContainsKey("BlackBarCrop"))
{
return;
}
var path = video.Path;
if (string.IsNullOrEmpty(path) || !File.Exists(path)) return;
await _ffmpegSemaphore.WaitAsync();
try
{
double limit = Plugin.Instance!.Configuration.CropDetectLimit;
string cropData = await CropHelper.DetectCropAsync(path, limit);
if (!string.IsNullOrEmpty(cropData))
{
if (video.ProviderIds == null)
{
video.ProviderIds = new System.Collections.Generic.Dictionary<string, string>();
}
video.ProviderIds["BlackBarCrop"] = cropData;
await _libraryManager.UpdateItemAsync(video, video, ItemUpdateType.MetadataEdit, CancellationToken.None);
_logger.LogInformation("Saved crop proportions {CropData} for file {Path}", cropData, path);
}
}
finally
{
_ffmpegSemaphore.Release();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing video: {Path}", video.Path);
}
}
public void Dispose()
{
_libraryManager.ItemAdded -= OnItemAddedOrUpdated;
_libraryManager.ItemUpdated -= OnItemAddedOrUpdated;
_ffmpegSemaphore.Dispose();
}
}
}