Skip to content

feat(english): add TinyTranslation source - #2685

Open
RibatTRW wants to merge 8 commits into
lnreader:masterfrom
RibatTRW:fm/lnreader-tinytranslation-250
Open

RibatTRW wants to merge 8 commits into
lnreader:masterfrom
RibatTRW:fm/lnreader-tinytranslation-250

Conversation

@RibatTRW

@RibatTRW RibatTRW commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #250

Closes #250

AI authorship: this change was written by an AI agent (Claude Haiku 5.5) working under a human operator's direction. No human has reviewed the code in this PR.

Intent

Work on #250 and include screenshots of the working fix in the PR.

Issue 250, "[Source Request] TinyTL / TinyTranslation" (opened four years ago): the requester wants the site added as a source. The mobile host no longer resolves, but the site itself is live at https://www.tinytranslation.xyz/ (200) with /list-novels/, novel pages under /series/<slug>/, and chapters under /<slug>/<slug>-<n>/; a chapter page returns 200 with about 6.1k characters of readable text. No dedicated plugin covers the site today - the shared NovelUpdates source has a partial tinytranslation case, which only helps users who come through NovelUpdates, not the site itself. Content is English.

Make sure the fix's pull request shows a photo of the plugin working correctly inside the plugin playground, and run that screenshot process headless if possible.

What Changed

  • Adds a standalone English plugin, plugins/english/tinytranslation.ts (id tinytranslation, version 1.0.0), for https://www.tinytranslation.xyz. It browses and searches the single-page /list-novels/ catalogue, reads novel details from /series/<slug>/ pages (cover, author, genres, synopsis, and status from the list's status headings), and collects chapters from the lists under the "Chapter:" heading.
  • Chapter text is read from the .entry-content .content block, with navigation, scripts, ads, and translate widgets removed. Pages without readable text raise an error instead of returning empty content.
  • Adds the plugin icon at public/static/src/en/tinytranslation/icon.png.

Risk Assessment

✅ Low: The change is a single new, self-contained standalone plugin with a valid 96x96 icon; the chapter traversal and label-regex fixes match the recorded decisions and the cached live pages show no non-chapter links inside the chapter section, leaving only the ask-user status gap.

Testing

All scenarios were driven live in the playground headless. The plugin lists the catalogue, searches by title, parses novels (including the avalon heading typo) and chapters, and surfaces errors correctly. Its status lookup stays non-fatal when /list-novels/ fails. Every scenario passed; the only observation is a generic WordPress icon, which is informational.

  • Live validation: ✅ go - 10 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Plugin appears in the playground sidebar and can be selected ✅ pass live playground-tinytranslation-selected.png; sidebar search 'tiny' lists TinyTranslation and selecting it shows the plugin header
Popular/latest fetch lists the site's series from /list-novels/ ✅ pass live pr-1-popular.png; FETCH via real plugin popularNovels, 63 series
Title search 'mishearing' returns 'A Tale of Development in Another World Begins with a Mishearing' ✅ pass live pr-2-search.png
Adversarial: a nonsense search returns no results, not the whole catalogue ✅ pass live adv-search-no-results.png shows 'No results found'
Parse novel /series/isekai-develop/ shows title, author, Ongoing status, genres, summary and 353 chapters ✅ pass live pr-3-parse-novel.png
Adversarial: avalon page with 'Chapter hapter:' heading typo still reads its chapter list (269 chapters, no error) ✅ pass live adv-avalon-typo-heading.png
Adversarial: a missing novel path surfaces a clear error instead of an empty novel ✅ pass live parse-novel-missing-settled.png shows 'TinyTranslation: HTTP 404.'
Parse chapter /isekai-mishearing/develop-1/ returns readable chapter text (11,505 characters) ✅ pass live pr-4-parse-chapter.png
Adversarial: parse chapter on a series page path errors rather than returning non-chapter content ✅ pass live parse-chapter-series-page.png shows 'TinyTranslation: no readable chapter text was found.'
Adversarial: if /list-novels/ fails (forced 500), parse novel still succeeds with no status ✅ pass live adv-status-lookup-fails.png; text check: novel title and author present, no status badge, no error
  • Evidence: PR 1: popular novels list in playground (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/pr-1-popular.png)
  • Evidence: PR 2: title search 'mishearing' returns the novel (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/pr-2-search.png)
  • Evidence: PR 3: parse novel /series/isekai-develop/ with status, author, genres, summary, 353 chapters (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/pr-3-parse-novel.png)
  • Evidence: PR 4: parse chapter /isekai-mishearing/develop-1/ with 11,505 characters of text (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/pr-4-parse-chapter.png)
  • Evidence: Adversarial: status lookup forced to 500 still parses the novel with no status (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/adv-status-lookup-fails.png)
  • Evidence: Adversarial: avalon page with 'Chapter hapter:' heading reads 269 chapters (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/adv-avalon-typo-heading.png)
  • Evidence: Adversarial: nonsense search shows No results found (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/adv-search-no-results.png)
  • Evidence: Adversarial: missing novel path shows 'TinyTranslation: HTTP 404.' (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/parse-novel-missing-settled.png)
  • Evidence: Adversarial: parse chapter on a series path shows 'TinyTranslation: no readable chapter text was found.' (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/parse-chapter-series-page.png)
  • Evidence: Plugin selected in playground sidebar (local file: ~/.no-mistakes/evidence/01M4ZV1NAK50TFBV18P6PWQXXF/playground-tinytranslation-selected.png)
  • Outcome: ⚠️ 1 info across 1 run (18m26s)

