[optimize] code optimize
This commit is contained in:
61
.idea/.idea.Abyss/.idea/workspace.xml
generated
61
.idea/.idea.Abyss/.idea/workspace.xml
generated
@@ -10,24 +10,21 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="bf317275-3039-49bb-a475-725a800a0cce" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Components/Controllers/Task/TaskController.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Components/Tools/TemporaryDB.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Chip.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Comment.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Task.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/TaskCreation.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Video.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Toolkits/image-creator.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Toolkits/image-sum.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Toolkits/update-tags.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Toolkits/update-video.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss.sln.DotSettings.user" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss.sln.DotSettings.user" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Controllers/Media/ImageController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Controllers/Media/ImageController.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Controllers/Media/VideoController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Controllers/Media/VideoController.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Services/ConfigureService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Services/ConfigureService.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Services/ResourceService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Services/ResourceService.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Services/UserService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Services/UserService.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Static/Helpers.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Static/Helpers.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Program.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Tools/NaturalStringComparer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Tools/NaturalStringComparer.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Model/Bookmark.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Model/Bookmark.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Model/Comic.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Model/Comic.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Properties/launchSettings.json" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Properties/launchSettings.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/appsettings.Development.json" beforeDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -43,6 +40,7 @@
|
||||
<component name="HighlightingSettingsPerFile">
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/011a191356a243438f987de3ec3d6c6230800/04/8419ff35/ServiceProvider.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/457530be4752476295767457c3639889d1a000/4c/4b962087/Monitor.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/457530be4752476295767457c3639889d1a000/d0/3b166e9e/String.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/5df2accb46d040ccbbbe8331bf4d24b61daa00/df/93debd37/ControllerBase.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/7598e47d5cdf4107ba88f8220720fdc89000/a6/79d67871/xxHash128.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/f09ccaeb94c34c2299acd3efee0facee1a400/81/137b58b4/Key.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
@@ -54,9 +52,10 @@
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Services/UserService.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Static/Helpers.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Tools/TemporaryDB.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Bookmark.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/ChallengeResponse.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Chip.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Comic.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Comment.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/ResourceAttribute.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Task.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
@@ -65,6 +64,7 @@
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/UserCreating.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Video.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/AbyssCli/Program.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file:///storage/Images/31/summary.json" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file:///usr/lib/dotnet/sdk/9.0.109/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.targets" root0="FORCE_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
|
||||
@@ -93,17 +93,17 @@
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"XThreadsFramesViewSplitterKey": "0.30266345",
|
||||
"git-widget-placeholder": "dev-task",
|
||||
"last_opened_file_path": "/home/acite/embd/WebProjects/Abyss/.gitignore",
|
||||
"last_opened_file_path": "/storage/Images/31/summary.json",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RunManager" selected=".NET Launch Settings Profile.Abyss: https">
|
||||
<component name="RunManager" selected="Publish to folder.Publish Abyss to folder">
|
||||
<configuration name="Publish Abyss to folder x86" type="DotNetFolderPublish" factoryName="Publish to folder">
|
||||
<riderPublish configuration="Release" platform="Any CPU" produce_single_file="true" ready_to_run="true" self_contained="true" target_folder="/opt/security/https/server" target_framework="net9.0" uuid_high="3690631506471504162" uuid_low="-4858628519588143325">
|
||||
<runtimes>
|
||||
@@ -198,7 +198,19 @@
|
||||
<workItem from="1756145197559" duration="780000" />
|
||||
<workItem from="1756205686118" duration="5398000" />
|
||||
<workItem from="1756277940361" duration="1097000" />
|
||||
<workItem from="1756293105406" duration="17059000" />
|
||||
<workItem from="1756293105406" duration="18336000" />
|
||||
<workItem from="1756364194123" duration="748000" />
|
||||
<workItem from="1756553959939" duration="2071000" />
|
||||
<workItem from="1756611257955" duration="11070000" />
|
||||
<workItem from="1756693065091" duration="645000" />
|
||||
<workItem from="1756879449291" duration="630000" />
|
||||
<workItem from="1756905732385" duration="955000" />
|
||||
<workItem from="1756953389550" duration="29000" />
|
||||
<workItem from="1756995048032" duration="3919000" />
|
||||
<workItem from="1757064153985" duration="1107000" />
|
||||
<workItem from="1757076719875" duration="601000" />
|
||||
<workItem from="1757219779961" duration="112000" />
|
||||
<workItem from="1757386288260" duration="3634000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
@@ -218,7 +230,7 @@
|
||||
<entry key="branch">
|
||||
<value>
|
||||
<list>
|
||||
<option value="main" />
|
||||
<option value="dev-task" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
@@ -248,19 +260,6 @@
|
||||
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
|
||||
<option name="timeStamp" value="3" />
|
||||
</breakpoint>
|
||||
<line-breakpoint enabled="true" type="DotNet Breakpoints">
|
||||
<url>file://$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs</url>
|
||||
<line>60</line>
|
||||
<properties documentPath="$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs" containingFunctionPresentation="Method 'CreateVideoTask'">
|
||||
<startOffsets>
|
||||
<option value="2099" />
|
||||
</startOffsets>
|
||||
<endOffsets>
|
||||
<option value="2163" />
|
||||
</endOffsets>
|
||||
</properties>
|
||||
<option name="timeStamp" value="13" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKey_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ff09ccaeb94c34c2299acd3efee0facee1a400_003F81_003F137b58b4_003FKey_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMonitor_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F457530be4752476295767457c3639889d1a000_003F4c_003F4b962087_003FMonitor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AServiceProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F011a191356a243438f987de3ec3d6c6230800_003F04_003F8419ff35_003FServiceProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F457530be4752476295767457c3639889d1a000_003Fd0_003F3b166e9e_003FString_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AxxHash128_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7598e47d5cdf4107ba88f8220720fdc89000_003Fa6_003F79d67871_003FxxHash128_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
@@ -1,6 +1,9 @@
|
||||
using Abyss.Components.Services;
|
||||
using Abyss.Components.Static;
|
||||
using Abyss.Components.Tools;
|
||||
using Abyss.Model;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Abyss.Components.Controllers.Media;
|
||||
@@ -28,7 +31,7 @@ public class ImageController(ILogger<ImageController> logger, ResourceService rs
|
||||
if(r == null)
|
||||
return StatusCode(401, new { message = "Unauthorized" });
|
||||
|
||||
return Ok(r);
|
||||
return Ok(r.NaturalSort(x => x));
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
@@ -42,6 +45,27 @@ public class ImageController(ILogger<ImageController> logger, ResourceService rs
|
||||
|
||||
return Ok(await System.IO.File.ReadAllTextAsync(d));
|
||||
}
|
||||
|
||||
[HttpPost("{id}/bookmark")]
|
||||
public async Task<IActionResult> Bookmark(string id, string token, [FromBody] Bookmark bookmark)
|
||||
{
|
||||
var d = Helpers.SafePathCombine(ImageFolder, [id, "summary.json"]);
|
||||
if (d == null) return StatusCode(403, new { message = "403 Denied" });
|
||||
|
||||
var r = await rs.Update(d, token, Ip);
|
||||
if (!r) return StatusCode(403, new { message = "403 Denied" });
|
||||
|
||||
Comic c = JsonConvert.DeserializeObject<Comic>(await System.IO.File.ReadAllTextAsync(d))!;
|
||||
|
||||
var bookmarkPage = Helpers.SafePathCombine(ImageFolder, [id, bookmark.Page]);
|
||||
if(!System.IO.File.Exists(bookmarkPage))
|
||||
return BadRequest();
|
||||
|
||||
c.Bookmarks.Add(bookmark);
|
||||
var o = JsonConvert.SerializeObject(c);
|
||||
await System.IO.File.WriteAllTextAsync(d, o);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("{id}/{file}")]
|
||||
public async Task<IActionResult> Get(string id, string file, string token)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Diagnostics;
|
||||
using Abyss.Components.Services;
|
||||
using Abyss.Components.Static;
|
||||
using Abyss.Components.Tools;
|
||||
using Abyss.Model;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Abyss.Components.Controllers.Media;
|
||||
|
||||
@@ -38,10 +41,24 @@ public class VideoController(ILogger<VideoController> logger, ResourceService rs
|
||||
var d = Helpers.SafePathCombine(VideoFolder, klass);
|
||||
if (d == null) return StatusCode(403, new { message = "403 Denied" });
|
||||
var r = await rs.Query(d, token, Ip);
|
||||
|
||||
if (r == null) return StatusCode(401, new { message = "Unauthorized" });
|
||||
|
||||
var rv = r.Select(x =>
|
||||
{
|
||||
return Helpers.SafePathCombine(VideoFolder, [klass, x, "summary.json"]);
|
||||
}).ToArray();
|
||||
|
||||
for (int i = 0; i < rv.Length; i++)
|
||||
{
|
||||
if(rv[i] == null) continue;
|
||||
rv[i] = await System.IO.File.ReadAllTextAsync(rv[i] ?? "");
|
||||
}
|
||||
|
||||
var sv = rv.Where(x => x!=null).Select(x => x ?? "")
|
||||
.Select(x => JsonConvert.DeserializeObject<Video>(x)).ToArray();
|
||||
|
||||
|
||||
return Ok(r);
|
||||
return Ok(sv.Zip(r, (x, y) => (x, y)).NaturalSort(x => x.x.name).Select(x => x.y).ToArray());
|
||||
}
|
||||
|
||||
[HttpGet("{klass}/{id}")]
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace Abyss.Components.Services;
|
||||
public class ConfigureService
|
||||
{
|
||||
public string MediaRoot { get; set; } = Environment.GetEnvironmentVariable("MEDIA_ROOT") ?? "/opt";
|
||||
public string DebugMode { get; set; } = Environment.GetEnvironmentVariable("DEBUG_MODE") ?? "Production";
|
||||
public string Version { get; } = "Alpha v0.1";
|
||||
public string UserDatabase { get; set; } = "user.db";
|
||||
public string RaDatabase { get; set; } = "ra.db";
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ResourceService
|
||||
private readonly SQLiteAsyncConnection _database;
|
||||
|
||||
private static readonly Regex PermissionRegex =
|
||||
new Regex(@"^([r-][w-]),([r-][w-]),([r-][w-])$", RegexOptions.Compiled);
|
||||
new(@"^([r-][w-]),([r-][w-]),([r-][w-])$", RegexOptions.Compiled);
|
||||
|
||||
public ResourceService(ILogger<ResourceService> logger, ConfigureService config, IMemoryCache cache,
|
||||
UserService user)
|
||||
@@ -47,7 +47,7 @@ public class ResourceService
|
||||
}
|
||||
|
||||
// Create UID only for resources, without considering advanced hash security such as adding salt
|
||||
private string Uid(string path)
|
||||
private static string Uid(string path)
|
||||
{
|
||||
var b = Encoding.UTF8.GetBytes(path);
|
||||
var r = XxHash128.Hash(b, 0x11451419);
|
||||
@@ -169,8 +169,16 @@ public class ResourceService
|
||||
return await Valid(path, token, OperationType.Read, ip);
|
||||
}
|
||||
|
||||
public async Task<bool> Update(string path, string token, string ip)
|
||||
{
|
||||
return await Valid(path, token, OperationType.Write, ip);
|
||||
}
|
||||
|
||||
public async Task<bool> Initialize(string path, string token, string username, string ip)
|
||||
{
|
||||
// TODO: Use a more elegant Debug mode
|
||||
if (_config.DebugMode == "Debug")
|
||||
goto debug;
|
||||
// 1. Authorization: Verify the operation is performed by 'root'
|
||||
var requester = _user.Validate(token, ip);
|
||||
if (requester != "root")
|
||||
@@ -178,7 +186,7 @@ public class ResourceService
|
||||
_logger.LogWarning($"Permission denied: Non-root user '{requester ?? "unknown"}' attempted to initialize resources.");
|
||||
return false;
|
||||
}
|
||||
|
||||
debug:
|
||||
// 2. Validation: Ensure the target path and owner are valid
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
|
||||
@@ -28,7 +28,9 @@ public class UserService
|
||||
_database.CreateTableAsync<User>().Wait();
|
||||
var rootUser = _database.Table<User>().Where(x => x.Name == "root").FirstOrDefaultAsync().Result;
|
||||
|
||||
_cache.Set("acite", $"acite@127.0.0.1", DateTimeOffset.Now.AddDays(1));
|
||||
if (_config.DebugMode == "Debug")
|
||||
_cache.Set("root", $"root@127.0.0.1", DateTimeOffset.Now.AddHours(1));
|
||||
// Test token, can only be used locally. Will be destroyed in one hour.
|
||||
|
||||
if (rootUser == null)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
namespace Abyss.Components.Tools;
|
||||
|
||||
public class TemporaryDB
|
||||
public static class NaturalSortExtensions
|
||||
{
|
||||
|
||||
public static IOrderedEnumerable<T> NaturalSort<T>(this IEnumerable<T> source, Func<T, string> keySelector)
|
||||
{
|
||||
return source.OrderBy(keySelector, new NaturalStringComparer());
|
||||
}
|
||||
}
|
||||
|
||||
public class NaturalStringComparer : IComparer<string>
|
||||
{
|
||||
public int Compare(string? a, string? b)
|
||||
{
|
||||
if (a == null && b == null) return 0;
|
||||
if (a == null) return -1;
|
||||
if (b == null) return 1;
|
||||
|
||||
int aIndex = 0;
|
||||
int bIndex = 0;
|
||||
|
||||
while (aIndex < a.Length && bIndex < b.Length)
|
||||
{
|
||||
if (char.IsDigit(a[aIndex]) && char.IsDigit(b[bIndex]))
|
||||
{
|
||||
long aNum = 0;
|
||||
long bNum = 0;
|
||||
|
||||
while (aIndex < a.Length && char.IsDigit(a[aIndex]))
|
||||
{
|
||||
aNum = aNum * 10 + (a[aIndex] - '0');
|
||||
aIndex++;
|
||||
}
|
||||
|
||||
while (bIndex < b.Length && char.IsDigit(b[bIndex]))
|
||||
{
|
||||
bNum = bNum * 10 + (b[bIndex] - '0');
|
||||
bIndex++;
|
||||
}
|
||||
|
||||
if (aNum != bNum)
|
||||
{
|
||||
return aNum.CompareTo(bNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int charCompare = a[aIndex].CompareTo(b[bIndex]);
|
||||
if (charCompare != 0)
|
||||
{
|
||||
return charCompare;
|
||||
}
|
||||
aIndex++;
|
||||
bIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return a.Length.CompareTo(b.Length);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Abyss.Model;
|
||||
|
||||
public class Bookmark
|
||||
{
|
||||
|
||||
[JsonProperty("page")]
|
||||
public string Page { get; set; } = "";
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; } = "";
|
||||
}
|
||||
@@ -1,6 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Abyss.Model;
|
||||
|
||||
public class Comic
|
||||
{
|
||||
|
||||
[JsonProperty("comic_name")]
|
||||
public string ComicName { get; set; } = "";
|
||||
[JsonProperty("page_count")]
|
||||
public int PageCount { get; set; }
|
||||
[JsonProperty("bookmarks")]
|
||||
public List<Bookmark> Bookmarks { get; set; } = new();
|
||||
[JsonProperty("author")]
|
||||
public string Author { get; set; } = "";
|
||||
[JsonProperty("list")]
|
||||
public List<string> List { get; set; } = new();
|
||||
}
|
||||
@@ -18,7 +18,8 @@
|
||||
"applicationUrl": "https://localhost:7013;http://localhost:5198",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"MEDIA_ROOT" : "/storage"
|
||||
"MEDIA_ROOT" : "/storage",
|
||||
"DEBUG_MODE" : "Debug"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user