Skip to content

Commit

Permalink
Merge pull request #256 from C9Glax/cuttingedge-merge-candidate
Browse files Browse the repository at this point in the history
Cuttingedge merge candidate
  • Loading branch information
C9Glax authored Sep 28, 2024
2 parents 68d7ef2 + a3ae3c3 commit 30c4476
Show file tree
Hide file tree
Showing 16 changed files with 181 additions and 81 deletions.
21 changes: 1 addition & 20 deletions .github/workflows/docker-image-cuttingedge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,7 @@ jobs:

runs-on: ubuntu-latest

steps:
- name: Clear cache
uses: actions/github-script@v6
with:
script: |
console.log("About to clear")
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
console.log(cache)
github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
}
console.log("Clear completed")
steps:
- name: Checkout
uses: actions/checkout@v4

Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
ARG DOTNET=8.0

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/runtime:$DOTNET AS base
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime:$DOTNET AS base

Check warning on line 4 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/

Check warning on line 4 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/

Check warning on line 4 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/

Check warning on line 4 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/
WORKDIR /publish
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
Expand All @@ -22,7 +22,7 @@ RUN dotnet restore /src/Tranga.sln
COPY . /src/
RUN dotnet publish -c Release --property:OutputPath=/publish -maxcpucount:1

FROM --platform=$BUILDPLATFORM base AS runtime
FROM --platform=$TARGETPLATFORM base AS runtime

Check warning on line 25 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/

Check warning on line 25 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/

Check warning on line 25 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/

Check warning on line 25 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior

