feat: extract scan library classes and add scheduler
This commit is contained in:
parent
57c0bb660c
commit
be89bddf1b
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Quartz" Version="3.13.1" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.13.1" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.13.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using AutoScan.Options;
|
using AutoScan.Options;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
namespace AutoScan;
|
namespace AutoScan;
|
||||||
|
|
||||||
@ -7,16 +9,44 @@ public class AutoScanApp
|
|||||||
{
|
{
|
||||||
private readonly AutoScanOptions _options;
|
private readonly AutoScanOptions _options;
|
||||||
private readonly ILogger<AutoScanApp> _logger;
|
private readonly ILogger<AutoScanApp> _logger;
|
||||||
|
private readonly IScheduler _scheduler;
|
||||||
|
|
||||||
public AutoScanApp(AutoScanOptions options, ILogger<AutoScanApp> logger)
|
public AutoScanApp(IOptions<AutoScanOptions> options, ILogger<AutoScanApp> logger, IScheduler scheduler)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options.Value;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_scheduler = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Run()
|
public async Task Run(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("AutoScanApp is running...");
|
_logger.LogInformation("AutoScanApp is running...");
|
||||||
_logger.LogInformation("Waiting for next scan at {At}.", _options.At);
|
|
||||||
|
var at = DateTime.Now.AddMinutes(1).ToString("HH:mm");
|
||||||
|
var cron = CronFromAt(at);
|
||||||
|
_logger.LogInformation("Waiting for next scan at {At} [{cron}].", at, cron);
|
||||||
|
|
||||||
|
await _scheduler.Start(cancellationToken);
|
||||||
|
_logger.LogInformation("Scheduler started successfully!");
|
||||||
|
|
||||||
|
// define the job and tie it to our HelloJob class
|
||||||
|
IJobDetail job = JobBuilder.Create<ScanJob>()
|
||||||
|
.WithIdentity("job1", "group1")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
ITrigger trigger = TriggerBuilder.Create()
|
||||||
|
.WithIdentity("trigger1", "group1")
|
||||||
|
.WithCronSchedule(cron)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await _scheduler.ScheduleJob(job, trigger, cancellationToken);
|
||||||
|
_logger.LogInformation("Scheduled job successfully!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string CronFromAt(string at)
|
||||||
|
{
|
||||||
|
var parts = at.Split(':');
|
||||||
|
return $"0 {parts[1]} {parts[0]} * * ?";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
31
src/CasaBot/AutoScan/DependencyInjectionExtensions.cs
Normal file
31
src/CasaBot/AutoScan/DependencyInjectionExtensions.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using CasaBotApp;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace AutoScan;
|
||||||
|
|
||||||
|
public static class DependencyInjectionExtensions
|
||||||
|
{
|
||||||
|
public static void AddAutoScan(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<ShinobiConnector>();
|
||||||
|
services.AddSingleton<DVRScanner>();
|
||||||
|
services.AddSingleton<FfmpegWrapper>();
|
||||||
|
services.AddSingleton<AutoScanApp>();
|
||||||
|
services.AddQuartz(q =>
|
||||||
|
{
|
||||||
|
q.UseMicrosoftDependencyInjectionJobFactory();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
|
||||||
|
|
||||||
|
services.AddSingleton<IScheduler>(sp =>
|
||||||
|
{
|
||||||
|
var schedulerFactory = sp.GetRequiredService<ISchedulerFactory>();
|
||||||
|
var tsk = schedulerFactory.GetScheduler();
|
||||||
|
tsk.Wait();
|
||||||
|
return tsk.Result;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
namespace AutoScan.Options;
|
namespace AutoScan.Options;
|
||||||
|
|
||||||
public class AutoScanOptions
|
public record AutoScanOptions
|
||||||
{
|
{
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
public string? At { get; set; }
|
public string? At { get; set; }
|
||||||
|
24
src/CasaBot/AutoScan/ScanJob.cs
Normal file
24
src/CasaBot/AutoScan/ScanJob.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using AutoScan.Options;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace AutoScan;
|
||||||
|
|
||||||
|
public class ScanJob : IJob
|
||||||
|
{
|
||||||
|
private readonly ILogger<ScanJob> _logger;
|
||||||
|
private readonly AutoScanOptions _options;
|
||||||
|
|
||||||
|
public ScanJob(ILogger<ScanJob> logger, IOptionsSnapshot<AutoScanOptions> options)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_options = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Scheduled scan executed with ops: {Options}", _options);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
@ -6,10 +6,10 @@ public class ShinobiConnector
|
|||||||
{
|
{
|
||||||
//TODO move class to auto scan library
|
//TODO move class to auto scan library
|
||||||
private readonly ILogger<ShinobiConnector> _logger;
|
private readonly ILogger<ShinobiConnector> _logger;
|
||||||
private readonly string _shinobivUrl = "https://shinobi.francelsoft.com";
|
private readonly string _shinobivUrl = "";
|
||||||
private readonly string _apikey = "OGD6nsGGzA1NL48M5Tg7Wbzto62oPl";
|
private readonly string _apikey = "";
|
||||||
private readonly string _groupId = "aInxuWCYLI";
|
private readonly string _groupId = "";
|
||||||
private readonly string _monitorId = "mQ3kQ5qjKK";
|
private readonly string _monitorId = "";
|
||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
public ShinobiConnector(ILogger<ShinobiConnector> logger, HttpClient httpClient)
|
public ShinobiConnector(ILogger<ShinobiConnector> logger, HttpClient httpClient)
|
@ -1,6 +0,0 @@
|
|||||||
namespace CasaBotApp;
|
|
||||||
|
|
||||||
public class BotConfiguration
|
|
||||||
{
|
|
||||||
public required string Token { get; set; }
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Telegram.Bot;
|
using Telegram.Bot;
|
||||||
using Telegram.Bot.Polling;
|
using Telegram.Bot.Polling;
|
||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
@ -10,28 +11,28 @@ namespace CasaBotApp;
|
|||||||
public class BotHandler
|
public class BotHandler
|
||||||
{
|
{
|
||||||
private readonly ILogger<BotHandler> _logger;
|
private readonly ILogger<BotHandler> _logger;
|
||||||
private readonly BotConfiguration _botConfiguration;
|
private readonly TelegramOptions _telegramOptions;
|
||||||
private readonly List<ChatId> _subscribers = [];
|
private readonly List<ChatId> _subscribers = [];
|
||||||
|
|
||||||
private TelegramBotClient? _bot;
|
private TelegramBotClient? _bot;
|
||||||
|
|
||||||
|
|
||||||
public BotHandler(BotConfiguration botConfiguration, ILogger<BotHandler> logger)
|
public BotHandler(IOptions<TelegramOptions> telegramConfiguration, ILogger<BotHandler> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
if (string.IsNullOrEmpty(botConfiguration.Token))
|
if (string.IsNullOrEmpty(telegramConfiguration.Value.BotToken))
|
||||||
{
|
{
|
||||||
_logger.LogError("Bot token is not provided");
|
_logger.LogError("Bot token is not provided");
|
||||||
throw new ArgumentException("Bot token is required", nameof(botConfiguration));
|
throw new ArgumentException("Bot token is required", nameof(telegramConfiguration));
|
||||||
}
|
}
|
||||||
_botConfiguration = botConfiguration;
|
_telegramOptions = telegramConfiguration.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Start(CancellationToken cancellationToken)
|
public void Start(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Starting bot...");
|
_logger.LogInformation("Starting bot...");
|
||||||
_bot = new TelegramBotClient(_botConfiguration.Token, cancellationToken: cancellationToken);
|
_bot = new TelegramBotClient(_telegramOptions.BotToken, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
|
||||||
_bot.OnError += OnError;
|
_bot.OnError += OnError;
|
||||||
|
@ -13,73 +13,79 @@ IConfigurationRoot configuration = new ConfigurationBuilder()
|
|||||||
.AddEnvironmentVariables()
|
.AddEnvironmentVariables()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var serviceCollection = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
serviceCollection.AddSingleton(configuration);
|
services.AddSingleton(configuration);
|
||||||
serviceCollection.AddLogging(builder =>
|
services.AddLogging(builder =>
|
||||||
{
|
{
|
||||||
builder.AddConfiguration(configuration.GetSection("Logging"));
|
builder.AddConfiguration(configuration.GetSection("Logging"));
|
||||||
builder.AddConsole();
|
// builder.AddConsole();
|
||||||
});
|
//add time to logs
|
||||||
serviceCollection.AddSingleton(new BotConfiguration()
|
builder.AddSimpleConsole(options =>
|
||||||
{
|
{
|
||||||
Token = configuration.GetValue<string>("TelegramToken") ?? ""
|
options.IncludeScopes = true;
|
||||||
|
options.SingleLine = true;
|
||||||
|
options.TimestampFormat = "[HH:mm:ss] ";
|
||||||
|
});
|
||||||
});
|
});
|
||||||
serviceCollection.Configure<AutoScan.Options.AutoScanOptions>(configuration.GetSection("AutoScan"));
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<BotHandler>();
|
services.Configure<TelegramOptions>(configuration.GetSection("Telegram"));
|
||||||
serviceCollection.AddSingleton<ShinobiConnector>();
|
services.Configure<AutoScan.Options.AutoScanOptions>(configuration.GetSection("AutoScan"));
|
||||||
serviceCollection.AddSingleton<DVRScanner>();
|
|
||||||
serviceCollection.AddSingleton<FfmpegWrapper>();
|
|
||||||
serviceCollection.AddSingleton<AutoScanApp>();
|
|
||||||
serviceCollection.AddHttpClient();
|
|
||||||
|
|
||||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
services.AddSingleton<BotHandler>();
|
||||||
|
|
||||||
|
services.AddAutoScan();
|
||||||
|
services.AddHttpClient();
|
||||||
|
|
||||||
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
var logger = serviceProvider.GetService<ILogger<Program>>()!;
|
var logger = serviceProvider.GetService<ILogger<Program>>()!;
|
||||||
|
|
||||||
var botHandler = serviceProvider.GetService<BotHandler>()!;
|
var botHandler = serviceProvider.GetService<BotHandler>()!;
|
||||||
|
var autoScanApp = serviceProvider.GetService<AutoScanApp>()!;
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
botHandler.Start(cts.Token);
|
autoScanApp.Run(cts.Token);
|
||||||
|
// botHandler.Start(cts.Token);
|
||||||
|
|
||||||
_ = SendMessageToSubscribers(cts.Token);
|
_ = SendMessageToSubscribers(cts.Token);
|
||||||
|
|
||||||
var videoFileName = configuration.GetValue<string>("VideoFileName") ?? "video.mp4";
|
// var videoFileName = configuration.GetValue<string>("VideoFileName") ?? "video.mp4";
|
||||||
if (configuration.GetValue<bool>("Fetch"))
|
// if (configuration.GetValue<bool>("Fetch"))
|
||||||
{
|
// {
|
||||||
var shinobiConnector = serviceProvider.GetService<ShinobiConnector>()!;
|
// var shinobiConnector = serviceProvider.GetService<ShinobiConnector>()!;
|
||||||
await shinobiConnector.FetchLastVideo(videoFileName);
|
// await shinobiConnector.FetchLastVideo(videoFileName);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (configuration.GetValue<bool>("Scan"))
|
// if (configuration.GetValue<bool>("Scan"))
|
||||||
{
|
// {
|
||||||
var dvrScanner = serviceProvider.GetService<DVRScanner>()!;
|
// var dvrScanner = serviceProvider.GetService<DVRScanner>()!;
|
||||||
await dvrScanner.ScanVideos(cts.Token);
|
// await dvrScanner.ScanVideos(cts.Token);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if(configuration.GetValue<bool>("Screenshot"))
|
// if(configuration.GetValue<bool>("Screenshot"))
|
||||||
{
|
// {
|
||||||
var detected = "2025-02-12T07-00-02.DSME_0001.avi";
|
// var detected = "2025-02-12T07-00-02.DSME_0001.avi";
|
||||||
var ffmpegWrapper = serviceProvider.GetService<FfmpegWrapper>()!;
|
// var ffmpegWrapper = serviceProvider.GetService<FfmpegWrapper>()!;
|
||||||
var duration = await ffmpegWrapper.GetVideoDuration($@".\media\detected\{detected}");
|
// var duration = await ffmpegWrapper.GetVideoDuration($@".\media\detected\{detected}");
|
||||||
logger.LogInformation("Video duration: {Duration}", duration);
|
// logger.LogInformation("Video duration: {Duration}", duration);
|
||||||
var middleTime = (duration / 2).Add(TimeSpan.FromSeconds(0.5));
|
// var middleTime = (duration / 2).Add(TimeSpan.FromSeconds(0.5));
|
||||||
|
//
|
||||||
//Extract frame at middle time
|
// //Extract frame at middle time
|
||||||
var screenshotPath = $@".\media\detected\{detected}-ss.png";
|
// var screenshotPath = $@".\media\detected\{detected}-ss.png";
|
||||||
await ffmpegWrapper.ExtractFrame($@".\media\detected\{detected}", screenshotPath, middleTime);
|
// await ffmpegWrapper.ExtractFrame($@".\media\detected\{detected}", screenshotPath, middleTime);
|
||||||
logger.LogInformation("Screenshot extracted at {MiddleTime}", middleTime);
|
// logger.LogInformation("Screenshot extracted at {MiddleTime}", middleTime);
|
||||||
|
//
|
||||||
//botHandler.Subscribe(115151151);
|
// //botHandler.Subscribe(115151151);
|
||||||
await botHandler.UpdatePhoto(screenshotPath);
|
// await botHandler.UpdatePhoto(screenshotPath);
|
||||||
}
|
// }
|
||||||
|
|
||||||
logger.LogInformation("Bot started");
|
logger.LogInformation("Bot started");
|
||||||
logger.LogInformation("Press any key to stop the bot...");
|
logger.LogInformation("Press any key to stop the bot...");
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
cts.Cancel(); // stop the bot
|
cts.Cancel(); // stop the bot
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
7
src/CasaBot/CasaBotApp/TelegramOptions.cs
Normal file
7
src/CasaBot/CasaBotApp/TelegramOptions.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace CasaBotApp;
|
||||||
|
|
||||||
|
public class TelegramOptions
|
||||||
|
{
|
||||||
|
public string? BotToken { get; set; }
|
||||||
|
public long[] SubscribedChatIds { get; set; } = [];
|
||||||
|
}
|
@ -3,9 +3,14 @@
|
|||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Debug",
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information",
|
||||||
|
"Quartz": "Information"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Telegram":{
|
||||||
|
"BotToken": "__token__",
|
||||||
|
"SubscribedChatIds": []
|
||||||
|
},
|
||||||
"AutoScan": {
|
"AutoScan": {
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
"At": "07:00",
|
"At": "07:00",
|
||||||
|
Loading…
Reference in New Issue
Block a user