diff --git a/src/CasaBot/AutoScan/AutoScanApp.cs b/src/CasaBot/AutoScan/AutoScanApp.cs index 3f48edf..a02e13d 100644 --- a/src/CasaBot/AutoScan/AutoScanApp.cs +++ b/src/CasaBot/AutoScan/AutoScanApp.cs @@ -14,6 +14,8 @@ public class AutoScanApp private readonly ILogger _logger; private readonly IScheduler _scheduler; private readonly IChainerListenerFactory _chainerListenerFactory; + + public Func? OnScanCompleted { get; set; } public AutoScanApp(IOptions options, ILogger logger, IScheduler scheduler, IChainerListenerFactory chainerListenerFactory) { @@ -60,6 +62,7 @@ public class AutoScanApp var chainer = _chainerListenerFactory.CreateChainerListener("Scan Chainer"); chainer.AddJobChainLink(downloaderJob.Key, scannerJob.Key); + chainer.OnJobChainFinished = async () => await OnScanCompleted?.Invoke(_options); _scheduler.ListenerManager.AddJobListener(chainer, GroupMatcher.GroupEquals(groupName)); diff --git a/src/CasaBot/AutoScan/Implementations/DVRScanner.cs b/src/CasaBot/AutoScan/Implementations/DVRScanner.cs index 041c561..a557d3f 100644 --- a/src/CasaBot/AutoScan/Implementations/DVRScanner.cs +++ b/src/CasaBot/AutoScan/Implementations/DVRScanner.cs @@ -28,7 +28,7 @@ public class DVRScanner : IDVRScanner { _logger.LogDebug("Scanning videos..."); var folderParam = Path.Combine(_options.MediaFolder!, "*.mp4"); - var arguments = $"-i {folderParam} -c {_options.Scanner.ConfigFile} --thumbnails highscore"; + var arguments = $"-i {folderParam} -c {_options.Scanner.ConfigFile} --output-dir {_options.Scanner.DetectionFolder} --thumbnails highscore"; _logger.LogDebug("Executing command: {_dvrScannerFile} {arguments}", _options.Scanner.Exe, arguments); var process = new Process { @@ -36,7 +36,7 @@ public class DVRScanner : IDVRScanner { FileName = _options.Scanner.Exe, Arguments = arguments, - RedirectStandardOutput = true, + RedirectStandardOutput = false, RedirectStandardError = false, UseShellExecute = false, CreateNoWindow = true, diff --git a/src/CasaBot/AutoScan/Implementations/ShinobiConnector.cs b/src/CasaBot/AutoScan/Implementations/ShinobiConnector.cs index 34aeda0..aa41a78 100644 --- a/src/CasaBot/AutoScan/Implementations/ShinobiConnector.cs +++ b/src/CasaBot/AutoScan/Implementations/ShinobiConnector.cs @@ -48,7 +48,7 @@ public class ShinobiConnector : IDVRConnector }).OrderBy(x => x.time).ToList(); } - public async Task DownloadMonitorVideo(VideoDetail video, string downloadFolder, CancellationToken cancellationToken = default) + public async Task DownloadMonitorVideo(VideoDetail video, string downloadFolder, bool runDry, CancellationToken cancellationToken = default) { var endpoint = $"{_options.URL}{video.href}"; _logger.LogDebug("Fetching video from endpoint: {Endpoint}", endpoint); @@ -62,7 +62,7 @@ public class ShinobiConnector : IDVRConnector _logger.LogDebug("Downloading video..."); var videoData = await _httpClient.GetByteArrayAsync(endpoint, cancellationToken); - if(_options.RunDry) + if(runDry) { _logger.LogInformation("RunDry is enabled, skipping video download"); return; diff --git a/src/CasaBot/AutoScan/Interfaces/IDVRConnector.cs b/src/CasaBot/AutoScan/Interfaces/IDVRConnector.cs index e13878a..8fd1ffb 100644 --- a/src/CasaBot/AutoScan/Interfaces/IDVRConnector.cs +++ b/src/CasaBot/AutoScan/Interfaces/IDVRConnector.cs @@ -5,5 +5,5 @@ namespace AutoScan.Interfaces; public interface IDVRConnector { Task> FetchMonitorVideosBetween(DateTime from, DateTime to, CancellationToken cancellationToken = default); - Task DownloadMonitorVideo(VideoDetail video, string downloadFolder, CancellationToken cancellationToken = default); + Task DownloadMonitorVideo(VideoDetail video, string downloadFolder, bool runDry = false, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/CasaBot/AutoScan/Jobs/DownloaderJob.cs b/src/CasaBot/AutoScan/Jobs/DownloaderJob.cs index 041e016..7b63a03 100644 --- a/src/CasaBot/AutoScan/Jobs/DownloaderJob.cs +++ b/src/CasaBot/AutoScan/Jobs/DownloaderJob.cs @@ -65,7 +65,7 @@ public class DownloaderJob : IJob foreach (var video in videos) { _logger.LogDebug("Downloading video {Filename}", video.filename); - await _dvrConnector.DownloadMonitorVideo(video, _options.MediaFolder, context.CancellationToken); + await _dvrConnector.DownloadMonitorVideo(video, _options.MediaFolder, _options.RunDry, context.CancellationToken); } context.Result = new JobResult() @@ -78,8 +78,9 @@ public class DownloaderJob : IJob private void CleanMediaFolder() { - if (_options.MediaFolder is not null) + if (_options.MediaFolder is not null && !_options.RunDry) { + _logger.LogDebug("Cleaning media folder {MediaFolder}", _options.MediaFolder); Directory.CreateDirectory(Path.GetDirectoryName(_options.MediaFolder)!); foreach (var file in Directory.GetFiles(_options.MediaFolder)) { @@ -87,8 +88,9 @@ public class DownloaderJob : IJob } } - if(_options.Scanner?.DetectionFolder is not null) + if(_options.Scanner?.DetectionFolder is not null && !_options.Scanner.RunDry) { + _logger.LogDebug("Cleaning detection folder {DetectionFolder}", _options.Scanner.DetectionFolder); Directory.CreateDirectory(Path.GetDirectoryName(_options.Scanner.DetectionFolder)!); foreach (var file in Directory.GetFiles(_options.Scanner.DetectionFolder)) { @@ -96,15 +98,5 @@ public class DownloaderJob : IJob } } - if(_options.Screenshot?.Folder is not null) - { - Directory.CreateDirectory(Path.GetDirectoryName(_options.Screenshot.Folder)!); - foreach (var file in Directory.GetFiles(_options.Screenshot.Folder)) - { - File.Delete(file); - } - } - - } } \ No newline at end of file diff --git a/src/CasaBot/AutoScan/Jobs/ScannerJob.cs b/src/CasaBot/AutoScan/Jobs/ScannerJob.cs index e13cc93..2e6bc19 100644 --- a/src/CasaBot/AutoScan/Jobs/ScannerJob.cs +++ b/src/CasaBot/AutoScan/Jobs/ScannerJob.cs @@ -14,12 +14,10 @@ public class ScannerJob : IJob _logger = logger; _scanner = scanner; } - public Task Execute(IJobExecutionContext context) + public async Task Execute(IJobExecutionContext context) { _logger.LogInformation("Scanner {scannerName} is ready to scan!", _scanner.GetType().Name); - _scanner.ScanVideos(); - return Task.CompletedTask; - + await _scanner.ScanVideos(); } } \ No newline at end of file diff --git a/src/CasaBot/AutoScan/Listener/ChainerListener.cs b/src/CasaBot/AutoScan/Listener/ChainerListener.cs index a483a98..5fe80b1 100644 --- a/src/CasaBot/AutoScan/Listener/ChainerListener.cs +++ b/src/CasaBot/AutoScan/Listener/ChainerListener.cs @@ -9,6 +9,7 @@ public class ChainerListener : JobListenerSupport { private readonly ILogger _logger; private readonly Dictionary _chainLinks; + public Func OnJobChainFinished { get; set; } public ChainerListener(string name, ILogger logger) { @@ -51,7 +52,13 @@ public class ChainerListener : JobListenerSupport if (sj == null) { - return; + //check if it's the last one in the chain + if (_chainLinks.ContainsValue(context.JobDetail.Key)) + { + _logger.LogInformation("Job '{JobKey}' is the last in the chain", context.JobDetail.Key); + await OnJobChainFinished?.Invoke(); + return; + } } _logger.LogInformation("Job '{JobKey}' will now chain to Job '{sj}'", context.JobDetail.Key, sj); diff --git a/src/CasaBot/AutoScan/Options/AutoScanOptions.cs b/src/CasaBot/AutoScan/Options/AutoScanOptions.cs index a915c3e..fe5bbcf 100644 --- a/src/CasaBot/AutoScan/Options/AutoScanOptions.cs +++ b/src/CasaBot/AutoScan/Options/AutoScanOptions.cs @@ -2,6 +2,7 @@ namespace AutoScan.Options; public record AutoScanOptions { + public bool RunDry { get; set; } = false; public bool Enabled { get; set; } public string At { get; set; } = "06:00"; public bool FromDayBefore { get; set; } @@ -10,5 +11,4 @@ public record AutoScanOptions public int MaxAmount { get; set; } public string? MediaFolder { get; set; } public ScannerOptions? Scanner { get; set; } - public ScreenshotOptions? Screenshot { get; set; } } \ No newline at end of file diff --git a/src/CasaBot/AutoScan/Options/ScreenshotOptions.cs b/src/CasaBot/AutoScan/Options/ScreenshotOptions.cs deleted file mode 100644 index 044a6fe..0000000 --- a/src/CasaBot/AutoScan/Options/ScreenshotOptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AutoScan.Options; - -public class ScreenshotOptions -{ - public string? Folder { get; set; } - public int OffsetSeconds { get; set; } -} \ No newline at end of file diff --git a/src/CasaBot/AutoScan/Options/ShinobiOptions.cs b/src/CasaBot/AutoScan/Options/ShinobiOptions.cs index da72cfd..a5b710d 100644 --- a/src/CasaBot/AutoScan/Options/ShinobiOptions.cs +++ b/src/CasaBot/AutoScan/Options/ShinobiOptions.cs @@ -6,5 +6,4 @@ public class ShinobiOptions public string? APIKey { get; set; } public string? GroupId { get; set; } public string? MonitorId { get; set; } - public bool RunDry { get; set; } = false; } \ No newline at end of file diff --git a/src/CasaBot/CasaBotApp/BotHandler.cs b/src/CasaBot/CasaBotApp/BotHandler.cs index 59f54ca..5ebb717 100644 --- a/src/CasaBot/CasaBotApp/BotHandler.cs +++ b/src/CasaBot/CasaBotApp/BotHandler.cs @@ -89,6 +89,32 @@ public class BotHandler : IUpdateHandler await SndPhoto(subscriber, stream); } } + + public async Task UpdatePhotos(string[] paths) + { + + if (_subscribers.Count == 0) + { + _logger.LogWarning("No subscribers to send message to"); + return; + } + + var streams = paths.Select(File.OpenRead).ToList(); + var photos = streams.Select(stream => new PhotoFile(stream)).Cast().ToList(); + + foreach (var subscriber in _subscribers) + { + var request = new SendMediaGroup(subscriber.Id.ToString(), photos); + await _bot.HandleAsync(request); + } + + foreach (var stream in streams) + { + stream.Close(); + await stream.DisposeAsync(); + } + } + private async Task SendImageTest(long id) { await using var stream = File.OpenRead(@"C:\Users\GuillermoMarcel\Pictures\prueba.jpeg"); diff --git a/src/CasaBot/CasaBotApp/Dockerfile b/src/CasaBot/CasaBotApp/Dockerfile index ce2d979..34a12c2 100644 --- a/src/CasaBot/CasaBotApp/Dockerfile +++ b/src/CasaBot/CasaBotApp/Dockerfile @@ -18,6 +18,11 @@ RUN dotnet publish "CasaBotApp/CasaBotApp.csproj" -a $TARGETARCH --no-restore -o # Runtime stage FROM mcr.microsoft.com/dotnet/runtime:9.0 WORKDIR /app + +# I need to run this "python3 -m pip install dvr-scan[opencv]" install everything needed +RUN apt-get update && apt-get install -y python3 python3-pip +RUN python3 -m pip install dvr-scan[opencv-headless] --break-system-packages + COPY --link --from=build /app . USER $APP_UID ENTRYPOINT ["dotnet", "CasaBotApp.dll"] diff --git a/src/CasaBot/CasaBotApp/Program.cs b/src/CasaBot/CasaBotApp/Program.cs index 1e61b3e..4215698 100644 --- a/src/CasaBot/CasaBotApp/Program.cs +++ b/src/CasaBot/CasaBotApp/Program.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Telegram.Bots; using Telegram.Bots.Extensions.Polling; @@ -60,7 +61,17 @@ using var cts = new CancellationTokenSource(); _ = autoScanApp.Run(cts.Token); botHandler.Start(cts.Token); -_ = SendMessageToSubscribers(cts.Token); +autoScanApp.OnScanCompleted = async options => +{ + logger.LogInformation("Scan completed at {At}", DateTime.Now); + + //list all the images in the detection folder + if (options.Scanner?.DetectionFolder is null) + return; + var images = Directory.GetFiles(options.Scanner.DetectionFolder , "*.jpg"); + botHandler.UpdatePhotos(images); +}; + _ = host.RunAsync(cts.Token); @@ -72,15 +83,5 @@ await cts.CancelAsync(); // stop the bot return; -async Task SendMessageToSubscribers(CancellationToken cancellationToken) -{ - while (!cancellationToken.IsCancellationRequested) - { - await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); - logger.LogInformation("Sending message to subscribers"); - await botHandler.Update($"Hello from CasaBot! at {DateTime.Now}"); - } -} - diff --git a/src/CasaBot/CasaBotApp/appsettings.json b/src/CasaBot/CasaBotApp/appsettings.json index 5066a5a..15baf3b 100644 --- a/src/CasaBot/CasaBotApp/appsettings.json +++ b/src/CasaBot/CasaBotApp/appsettings.json @@ -18,10 +18,10 @@ "APIKey": "APIKEY", "GroupId": "Group", "MonitorId": "Monitor", - "RunDry": false }, "AutoScan": { - "Enabled": false, + "Enabled": true, + "RunDry": true, "At": "07:00", "FromDayBefore": true, "From": "23:00", @@ -32,11 +32,7 @@ "Exe": "./dvr-scanner/dvr-scan.exe", "ConfigFile": "./dvr-scanner/dvr-scan.cfg", "DetectionFolder": "./media/detections/", - "RunDry": false - }, - "Screenshot": { - "Folder": "./media/screenshots/", - "OffsetSeconds": 0 + "RunDry": true } } } \ No newline at end of file