Screenshots

These screenshots come from the repository's plugin playground (npm run dev:start), driven headless in Chromium, with this source's live results on screen. They are not from the LNReader app: the Android toolchain is not installed on the machine that captured them.

Plugin playground: TinyTranslation popular listing (63 series)

Plugin playground: TinyTranslation search results for "isekai"

Plugin playground: novel detail with status, author, genres, 370 chapters

Plugin playground: chapter list, start (Volume 1)

Plugin playground: chapter list, end (Volume 5 Chapter 74 is row 369 of 370)

Plugin playground: parsed chapter text

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 4 issues (2 warnings, 2 infos)
  • ⚠️ plugins/english/tinytranslation.ts:53 - The plugin ignores the status the site exposes. /list-novels/ groups series under On-going, Completed and Dropped &lt;h3&gt; headings (cached list.html), but catalogue() pushes items with no status and parseNovel() (lines 153-161) never sets one. AGENTS.md says to exercise status when the target site exposes it. The intent does not require status, so adding it extends the change: ask the author whether to map the group heading to NovelStatus (catalogue) and read it on the novel page (parseNovel return), or to accept the omission for this version.

🔧 Fix applied.
2 warnings still open:

  • ⚠️ plugins/english/tinytranslation.ts:53 - The plugin ignores the status the site exposes. /list-novels/ groups series under On-going, Completed and Dropped &lt;h3&gt; headings (cached list.html), but catalogue() pushes items with no status and parseNovel() (lines 153-161) never sets one. AGENTS.md says to exercise status when the target site exposes it. The intent does not require status, so adding it extends the change: ask the author whether to map the group heading to NovelStatus (catalogue) and read it on the novel page (parseNovel return), or to accept the omission for this version.
  • ⚠️ plugins/english/tinytranslation.ts:171 - parseNovel fetches the whole /list-novels/ catalogue only to read the novel's status, with no error handling. request() throws on any non-OK response, so a transient failure or 5xx on /list-novels/ makes parseNovel reject even though the novel page and its chapters were already parsed successfully. Status is optional metadata, so this lookup should not be able to fail the novel. Remedy: wrap the catalogue lookup in a try/catch that leaves status undefined on failure. This corrects existing error handling inside the status feature the author already requested, so it is a routine auto-fix. Sibling: none in the changed code; popularNovels and searchNovels call catalogue() directly and correctly surface their own errors.

🔧 Fix applied.
4 issues (2 warnings, 2 infos) still open:

  • ⚠️ plugins/english/tinytranslation.ts:53 - The plugin ignores the status the site exposes. /list-novels/ groups series under On-going, Completed and Dropped &lt;h3&gt; headings (cached list.html), but catalogue() pushes items with no status and parseNovel() (lines 153-161) never sets one. AGENTS.md says to exercise status when the target site exposes it. The intent does not require status, so adding it extends the change: ask the author whether to map the group heading to NovelStatus (catalogue) and read it on the novel page (parseNovel return), or to accept the omission for this version.
  • ⚠️ plugins/english/tinytranslation.ts:171 - parseNovel fetches the whole /list-novels/ catalogue only to read the novel's status, with no error handling. request() throws on any non-OK response, so a transient failure or 5xx on /list-novels/ makes parseNovel reject even though the novel page and its chapters were already parsed successfully. Status is optional metadata, so this lookup should not be able to fail the novel. Remedy: wrap the catalogue lookup in a try/catch that leaves status undefined on failure. This corrects existing error handling inside the status feature the author already requested, so it is a routine auto-fix. Sibling: none in the changed code; popularNovels and searchNovels call catalogue() directly and correctly surface their own errors.
  • ℹ️ plugins/english/tinytranslation.ts:171 - parseNovel fetches the full /list-novels/ catalogue on every novel open, only to read the status. This doubles the network cost of opening a novel. The status lookup is the author-requested feature and its failure is already contained by the try/catch, so this is a cost tradeoff, not a defect.
  • ℹ️ plugins/english/tinytranslation.ts:142 - Chapter collection continues through every element after the 'Chapter:' heading until the next h1-h6, per the recorded round-5 decision. A sidebar or footer list placed after the chapter section, with no heading in between, that contains two-segment same-origin links (for example /category/x/) would be collected as chapters. The live markup was not re-verified in this pass, and the per-decision CHAPTER_PATH and series filters are what limit it.
