mirror of
https://github.com/C9Glax/tranga.git
synced 2025-04-12 19:36:08 +02:00
Custom Chapter-Naming scheme
https://github.com/C9Glax/tranga/issues/92
This commit is contained in:
parent
c94c55300c
commit
9350de0ae9
@ -1,5 +1,6 @@
|
||||
using API.MangaDownloadClients;
|
||||
using API.Schema;
|
||||
using API.Schema.Jobs;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@ -199,4 +200,67 @@ public class SettingsController(PgsqlContext context) : Controller
|
||||
TrangaSettings.UpdateAprilFoolsMode(enabled);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Chapter Naming Scheme
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Placeholders:
|
||||
/// %M Manga Name
|
||||
/// %V Volume
|
||||
/// %C Chapter
|
||||
/// %T Title
|
||||
/// %A Author (first in list)
|
||||
/// %I Chapter Internal ID
|
||||
/// %i Manga Internal ID
|
||||
/// %Y Year (Manga)
|
||||
///
|
||||
/// ?_(...) replace _ with a value from above:
|
||||
/// Everything inside the braces will only be added if the value of %_ is not null
|
||||
/// </remarks>
|
||||
/// <response code="200"></response>
|
||||
[HttpGet("ChapterNamingScheme")]
|
||||
[ProducesResponseType<string>(Status200OK, "text/plain")]
|
||||
public IActionResult GetCustomNamingScheme()
|
||||
{
|
||||
return Ok(TrangaSettings.chapterNamingScheme);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Chapter Naming Scheme
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Placeholders:
|
||||
/// %M Manga Name
|
||||
/// %V Volume
|
||||
/// %C Chapter
|
||||
/// %T Title
|
||||
/// %A Author (first in list)
|
||||
/// %I Chapter Internal ID
|
||||
/// %i Manga Internal ID
|
||||
/// %Y Year (Manga)
|
||||
///
|
||||
/// ?_(...) replace _ with a value from above:
|
||||
/// Everything inside the braces will only be added if the value of %_ is not null
|
||||
/// </remarks>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPatch("ChapterNamingScheme")]
|
||||
[ProducesResponseType(Status200OK)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult SetCustomNamingScheme([FromBody]string namingScheme)
|
||||
{
|
||||
try
|
||||
{
|
||||
TrangaSettings.UpdateChapterNamingScheme(namingScheme);
|
||||
MoveFileOrFolderJob[] newJobs =
|
||||
context.Chapters.Where(c => c.Downloaded).Select(c => c.UpdateArchiveFileName()).Where(x => x != null).ToArray()!;
|
||||
context.Jobs.AddRange(newJobs);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return StatusCode(500, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using API.Schema.Jobs;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -86,7 +88,7 @@ public class Chapter : IComparable<Chapter>
|
||||
return UpdateArchiveFileName();
|
||||
}
|
||||
|
||||
private MoveFileOrFolderJob? UpdateArchiveFileName()
|
||||
internal MoveFileOrFolderJob? UpdateArchiveFileName()
|
||||
{
|
||||
string? oldPath = FullArchiveFilePath;
|
||||
if (oldPath is null)
|
||||
@ -106,9 +108,76 @@ public class Chapter : IComparable<Chapter>
|
||||
return File.Exists(path);
|
||||
}
|
||||
|
||||
/// Placeholders:
|
||||
/// %M Manga Name
|
||||
/// %V Volume
|
||||
/// %C Chapter
|
||||
/// %T Title
|
||||
/// %A Author (first in list)
|
||||
/// %I Chapter Internal ID
|
||||
/// %i Manga Internal ID
|
||||
/// %Y Year (Manga)
|
||||
private static readonly Regex NullableRex = new(@"\?([a-zA-Z])\(([^\)]*)\)|(.+?)");
|
||||
private static readonly Regex ReplaceRexx = new(@"%([a-zA-Z])|(.+?)");
|
||||
private string GetArchiveFilePath(string? parentMangaName = null)
|
||||
{
|
||||
return $"{parentMangaName ?? ParentManga?.Name ?? ""} - Vol.{VolumeNumber ?? 0} Ch.{ChapterNumber}{(Title is null ? "" : $" - {Title}")}.cbz";
|
||||
string archiveNamingScheme = TrangaSettings.chapterNamingScheme;
|
||||
StringBuilder stringBuilder = new();
|
||||
foreach (Match nullable in NullableRex.Matches(archiveNamingScheme))
|
||||
{
|
||||
if (nullable.Groups[3].Success)
|
||||
{
|
||||
stringBuilder.Append(nullable.Groups[3].Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
char placeholder = nullable.Groups[1].Value[0];
|
||||
bool isNull = placeholder switch
|
||||
{
|
||||
'M' => ParentManga?.Name is null && parentMangaName is null,
|
||||
'V' => VolumeNumber is null,
|
||||
'C' => ChapterNumber is null,
|
||||
'T' => Title is null,
|
||||
'A' => ParentManga?.Authors?.FirstOrDefault()?.AuthorName is null,
|
||||
'I' => ChapterId is null,
|
||||
'i' => ParentMangaId is null,
|
||||
'Y' => ParentManga?.Year is null,
|
||||
_ => true
|
||||
};
|
||||
if(!isNull)
|
||||
stringBuilder.Append(nullable.Groups[2].Value);
|
||||
}
|
||||
|
||||
string checkedString = stringBuilder.ToString();
|
||||
stringBuilder = new();
|
||||
|
||||
foreach (Match replace in ReplaceRexx.Matches(checkedString))
|
||||
{
|
||||
if (replace.Groups[2].Success)
|
||||
{
|
||||
stringBuilder.Append(replace.Groups[2].Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
char placeholder = replace.Groups[1].Value[0];
|
||||
string? value = placeholder switch
|
||||
{
|
||||
'M' => ParentManga?.Name ?? parentMangaName,
|
||||
'V' => VolumeNumber?.ToString(),
|
||||
'C' => ChapterNumber,
|
||||
'T' => Title,
|
||||
'A' => ParentManga?.Authors?.FirstOrDefault()?.AuthorName,
|
||||
'I' => ChapterId,
|
||||
'i' => ParentMangaId,
|
||||
'Y' => ParentManga?.Year.ToString(),
|
||||
_ => null
|
||||
};
|
||||
stringBuilder.Append(value);
|
||||
}
|
||||
|
||||
stringBuilder.Append(".cbz");
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private static int CompareChapterNumbers(string ch1, string ch2)
|
||||
|
@ -3,7 +3,6 @@ using API.MangaDownloadClients;
|
||||
using API.Schema;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static System.IO.UnixFileMode;
|
||||
|
||||
namespace API;
|
||||
|
||||
@ -16,6 +15,21 @@ public static class TrangaSettings
|
||||
public static string userAgent { get; private set; } = DefaultUserAgent;
|
||||
public static int compression{ get; private set; } = 40;
|
||||
public static bool bwImages { get; private set; } = false;
|
||||
/// <summary>
|
||||
/// Placeholders:
|
||||
/// %M Manga Name
|
||||
/// %V Volume
|
||||
/// %C Chapter
|
||||
/// %T Title
|
||||
/// %A Author (first in list)
|
||||
/// %I Chapter Internal ID
|
||||
/// %i Manga Internal ID
|
||||
/// %Y Year (Manga)
|
||||
///
|
||||
/// ?_(...) replace _ with a value from above:
|
||||
/// Everything inside the braces will only be added if the value of %_ is not null
|
||||
/// </summary>
|
||||
public static string chapterNamingScheme { get; private set; } = "%M - ?V(Vol.%V )Ch.%C?T( - %T)";
|
||||
[JsonIgnore]
|
||||
public static string settingsFilePath => Path.Join(workingDirectory, "settings.json");
|
||||
[JsonIgnore]
|
||||
@ -70,42 +84,6 @@ public static class TrangaSettings
|
||||
ExportSettings();
|
||||
}
|
||||
|
||||
public static void UpdateDownloadLocation(string newPath, bool moveFiles = true)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
Directory.CreateDirectory(newPath, GroupRead | GroupWrite | None | OtherRead | OtherWrite | UserRead | UserWrite);
|
||||
else
|
||||
Directory.CreateDirectory(newPath);
|
||||
|
||||
if (moveFiles)
|
||||
MoveContentsOfDirectoryTo(TrangaSettings.downloadLocation, newPath);
|
||||
|
||||
TrangaSettings.downloadLocation = newPath;
|
||||
ExportSettings();
|
||||
}
|
||||
|
||||
private static void MoveContentsOfDirectoryTo(string oldDir, string newDir)
|
||||
{
|
||||
string[] directoryPaths = Directory.GetDirectories(oldDir);
|
||||
string[] filePaths = Directory.GetFiles(oldDir);
|
||||
foreach (string file in filePaths)
|
||||
{
|
||||
string newPath = Path.Join(newDir, Path.GetFileName(file));
|
||||
File.Move(file, newPath, true);
|
||||
}
|
||||
foreach(string directory in directoryPaths)
|
||||
{
|
||||
string? dirName = Path.GetDirectoryName(directory);
|
||||
if(dirName is null)
|
||||
continue;
|
||||
string newPath = Path.Join(newDir, dirName);
|
||||
if(Directory.Exists(newPath))
|
||||
MoveContentsOfDirectoryTo(directory, newPath);
|
||||
else
|
||||
Directory.Move(directory, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateUserAgent(string? customUserAgent)
|
||||
{
|
||||
userAgent = customUserAgent ?? DefaultUserAgent;
|
||||
@ -118,6 +96,12 @@ public static class TrangaSettings
|
||||
ExportSettings();
|
||||
}
|
||||
|
||||
public static void UpdateChapterNamingScheme(string namingScheme)
|
||||
{
|
||||
chapterNamingScheme = namingScheme;
|
||||
ExportSettings();
|
||||
}
|
||||
|
||||
public static void ResetRequestLimits()
|
||||
{
|
||||
requestLimits = DefaultRequestLimits;
|
||||
@ -154,7 +138,7 @@ public static class TrangaSettings
|
||||
|
||||
public static JObject AsJObject()
|
||||
{
|
||||
JObject jobj = new JObject();
|
||||
JObject jobj = new ();
|
||||
jobj.Add("downloadLocation", JToken.FromObject(downloadLocation));
|
||||
jobj.Add("workingDirectory", JToken.FromObject(workingDirectory));
|
||||
jobj.Add("userAgent", JToken.FromObject(userAgent));
|
||||
@ -163,6 +147,7 @@ public static class TrangaSettings
|
||||
jobj.Add("compression", JToken.FromObject(compression));
|
||||
jobj.Add("bwImages", JToken.FromObject(bwImages));
|
||||
jobj.Add("startNewJobTimeoutMs", JToken.FromObject(startNewJobTimeoutMs));
|
||||
jobj.Add("chapterNamingScheme", JToken.FromObject(chapterNamingScheme));
|
||||
return jobj;
|
||||
}
|
||||
|
||||
@ -187,5 +172,7 @@ public static class TrangaSettings
|
||||
bwImages = bwi.Value<bool>()!;
|
||||
if (jobj.TryGetValue("startNewJobTimeoutMs", out JToken? snjt))
|
||||
startNewJobTimeoutMs = snjt.Value<int>()!;
|
||||
if (jobj.TryGetValue("chapterNamingScheme", out JToken? cns))
|
||||
chapterNamingScheme = cns.Value<string>()!;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user