From 80c5b7b242f1e1248f5316f35c5b41f0c9357e8f Mon Sep 17 00:00:00 2001 From: MIRIMIRIM <59959583+MIRIMIRIM@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:08:57 +0800 Subject: [PATCH] Feat/aot (#14) * chore: upgrade to dotnet 8 * feat: adapt source generation * feat: replace CommandLineParser with System.CommandLine Signed-off-by: MIRIMIRIM <59959583+MIRIMIRIM@users.noreply.github.com> * feat: upgrade System.CommandLine Signed-off-by: MIRIMIRIM <59959583+MIRIMIRIM@users.noreply.github.com> * Update OKP.Core.csproj * fix warning CS8604 * use Tommy instead of Tomlyn * not use gha build nativeaot * feat: remove unused satellite resource languages --------- Signed-off-by: MIRIMIRIM <59959583+MIRIMIRIM@users.noreply.github.com> Co-authored-by: TautCony --- .github/workflows/dotnet-ci.yml | 34 +-- OKP.Core/Interface/Acgnx/AcgnxAdapter.cs | 20 +- OKP.Core/Interface/Bangumi/BangumiAdapter.cs | 10 +- OKP.Core/Interface/Bangumi/BangumiModels.cs | 17 +- OKP.Core/Interface/TorrentContent.cs | 9 +- OKP.Core/OKP.Core.csproj | 18 +- OKP.Core/Program.cs | 292 +++++++++++-------- OKP.Core/Utils/HttpHelper.cs | 5 +- OKP.Core/Utils/TagHelper.cs | 7 +- OKP.Core/Utils/TomlParseHelper.cs | 97 ++++++ nuget.config | 6 + 11 files changed, 343 insertions(+), 172 deletions(-) create mode 100644 OKP.Core/Utils/TomlParseHelper.cs create mode 100644 nuget.config diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 3ea2c77..b4cd527 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -20,20 +20,20 @@ jobs: - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.x + dotnet-version: 8.x - name: Publish the application - run: dotnet publish OKP.Core --configuration ${{ matrix.configuration }} --runtime ${{ matrix.runtime-identifier }} --self-contained false + run: dotnet publish OKP.Core --configuration ${{ matrix.configuration }} --runtime ${{ matrix.runtime-identifier }} /p:PublishAot=false - name: Upload build artifacts uses: actions/upload-artifact@v3 with: name: OKP.Core-${{ matrix.runtime-identifier }}-${{ matrix.configuration }} path: | - OKP.Core/bin/${{ matrix.configuration }}/net6.0/${{ matrix.runtime-identifier }}/publish/* - !OKP.Core/bin/${{ matrix.configuration }}/net6.0/${{ matrix.runtime-identifier }}/publish/*.pdb - !OKP.Core/bin/${{ matrix.configuration }}/net6.0/${{ matrix.runtime-identifier }}/publish/*.dbg - !OKP.Core/bin/${{ matrix.configuration }}/net6.0/${{ matrix.runtime-identifier }}/publish/*.dwarf + OKP.Core/bin/${{ matrix.configuration }}/net8.0/${{ matrix.runtime-identifier }}/publish/* + !OKP.Core/bin/${{ matrix.configuration }}/net8.0/${{ matrix.runtime-identifier }}/publish/*.pdb + !OKP.Core/bin/${{ matrix.configuration }}/net8.0/${{ matrix.runtime-identifier }}/publish/*.dbg + !OKP.Core/bin/${{ matrix.configuration }}/net8.0/${{ matrix.runtime-identifier }}/publish/*.dwarf glue: name: 'Build (Release, osx-universal)' @@ -43,8 +43,8 @@ jobs: steps: - name: Setup working directory run: | - mkdir -p OKP.Core/bin/Release/net6.0/osx-x64/publish - mkdir -p OKP.Core/bin/Release/net6.0/osx-arm64/publish + mkdir -p OKP.Core/bin/Release/net8.0/osx-x64/publish + mkdir -p OKP.Core/bin/Release/net8.0/osx-arm64/publish - name: Setup lipo run: | @@ -56,26 +56,26 @@ jobs: uses: actions/download-artifact@v3 with: name: OKP.Core-osx-x64-Release - path: OKP.Core/bin/Release/net6.0/osx-x64/publish + path: OKP.Core/bin/Release/net8.0/osx-x64/publish - name: Download arm64 build uses: actions/download-artifact@v3 with: name: OKP.Core-osx-arm64-Release - path: OKP.Core/bin/Release/net6.0/osx-arm64/publish + path: OKP.Core/bin/Release/net8.0/osx-arm64/publish - name: Glue the binary run: | - mkdir -p OKP.Core/bin/Release/net6.0/osx-universal/publish - lipo -create OKP.Core/bin/Release/net6.0/osx-x64/publish/OKP.Core OKP.Core/bin/Release/net6.0/osx-arm64/publish/OKP.Core -output OKP.Core/bin/Release/net6.0/osx-universal/publish/OKP.Core - mv OKP.Core/bin/Release/net6.0/osx-x64/publish/config OKP.Core/bin/Release/net6.0/osx-universal/publish/config + mkdir -p OKP.Core/bin/Release/net8.0/osx-universal/publish + lipo -create OKP.Core/bin/Release/net8.0/osx-x64/publish/OKP.Core OKP.Core/bin/Release/net8.0/osx-arm64/publish/OKP.Core -output OKP.Core/bin/Release/net8.0/osx-universal/publish/OKP.Core + mv OKP.Core/bin/Release/net8.0/osx-x64/publish/config OKP.Core/bin/Release/net8.0/osx-universal/publish/config - name: Upload build artifacts uses: actions/upload-artifact@v3 with: name: OKP.Core-osx-universal-Release path: | - OKP.Core/bin/Release/net6.0/osx-universal/publish/* - !OKP.Core/bin/Release/net6.0/osx-universal/publish/*.pdb - !OKP.Core/bin/Release/net6.0/osx-universal/publish/*.dbg - !OKP.Core/bin/Release/net6.0/osx-universal/publish/*.dwarf + OKP.Core/bin/Release/net8.0/osx-universal/publish/* + !OKP.Core/bin/Release/net8.0/osx-universal/publish/*.pdb + !OKP.Core/bin/Release/net8.0/osx-universal/publish/*.dbg + !OKP.Core/bin/Release/net8.0/osx-universal/publish/*.dwarf diff --git a/OKP.Core/Interface/Acgnx/AcgnxAdapter.cs b/OKP.Core/Interface/Acgnx/AcgnxAdapter.cs index 2433e55..84ea01f 100644 --- a/OKP.Core/Interface/Acgnx/AcgnxAdapter.cs +++ b/OKP.Core/Interface/Acgnx/AcgnxAdapter.cs @@ -2,7 +2,6 @@ using Serilog; using System.Net; using System.Net.Http.Json; -using System.Text.Json; using System.Text.Json.Serialization; using static OKP.Core.Interface.TorrentContent; @@ -101,11 +100,7 @@ public override async Task PingAsync() if (result.IsSuccessStatusCode && !raw.Contains("(new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - NumberHandling = JsonNumberHandling.AllowReadingFromString - }); + var apiContent = await result.Content.ReadFromJsonAsync(AcgnxModelsSourceGenerationContext.Default.AcgnxApiStatus); if (apiContent == null) { Log.Error("{Site} api server down", site); @@ -160,11 +155,7 @@ public override async Task PostAsync() Log.Verbose("{Site} formdata content: {@MultipartFormDataContent}", site, form); var result = await httpClient.PostAsyncWithRetry(apiUrl, form); var raw = await result.Content.ReadAsStringAsync(); - var apiContent = await result.Content.ReadFromJsonAsync(new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - NumberHandling = JsonNumberHandling.AllowReadingFromString - }); + var apiContent = await result.Content.ReadFromJsonAsync(AcgnxModelsSourceGenerationContext.Default.AcgnxApiStatus); if (result.StatusCode == HttpStatusCode.OK && apiContent != null && !raw.Contains(" PingAsync() { var pingReq = await httpClient.GetAsync(pingUrl); var raw = await pingReq.Content.ReadAsStringAsync(); - var teamList = await pingReq.Content.ReadFromJsonAsync(); + var teamList = await pingReq.Content.ReadFromJsonAsync(BangumiModelsSourceGenerationContext.Default.TeamInfoArray); if (!pingReq.IsSuccessStatusCode || teamList == null) { Log.Error("Cannot connect to {Site}.{NewLine}" + @@ -107,9 +107,9 @@ public override async Task PostAsync() teamsync = false, file_id = fileId, }; - var response = await httpClient.PostAsJsonAsyncWithRetry(postUrl, addRequest); + var response = await httpClient.PostAsJsonAsyncWithRetry(postUrl, addRequest, BangumiModelsSourceGenerationContext.Default.AddRequest); var raw = await response.Content.ReadAsStringAsync(); - var result = await response.Content.ReadFromJsonAsync(); + var result = await response.Content.ReadFromJsonAsync(BangumiModelsSourceGenerationContext.Default.AddResponse); if (!response.IsSuccessStatusCode || result == null) { Log.Error("{Site} upload failed. Unknown reson. {NewLine} {Raw}", site, Environment.NewLine, raw); @@ -134,13 +134,13 @@ private async Task UploadTorrent(TorrentContent torrent) { torrent.Data.ByteArrayContent, "file", torrent.Data.FileInfo.Name } }; var response = await httpClient.PostAsyncWithRetry(uploadUrl, form); - var result = await response.Content.ReadFromJsonAsync(); + var result = await response.Content.ReadFromJsonAsync(BangumiModelsSourceGenerationContext.Default.UploadResponse); if (result == null || !result.success || result.file_id == null) { Log.Debug("可能是 {Site} 发布频率限制,先等 1 分钟", site); Thread.Sleep(60000); response = await httpClient.PostAsyncWithRetry(uploadUrl, form); - result = await response.Content.ReadFromJsonAsync(); + result = await response.Content.ReadFromJsonAsync(BangumiModelsSourceGenerationContext.Default.UploadResponse); if (result == null || !result.success || result.file_id == null) { throw new HttpRequestException("Failed to upload torrent file"); diff --git a/OKP.Core/Interface/Bangumi/BangumiModels.cs b/OKP.Core/Interface/Bangumi/BangumiModels.cs index 599cfbf..dbe3dac 100644 --- a/OKP.Core/Interface/Bangumi/BangumiModels.cs +++ b/OKP.Core/Interface/Bangumi/BangumiModels.cs @@ -1,4 +1,7 @@ // ReSharper disable InconsistentNaming, IdentifierTypo + +using System.Text.Json.Serialization; + namespace OKP.Core.Interface.Bangumi { #pragma warning disable CS8618 @@ -75,6 +78,18 @@ public class TeamInfo public DateTime regDate { get; set; } public bool approved { get; set; } } - } + + [JsonSerializable(typeof(BangumiModels.UploadResponse))] + [JsonSerializable(typeof(BangumiModels.AddRequest))] + [JsonSerializable(typeof(BangumiModels.AddResponse))] + [JsonSerializable(typeof(BangumiModels.Torrent))] + [JsonSerializable(typeof(BangumiModels.TeamList))] + [JsonSerializable(typeof(BangumiModels.TeamInfo))] + [JsonSerializable(typeof(BangumiModels.TeamInfo[]))] + [JsonSourceGenerationOptions( + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + NumberHandling = JsonNumberHandling.AllowReadingFromString) + ] + internal partial class BangumiModelsSourceGenerationContext : JsonSerializerContext; } diff --git a/OKP.Core/Interface/TorrentContent.cs b/OKP.Core/Interface/TorrentContent.cs index de3e742..89e325d 100644 --- a/OKP.Core/Interface/TorrentContent.cs +++ b/OKP.Core/Interface/TorrentContent.cs @@ -6,7 +6,6 @@ using System.Net.Http.Headers; using System.Text; using System.Text.RegularExpressions; -using Tomlyn; namespace OKP.Core.Interface { @@ -46,8 +45,8 @@ public TorrentData(string filename) public string? FilenameRegex { get; set; } public string? ResolutionRegex { get; set; } public string? SettingPath { get; set; } - public bool HasSubtitle { get; set; } - public bool IsFinished { get; set; } + // public bool HasSubtitle { get; set; } + // public bool IsFinished { get; set; } public string? CookiePath { get; set; } public List? Tags { get; set; } public List? TorrentFlags { get; set; } @@ -116,7 +115,7 @@ public static TorrentContent Build(string filename, string settingFile, string a throw new IOException(); } - var torrentC = Toml.ToModel(File.ReadAllText(settingFilePath)); + var torrentC = TomlParseHelper.DeserializeTorrentContent(settingFilePath); torrentC.SettingPath = Path.GetDirectoryName(settingFilePath); //if (!File.Exists(torrentC.CookiePath)) //{ @@ -172,7 +171,7 @@ public static TorrentContent Build(string filename, string settingFile, string a var userPropPath = IOHelper.BasePath(Constants.DefaultUserPropsPath, Constants.UserPropertiesFileName); if (File.Exists(userPropPath)) { - var userProp = Toml.ToModel(File.ReadAllText(userPropPath)); + var userProp = TomlParseHelper.DeserializeUserProperties(userPropPath); if (userProp.UserProp == null) return torrentC; diff --git a/OKP.Core/OKP.Core.csproj b/OKP.Core/OKP.Core.csproj index 6be03ff..e280e2b 100644 --- a/OKP.Core/OKP.Core.csproj +++ b/OKP.Core/OKP.Core.csproj @@ -2,23 +2,27 @@ Exe - net6.0 + net8.0 enable enable - true + true 1.0.2-beta Copyright (C) 2023 AmusementClub Released under the GNU GPLv3+. + true + en-US - - + - - - + + + + + + diff --git a/OKP.Core/Program.cs b/OKP.Core/Program.cs index 3024fed..42dccc6 100644 --- a/OKP.Core/Program.cs +++ b/OKP.Core/Program.cs @@ -1,4 +1,4 @@ -using CommandLine; +using System.CommandLine; using OKP.Core.Interface; using OKP.Core.Interface.Acgnx; using OKP.Core.Interface.Acgrip; @@ -15,133 +15,181 @@ namespace OKP.Core { internal class Program { -#pragma warning disable CS8618 - - private class Options + public static void Main(string[] args) { - [Value(0, Min = 1, Required = true, MetaName = "torrent", HelpText = "Torrents to be published.(Or Cookie file exported by Get Cookies.txt.)")] - public IEnumerable? TorrentFile { get; set; } - [Option("cookies", Required = false, Default = null, HelpText = "Cookie file to be used.")] - public string? Cookies { get; set; } - [Option('s', "setting", Required = false, Default = Constants.DefaultSettingFileName, HelpText = "(Not required) Specific setting file.")] - public string SettingFile { get; set; } - [Option('l', "log_level", Default = "Debug", HelpText = "Log level.")] - public string? LogLevel { get; set; } - [Option("log_file", Required = false, Default = Constants.DefaultLogFileName, HelpText = "Log file.")] - public string LogFile { get; set; } - [Option('y', HelpText = "Skip reaction.")] - public bool NoReaction { get; set; } - [Option("allow_skip",HelpText="Ignore login fail and continue publishing.")] - public bool AllowSkip { get;set; } + var torrentArgument = new CliArgument?>("torrent") + { + Description = "Torrents to be published. (Or Cookie file exported by Get Cookies.txt.)" + }; + + var cookiesOption = new CliOption("--cookies") + { + DefaultValueFactory = _ => null, + Description = "Cookie file to be used." + }; + + var settingOption = new CliOption("--setting", "-s") + { + DefaultValueFactory = _ => Constants.DefaultSettingFileName, + Description = "(Not required) Specific setting file." + }; + + var logLevelOption = new CliOption("--log_level", "-l") + { + DefaultValueFactory = _ => "Debug", + Description = "Log level." + }; + + var logFileOption = new CliOption("--log_file") + { + DefaultValueFactory = _ => Constants.DefaultLogFileName, + Description = "Log file." + }; + + var noReactionOption = new CliOption("--no_reaction", "-y") + { + Description = "Skip reaction." + }; + + var allowSkipOption = new CliOption("--allow_skip") + { + Description = "Ignore login fail and continue publishing." + }; + + var rootCommand = new CliRootCommand("One Key Publish") + { + torrentArgument, + cookiesOption, + settingOption, + logLevelOption, + logFileOption, + noReactionOption, + allowSkipOption, + }; + + rootCommand.SetAction((result, _) => + { + var torrentFile = result.GetValue(torrentArgument); + var cookies = result.GetValue(cookiesOption); + var settingFile = result.GetValue(settingOption); + var logLevel = result.GetValue(logLevelOption); + var logFile = result.GetValue(logFileOption); + var noReaction = result.GetValue(noReactionOption); + var allowSkip = result.GetValue(allowSkipOption); + + ActionHandler(torrentFile, cookies, settingFile!, logLevel!, logFile!, noReaction, allowSkip); + return Task.CompletedTask; + }); + + rootCommand.Parse(args).Invoke(); + IOHelper.ReadLine(); } -#pragma warning restore CS8618 - public static void Main(string[] args) + private static void ActionHandler(IEnumerable? torrentFile, string? cookies, string settingFile, string logLevel, string logFile, bool noReaction, bool allowSkip) { - Parser.Default.ParseArguments(args) - .WithParsed(o => - { - var levelSwitch = new LoggingLevelSwitch - { - MinimumLevel = o.LogLevel?.ToLower() switch - { - "verbose" => LogEventLevel.Verbose, - "debug" => LogEventLevel.Debug, - "info" => LogEventLevel.Information, - _ => LogEventLevel.Debug - } - }; - Log.Logger = new LoggerConfiguration() - .MinimumLevel.ControlledBy(levelSwitch) - .WriteTo.Console() - .WriteTo.File(o.LogFile, - rollingInterval: RollingInterval.Month, - rollOnFileSizeLimit: true) - .CreateLogger(); - IOHelper.NoReaction = o.NoReaction; - Console.OutputEncoding = System.Text.Encoding.UTF8; - if (o.TorrentFile is null) - { - Log.Fatal("o.TorrentFile is null"); - return; - } - var addCookieCount = 0; - foreach (var file in o.TorrentFile) - { - if (!File.Exists(file)) - { - Log.Error("文件{File}不存在", file); - continue; - } - var extension = (Path.GetExtension(file) ?? "").AsSpan(); + var levelSwitch = new LoggingLevelSwitch + { + MinimumLevel = logLevel.ToLower() switch + { + "verbose" => LogEventLevel.Verbose, + "debug" => LogEventLevel.Debug, + "info" => LogEventLevel.Information, + _ => LogEventLevel.Debug + } + }; + Log.Logger = new LoggerConfiguration() + .MinimumLevel.ControlledBy(levelSwitch) + .WriteTo.Console() + .WriteTo.File(logFile, + rollingInterval: RollingInterval.Month, + rollOnFileSizeLimit: true) + .CreateLogger(); + IOHelper.NoReaction = noReaction; + if (torrentFile is null) + { + Log.Fatal("o.TorrentFile is null"); + return; + } + var addCookieCount = 0; + foreach (var file in torrentFile) + { + if (!File.Exists(file)) + { + Log.Error("文件{File}不存在", file); + continue; + } + var extension = (Path.GetExtension(file) ?? "").AsSpan(); - if (extension.Equals(".torrent", StringComparison.OrdinalIgnoreCase)) - { - Log.Information("正在发布 {File}", file); - SinglePublish(file, o.SettingFile, o.Cookies,o.AllowSkip); - continue; - } - if (extension.Equals(".torrent", StringComparison.OrdinalIgnoreCase)) - { - if (o.Cookies is null) - { - Log.Information("请输入Cookie文件名,不需要包含扩展名,相对目录默认为{DefaultPath}", IOHelper.BasePath(Constants.DefaultCookiePath)); - IOHelper.HintText(Constants.DefaultCookieFile); - var filename = IOHelper.ReadLine(); - if (File.Exists(filename)) - { - o.Cookies = filename; - Log.Error("你指定的Cookie文件{File}已经存在!继续添加可能会覆盖之前保存的Cookie!", o.Cookies); - IOHelper.ReadLine(); - HttpHelper.GlobalCookieContainer.LoadFromTxt(o.Cookies); - } - else - { - if (!Directory.Exists(IOHelper.BasePath(Constants.DefaultCookiePath))) - { - Directory.CreateDirectory(IOHelper.BasePath(Constants.DefaultCookiePath)); - } - o.Cookies = IOHelper.BasePath(Constants.DefaultCookiePath, (filename?.Length == 0 ? Constants.DefaultCookieFile : filename) + ".txt"); - if (File.Exists(o.Cookies)) - { - Log.Error("你指定的Cookie文件{File}已经存在!继续添加可能会覆盖之前保存的Cookie!", o.Cookies); - IOHelper.ReadLine(); - HttpHelper.GlobalCookieContainer.LoadFromTxt(o.Cookies); - } - } - Log.Information("请输入你使用的浏览器UserAgent:"); - var ua = IOHelper.ReadLine(); - while (ua is null || !HttpHelper.UaRegex.IsMatch(ua)) - { - Log.Information("你必须输入一个合法的UserAgent以确保你的cookie可以正常使用:"); - ua = IOHelper.ReadLine(); - } - HttpHelper.GlobalUserAgent = ua; - } - if (File.Exists(IOHelper.BasePath(Constants.DefaultCookiePath, Constants.DefaultCookieFile + ".txt"))) - { - HttpHelper.GlobalCookieContainer.LoadFromTxt(IOHelper.BasePath(Constants.DefaultCookiePath, Constants.DefaultCookieFile + ".txt")); - } - Log.Information("正在添加Cookie文件{File}", file); - AddCookies(file); - addCookieCount++; - Log.Information("Cookie文件{File}添加完成,按回车键继续添加", file); - IOHelper.ReadLine(); - } - else - { - Log.Error("不受支持的文件格式{File}", file); - } - if (o.Cookies is not null) - { - Log.Information("共输入了{Count}个Cookie文件", addCookieCount); - HttpHelper.GlobalCookieContainer.SaveToTxt(o.Cookies, HttpHelper.GlobalUserAgent); - Log.Information("保存成功,Cookie文件保存在{Path}", o.Cookies); - } - } - }); - IOHelper.ReadLine(); + if (extension.Equals(".torrent", StringComparison.OrdinalIgnoreCase)) + { + Log.Information("正在发布 {File}", file); + SinglePublish(file, settingFile, cookies, allowSkip); + continue; + } + if (extension.Equals(".txt", StringComparison.OrdinalIgnoreCase)) + { + if (cookies is null) + { + Log.Information("请输入Cookie文件名,不需要包含扩展名,相对目录默认为{DefaultPath}", + IOHelper.BasePath(Constants.DefaultCookiePath)); + IOHelper.HintText(Constants.DefaultCookieFile); + var filename = IOHelper.ReadLine(); + if (File.Exists(filename)) + { + cookies = filename; + Log.Error("你指定的Cookie文件{File}已经存在!继续添加可能会覆盖之前保存的Cookie!", cookies); + IOHelper.ReadLine(); + HttpHelper.GlobalCookieContainer.LoadFromTxt(cookies); + } + else + { + if (!Directory.Exists(IOHelper.BasePath(Constants.DefaultCookiePath))) + { + Directory.CreateDirectory(IOHelper.BasePath(Constants.DefaultCookiePath)); + } + cookies = IOHelper.BasePath(Constants.DefaultCookiePath, + (filename?.Length == 0 ? Constants.DefaultCookieFile : filename) + ".txt"); + if (File.Exists(cookies)) + { + Log.Error("你指定的Cookie文件{File}已经存在!继续添加可能会覆盖之前保存的Cookie!", cookies); + IOHelper.ReadLine(); + HttpHelper.GlobalCookieContainer.LoadFromTxt(cookies); + } + } + Log.Information("请输入你使用的浏览器UserAgent:"); + var ua = IOHelper.ReadLine(); + while (ua is null || !HttpHelper.UaRegex.IsMatch(ua)) + { + Log.Information("你必须输入一个合法的UserAgent以确保你的cookie可以正常使用:"); + ua = IOHelper.ReadLine(); + } + HttpHelper.GlobalUserAgent = ua; + } + if (File.Exists(IOHelper.BasePath(Constants.DefaultCookiePath, + Constants.DefaultCookieFile + ".txt"))) + { + HttpHelper.GlobalCookieContainer.LoadFromTxt(IOHelper.BasePath(Constants.DefaultCookiePath, + Constants.DefaultCookieFile + ".txt")); + } + Log.Information("正在添加Cookie文件{File}", file); + AddCookies(file); + addCookieCount++; + Log.Information("Cookie文件{File}添加完成,按回车键继续添加", file); + IOHelper.ReadLine(); + } + else + { + Log.Error("不受支持的文件格式{File}", file); + } + if (cookies is not null) + { + Log.Information("共输入了{Count}个Cookie文件", addCookieCount); + HttpHelper.GlobalCookieContainer.SaveToTxt(cookies, HttpHelper.GlobalUserAgent); + Log.Information("保存成功,Cookie文件保存在{Path}", cookies); + } + } } + private static void SinglePublish(string file, string settingFile, string? cookies,bool allowSkip) { if (!File.Exists(file)) diff --git a/OKP.Core/Utils/HttpHelper.cs b/OKP.Core/Utils/HttpHelper.cs index f0729b1..c3d2754 100644 --- a/OKP.Core/Utils/HttpHelper.cs +++ b/OKP.Core/Utils/HttpHelper.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http.Json; using System.Text; +using System.Text.Json.Serialization.Metadata; using System.Text.RegularExpressions; namespace OKP.Core.Utils @@ -37,13 +38,13 @@ public static async Task GetAsyncWithRetry(this HttpClient HandleSetCookie(httpClient, setCookie, res); return res; } - public static async Task PostAsJsonAsyncWithRetry(this HttpClient httpClient, string? uri, TValue content, bool setCookie = true, CancellationToken cancellationToken = default) + public static async Task PostAsJsonAsyncWithRetry(this HttpClient httpClient, string? uri, TValue content, JsonTypeInfo jsonTypeInfo, bool setCookie = true, CancellationToken cancellationToken = default) { if (httpClient.BaseAddress is null) { throw new NotImplementedException("httpClient.BaseAddress is null"); } - var res = await policy.ExecuteAsync(() => httpClient.PostAsJsonAsync(uri, content, cancellationToken)); + var res = await policy.ExecuteAsync(() => httpClient.PostAsJsonAsync(uri, content, jsonTypeInfo, cancellationToken)); HandleSetCookie(httpClient, setCookie, res); return res; } diff --git a/OKP.Core/Utils/TagHelper.cs b/OKP.Core/Utils/TagHelper.cs index 6f65302..b729c06 100644 --- a/OKP.Core/Utils/TagHelper.cs +++ b/OKP.Core/Utils/TagHelper.cs @@ -7,7 +7,7 @@ namespace OKP.Core.Utils; public class Tag { - [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonConverter(typeof(JsonStringEnumConverter))] public TorrentContent.ContentTypes? Key { get; set; } public string? Value { get; set; } @@ -80,6 +80,9 @@ public Tag() } } +[JsonSerializable(typeof(Tag))] +internal partial class TagSourceGenerationContext : JsonSerializerContext; + public static class TagHelper { public static Tag LoadTagConfig(string configName) @@ -92,7 +95,7 @@ public static Tag LoadTagConfig(string configName) var content = File.ReadAllText(configPath); try { - var ret = JsonSerializer.Deserialize(content); + var ret = JsonSerializer.Deserialize(content, TagSourceGenerationContext.Default.Tag); return ret ?? new Tag(); } catch (JsonException ex) diff --git a/OKP.Core/Utils/TomlParseHelper.cs b/OKP.Core/Utils/TomlParseHelper.cs new file mode 100644 index 0000000..d914e46 --- /dev/null +++ b/OKP.Core/Utils/TomlParseHelper.cs @@ -0,0 +1,97 @@ +using OKP.Core.Interface; +using static OKP.Core.Interface.TorrentContent; +using Tommy; + +namespace OKP.Core.Utils; + +internal static class TomlParseHelper +{ + internal static TorrentContent DeserializeTorrentContent(string filePath) + { + using var reader = File.OpenText(filePath); + var table = TOML.Parse(reader); + + var torrenC = new TorrentContent() + { + DisplayName = ConvertToString(table["display_name"]), + GroupName = ConvertToString(table["group_name"]), + Poster = ConvertToString(table["poster"]), + About = ConvertToString(table["about"]), + FilenameRegex = ConvertToString(table["filename_regex"]), + ResolutionRegex = ConvertToString(table["resolution_regex"]), + SettingPath = ConvertToString(table["setting_path"]), + CookiePath = ConvertToString(table["cookie_path"]), + }; + + var tags = table["tags"]; + if (tags.HasValue) + { + torrenC.Tags = new List(tags.ChildrenCount); + foreach (var tag in tags) + { + if (Enum.TryParse(tag.ToString(), out ContentTypes tagEnum)) + { + torrenC.Tags.Add(tagEnum); + } + } + } + + var torrentFlags = table["torrent_flags"]; + if (torrentFlags.HasValue) + { + torrenC.TorrentFlags = new List(torrentFlags.ChildrenCount); + foreach (var tag in tags) + { + if (Enum.TryParse(tag.ToString(), out NyaaTorrentFlags tagEnum)) + { + torrenC.TorrentFlags.Add(tagEnum); + } + } + } + + var introTemplates = table["intro_template"]; + if (introTemplates.HasValue) + { + torrenC.IntroTemplate = new List