feat: OnScanCompleted event & output dir & send photos
This commit is contained in:
parent
ea02a726ef
commit
a6ac0187f1
@ -14,6 +14,8 @@ public class AutoScanApp
|
||||
private readonly ILogger<AutoScanApp> _logger;
|
||||
private readonly IScheduler _scheduler;
|
||||
private readonly IChainerListenerFactory _chainerListenerFactory;
|
||||
|
||||
public Func<AutoScanOptions, Task>? OnScanCompleted { get; set; }
|
||||
|
||||
public AutoScanApp(IOptions<AutoScanOptions> options, ILogger<AutoScanApp> 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<JobKey>.GroupEquals(groupName));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -5,5 +5,5 @@ namespace AutoScan.Interfaces;
|
||||
public interface IDVRConnector
|
||||
{
|
||||
Task<List<VideoDetail>> 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ public class ChainerListener : JobListenerSupport
|
||||
{
|
||||
private readonly ILogger<ChainerListener> _logger;
|
||||
private readonly Dictionary<JobKey, JobKey> _chainLinks;
|
||||
public Func<Task> OnJobChainFinished { get; set; }
|
||||
|
||||
public ChainerListener(string name, ILogger<ChainerListener> 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);
|
||||
|
@ -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; }
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace AutoScan.Options;
|
||||
|
||||
public class ScreenshotOptions
|
||||
{
|
||||
public string? Folder { get; set; }
|
||||
public int OffsetSeconds { get; set; }
|
||||
}
|
@ -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;
|
||||
}
|
@ -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<IGroupableMedia>().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");
|
||||
|
@ -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"]
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user