⚠️ **Test** - 1 info
  • ℹ️ public/static/src/en/tinytranslation/icon.png - The plugin icon is a generic WordPress logo rather than the site's own mark. It meets the 96x96 PNG rule and does not affect behavior, so this is informational only.
  • Live validation: ✅ go - 10 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Plugin appears in the playground sidebar and can be selected ✅ pass live playground-tinytranslation-selected.png; sidebar search 'tiny' lists TinyTranslation and selecting it shows the plugin header
Popular/latest fetch lists the site's series from /list-novels/ ✅ pass live pr-1-popular.png; FETCH via real plugin popularNovels, 63 series
Title search 'mishearing' returns 'A Tale of Development in Another World Begins with a Mishearing' ✅ pass live pr-2-search.png
Adversarial: a nonsense search returns no results, not the whole catalogue ✅ pass live adv-search-no-results.png shows 'No results found'
Parse novel /series/isekai-develop/ shows title, author, Ongoing status, genres, summary and 353 chapters ✅ pass live pr-3-parse-novel.png
Adversarial: avalon page with 'Chapter hapter:' heading typo still reads its chapter list (269 chapters, no error) ✅ pass live adv-avalon-typo-heading.png
Adversarial: a missing novel path surfaces a clear error instead of an empty novel ✅ pass live parse-novel-missing-settled.png shows 'TinyTranslation: HTTP 404.'
Parse chapter /isekai-mishearing/develop-1/ returns readable chapter text (11,505 characters) ✅ pass live pr-4-parse-chapter.png
Adversarial: parse chapter on a series page path errors rather than returning non-chapter content ✅ pass live parse-chapter-series-page.png shows 'TinyTranslation: no readable chapter text was found.'
Adversarial: if /list-novels/ fails (forced 500), parse novel still succeeds with no status ✅ pass live adv-status-lookup-fails.png; text check: novel title and author present, no status badge, no error
  • npm run check:plugin -- plugins/english/tinytranslation.ts (live: popularNovels PASS 63 novels, searchNovels PASS, parseNovel PASS 353 chapters, parseChapter PASS 11499 chars)
  • npm run dev:start (playground served on :3001 because :3000 is held by other sessions; the playground hard-codes its CORS proxy at localhost:3000)
  • Headless system Chromium 152 driven with puppeteer-core (installed in /tmp/tt-tools, outside the worktree). Playground fetches to localhost:3000 were fulfilled by Puppeteer request interception that forwards to the real target with the proxy's CORS headers. The plugin, playground UI and parse code are all real; only the proxy transport was shimmed.
  • Scenario driver /tmp/tt-tools/final.mjs: select TinyTranslation in sidebar; Popular Fetch; Search 'mishearing' and 'zzqqxx'; Parse Novel /series/isekai-develop/, /series/avalon/, /series/does-not-exist-xyz/ (HTTP 404 path); Parse Chapter /isekai-mishearing/develop-1/ and /series/isekai-develop/ (series path); forced 500 on /list-novels/ during Parse Novel to exercise the status-lookup guard
  • Clean-up: killed only my own vite process (pid 2443093); ran npm run clean:multisrc to remove generated gitignored multi-source plugins; worktree status is clean
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Add a standalone English source for https://www.tinytranslation.xyz/.

- Browse: reads the single /list-novels/ catalogue (on-going, completed
  and dropped groups); there is no pagination.
- Novel: reads the series title, author, genres, synopsis and cover
  (placeholder covers fall back to defaultCover), and every chapter in
  the "Chapter:" list, which can be split into one <ul> per volume.
- Chapter: reads the chapter body and drops navigation, scripts and the
  bookmark prompt.
- Search: matches the catalogue by title and adds novels found by the
  site's own chapter search, which is capped at 10 seconds.

No existing multisrc generator matches this site's markup, so this is a
standalone plugin.

Fixes lnreader#250
@greptile-apps

greptile-apps Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issue was established.

Summary

Adds TinyTranslation as a standalone English source.

  • Readers can browse and search TinyTranslation's novel list.
  • Series pages show novel details, and chapter pages return cleaned text.

No actionable issues were established.

Acknowledgments supplied under RibatTRW’s PR description: the extra catalogue request for status is an accepted cost tradeoff; the generic WordPress icon is informational; possible sidebar links entering the chapter list are a known concern without an observed affected page.

Reviews (1) · Last reviewed commit: "no-mistakes(review): Guard optional stat..." · Reviewed by Greptile

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TinyTL

1 participant