Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
7071657
Merge script
Rojikku Jul 4, 2026
0aa0310
Allow partial merges
Rojikku Jul 4, 2026
5fb0191
Stop evil pager rampage
Rojikku Jul 4, 2026
1be4cec
Lib, Compiler, and Core
Rojikku Jul 4, 2026
221899f
Seems okay
Rojikku Jul 4, 2026
8362ff0
Gradle
Rojikku Jul 6, 2026
0a2bfaa
CONTRIB - Consider changing references of KEI to NS
Rojikku Jul 6, 2026
237c8d3
Add missing ns.plugins.extension catalog entry
Rojikku Jul 7, 2026
0def656
Fix modern extension plugin lookup and register extension-legacy
Rojikku Jul 7, 2026
1349695
Restore keiyoushi.gradle.extensions.baseVersionCode; fix keep-rules c…
Rojikku Jul 7, 2026
a2ade1f
Default keiyoushi.libVersion to 1.4 for existing extensions/themes
Rojikku Jul 7, 2026
98c7b1a
Fix theme-change detection for legacy Groovy extensions
Rojikku Jul 7, 2026
109a4c2
Bridge legacy extensions into the new tachiyomix.* manifest metadata
Rojikku Jul 7, 2026
709fe5f
Adopt the new tachiyomix index/store format for create-repo.py and me…
Rojikku Jul 7, 2026
38acf7b
Phase F: real dual libVersion plumbing (1.4 vs 1.6 extensions-lib)
Rojikku Jul 7, 2026
cd3a9ce
Stamp all multisrc themes with explicit libVersion = "1.4"
Rojikku Jul 7, 2026
8c25945
Stamp all legacy extensions with explicit libVersion = '1.4'
Rojikku Jul 7, 2026
4650049
Make 1.6 the default libVersion; require and wire it in PluginExtensi…
Rojikku Jul 7, 2026
a65dc5a
chapterutils: accept existingChapters directly instead of RefreshContext
Rojikku Jul 7, 2026
d702822
Migrate NovelFire to getMangaUpdate; bump to libVersion 1.6
Rojikku Jul 7, 2026
6b7cc44
Migrate LightNovelWorld to getMangaUpdate; bump to libVersion 1.6
Rojikku Jul 7, 2026
2fd593d
Migrate ReadNovelFull theme (and NovelLive) to getMangaUpdate; bump l…
Rojikku Jul 7, 2026
f6b5182
Phase E: RateLimited-aware self-throttle convenience for OkHttpClient…
Rojikku Jul 7, 2026
6f8921b
NovelFire: implement RateLimited as the real first example
Rojikku Jul 7, 2026
5f2f2ff
Update sync tag
Rojikku Jul 7, 2026
2ae462a
Regenerate index_pb2 stubs to include the fork's isNovel field
Rojikku Jul 12, 2026
ff4d696
Update extensions-lib
Rojikku Jul 12, 2026
421f1d5
scripts: fix sync-kei.sh conflict/failure classification and undo ins…
Rojikku Jul 12, 2026
1262dba
scripts: add --status mode, .kei-sync-ignore, and a persistent sync log
Rojikku Jul 12, 2026
9451142
scripts: polish sync-kei.sh (help, arg validation, stderr capture, de…
Rojikku Jul 12, 2026
4a032a3
scripts: add kei-sync-vscode, a local decision-tracking VSCode helper
Rojikku Jul 12, 2026
42ad42c
scripts: detect renames/deletions and orphaned local-only files
Rojikku Jul 12, 2026
da49652
scripts: fix false fork-customizations diffs for already-deleted renames
Rojikku Jul 12, 2026
591ae99
scripts: pin syncs to a local branch, fix untracked-file misclassific…
Rojikku Jul 12, 2026
0bce5a6
build-logic: restore fork customizations lost in kei's plugin refactor
Rojikku Jul 12, 2026
b9491d2
publish pipeline: restore NovelSourcery branding and isNovel emission
Rojikku Jul 12, 2026
e20265e
sync kei: CI workflows, docs, KSP compiler, misc build config
Rojikku Jul 12, 2026
cc8986f
publish pipeline: switch asset URLs to jsdelivr, fix purge target
Rojikku Jul 13, 2026
d9cc794
sync-kei.sh: rewrite table + identical-block collapse to stop repeat …
Rojikku Jul 13, 2026
9e2d206
chore: sync kei to 7d508b834809f21b6c5f4569e5a97f1dab456a47
Rojikku Jul 13, 2026
b00f7f3
CONTRIBUTING.md: fix stale kei Discord link and inconsistent org casing
Rojikku Jul 13, 2026
7883a01
kei-sync-rewrite: case-insensitive matching, scope org-name casing pe…
Rojikku Jul 13, 2026
7ea043a
chore: sync kei to 38fe0f76733322b53e7c1665f3e9abab140c81f6
Rojikku Jul 13, 2026
f3739e7
Kei Merge
Rojikku Jul 13, 2026
cd4da5c
lib-multisrc: fix stale keiyoushi.gradle.extensions import (PR 146 CI…
Rojikku Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/01_report_issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ body:
description: |
You can find your Tsundoku/Tsundoku fork version number in **More → About**.
placeholder: |
Example: "Tsundoku 0.1.0"
Example: "Tsundoku 0.2.0"
validations:
required: true

Expand Down Expand Up @@ -95,7 +95,7 @@ body:
required: true
- label: I have written a short but informative title.
required: true
- label: I have updated the app to version **[0.1.0](https://github.com/tsundoku-otaku/tsundoku/releases/latest)**.
- label: I have updated the app to version **[0.2.0](https://github.com/tsundoku-otaku/tsundoku/releases/latest)**.
required: true
- label: I have updated the extension to the latest version (as listed on the [extensions listing](https://novelsourcery.github.io/extensions/) page).
required: true
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/05_request_feature.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ body:
required: true
- label: If this is an issue with the app itself, I should be opening an issue in the [app repository](https://github.com/tsundoku-otaku/tsundoku/issues/).
required: true
- label: I have updated the app to version **[0.1.1](https://github.com/tsundoku-otaku/tsundoku/releases/latest)**.
- label: I have updated the app to version **[0.2.0](https://github.com/tsundoku-otaku/tsundoku/releases/latest)**.
required: true
- label: I will correctly fill out all of the requested information in this form.
required: true
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/06_request_meta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ body:
required: true
- label: If this is an issue with the app itself, I should be opening an issue in the [app repository](https://github.com/tsundoku-otaku/tsundoku/issues/).
required: true
- label: I have updated the app to version **[0.1.1](https://github.com/tsundoku-otaku/tsundoku/releases/latest)**.
- label: I have updated the app to version **[0.2.0](https://github.com/tsundoku-otaku/tsundoku/releases/latest)**.
required: true
- label: I have updated the extension to the latest version (as listed on the [extensions listing](https://novelsourcery.github.io/extensions/) page).
required: true
Expand Down
2 changes: 0 additions & 2 deletions .github/always_build.json

This file was deleted.

6 changes: 3 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Checklist:

- [ ] Updated `extVersionCode` value in `build.gradle` for individual extensions
- [ ] Updated `overrideVersionCode` or `baseVersionCode` as needed for all multisrc extensions
- [ ] Updated `versionCode` value in `build.gradle.kts`
- [ ] Updated `baseVersionCode` in `build.gradle.kts` (if updated multisrc theme code)
- [ ] Referenced all related issues in the PR body (e.g. "Closes #xyz")
- [ ] Added the `isNsfw = true` flag in `build.gradle` when appropriate
- [ ] Set the `contentWarning` configuration in `build.gradle.kts` appropriately
- [ ] Have not changed source names
- [ ] Have explicitly kept the `id` if a source's name or language were changed
- [ ] Have tested the modifications by compiling and running the extension through Android Studio
Expand Down
15 changes: 0 additions & 15 deletions .github/scripts/commit-repo.sh

This file was deleted.

85 changes: 0 additions & 85 deletions .github/scripts/create-repo.py

This file was deleted.

17 changes: 7 additions & 10 deletions .github/scripts/generate-build-matrices.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import subprocess
import sys
from pathlib import Path
from typing import NoReturn

EXTENSION_REGEX = re.compile(r"^src/(?P<lang>\w+)/(?P<extension>\w+)")
MULTISRC_LIB_REGEX = re.compile(r"^lib-multisrc/(?P<multisrc>\w+)")
LIB_REGEX = re.compile(r"^lib/(?P<lib>\w+)")
MODULE_REGEX = re.compile(r"^:src:(?P<lang>\w+):(?P<extension>\w+)$")
CORE_FILES_REGEX = re.compile(
r"^(common/|core/|gradle/|build\.gradle\.kts|common\.gradle|gradle\.properties|settings\.gradle\.kts|.github/scripts)"
r"^(common/|compiler/|core/|gradle/|build\.gradle\.kts|gradle\.properties|settings\.gradle\.kts|.github/scripts)"
)

def run_command(command: str) -> str:
Expand Down Expand Up @@ -98,7 +97,10 @@ def resolve_ext(multisrcs: set[str], libs: set[str]) -> set[tuple[str, str]]:

patterns = []
if multisrc_pattern:
# Most extensions still use the legacy Groovy `themePkg` property; only a
# handful have migrated to the modern DSL's `theme` property so far.
patterns.append(rf"themePkg\s*=\s*['\"]({multisrc_pattern})['\"]")
patterns.append(rf"theme\s*=\s*['\"]({multisrc_pattern})['\"]")
if lib_pattern:
patterns.append(rf"project\([\"']:(?:lib):({lib_pattern})[\"']\)")

Expand All @@ -108,7 +110,9 @@ def resolve_ext(multisrcs: set[str], libs: set[str]) -> set[tuple[str, str]]:

for lang in Path("src").iterdir():
for extension in lang.iterdir():
build_file = extension / "build.gradle"
build_file = extension / "build.gradle.kts"
if not build_file.is_file():
build_file = extension / "build.gradle"
if not build_file.is_file():
continue

Expand Down Expand Up @@ -179,13 +183,6 @@ def get_module_list(ref: str) -> tuple[list[str], list[str]]:
modules.update([f":src:{lang}:{extension}" for lang, extension in extensions])
deleted.update([f"{lang}.{extension}" for lang, extension in extensions])

if os.getenv("IS_PR_CHECK") != "true":
with Path(".github/always_build.json").open() as always_build_file:
always_build = json.load(always_build_file)
for extension in always_build:
modules.add(":src:" + extension.replace(".", ":"))
deleted.add(extension)

return list(modules), list(deleted)

def get_all_modules() -> tuple[list[str], list[str]]:
Expand Down
65 changes: 65 additions & 0 deletions .github/scripts/index.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
syntax = "proto3";

// Upstream source: https://github.com/mihonapp/tachiyomix/blob/e4d546c/index/index.proto
//
// divergence: Resources.jarUrl (field 501), Extension.isNovel (field 8000, reserved 8000+ block
// for fork fields so they never collide with new upstream fields)
//
// Regenerate the Python bindings after editing:
// protoc --python_out=. --pyi_out=. index.proto

message Index {
string name = 1;
string badgeLabel = 2;
string signingKey = 3;
Contact contact = 4;
oneof extensions {
ExtensionList extensionList = 101;
string extensionListUrl = 102;
}
}

message Contact {
string website = 1;
optional string discord = 2;
}

message ExtensionList {
repeated Extension extensions = 1;
}

message Extension {
string name = 1;
string packageName = 2;
Resources resources = 3;
string extensionLib = 4;
int64 versionCode = 5;
string versionName = 6;
ContentWarning contentWarning = 7;
repeated Source sources = 8;

// Fork field, reserved 8000+ block so it never collides with new upstream fields.
bool isNovel = 8000;
}

message Resources {
string apkUrl = 1;
string iconUrl = 2;
string jarUrl = 501;
}

message Source {
int64 id = 1;
string name = 2;
string language = 3;
string homeUrl = 4;
repeated string mirrorUrls = 5;
optional string message = 7;
}

enum ContentWarning {
CONTENT_WARNING_UNSPECIFIED = 0;
CONTENT_WARNING_SAFE = 1;
CONTENT_WARNING_MIXED = 2;
CONTENT_WARNING_NSFW = 3;
}
22 changes: 11 additions & 11 deletions .github/scripts/index_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions .github/scripts/index_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ DESCRIPTOR: _descriptor.FileDescriptor

class ContentWarning(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
CONTENT_WARNING_UNSPECIFIED: _ClassVar[ContentWarning]
CONTENT_WARNING_SAFE: _ClassVar[ContentWarning]
CONTENT_WARNING_MIXED: _ClassVar[ContentWarning]
CONTENT_WARNING_NSFW: _ClassVar[ContentWarning]
CONTENT_WARNING_UNSPECIFIED: ContentWarning
CONTENT_WARNING_SAFE: ContentWarning
CONTENT_WARNING_MIXED: ContentWarning
CONTENT_WARNING_NSFW: ContentWarning
Expand Down Expand Up @@ -47,7 +49,7 @@ class ExtensionList(_message.Message):
def __init__(self, extensions: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...

class Extension(_message.Message):
__slots__ = ("name", "packageName", "resources", "extensionLib", "versionCode", "versionName", "contentWarning", "sources")
__slots__ = ("name", "packageName", "resources", "extensionLib", "versionCode", "versionName", "contentWarning", "sources", "isNovel")
NAME_FIELD_NUMBER: _ClassVar[int]
PACKAGENAME_FIELD_NUMBER: _ClassVar[int]
RESOURCES_FIELD_NUMBER: _ClassVar[int]
Expand All @@ -56,6 +58,7 @@ class Extension(_message.Message):
VERSIONNAME_FIELD_NUMBER: _ClassVar[int]
CONTENTWARNING_FIELD_NUMBER: _ClassVar[int]
SOURCES_FIELD_NUMBER: _ClassVar[int]
ISNOVEL_FIELD_NUMBER: _ClassVar[int]
name: str
packageName: str
resources: Resources
Expand All @@ -64,15 +67,18 @@ class Extension(_message.Message):
versionName: str
contentWarning: ContentWarning
sources: _containers.RepeatedCompositeFieldContainer[Source]
def __init__(self, name: _Optional[str] = ..., packageName: _Optional[str] = ..., resources: _Optional[_Union[Resources, _Mapping]] = ..., extensionLib: _Optional[str] = ..., versionCode: _Optional[int] = ..., versionName: _Optional[str] = ..., contentWarning: _Optional[_Union[ContentWarning, str]] = ..., sources: _Optional[_Iterable[_Union[Source, _Mapping]]] = ...) -> None: ...
isNovel: bool
def __init__(self, name: _Optional[str] = ..., packageName: _Optional[str] = ..., resources: _Optional[_Union[Resources, _Mapping]] = ..., extensionLib: _Optional[str] = ..., versionCode: _Optional[int] = ..., versionName: _Optional[str] = ..., contentWarning: _Optional[_Union[ContentWarning, str]] = ..., sources: _Optional[_Iterable[_Union[Source, _Mapping]]] = ..., isNovel: _Optional[bool] = ...) -> None: ...

class Resources(_message.Message):
__slots__ = ("apkUrl", "iconUrl")
__slots__ = ("apkUrl", "iconUrl", "jarUrl")
APKURL_FIELD_NUMBER: _ClassVar[int]
ICONURL_FIELD_NUMBER: _ClassVar[int]
JARURL_FIELD_NUMBER: _ClassVar[int]
apkUrl: str
iconUrl: str
def __init__(self, apkUrl: _Optional[str] = ..., iconUrl: _Optional[str] = ...) -> None: ...
jarUrl: str
def __init__(self, apkUrl: _Optional[str] = ..., iconUrl: _Optional[str] = ..., jarUrl: _Optional[str] = ...) -> None: ...

class Source(_message.Message):
__slots__ = ("id", "name", "language", "homeUrl", "mirrorUrls", "message")
Expand Down
Loading
Loading