RedundantTargetPlatform: Setting platform to predefined $TARGETPLATFORM in FROM is redundant as this is the default behavior More info: https://docs.docker.com/go/dockerfile/rule/redundant-target-platform/
EXPOSE 6531
ARG UNAME=tranga
ARG UID=1000
Expand Down
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ Tranga can download Chapters and Metadata from "Scanlation" sites such as
- [Bato.to](https://bato.to/v3x) (en)
- [Manga4Life](https://manga4life.com) (en)
- [ManhuaPlus](https://manhuaplus.org/) (en)
- [MangaHere](https://www.mangahere.cc/) (en) (Their covers suck)
- ❓ Open an [issue](https://github.com/C9Glax/tranga/issues)
- [MangaHere](https://www.mangahere.cc/) (en) (Their covers aren't scrapeable.)
- ❓ Open an [issue](https://github.com/C9Glax/tranga/issues/new?assignees=&labels=New+Connector&projects=&template=new_connector.yml&title=%5BNew+Connector%5D%3A+)

and trigger a library-scan with [Komga](https://komga.org/) and [Kavita](https://www.kavitareader.com/).
Notifications can be sent to your devices using [Gotify](https://gotify.net/) and [LunaSea](https://www.lunasea.app/).
Notifications can be sent to your devices using [Gotify](https://gotify.net/), [LunaSea](https://www.lunasea.app/) or [Ntfy](https://ntfy.sh/
).

### What this does and doesn't do

Expand Down Expand Up @@ -92,6 +93,16 @@ That is why I wanted to create my own project, in a language I understand, and t

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Star History

<a href="https://star-history.com/#c9glax/tranga&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=c9glax/tranga&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=c9glax/tranga&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=c9glax/tranga&type=Date" />
</picture>
</a>

<!-- GETTING STARTED -->
## Getting Started

Expand All @@ -107,14 +118,9 @@ access the folder.
### Prerequisites

#### To Build
[.NET-Core 7.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/7.0)
[.NET-Core 8.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
#### To Run
[.NET-Core 7.0 Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) scroll down a bit, should be on the right the second item.

<!-- ROADMAP -->
## Roadmap

- [ ]
[.NET-Core 8.0 Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) scroll down a bit, should be on the right the second item.

See the [open issues](https://github.com/C9Glax/tranga/issues) for a full list of proposed features (and known issues).

Expand Down
22 changes: 12 additions & 10 deletions Tranga/Chapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,24 +84,26 @@ public int CompareTo(object? obj)
/// <returns>true if chapter is present</returns>
internal bool CheckChapterIsDownloaded()
{
if (!Directory.Exists(Path.Join(TrangaSettings.downloadLocation, parentManga.folderName)))
string mangaDirectory = Path.Join(TrangaSettings.downloadLocation, parentManga.folderName);
if (!Directory.Exists(mangaDirectory))
return false;
FileInfo[] archives = new DirectoryInfo(Path.Join(TrangaSettings.downloadLocation, parentManga.folderName)).GetFiles().Where(file => file.Name.Split('.')[^1] == "cbz").ToArray();
FileInfo[] archives = new DirectoryInfo(mangaDirectory).GetFiles("*.cbz");
Regex volChRex = new(@"(?:Vol(?:ume)?\.([0-9]+)\D*)?Ch(?:apter)?\.([0-9]+(?:\.[0-9]+)*)");

Chapter t = this;
string thisPath = GetArchiveFilePath();
string correctPath = GetArchiveFilePath();
FileInfo? archive = archives.FirstOrDefault(archive =>
{
Match m = volChRex.Match(archive.Name);
string archiveVolNum = m.Groups[1].Success ? m.Groups[1].Value : "0";
string archiveChNum = m.Groups[2].Value;
return archiveVolNum == t.volumeNumber && archiveChNum == t.chapterNumber ||
archiveVolNum == "0" && archiveChNum == t.chapterNumber;
/*Uncommenting this section will only allow *Version without Volume number* -> *Version with Volume number* but not the other way
if (m.Groups[1].Success)
return m.Groups[1].Value == t.volumeNumber && m.Groups[2].Value == t.chapterNumber;
else*/
return m.Groups[2].Value == t.chapterNumber;
});
if(archive is not null && thisPath != archive.FullName)
archive.MoveTo(thisPath, true);
return archive is not null;
if(archive is not null && archive.FullName != correctPath)
archive.MoveTo(correctPath, true);
return (archive is not null);
}
/// <summary>
/// Creates full file path of chapter-archive
Expand Down
4 changes: 2 additions & 2 deletions Tranga/GlobalBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ protected void Log(string fStr, params object?[] replace)
Log(string.Format(fStr, replace));
}

protected void SendNotifications(string title, string text)
protected void SendNotifications(string title, string text, bool buffer = false)
{
foreach (NotificationConnector nc in notificationConnectors)
nc.SendNotification(title, text);
nc.SendNotification(title, text, buffer);
}

protected void AddNotificationConnector(NotificationConnector notificationConnector)
Expand Down
2 changes: 1 addition & 1 deletion Tranga/Jobs/DownloadChapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBos
if (success == HttpStatusCode.OK)
{
UpdateLibraries();
SendNotifications("Chapter downloaded", $"{chapter.parentManga.sortName} - {chapter.chapterNumber}");
SendNotifications("Chapter downloaded", $"{chapter.parentManga.sortName} - {chapter.chapterNumber}", true);
}
});
downloadTask.Start();
Expand Down
2 changes: 1 addition & 1 deletion Tranga/LibraryConnectors/Kavita.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private static string GetToken(string baseUrl, string username, string password,
return "";
}

public override void UpdateLibrary()
protected override void UpdateLibraryInternal()
{
Log("Updating libraries.");
foreach (KavitaLibrary lib in GetLibraries())
Expand Down
2 changes: 1 addition & 1 deletion Tranga/LibraryConnectors/Komga.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public override string ToString()
return $"Komga {baseUrl}";
}

public override void UpdateLibrary()
protected override void UpdateLibraryInternal()
{
Log("Updating libraries.");
foreach (KomgaLibrary lib in GetLibraries())
Expand Down
44 changes: 43 additions & 1 deletion Tranga/LibraryConnectors/LibraryConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public enum LibraryType : byte
public string baseUrl { get; }
// ReSharper disable once MemberCanBeProtected.Global
public string auth { get; } //Base64 encoded, if you use your password everywhere, you have problems
private DateTime? _updateLibraryRequested = null;
private readonly Thread? _libraryBufferThread = null;
private const int NoChangeTimeout = 2, BiggestInterval = 20;

protected LibraryConnector(GlobalBase clone, string baseUrl, string auth, LibraryType libraryType) : base(clone)
{
Expand All @@ -28,8 +31,47 @@ protected LibraryConnector(GlobalBase clone, string baseUrl, string auth, Librar
this.baseUrl = baseUrlRex.Match(baseUrl).Value;
this.auth = auth;
this.libraryType = libraryType;

if (TrangaSettings.bufferLibraryUpdates)
{
_libraryBufferThread = new(CheckLibraryBuffer);
_libraryBufferThread.Start();
}
}

private void CheckLibraryBuffer()
{
while (true)
{
if (_updateLibraryRequested is not null && DateTime.Now.Subtract((DateTime)_updateLibraryRequested) > TimeSpan.FromMinutes(NoChangeTimeout)) //If no updates have been requested for NoChangeTimeout minutes, update library
{
UpdateLibraryInternal();
_updateLibraryRequested = null;
}
Thread.Sleep(100);
}
}
public abstract void UpdateLibrary();

public void UpdateLibrary()
{
_updateLibraryRequested ??= DateTime.Now;
if (!TrangaSettings.bufferLibraryUpdates)
{
UpdateLibraryInternal();
return;
}else if (_updateLibraryRequested is not null &&
DateTime.Now.Subtract((DateTime)_updateLibraryRequested) > TimeSpan.FromMinutes(BiggestInterval)) //If the last update has been more than BiggestInterval minutes ago, update library
{
UpdateLibraryInternal();
_updateLibraryRequested = null;
}
else if(_updateLibraryRequested is not null)
{
Log($"Buffering Library Updates (Updates in latest {((DateTime)_updateLibraryRequested).Add(TimeSpan.FromMinutes(BiggestInterval)).Subtract(DateTime.Now)} or {((DateTime)_updateLibraryRequested).Add(TimeSpan.FromMinutes(NoChangeTimeout)).Subtract(DateTime.Now)})");
}
}

protected abstract void UpdateLibraryInternal();
internal abstract bool Test();

protected static class NetClient
Expand Down
2 changes: 1 addition & 1 deletion Tranga/MangaConnectors/MangaKatana.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public MangaKatana(GlobalBase clone) : base(clone, "MangaKatana", ["en"])
public override Manga[] GetManga(string publicationTitle = "")
{
Log($"Searching Publications. Term=\"{publicationTitle}\"");
string sanitizedTitle = string.Join('_', Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
string sanitizedTitle = string.Join("%20", Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
string requestUrl = $"https://mangakatana.com/?search={sanitizedTitle}&search_by=book_name";
RequestResult requestResult =
downloadClient.MakeRequest(requestUrl, RequestType.Default);
Expand Down
2 changes: 1 addition & 1 deletion Tranga/NotificationConnectors/Gotify.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public override string ToString()
return $"Gotify {endpoint}";
}

public override void SendNotification(string title, string notificationText)
protected override void SendNotificationInternal(string title, string notificationText)
{
Log($"Sending notification: {title} - {notificationText}");
MessageData message = new(title, notificationText);
Expand Down
2 changes: 1 addition & 1 deletion Tranga/NotificationConnectors/LunaSea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public override string ToString()
return $"LunaSea {id}";
}

public override void SendNotification(string title, string notificationText)
protected override void SendNotificationInternal(string title, string notificationText)
{
Log($"Sending notification: {title} - {notificationText}");
MessageData message = new(title, notificationText);
Expand Down
60 changes: 59 additions & 1 deletion Tranga/NotificationConnectors/NotificationConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,72 @@
public abstract class NotificationConnector : GlobalBase
{
public readonly NotificationConnectorType notificationConnectorType;
private DateTime? _notificationRequested = null;
private readonly Thread? _notificationBufferThread = null;
private const int NoChangeTimeout = 3, BiggestInterval = 30;
private List<KeyValuePair<string, string>> _notifications = new();

protected NotificationConnector(GlobalBase clone, NotificationConnectorType notificationConnectorType) : base(clone)
{
Log($"Creating notificationConnector {Enum.GetName(notificationConnectorType)}");
this.notificationConnectorType = notificationConnectorType;


if (TrangaSettings.bufferLibraryUpdates)
{
_notificationBufferThread = new(CheckNotificationBuffer);
_notificationBufferThread.Start();
}
}

private void CheckNotificationBuffer()
{
while (true)
{
if (_notificationRequested is not null && DateTime.Now.Subtract((DateTime)_notificationRequested) > TimeSpan.FromMinutes(NoChangeTimeout)) //If no updates have been requested for NoChangeTimeout minutes, update library
{
string[] uniqueTitles = _notifications.DistinctBy(n => n.Key).Select(n => n.Key).ToArray();
Log($"Notification Buffer sending! Notifications: {string.Join(", ", uniqueTitles)}");
foreach (string ut in uniqueTitles)
{
string[] texts = _notifications.Where(n => n.Key == ut).Select(n => n.Value).ToArray();
SendNotificationInternal($"{ut} ({texts.Length})", string.Join('\n', texts));
}
_notificationRequested = null;
_notifications.Clear();
}
Thread.Sleep(100);
}
}

public enum NotificationConnectorType : byte { Gotify = 0, LunaSea = 1, Ntfy = 2 }

public void SendNotification(string title, string notificationText, bool buffer = false)
{
_notificationRequested ??= DateTime.Now;
if (!TrangaSettings.bufferNotifications || !buffer)
{
SendNotificationInternal(title, notificationText);
return;
}
_notifications.Add(new(title, notificationText));
if (_notificationRequested is not null &&
DateTime.Now.Subtract((DateTime)_notificationRequested) > TimeSpan.FromMinutes(BiggestInterval)) //If the last update has been more than BiggestInterval minutes ago, update library
{
string[] uniqueTitles = _notifications.DistinctBy(n => n.Key).Select(n => n.Key).ToArray();
foreach (string ut in uniqueTitles)
{
string[] texts = _notifications.Where(n => n.Key == ut).Select(n => n.Value).ToArray();
SendNotificationInternal(ut, string.Join('\n', texts));
}
_notificationRequested = null;
_notifications.Clear();
}
else if(_notificationRequested is not null)
{
Log($"Buffering Notifications (Updates in latest {((DateTime)_notificationRequested).Add(TimeSpan.FromMinutes(BiggestInterval)).Subtract(DateTime.Now)} or {((DateTime)_notificationRequested).Add(TimeSpan.FromMinutes(NoChangeTimeout)).Subtract(DateTime.Now)})");
}
}

public abstract void SendNotification(string title, string notificationText);
protected abstract void SendNotificationInternal(string title, string notificationText);
}
2 changes: 1 addition & 1 deletion Tranga/NotificationConnectors/Ntfy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public override string ToString()
return $"Ntfy {endpoint} {topic}";
}

public override void SendNotification(string title, string notificationText)
protected override void SendNotificationInternal(string title, string notificationText)
{
Log($"Sending notification: {title} - {notificationText}");
MessageData message = new(title, topic, notificationText);
Expand Down
1 change: 1 addition & 0 deletions Tranga/Tranga.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Tranga(Logger? logger) : base(logger)
this._server = new Server(this);
string[] emojis = { "(•‿•)", "(づ \u25d5\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=", "(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~","૮ \u00b4• ﻌ \u00b4• ა", "(\u02c3\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"};
SendNotifications("Tranga Started", emojis[Random.Shared.Next(0,emojis.Length-1)]);
Log(TrangaSettings.AsJObject().ToString());
}

public MangaConnector? GetConnector(string name)
Expand Down
Loading

0 comments on commit 30c4476

Please sign in to comment.