From a650d4197a01f8a708e3a054ce65abf4054bd577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E8=AF=9A?= Date: Tue, 30 Sep 2025 17:17:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20docker-compose.yml=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=AA=92=E4=BD=93=E6=96=87=E4=BB=B6=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=EF=BC=8C=E7=A7=BB=E9=99=A4=20JobTriggerController=20?= =?UTF-8?q?=E5=92=8C=20NotifyController=20=E4=B8=AD=E7=9A=84=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- src/Core/Command.cs | 23 - src/Core/Tools.cs | 9 - src/Core/WxNotify.cs | 28 - src/Service/Jobs/ChineseNfoRegistry.Bak.cs | 482 ------------------ src/Service/Jobs/DiskActionMonitorRegistry.cs | 174 ------- src/Service/Jobs/DiskMonitorRegistry.cs | 104 ---- src/Service/Jobs/HealthyTaskRegistry.cs | 95 ---- src/Service/Jobs/LogTotalNotifyJobRegistry.cs | 106 ---- src/Service/Jobs/RSyncTaskRegistry.cs | 69 --- src/Service/Jobs/ShutdownRegistry.cs | 61 --- src/Service/Jobs/StartupRegistry.cs | 46 -- .../Controllers/JobTriggerController.cs | 86 ---- src/WebApi/Controllers/NotifyController.cs | 217 -------- src/WebApi/Controllers/XiaoController.cs | 34 -- 15 files changed, 1 insertion(+), 1535 deletions(-) delete mode 100644 src/Core/Command.cs delete mode 100644 src/Core/Tools.cs delete mode 100644 src/Service/Jobs/ChineseNfoRegistry.Bak.cs delete mode 100644 src/Service/Jobs/DiskActionMonitorRegistry.cs delete mode 100644 src/Service/Jobs/DiskMonitorRegistry.cs delete mode 100644 src/Service/Jobs/HealthyTaskRegistry.cs delete mode 100644 src/Service/Jobs/LogTotalNotifyJobRegistry.cs delete mode 100644 src/Service/Jobs/RSyncTaskRegistry.cs delete mode 100644 src/Service/Jobs/ShutdownRegistry.cs delete mode 100644 src/Service/Jobs/StartupRegistry.cs delete mode 100644 src/WebApi/Controllers/XiaoController.cs diff --git a/docker-compose.yml b/docker-compose.yml index 4cad19a..7d7f1e6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ - /etc/localtime:/etc/localtime:ro - /wd/media/tv:/data/media/tv:rw - /wd/media/anime:/data/media/anime:rw - - /wd/media/anime-other:/data/media/anime-other:rw + - /wd/media/others/anime:/data/media/anime-other:rw - /wd/apps/vols/nas_robot:/app/data:rw - /wd:/host/wd:ro - /proc/mounts:/host/proc/mounts:ro diff --git a/src/Core/Command.cs b/src/Core/Command.cs deleted file mode 100644 index 10da212..0000000 --- a/src/Core/Command.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Net; -using System.Net.Http.Json; - -namespace Core; - -public static class Command -{ - public static async Task<(HttpStatusCode responseCode, string responseStr)> ExecAsync(params string[] commands) - { - var execUrl = "http://192.168.31.14:45321/exec"; - - var client = new HttpClient(); - var content = JsonContent.Create(new - { - Token = "4CeVaIQGbB4Qln9%V@Bh8bMYSpHIUV66", - Script = commands - }); - - var response = await client.PostAsync(execUrl, content); - - return (response.StatusCode, await response.Content.ReadAsStringAsync()); - } -} \ No newline at end of file diff --git a/src/Core/Tools.cs b/src/Core/Tools.cs deleted file mode 100644 index 0edb4cc..0000000 --- a/src/Core/Tools.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Core; - -public static class Tools -{ - public static long ToUnixTimeMilliseconds(this DateTime dateTime) - { - return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds(); - } -} \ No newline at end of file diff --git a/src/Core/WxNotify.cs b/src/Core/WxNotify.cs index a629344..5ee54df 100644 --- a/src/Core/WxNotify.cs +++ b/src/Core/WxNotify.cs @@ -4,34 +4,6 @@ namespace Core; public static class WxNotify { - public static async Task SendDiskInfoAsync(string msg) - { - // 晚上11点到早上8点不通知,输出到控制台 - if (DateTime.Now.Hour >= 23 || DateTime.Now.Hour < 8) - { - Console.WriteLine("======================Skip WxNotify======================"); - Console.WriteLine(msg); - Console.WriteLine("======================Skip WxNotify======================"); - return; - } - - var wxRebotUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=96f9fa23-a959-4492-ac3a-7415fae19680"; - var client = new HttpClient(); - var requestBody = - """ - { - "msgtype": "markdown", - "markdown": { - "content": "{Msg}" - } - } - """; - - // 转义 - requestBody = requestBody.Replace("{Msg}", msg.Replace("\r\n", "\n")); - await client.PostAsync(wxRebotUrl, new StringContent(requestBody, Encoding.UTF8, "application/json")); - } - public static async Task SendCommonAsync(string msg) { var wxRebotUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=96f9fa23-a959-4492-ac3a-7415fae19680"; diff --git a/src/Service/Jobs/ChineseNfoRegistry.Bak.cs b/src/Service/Jobs/ChineseNfoRegistry.Bak.cs deleted file mode 100644 index d641922..0000000 --- a/src/Service/Jobs/ChineseNfoRegistry.Bak.cs +++ /dev/null @@ -1,482 +0,0 @@ -// using System.Diagnostics; -// using System.Net; -// using System.Text.Json.Nodes; -// using System.Xml; -// using Core; -// using FluentScheduler; -// using Interface.Jobs; -// using Microsoft.Extensions.Configuration; -// using Microsoft.Extensions.Logging; -// -// namespace Service.Jobs; -// -// public class ChineseNfoRegistry : Registry, IChineseNfoRegistry -// { -// private readonly IConfiguration _configuration; -// private readonly ILogger _logger; -// private readonly HttpClient _client; -// -// public ChineseNfoRegistry(IConfiguration configuration, ILogger logger) -// { -// _configuration = configuration; -// _logger = logger; -// -// var httpClientHandler = new HttpClientHandler(); -// -// var proxyAddress = _configuration["ChineseNfo:HttpProxy"]; -// -// if (string.IsNullOrEmpty(proxyAddress) == false) -// { -// httpClientHandler.Proxy = string.IsNullOrEmpty(proxyAddress) ? null : new WebProxy(proxyAddress, false); -// httpClientHandler.UseProxy = !string.IsNullOrEmpty(proxyAddress); -// } -// -// _client = new HttpClient(httpClientHandler); -// _client.BaseAddress = new Uri("http://api.themoviedb.org"); -// -// Schedule(() => Job(true, true)).ToRunEvery(1).Days(); -// } -// -// public async void Job(bool ignoreLocked, bool ignoreCompleted) -// { -// try -// { -// await JobExecute(ignoreLocked, ignoreCompleted); -// } -// catch (Exception e) -// { -// _logger.LogError(e, "ChineseNfoRegistry.Job() error"); -// } -// } -// -// -// private async Task JobExecute(bool ignoreLocked, bool ignoreCompleted) -// { -// // 读取环境变量 tv folder -// var tvFolder = _configuration["ChineseNfo:TvFolder"]; -// if (string.IsNullOrEmpty(tvFolder)) -// { -// Console.WriteLine("请设置环境变量 tv_folder"); -// return; -// } -// -// var successCount = 0; -// var failedCount = 0; -// var skippedCount = 0; -// -// // 扫描 tvshow.nfo 文件 -// var tvShowFiles = Directory.GetFiles(tvFolder, "tvshow.nfo", SearchOption.AllDirectories); -// -// foreach (var tvShowFile in tvShowFiles) -// { -// var nfoContent = File.ReadAllText(tvShowFile); -// -// // 读取 使用XML解析器 读取 60059 -// var tvXml = new XmlDocument(); -// tvXml.LoadXml(nfoContent); -// var uniqueIdNode = tvXml.SelectSingleNode("//uniqueid[@type='tmdb']"); -// if (uniqueIdNode == null) -// { -// Console.WriteLine($"{tvShowFile} & 未找到 tmdb id"); -// continue; -// } -// -// if (!int.TryParse(uniqueIdNode.InnerText, out var tmdbId)) -// { -// Console.WriteLine($"{tvShowFile} & tmdb id 不是数字"); -// continue; -// } -// -// await SetTvInfo(tvShowFile, tvXml, tmdbId); -// -// // 获取 tvShowFile 的文件夹 -// var folderPath = Path.GetDirectoryName(tvShowFile); -// -// if (folderPath == null) -// { -// Console.WriteLine($"{tvShowFile} & 未找到文件夹"); -// continue; -// } -// -// // 扫描文件夹下其他 nfo 文件 -// var seasonFiles = Directory.GetFiles(folderPath, "*.nfo", SearchOption.AllDirectories); -// -// seasonFiles = seasonFiles.Where(x => !x.EndsWith("tvshow.nfo")).ToArray(); -// -// foreach (var episodeFile in seasonFiles) -// { -// await SetEpisodeInfo(episodeFile, tmdbId); -// } -// } -// -// await WxNotify.SendCommonAsync($"ChineseNfoRegistry.Job() success: {successCount}, failed: {failedCount}, skipped: {skippedCount}"); -// -// async Task SetTvInfo(string tvShowFile,XmlDocument tvXml, int tmdbId) -// { -// // 检查 lockdata -// var lockedNode = tvXml.SelectSingleNode("//lockdata"); -// if (lockedNode != null && lockedNode.InnerText == "true" && ignoreLocked == false) -// { -// skippedCount++; -// Console.WriteLine($"{tvShowFile} & 已锁定"); -// return; -// } -// -// // 获取tv info -// var tvJson = await GetTmdbTv(tvShowFile, tmdbId); -// -// if (tvJson == null) -// { -// failedCount++; -// return; -// } -// -// var title = tvJson["name"]?.ToString(); -// var overview = tvJson["overview"]?.ToString(); -// var poster =tvJson["poster_path"]?.ToString(); -// var genres = tvJson["genres"] -// ?.AsArray() -// .Select(x => x?["name"]?.ToString()) -// .Where(x=> !string.IsNullOrEmpty(x)) -// .ToList(); -// -// if (!string.IsNullOrEmpty(title)) -// { -// title = $""; -// var titleNode = tvXml.SelectSingleNode("//title"); -// if (titleNode != null) -// { -// if (titleNode.InnerXml != title) -// { -// titleNode.InnerXml = title; -// successCount++; -// } -// } -// -// var sorttitleNode = tvXml.SelectSingleNode("//sorttitle"); -// if (sorttitleNode != null) -// { -// if (sorttitleNode.InnerXml != title) -// { -// sorttitleNode.InnerXml = title; -// successCount++; -// } -// } -// } -// -// if (!string.IsNullOrEmpty(overview)) -// { -// overview = $""; -// var plotNode = tvXml.SelectSingleNode("//plot"); -// if (plotNode != null) -// { -// if (plotNode.InnerXml != overview) -// { -// plotNode.InnerXml = overview; -// successCount++; -// } -// } -// -// var outlineNode = tvXml.SelectSingleNode("//outline"); -// if (outlineNode != null) -// { -// if (outlineNode.InnerXml != overview) -// { -// outlineNode.InnerXml = overview; -// successCount++; -// } -// } -// } -// -// if(!string.IsNullOrEmpty(poster)) -// { -// poster = $"http://image.tmdb.org/t/p/w1280/{poster}"; -// // 下载并覆盖海报 -// var posterPath = tvShowFile.Replace("tvshow.nfo", $"poster.{poster.Split('.').Last()}"); -// -// using var client = new HttpClient(); -// var response = await client.GetAsync(poster); -// if (response.IsSuccessStatusCode) -// { -// var bytes = await response.Content.ReadAsByteArrayAsync(); -// -// if (File.Exists(posterPath)) -// { -// File.Delete(posterPath); -// } -// -// await File.WriteAllBytesAsync(posterPath, bytes); -// successCount++; -// } -// } -// -// -// if (genres?.Any() == true) -// { -// // 删除原有的 节点 -// var genreNodes = tvXml.SelectNodes("//genre"); -// if (genreNodes != null) -// { -// foreach (XmlNode genreNode in genreNodes) -// { -// tvXml.DocumentElement?.RemoveChild(genreNode); -// } -// } -// -// // 添加新的 节点 -// foreach (var genre in genres) -// { -// var genreNode = tvXml.CreateElement("genre"); -// genreNode.InnerText = genre!; -// tvXml.DocumentElement?.AppendChild(genreNode); -// } -// successCount++; -// } -// -// if (successCount == 0) -// { -// skippedCount++; -// Console.WriteLine($"{tvShowFile} & 无更新"); -// return; -// } -// -// // 锁定节点 -// if(lockedNode == null) -// { -// lockedNode = tvXml.CreateElement("lockdata"); -// tvXml.DocumentElement?.AppendChild(lockedNode); -// lockedNode.InnerText = "true"; -// } -// else -// { -// lockedNode.InnerText = "true"; -// } -// -// // 添加一个已完成节点 -// var completedNode = tvXml.SelectSingleNode("//completed"); -// if (completedNode == null) -// { -// completedNode = tvXml.CreateElement("completed"); -// tvXml.DocumentElement?.AppendChild(completedNode); -// } -// completedNode.InnerText = "true"; -// -// try -// { -// tvXml.Save(tvShowFile); -// } -// catch (Exception e) -// { -// Console.WriteLine(e); -// failedCount++; -// } -// } -// -// async Task SetEpisodeInfo(string episodeFile, int tmdbId) -// { -// var episodeContent = await File.ReadAllTextAsync(episodeFile); -// var episodeXml = new XmlDocument(); -// episodeXml.LoadXml(episodeContent); -// -// // 判断有无 completed 节点 -// var completedNode = episodeXml.SelectSingleNode("//completed"); -// if (completedNode != null && ignoreCompleted == false) -// { -// skippedCount++; -// Console.WriteLine($"{episodeFile} & 已完成"); -// return; -// } -// -// // 判断 locked == true -// var lockedNode = episodeXml.SelectSingleNode("//lockdata"); -// if (lockedNode != null && lockedNode.InnerText == "true" && ignoreLocked == false) -// { -// skippedCount++; -// Console.WriteLine($"{episodeFile} & 已锁定"); -// return; -// } -// -// // 读取 1 -// var seasonNode = episodeXml.SelectSingleNode("//season"); -// if (seasonNode == null) -// { -// failedCount++; -// Console.WriteLine($"{episodeFile} & 未找到 season"); -// return; -// } -// -// // 读取 1 -// var episodeNode = episodeXml.SelectSingleNode("//episode"); -// if (episodeNode == null) -// { -// failedCount++; -// Console.WriteLine($"{episodeFile} & 未找到 episode"); -// return; -// } -// -// if (!int.TryParse(seasonNode.InnerText, out var season)) -// { -// failedCount++; -// Console.WriteLine($"{episodeFile} & season 不是数字"); -// return; -// } -// -// if (!int.TryParse(episodeNode.InnerText, out var episode)) -// { -// failedCount++; -// Console.WriteLine($"{episodeFile} & episode 不是数字"); -// return; -// } -// -// // 设置 title -// var titleNode = episodeXml.SelectSingleNode("//title"); -// if (titleNode == null) -// { -// failedCount++; -// Console.WriteLine($"{episodeFile} & 未找到 title"); -// return; -// } -// -// var json = await GetTmdbEpisode( -// episodeFile, -// tmdbId, -// season, -// episode); -// -// if (json == null) -// { -// failedCount++; -// return; -// } -// -// var title = json["name"]?.ToString(); -// var overview = json["overview"]?.ToString(); -// -// var isUpdate = false; -// if (!string.IsNullOrEmpty(title)) -// { -// title = $""; -// -// if (titleNode.InnerXml != title) -// { -// isUpdate = true; -// // 写入且不转义 -// titleNode.InnerXml = title; -// } -// } -// -// var plotNode = episodeXml.SelectSingleNode("//plot"); -// -// if (!string.IsNullOrEmpty(overview) && plotNode != null) -// { -// overview = $""; -// if (plotNode.InnerXml != overview) -// { -// isUpdate = true; -// plotNode.InnerXml = overview; -// } -// } -// -// if (!isUpdate) -// { -// skippedCount++; -// Console.WriteLine($"{episodeFile} & 无更新"); -// return; -// } -// -// successCount++; -// -// // 添加一个已完成节点 -// if (completedNode == null) -// { -// episodeXml.DocumentElement?.AppendChild(episodeXml.CreateElement("completed")); -// } -// -// // 锁定 -// if (lockedNode == null) -// { -// lockedNode = episodeXml.CreateElement("lockdata"); -// episodeXml.DocumentElement?.AppendChild(lockedNode); -// lockedNode.InnerText = "true"; -// } -// else -// { -// lockedNode.InnerText = "true"; -// } -// -// try -// { -// episodeXml.Save(episodeFile); -// } -// catch (Exception e) -// { -// Console.WriteLine(e); -// return; -// } -// -// Console.WriteLine($"{episodeFile} & {title} & {overview}"); -// } -// } -// -// private async Task GetTmdbTv( -// string path, -// int tmdbId) -// { -// const string tvUrl = "/3/tv/{0}?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN"; -// var requestUrl = string.Format(tvUrl, tmdbId); -// -// try -// { -// var response = await _client.GetAsync(requestUrl); -// -// if (!response.IsSuccessStatusCode) -// { -// Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}"); -// return null; -// } -// -// await Task.Delay(10000); -// -// var content = await response.Content.ReadAsStringAsync(); -// var json = JsonNode.Parse(content); -// return json as JsonObject; -// } -// catch (Exception e) -// { -// Console.WriteLine($"{requestUrl} & {path} \r {e}"); -// return null; -// } -// } -// -// private async Task GetTmdbEpisode( -// string path, -// int tmdbId, -// int season, -// int episode) -// { -// const string episodeUrl = "/3/tv/{0}/season/{1}/episode/{2}?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN"; -// var requestUrl = string.Format(episodeUrl, tmdbId, season, episode); -// -// try -// { -// var response = await _client.GetAsync(requestUrl); -// -// await Task.Delay(10000); -// -// if (!response.IsSuccessStatusCode) -// { -// Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}"); -// return null; -// } -// -// var content = await response.Content.ReadAsStringAsync(); -// var json = JsonNode.Parse(content); -// return json as JsonObject; -// } -// catch (Exception e) -// { -// Console.WriteLine($"{requestUrl} & {path} \r {e}"); -// return null; -// } -// } -// } \ No newline at end of file diff --git a/src/Service/Jobs/DiskActionMonitorRegistry.cs b/src/Service/Jobs/DiskActionMonitorRegistry.cs deleted file mode 100644 index 3202638..0000000 --- a/src/Service/Jobs/DiskActionMonitorRegistry.cs +++ /dev/null @@ -1,174 +0,0 @@ -using Core; -using FluentScheduler; -using Interface.Jobs; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace Service.Jobs; - -public enum DiskNotifyType -{ - Action, - Sleep -} - -public class DiskActionMonitorRegistry : Registry, IDiskActionMonitorRegistry -{ - private readonly IConfiguration _configuration; - private static Dictionary _lastReadCount = new(); - private static Dictionary _lastWriteCount = new(); - private readonly ILogger _logger; - private static readonly Dictionary> LatestNotifyTimes = new(); - private static readonly Dictionary LastChangedTimes = new(); - - public DiskActionMonitorRegistry(IConfiguration configuration, ILogger logger) - { - _configuration = configuration; - _logger = logger; - Schedule(Job).ToRunEvery(5).Seconds(); - } - - public async void Job() - { - try - { - await JobExecute(); - } - catch (Exception e) - { - _logger.LogError(e, "DiskActionMonitorRegistry.Job() error"); - } - } - - private async Task JobExecute() - { - var filePath = _configuration["DiskActionMonitor:FilePath"] ?? throw new ArgumentNullException($"DiskActionMonitor:FilePath"); - var disks = _configuration - .GetSection("DiskActionMonitor:Disks") - .GetChildren() - .Select(x => x.Value); - - - foreach (var disk in disks) - { - if (string.IsNullOrEmpty(disk)) - { - continue; - } - - if (!_lastReadCount.ContainsKey(disk)) - { - _lastReadCount.Add(disk, 0); - } - - if (!_lastWriteCount.ContainsKey(disk)) - { - _lastWriteCount.Add(disk, 0); - } - - if (!LatestNotifyTimes.ContainsKey(disk)) - { - LatestNotifyTimes.Add(disk, new()); - } - - if (!LastChangedTimes.ContainsKey(disk)) - { - LastChangedTimes.Add(disk, DateTime.Now); - } - - var content = await File.ReadAllTextAsync(string.Format(filePath, disk)); - - var cols = content.Split(" ", StringSplitOptions.RemoveEmptyEntries); - - var readCount = TryGetByIndex(cols, 2); - var writeCount = TryGetByIndex(cols, 6); - - if (!int.TryParse(readCount, out var read) || !int.TryParse(writeCount, out var write)) - { - continue; // 读取失败 - } - - var readDiff = read - _lastReadCount[disk]; - var writeDiff = write - _lastWriteCount[disk]; - - _lastReadCount[disk] = read; - _lastWriteCount[disk] = write; - - if (readDiff > 0 || writeDiff > 0) - { - _logger.LogInformation($"[{disk}] ReadDiff: {readDiff}, WriteDiff: {writeDiff}"); - } - - if (readDiff > 10 || writeDiff > 10) - { - // 上一次通知的是休眠或者没有通知 发现有变换通知变化 - if (LatestNotifyTimes[disk].Any() == false - || LatestNotifyTimes[disk].Last().Item2 == DiskNotifyType.Sleep) - { - LatestNotifyTimes[disk].Add((DateTime.Now, DiskNotifyType.Action)); - - await WxNotify.SendDiskInfoAsync(@$" -## 磁盘 {disk} 刚发生读写操作 🙋 - -> 当前累计读: {GetEasyReadNumber(read)} 、新增读: {GetEasyReadNumber(readDiff)} -> 当前累计写: {GetEasyReadNumber(write)} 、新增写: {GetEasyReadNumber(writeDiff)} - -当前时间: {DateTime.Now:yyyy-M-d H:m:s} "); - } - else if (DateTime.Now - LatestNotifyTimes[disk].Last().Item1 > TimeSpan.FromHours(1)) - { - LatestNotifyTimes[disk].Add((DateTime.Now, DiskNotifyType.Action)); - - await WxNotify.SendDiskInfoAsync(@$" -## 磁盘 {disk} 连续运行超一小时 👨‍💻 - -> 当前累计读: {GetEasyReadNumber(read)} -> 当前累计写: {GetEasyReadNumber(write)} - -当前时间: {DateTime.Now:yyyy-M-d H:m:s} "); - } - - _lastReadCount[disk] = read; - _lastWriteCount[disk] = write; - LastChangedTimes[disk] = DateTime.Now; - - continue; - } - - // 没有变化 上一次是启动通知且超过10分钟,通知休眠 - if (LatestNotifyTimes[disk].Any() == false - || (LatestNotifyTimes[disk].Last().Item2 == DiskNotifyType.Action - && DateTime.Now - LastChangedTimes[disk] > TimeSpan.FromMinutes(10))) - { - LatestNotifyTimes[disk].Add((DateTime.Now, DiskNotifyType.Sleep)); - - await WxNotify.SendDiskInfoAsync(@$" -## 磁盘 {disk} 长时间无读写变化 😪 - -> 上一次读写时间:{LatestNotifyTimes[disk].Last(x => x.Item2 == DiskNotifyType.Action).Item1:yyyy-M-d H:m:s} - -> 当前累计读: {GetEasyReadNumber(read)} -> 当前累计写: {GetEasyReadNumber(write)} - -当前时间: {DateTime.Now:yyyy-M-d H:m:s} "); - } - } - } - - private string TryGetByIndex(string[] arr, int index) => index < arr.Length ? arr[index] : string.Empty; - - private string GetEasyReadNumber(int number) - { - if (number < 10000) - { - return number.ToString(); - } - - if (number < 100000000) - { - return $"{number / 10000M:0.##} 万"; - } - - return $"{number / 100000000M:0.##} 亿"; - } -} \ No newline at end of file diff --git a/src/Service/Jobs/DiskMonitorRegistry.cs b/src/Service/Jobs/DiskMonitorRegistry.cs deleted file mode 100644 index 10b8d5d..0000000 --- a/src/Service/Jobs/DiskMonitorRegistry.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Diagnostics; -using System.Text; -using FluentScheduler; -using InfluxDB.Client; -using InfluxDB.Client.Api.Domain; -using InfluxDB.Client.Writes; -using Interface.Jobs; - -namespace Service.Jobs; - -public class DiskMonitorRegistry : Registry, IDiskMonitorRegistry -{ - public DiskMonitorRegistry() - { - Schedule(Job).ToRunNow().AndEvery(1).Hours(); - } - - public void Job() - { - try - { - JobExecute(); - } - catch (Exception e) - { - Console.WriteLine(e); - } - } - - private void JobExecute() - { - // 执行 cmd 命令 获取执行结果 - var command = "df -h"; - var process = new Process - { - StartInfo = new() - { - FileName = "/bin/bash", - Arguments = $"-c \"{command}\"", - RedirectStandardOutput = true, - UseShellExecute = false, - CreateNoWindow = true - } - }; - - process.Start(); - var result = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); - - var format = FormatResult(result); - - WriteToInfluxDB(format); - } - - private string FormatResult(string result) - { - var lines = result.Split("\n"); - var sb = new StringBuilder(); - foreach (var line in lines) - { - var cols = line.Split(" ", StringSplitOptions.RemoveEmptyEntries); - - if (line.Contains("/host/wd/")) - { - sb.AppendLine($"{cols[5].Substring("/host".Length)},{cols[1]},{cols[4].TrimEnd('%')},{cols[3]}"); - } - } - - return sb.ToString(); - } - - private void WriteToInfluxDB(string result) - { - var lines = result.Split("\n"); - - using var client = new InfluxDBClient("http://influxdb:8086", "BD4A71llb9_XbCA5mmKDbc_yTYwadPPLwyk4nAQ0l_yR_WJmw_-dMOWIs0KlS7-pZtHot_HrejY5GcOohKElmA=="); - using var writeApi = client.GetWriteApi(); - - foreach (var line in lines) - { - Console.WriteLine(line); - - var cols = line.Split(",", StringSplitOptions.RemoveEmptyEntries); - - if(cols.Length != 4) continue; - - var path = cols[0]; - var totalSize = cols[1]; - var usedPercent = cols[2]; - var available = cols[3]; - - var point = PointData - .Measurement("disk_usage") - .Tag("path", path) - .Field("total_size", totalSize) - .Field("used_percent", double.Parse(usedPercent)) - .Field("available", available) - .Timestamp(DateTime.UtcNow, WritePrecision.Ns); - - writeApi.WritePoint(point, "def-bucket", "def-org"); - Console.WriteLine($"[DiskMonitor] Write point: {point.ToLineProtocol()}"); - } - } -} \ No newline at end of file diff --git a/src/Service/Jobs/HealthyTaskRegistry.cs b/src/Service/Jobs/HealthyTaskRegistry.cs deleted file mode 100644 index af3c99c..0000000 --- a/src/Service/Jobs/HealthyTaskRegistry.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Diagnostics; -using System.Net; -using System.Net.Http.Headers; -using System.Net.Http.Json; -using System.Text; -using Core; -using FluentScheduler; -using Interface.Jobs; -using Microsoft.Extensions.Configuration; - -namespace Service.Jobs; - -public class HealthyTaskRegistry : Registry, IHealthyTaskRegistry -{ - private readonly IConfiguration _configuration; - - public HealthyTaskRegistry(IConfiguration configuration) - { - _configuration = configuration; - Schedule(Job).ToRunNow().AndEvery(2).Minutes(); - } - - public async void Job() - { - try - { - await JobExecute(); - } - catch (Exception e) - { - Console.WriteLine(e); - await WxNotify.SendCommonAsync($"HealthyTaskRegistry.Job() error: {e}"); - } - } - - private async Task JobExecute() - { - // 获取 配置 是个 KV 集合 - var configs = _configuration.GetSection("HealthyTasks"); - - // 遍历配置 - foreach (var item in configs.GetChildren()) - { - // 获取配置的 containerName 和 url - var containerName = item["ContainerName"]; - var url = item["Url"]; - - // 执行 - await ExecuteItem(containerName!, url!); - } - } - - private async Task ExecuteItem(string containerName, string url) - { - try - { - var client = new HttpClient(); - - // basic auth - string authInfo = Convert.ToBase64String(Encoding.ASCII.GetBytes("suncheng:SCsunch940622")); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo); - - var response = await client.GetAsync(url); - - if (response.StatusCode != HttpStatusCode.OK) - { - throw new Exception($"StatusCode: {response.StatusCode}"); - } - - Console.WriteLine($"ContainerName: {containerName}, Url: {url}, StatusCode: {response.StatusCode}"); - } - catch (Exception e) - { - Console.WriteLine(e); - await WxNotify.SendCommonAsync($"ExecuteItem {containerName} error: {e.Message}"); - await ExecuteReboot(containerName); - } - } - - private async Task ExecuteReboot(string containerName) - { - var command = $"docker restart {containerName}"; - - var (responseCode, message) = await Command.ExecAsync(command); - - if (responseCode != HttpStatusCode.OK) - { - await WxNotify.SendCommonAsync($"ExecuteReboot {containerName} error: {responseCode} message: {message}"); - } - else - { - await WxNotify.SendCommonAsync($"ContainerName: {containerName}"); - } - } -} \ No newline at end of file diff --git a/src/Service/Jobs/LogTotalNotifyJobRegistry.cs b/src/Service/Jobs/LogTotalNotifyJobRegistry.cs deleted file mode 100644 index e7101d0..0000000 --- a/src/Service/Jobs/LogTotalNotifyJobRegistry.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Text; -using Core; -using FluentScheduler; -using Interface.Jobs; -using Microsoft.Extensions.Configuration; -using Newtonsoft.Json.Linq; - -namespace Service.Jobs; - -public class LogTotalNotifyJobRegistry : Registry, ILogTotalNotifyJobRegistry -{ - private readonly IConfiguration _configuration; - - public LogTotalNotifyJobRegistry(IConfiguration configuration) - { - _configuration = configuration; - Schedule(Job).ToRunEvery(1).Days().At(8, 30); - } - - public async void Job() - { - try - { - // await JobExecute(); - } - catch (Exception e) - { - Console.WriteLine(e); - await WxNotify.SendCommonAsync($"LogTotalNotifyJobRegistry.Job() error: {e}"); - } - } - - private async Task JobExecute() - { - var client = new HttpClient(); - - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_configuration["Grafana:Token"]}"); - var requestBody = - """ - { - "queries": [ - { - "datasource": { - "type": "loki", - "uid": "edf5cwf6n6i2oe" - }, - "editorMode": "builder", - "expr": "sum by(container_name) (count_over_time({compose_project=~\"dockers|immich|nasrobot|elasticsearch|webui-docker\"} [1h]))", - "queryType": "range", - "refId": "A", - "datasourceId": 2, - "intervalMs": 3600000 - } - ], - "from": "1708963200000", - "to": "1709049600000" - } - """; - - requestBody = requestBody.Replace("1708963200000", DateTime.Today.AddDays(-2).ToUnixTimeMilliseconds().ToString()); - requestBody = requestBody.Replace("1709049600000", DateTime.Today.AddDays(-1).ToUnixTimeMilliseconds().ToString()); - - var content = new StringContent(requestBody, Encoding.UTF8, "application/json"); - var response = await client.PostAsync(_configuration["Grafana:LokiUrl"], content); - - var result = await response.Content.ReadAsStringAsync(); - - var jObject = JObject.Parse(result); - var frames = jObject["results"]?["A"]?["frames"]; - - if (frames == null) - { - throw new Exception("frames is null"); - } - - var msg = new StringBuilder(); - msg.AppendLine($"## {DateTime.Today.AddDays(-1):yyyy-MM-dd}日志明细如下:"); - var total = 0; - var kv = new Dictionary(); - foreach (var item in frames) - { - var name = item["schema"]?["fields"]?.LastOrDefault()?["labels"]?["container_name"]?.ToString(); - - if (string.IsNullOrEmpty(name)) - { - continue; - } - - var values = item["data"]?["values"]?.LastOrDefault()?.ToObject(); - - var value = values?.Sum() ?? 0; - total += value; - kv[name] = value; - } - - foreach (var (key, value) in kv.OrderByDescending(x => x.Value)) - { - msg.AppendLine($"**{key}**: {value}"); - } - - msg.AppendLine(""); - msg.AppendLine($"> **总计**: {total}"); - - await WxNotify.SendCommonAsync(msg.ToString()); - } -} \ No newline at end of file diff --git a/src/Service/Jobs/RSyncTaskRegistry.cs b/src/Service/Jobs/RSyncTaskRegistry.cs deleted file mode 100644 index a8488c9..0000000 --- a/src/Service/Jobs/RSyncTaskRegistry.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Diagnostics; -using System.Net.Http.Json; -using Core; -using FluentScheduler; -using Interface.Jobs; -using Microsoft.Extensions.Configuration; - -namespace Service.Jobs; - -public class RSyncTaskRegistry : Registry, IRSyncTaskRegistry -{ - private readonly IConfiguration _configuration; - - public RSyncTaskRegistry(IConfiguration configuration) - { - _configuration = configuration; - Schedule(Job).ToRunEvery(1).Days().At(10, 0); - } - - public async void Job() - { - try - { - // await JobExecute(); - } - catch (Exception e) - { - Console.WriteLine(e); - await WxNotify.SendCommonAsync($"RSyncTaskRegistry.Job() error: {e}"); - } - } - - private async Task JobExecute() - { - var config = _configuration.GetSection("SyncTask"); - - foreach (var item in config.GetSection("SyncPaths").GetChildren()) - { - var source = Path.Combine(config["SourceRoot"]!, item["Source"]!); - var isDeleteAfter = item["DeleteAfter"] == "true"; - await ExecuteItem(source, config["TargetRoot"]!, item["Target"]!, isDeleteAfter); - } - } - - private async Task ExecuteItem(string source, string remote, string destination, bool isDeleteAfter) - { - var logName = $"rclone_output_{destination.Replace("/", "_")}{DateTime.Now:yyMMddHHmm}.log"; - - var commands = new[] - { - $"rclone sync " + - $"{source} " + - $"{remote}:{destination} " + - $"--fast-list " + - $"--size-only " + - $"{(isDeleteAfter ? "--delete-after" : "--delete-excluded")} " + - $"> /wd/logs/{logName} 2>&1" - }; - - await WxNotify.SendCommonAsync($@"RSyncTaskRegistry.ExecuteItem() - -`{commands[0]}` - -> {DateTime.Now:yyyy-MM-dd HH:mm:ss} -"); - - _ = Command.ExecAsync(commands); - } -} \ No newline at end of file diff --git a/src/Service/Jobs/ShutdownRegistry.cs b/src/Service/Jobs/ShutdownRegistry.cs deleted file mode 100644 index 94e84f6..0000000 --- a/src/Service/Jobs/ShutdownRegistry.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Net; -using Core; -using FluentScheduler; -using Interface.Jobs; - -namespace Service.Jobs; - -public class ShutdownRegistry : Registry, IShutdownRegistry -{ - public ShutdownRegistry() - { - Schedule(Job).ToRunEvery(1).Days().At(23, 30); - } - - public async void Job() - { - try - { - await JobExecute(); - } - catch (Exception e) - { - Console.WriteLine(e); - await WxNotify.SendCommonAsync($"ShutdownRegistry.Job() error: {e}"); - } - } - - private async Task JobExecute() - { - var command = "shutdown 9"; - - var (responseCode, msg) = await Command.ExecAsync(command); - - var wxMsg = $@" -# 定时关机指令执行 - -> 执行结果:{responseCode} -> 执行消息:{msg} - -如需取消关机请点击:[取消关机](http://suncheng.online:35642/api/JobTrigger/CancelShutdown) - -"; - - await WxNotify.SendCommonAsync(wxMsg); - - if (responseCode == HttpStatusCode.OK) - { - // 每三分钟提醒一次 - _ = Task.Delay(3 * 60 * 1000).ContinueWith(async _ => await WxNotify.SendCommonAsync(wxMsg)); - } - } - - public async Task CancelShutdown() - { - var command = "shutdown -c"; - - var (responseCode, _) = await Command.ExecAsync(command); - - await WxNotify.SendCommonAsync($"取消关机指令执行完成 {responseCode}"); - } -} \ No newline at end of file diff --git a/src/Service/Jobs/StartupRegistry.cs b/src/Service/Jobs/StartupRegistry.cs deleted file mode 100644 index aabefb7..0000000 --- a/src/Service/Jobs/StartupRegistry.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Net; -using Core; -using FluentScheduler; -using Interface.Jobs; - -namespace Service.Jobs; - -public class StartupRegistry : Registry, IStartupRegistry -{ - public StartupRegistry() - { - Schedule(Job).ToRunNow(); - } - - public async void Job() - { - try - { - // await JobExecute(); - } - catch (Exception e) - { - Console.WriteLine(e); - await WxNotify.SendCommonAsync($"StartupRegistry.Job() error: {e}"); - } - } - - private async Task JobExecute() - { - var commands = new[] - { - "chmod 777 /var/run/docker.sock", - }; - - var (responseCode, _) = await Command.ExecAsync(commands); - - if (responseCode != HttpStatusCode.OK) - { - await WxNotify.SendCommonAsync($"StartupRegistry.Job() error: {responseCode}"); - } - else - { - await WxNotify.SendCommonAsync("StartupRegistry.Job() success"); - } - } -} \ No newline at end of file diff --git a/src/WebApi/Controllers/JobTriggerController.cs b/src/WebApi/Controllers/JobTriggerController.cs index 227dc18..9503f87 100644 --- a/src/WebApi/Controllers/JobTriggerController.cs +++ b/src/WebApi/Controllers/JobTriggerController.cs @@ -9,14 +9,7 @@ namespace WebApi.Controllers; public class JobTriggerController : BaseController { - private readonly ILogTotalNotifyJobRegistry _logTotalNotifyJobRegistry; - private readonly IDiskActionMonitorRegistry _diskActionMonitorRegistry; - private readonly IHealthyTaskRegistry _healthyTaskRegistry; - private readonly IRSyncTaskRegistry _rSyncTaskRegistry; - private readonly IStartupRegistry _startupRegistry; - private readonly IShutdownRegistry _shutdownRegistry; private readonly IChineseNfoRegistry _chineseNfoRegistry; - private readonly IDiskMonitorRegistry _diskMonitorRegistry; private readonly ILogger _logger; @@ -24,83 +17,13 @@ public class JobTriggerController : BaseController /// ctor /// public JobTriggerController( - ILogTotalNotifyJobRegistry logTotalNotifyJobRegistry, - IDiskActionMonitorRegistry diskActionMonitorRegistry, - IHealthyTaskRegistry healthyTaskRegistry, - IRSyncTaskRegistry rSyncTaskRegistry, - IStartupRegistry startupRegistry, - IShutdownRegistry shutdownRegistry, IChineseNfoRegistry chineseNfoRegistry, - IDiskMonitorRegistry diskMonitorRegistry, ILogger logger) { - _logTotalNotifyJobRegistry = logTotalNotifyJobRegistry; - _diskActionMonitorRegistry = diskActionMonitorRegistry; - _healthyTaskRegistry = healthyTaskRegistry; - _rSyncTaskRegistry = rSyncTaskRegistry; - _startupRegistry = startupRegistry; - _shutdownRegistry = shutdownRegistry; _chineseNfoRegistry = chineseNfoRegistry; - _diskMonitorRegistry = diskMonitorRegistry; _logger = logger; } - [HttpGet] - public string LogTotalNotify() - { - _logTotalNotifyJobRegistry.Job(); - - return "OK"; - } - - [HttpGet] - public string DiskActionMonitor() - { - _diskActionMonitorRegistry.Job(); - - return "OK"; - } - - [HttpGet] - public string HealthyTask() - { - _healthyTaskRegistry.Job(); - - return "OK"; - } - - - [HttpGet] - public string RSyncTask() - { - _rSyncTaskRegistry.Job(); - - return "OK"; - } - - [HttpGet] - public string Startup() - { - _startupRegistry.Job(); - - return "OK"; - } - - [HttpGet] - public string Shutdown() - { - _shutdownRegistry.Job(); - - return "OK"; - } - - [HttpGet] - public string CancelShutdown() - { - _shutdownRegistry.CancelShutdown(); - - return "OK"; - } [HttpGet] public string ConvertChineseNfo( @@ -152,7 +75,6 @@ public class JobTriggerController : BaseController return "OK"; } - [HttpGet] public string ConvertChineseNfoByPath( @@ -166,12 +88,4 @@ public class JobTriggerController : BaseController return "OK"; } - - [HttpGet] - public string DiskMonitor() - { - _diskMonitorRegistry.Job(); - - return "OK"; - } } \ No newline at end of file diff --git a/src/WebApi/Controllers/NotifyController.cs b/src/WebApi/Controllers/NotifyController.cs index d3b9620..4b4288d 100644 --- a/src/WebApi/Controllers/NotifyController.cs +++ b/src/WebApi/Controllers/NotifyController.cs @@ -21,40 +21,6 @@ public class NotifyController : BaseController Console.WriteLine(text); - /* - { - "movie": { - "id": 1, - "title": "Test Title", - "year": 1970, - "releaseDate": "1970-01-01", - "folderPath": "C:\\testpath", - "tmdbId": 0, - "tags": [ - "test-tag" - ] - }, - "remoteMovie": { - "tmdbId": 1234, - "imdbId": "5678", - "title": "Test title", - "year": 1970 - }, - "release": { - "quality": "Test Quality", - "qualityVersion": 1, - "releaseGroup": "Test Group", - "releaseTitle": "Test Title", - "indexer": "Test Indexer", - "size": 9999999, - "customFormatScore": 0 - }, - "eventType": "Test", - "instanceName": "Radarr", - "applicationUrl": "" -} - */ - var jsonObj = JsonConvert.DeserializeObject(text); var notify = @$"# Radarr通知: @@ -96,189 +62,6 @@ public class NotifyController : BaseController Console.WriteLine(text); - /* -{ - "series": { - "id": 86, - "title": "Demon Slayer: Kimetsu no Yaiba", - "titleSlug": "demon-slayer-kimetsu-no-yaiba", - "path": "/data/anime/Demon Slayer - Kimetsu no Yaiba", - "tvdbId": 348545, - "tvMazeId": 41469, - "tmdbId": 85937, - "imdbId": "tt9335498", - "type": "anime", - "year": 2019, - "genres": [ - "Action", - "Adventure", - "Animation", - "Anime", - "Drama", - "Fantasy", - "Thriller" - ], - "images": [ - { - "coverType": "banner", - "url": "/MediaCover/86/banner.jpg?lastWrite=638509998968281535", - "remoteUrl": "https://artworks.thetvdb.com/banners/graphical/5ccd960cc3aa0.jpg" - }, - { - "coverType": "poster", - "url": "/MediaCover/86/poster.jpg?lastWrite=638509998969561521", - "remoteUrl": "https://artworks.thetvdb.com/banners/v4/series/348545/posters/60908d475f49a.jpg" - }, - { - "coverType": "fanart", - "url": "/MediaCover/86/fanart.jpg?lastWrite=638509998971801497", - "remoteUrl": "https://artworks.thetvdb.com/banners/fanart/original/5c93cbb2b60b6.jpg" - }, - { - "coverType": "clearlogo", - "url": "/MediaCover/86/clearlogo.png?lastWrite=638509998972921485", - "remoteUrl": "https://artworks.thetvdb.com/banners/v4/series/348545/clearlogo/611c7fa8222d6.png" - } - ], - "tags": [ - "anime" - ] - }, - "episodes": [ - { - "id": 2716, - "episodeNumber": 2, - "seasonNumber": 5, - "title": "Water Hashira Giyu Tomioka's Pain", - "overview": "Kagaya's Kasugai Crow suddenly appears in front of Tamayo and invites her to the Demon Slayer headquarters — even though she is a demon. Meanwhile, Tanjiro, who is recovering at the Butterfly Mansion, receives a letter from Kagaya...", - "airDate": "2024-05-19", - "airDateUtc": "2024-05-19T14:15:00Z", - "seriesId": 86, - "tvdbId": 10445764 - } - ], - "release": { - "quality": "WEBDL-1080p", - "qualityVersion": 1, - "releaseGroup": "ToonsHub", - "releaseTitle": "[ToonsHub] Demon Slayer Kimetsu no Yaiba S05E02 1080p CR WEB-DL AAC2.0 x264 (Multi-Subs)", - "indexer": "Knaben ", - "size": 1395864320, - "customFormatScore": 0, - "customFormats": [] - }, - "downloadClient": "aria2", - "downloadClientType": "Aria2", - "downloadId": "915718C3A8A5B15BD3C32A2B05885953D96AFADD", - "customFormatInfo": { - "customFormats": [], - "customFormatScore": 0 - }, - "eventType": "Grab", - "instanceName": "Sonarr", - "applicationUrl": "" -} - - --------------------------- - -{ - "series": { - "id": 86, - "title": "Demon Slayer: Kimetsu no Yaiba", - "titleSlug": "demon-slayer-kimetsu-no-yaiba", - "path": "/data/anime/Demon Slayer - Kimetsu no Yaiba", - "tvdbId": 348545, - "tvMazeId": 41469, - "tmdbId": 85937, - "imdbId": "tt9335498", - "type": "anime", - "year": 2019, - "genres": [ - "Action", - "Adventure", - "Animation", - "Anime", - "Drama", - "Fantasy", - "Thriller" - ], - "images": [ - { - "coverType": "banner", - "url": "/MediaCover/86/banner.jpg?lastWrite=638509998968281535", - "remoteUrl": "https://artworks.thetvdb.com/banners/graphical/5ccd960cc3aa0.jpg" - }, - { - "coverType": "poster", - "url": "/MediaCover/86/poster.jpg?lastWrite=638509998969561521", - "remoteUrl": "https://artworks.thetvdb.com/banners/v4/series/348545/posters/60908d475f49a.jpg" - }, - { - "coverType": "fanart", - "url": "/MediaCover/86/fanart.jpg?lastWrite=638509998971801497", - "remoteUrl": "https://artworks.thetvdb.com/banners/fanart/original/5c93cbb2b60b6.jpg" - }, - { - "coverType": "clearlogo", - "url": "/MediaCover/86/clearlogo.png?lastWrite=638509998972921485", - "remoteUrl": "https://artworks.thetvdb.com/banners/v4/series/348545/clearlogo/611c7fa8222d6.png" - } - ], - "tags": [ - "anime" - ] - }, - "episodes": [ - { - "id": 2716, - "episodeNumber": 2, - "seasonNumber": 5, - "title": "Water Hashira Giyu Tomioka's Pain", - "overview": "Kagaya's Kasugai Crow suddenly appears in front of Tamayo and invites her to the Demon Slayer headquarters — even though she is a demon. Meanwhile, Tanjiro, who is recovering at the Butterfly Mansion, receives a letter from Kagaya...", - "airDate": "2024-05-19", - "airDateUtc": "2024-05-19T14:15:00Z", - "seriesId": 86, - "tvdbId": 10445764 - } - ], - "downloadInfo": { - "quality": "WEBDL-1080p", - "qualityVersion": 1, - "title": "Demon.Slayer.Kimetsu.no.Yaiba.S57E02.Water.Hashira.Giyu.Tomiokas.Pain.1080p.CR.WEB-DL.JPN.AAC2.0.H.264.MSubs-ToonsHub.mkv", - "size": 1446462408 - }, - "downloadClient": "aria2", - "downloadClientType": "Aria2", - "downloadId": "915718C3A8A5B15BD3C32A2B05885953D96AFADD", - "downloadStatus": "Warning", - "downloadStatusMessages": [ - { - "title": "One or more episodes expected in this release were not imported or missing from the release", - "messages": [] - }, - { - "title": "Demon.Slayer.Kimetsu.no.Yaiba.S57E02.Water.Hashira.Giyu.Tomiokas.Pain.1080p.CR.WEB-DL.JPN.AAC2.0.H.264.MSubs-ToonsHub.mkv", - "messages": [ - "Invalid season or episode" - ] - } - ], - "customFormatInfo": { - "customFormats": [], - "customFormatScore": 0 - }, - "release": { - "releaseTitle": "[ToonsHub] Demon Slayer Kimetsu no Yaiba S05E02 1080p CR WEB-DL AAC2.0 x264 (Multi-Subs)", - "indexer": "Knaben ", - "size": 1395864320 - }, - "eventType": "ManualInteractionRequired", - "instanceName": "Sonarr", - "applicationUrl": "" -} - */ - var jsonObj = JsonConvert.DeserializeObject(text); var notify = @$"# Sonarr通知: diff --git a/src/WebApi/Controllers/XiaoController.cs b/src/WebApi/Controllers/XiaoController.cs deleted file mode 100644 index cd89497..0000000 --- a/src/WebApi/Controllers/XiaoController.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Core; -using Microsoft.AspNetCore.Mvc; - -namespace WebApi.Controllers; - -public class XiaoController : BaseController -{ - private readonly ILogger _logger; - - public XiaoController(ILogger logger) - { - _logger = logger; - } - - [HttpGet] - public async Task GotoHomeGame() - { - await WxNotify.SendCommonAsync("接收到启动游戏机指令"); - - var commands = new[] - { - "grub-reboot 2", - "reboot" - }; - - _ = Task.Run(async () => - { - await Task.Delay(3000); - _ = await Command.ExecAsync(commands); - }); - - return "OK"; - } -} \ No newline at end of file