Skip to content

feat(indonesian): add Grensia source plugin - #2691

Open
RibatTRW wants to merge 5 commits into
lnreader:masterfrom
RibatTRW:fm/lnreader-grensia-241
Open

RibatTRW wants to merge 5 commits into
lnreader:masterfrom
RibatTRW:fm/lnreader-grensia-241

Conversation

@RibatTRW

@RibatTRW RibatTRW commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Intent

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

Issue 241, "[Source Request] Grensia" (opened four years ago; a duplicate was closed as #428): the requester wants the site added as a source. https://grensia.blogspot.com/ returns 200, and a chapter post such as https://grensia.blogspot.com/2022/08/isekai-wa-heiwa-deshita-chapter-1217.html returns 200 with readable text. No plugin and no generated source covers the site today. It is a Blogger site whose posts are the chapters; the content is Indonesian.

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 plugins/indonesian/grensia.ts source for grensia.blogspot.com (Blogger, Indonesian).
  • Browse: the site's own "List Novel" index (label novel), 38 series after dedupe.
  • Chapters: the site's HTML search for the series name, followed through the "Older Posts" pages. A post is a chapter when its headline's series name matches the novel's name, sorted oldest first with chapter numbers parsed from titles.
  • Search: site search grouped by series name, so series missing from the List Novel (for example Isekai wa Heiwa deshita) are still found.
  • Chapter text: the .post-body of the chapter page, with scripts, styles, ins, iframes and the "more" anchor removed.
  • Adds the 96x96 source icon at public/static/src/id/grensia/icon.png.

Closes #241

Screenshots

These come from this repo's plugin playground (npm run dev:start, headless Chromium), not from the LNReader app. The Android toolchain is not installed on this machine, so the plugin has not been tested in the app.

  1. Popular tab, Latest, after Fetch:

Plugin playground: Grensia popular novels

  1. Search for "Isekai" (returns Isekai wa Heiwa deshita, which the List Novel does not list):

Plugin playground: Grensia search results for Isekai

  1. Parse Novel for Isekai wa Heiwa deshita (cover, metadata, chapter count and dates):

Plugin playground: Grensia novel detail for Isekai wa Heiwa deshita

  1. Parse Chapter, Chapter 1 readable Indonesian text:

Plugin playground: Grensia chapter text

  1. Parse Novel for Eminence in Shadow and its chapter list:

Plugin playground: Grensia novel detail for Eminence in Shadow

Plugin playground: Grensia chapter list for Eminence in Shadow

Known gap (shipped by decision)

Five of the 38 series on the site's List Novel still show no chapters, because the title on the List Novel does not match the chapter posts' titles on the site. They are:

  • A Sword Master Childhood Friend Power Harassed Me Harshly
  • Sword Art Online Progressive Light Novel
  • We Live in Dragons Peak
  • I Became the Strongest With The Failure Frame
  • I'm the Evil Lord of an Intergalactic Empire!

The known gap was reviewed and the captain's decision was to ship with it, with no further fix round. No hard-coded per-series title map was added.

Blogger's search totals vary between requests. We observed 1220 and 1049 chapters for Isekai wa Heiwa deshita in different runs.

Testing

  • npm run check:plugin -- plugins/indonesian/grensia.ts: all four steps PASS (38 popular, 1 search result, 137 chapters, 12486-character chapter).
  • npm run build:full exits 0; eslint and prettier pass on the plugin file.
  • Playground screenshots above, driven headless with no user interaction in the app.
  • Live validation during the pipeline returned no-go on the adversarial sweep over every Popular series (the five series above). The test-step exception was recorded by no-mistakes.

Disclosure

This PR was written by an AI agent (Claude, via Claude Code). No human has reviewed it yet.

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 2 errors
  • 🚨 plugins/indonesian/grensia.ts:156 - 15 of 38 series in the Popular catalog return zero chapters from parseNovel (e.g. 'I Was Caught up in a Hero Summoning, but That World Is at Peace', 'Orc Eiyuu Monogatari Sontaku Retsuden'), because the catalog landing title does not match the chapter post titles. The same series are reachable with chapters via Search. This is the author's recorded known gap in commit 08fc0c6; the user must decide whether to ship with it or fix it.
  • ℹ️ plugins/indonesian/grensia.ts:226 - searchNovels('-') returns all 33 series because the normalized term is empty and key.indexOf('') === 0. This matches the review-3 finding the user already declined, so it is noted only.
  • ℹ️ plugins/indonesian/grensia.ts:233 - Search results include a near-duplicate entry 'Clearing an Isekai with the Zero-Believers Goddes' alongside 'Clearing an Isekai with the Zero-Believers Goddess', because the series-name derivation yields two different keys for one series. It is a cosmetic data issue, not a crash.
  • 🚨 live validation verdict: no-go (9 of 9 scenarios were driven live against the product); failed: Adversarial: Popular card for 'I Was Caught up in a Hero Summoning, but That World Is at Peace' → Parse Novel shows 0 chapters, although the same series has chapter posts reachable through Search, Adversarial sweep: every Popular catalog series is parsed through the real plugin code against the live site; 15 of 38 return zero chapters, matching the author's documented known gap
  • Live validation: ❌ no-go - 9 of 9 scenarios driven live against the product
Scenario Result Live Evidence
Live check of the standalone plugin against the real site: popularNovels, searchNovels, parseNovel and parseChapter all PASS (38 novels, 1 search hit for MAGICAL★EXPLORER, 137 chapters, 12486-char cha… ✅ pass live npm run check:plugin -- plugins/indonesian/grensia.ts output (all four steps PASS)
User opens the playground, selects Grensia in the plugin list, and the header and title switch to Grensia ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-1-popular-latest.png (header reads Grensia; plugin list shows 142 plugins including Grensia)
Popular → Latest → Fetch shows real Grensia novels with cover art, and falls back to the 'BOOK COVER NOT AVAILABLE' placeholder when a series has none ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-1-popular-latest.png
Search tab: typing 'Isekai' and clicking Search returns the 'Isekai wa Heiwa deshita' series (which the List Novel index does not list) with its cover ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-2-search-isekai.png
Search result → Parse Novel: 'Isekai wa Heiwa deshita' lists 1220 chapters, oldest first, with release dates, first/last-updated and a cover ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-3-parse-novel-isekai-wa-heiwa-deshita.png
Parse Chapter with the issue's example post path /2022/08/isekai-wa-heiwa-deshita-chapter-1217.html renders readable Indonesian body text (8426 characters) ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-4-parse-chapter-issue-example.png
Adversarial: Popular card for 'I Was Caught up in a Hero Summoning, but That World Is at Peace' → Parse Novel shows 0 chapters, although the same series has chapter posts reachable through Search ❌ fail live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-5-popular-card-parse-novel-zero-chapters.png (TOTAL CHAPTERS 0)
Adversarial sweep: every Popular catalog series is parsed through the real plugin code against the live site; 15 of 38 return zero chapters, matching the author's documented known gap ❌ fail live node sweep of the esbuild-bundled plugin: zero-chapter series: 15 of 38 (output in /tmp/grensia-driver/sweep/run.log)
Adversarial: a search term matching nothing ('zzqqxxnomatch') returns an empty list without error ✅ pass live node run of searchNovels against the live site: 0 results
  • npm ci in the worktree (dependency install, needed to run the toolchain)
  • npm run check:plugin -- plugins/indonesian/grensia.ts (live check, all four steps PASS)
  • npx vite --port 3000 --host 127.0.0.1 --strictPort as the playground server (port 3000 was already held by another process on [::1], so the playground was bound to IPv4 loopback only, and Chromium was given --host-resolver-rules=MAP localhost 127.0.0.1 so the hardcoded localhost:3000 fetch shim reaches it)
  • Headless Chromium driven over CDP from /tmp/grensia-driver/cdp.mjs (real mouse and keyboard events for Radix tabs and inputs; element.click() for list items and fetch buttons): Popular fetch, card arrow → Parse Novel, Search 'Isekai', Parse Novel fetch, Parse Chapter with the issue example path
  • Node sweep of all 38 Popular series through the esbuild-bundled plugin against the live site (parseNovel chapter counts)
  • Node adversarial checks: searchNovels('zzqqxxnomatch') → 0 results; searchNovels('-') → 33 results (info only)
  • Evidence copied to ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW (grensia-1..5 PNGs)
  • Stopped the playground server and headless Chromium; worktree git status is clean

🔧 No changes applied.
3 issues (2 errors, 1 warning) still open:

  • 🚨 plugins/indonesian/grensia.ts:178 - Series chapters are matched only by normalize(seriesName(post.title)) against the catalog name. For the 'I Was Caught up in a Hero Summoning, but That World Is at Peace' series, Blogger headlines read 'Isekai wa Heiwa deshita Chapter N', so parseNovel returns 0 chapters and searchNovels cannot find the series by its catalog title. The JSON-LD description on about 90 posts starts with 'Novel I Was Caught up in a Hero Summoning, but That World Is at Peace Indonesia Chapter N', which is a reliable key the plugin ignores. Remedy: also match posts whose description carries the landing name, and use the same rule in searchNovels so both paths agree.
  • ⚠️ plugins/indonesian/grensia.ts:235 - The known gap from the previous round still stands for the other 14 of 38 Popular series that return 0 chapters. This run did not re-drive that sweep, so its current size is unverified here. The user should decide whether to ship with the gap or fix it before this is marked ready.
  • 🚨 live validation verdict: no-go (7 of 8 scenarios were driven live against the product); failed: Adversarial: Popular card 'I Was Caught up in a Hero Summoning, but That World Is at Peace' lists its chapters in Parse Novel, Adversarial: searching the catalog title for that series returns it
  • Live validation: ❌ no-go - 7 of 8 scenarios driven live against the product
Scenario Result Live Evidence
Grensia appears in the plugin playground list and opens to its tabs ✅ pass live 1-popular-catalog.png (plugin selected, Popular/Search/Parse Novel/Parse Chapter tabs shown)
Popular tab lists Grensia series with cover images after Fetch ✅ pass live 1-popular-catalog.png shows 38 series cards with covers; one series falls back to the default 'book cover not available' image
Search for 'isekai' returns matching Grensia series ✅ pass live 2-search-isekai.png shows three series, including Isekai wa Heiwa deshita
Parse Novel for Isekai wa Heiwa deshita lists all chapters in order with release dates ✅ pass live 3-parse-novel-isekai-wa-heiwa-deshita.png shows TOTAL CHAPTERS 1220, first chapter Aug 20, 2020, chapter list starting at Chapter 1
Parse Chapter for chapter 1217 returns readable Indonesian body text ✅ pass live 4-parse-chapter-1217.png shows CHAPTER CONTENT (8426 characters) with Indonesian prose
Adversarial: Popular card 'I Was Caught up in a Hero Summoning, but That World Is at Peace' lists its chapters in Parse Novel ❌ fail live 5-parse-novel-hero-summoning-zero-chapters.png shows TOTAL CHAPTERS 0; chapter headlines use 'Isekai wa Heiwa deshita', and ~90 posts carry the catalog title only in the JSON-LD description
Adversarial: searching the catalog title for that series returns it ❌ fail live 2b-search-hero-summoning.png and 2c-search-hero-summoning-full-title.png both show No results found
Adversarial sweep: every Popular catalog series parses to a non-empty chapter list ⏸️ untested no Not re-run in this pass to keep the step proportionate; it can be re-driven with a scripted call to the plugin's popularNovels and parseNovel against the live site, or in the playground one card at a…
  • npm run check:plugin -- plugins/indonesian/grensia.ts (popularNovels 38, searchNovels 1, parseNovel 137 chapters, parseChapter 12486 chars; all PASS)
  • npm run dev:start (multisrc regenerated) and a Vite server on 127.0.0.1:3000 for the playground proxy
  • Headless Chromium with --host-resolver-rules=MAP localhost 127.0.0.1, driven via chrome-devtools-axi: Grensia selected in the plugin list, Popular Fetch, Search 'isekai', Parse Novel for Isekai wa Heiwa deshita, Parse Chapter /2022/08/isekai-wa-heiwa-deshita-chapter-1217.html, Parse Novel for the Hero Summoning Popular card (opened via its arrow button), Search 'Hero Summoning' and the full catalog title
  • Direct curl against grensia.blogspot.com search pages to inspect JSON-LD headline vs description for the Hero Summoning series (about 90 description matches vs 0 headline matches)
  • Stopped my Vite and Chromium afterwards; the other worktree's server on port 3000 was left untouched

🔧 Fix applied.
2 errors still open:

  • 🚨 plugins/indonesian/grensia.ts:178 - 10 of 38 Popular series still return zero chapters from parseNovel (down from 15), because catalog landing titles do not match chapter post headlines or descriptions. This is the known gap recorded in commit 08fc0c6. Ship with it or fix it? The Hero Summoning series is fixed.
  • 🚨 live validation verdict: no-go (6 of 6 scenarios were driven live against the product); failed: Adversarial: every Popular catalog series parses to a non-empty chapter list
  • Live validation: ❌ no-go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Popular catalog lists Grensia series with covers in the playground ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/r2-2-popular-fetched.png
Searching 'Hero Summoning' returns the series 'I Was Caught up in a Hero Summoning, but That World Is at Peace' ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/r2-3-search-hero-summoning.png
Parse Novel for the Hero Summoning series lists its chapters (the test-1 regression) ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/r2-4-parse-novel-hero-summoning.png
Parse Chapter for issue #241's example post returns readable Indonesian text ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/r2-5-parse-chapter-1217.png
Adversarial: searching the full catalog title for the Hero Summoning series returns it ✅ pass live Sweep script output via the bundled real plugin: 'search catalog title -> I Was Caught up in a Hero Summoning, but That World Is at Peace'; hero chapters 227
Adversarial: every Popular catalog series parses to a non-empty chapter list ❌ fail live Sweep script output: 'zero-chapter series 10 of 38' (Orc Eiyuu Monogatari Sontaku Retsuden, Naze Boku no Sekai wo Dare mo Oboeteinainoka?, A Sword Master Childhood Friend Power Harassed Me Harshly, I…
  • npm run check:plugin -- plugins/indonesian/grensia.ts (all four checks PASS: 38 popular, 1 search result, 137 chapters, 12486-char chapter)
  • Started the playground with npx vite --host (the default bind is IPv6-only, and the app hardcodes http://localhost:3000)
  • Drove the playground headless (system Chromium with remote debugging, isolated profile) at http://localhost:3000/?plugin=grensia: Popular tab, Fetch
  • Search tab, term 'Hero Summoning'
  • Parse Novel tab, path for 'I Was Caught up in a Hero Summoning, but That World Is at Peace', Fetch (227 chapters)
  • Parse Chapter tab, path /2022/08/isekai-wa-heiwa-deshita-chapter-1217.html, Fetch (8426 characters of readable text)
  • Bundled plugins/indonesian/grensia.ts with esbuild and ran popularNovels + parseNovel over all 38 series, plus searchNovels for the catalog title and 'Hero Summoning' (script in /tmp/grensia-sweep, outside the worktree)
  • Stopped the Vite server and headless Chromium; worktree left clean (git status empty)

🔧 Fix applied.
2 errors still open:

  • 🚨 plugins/indonesian/grensia.ts:178 - 5 of 38 Popular series still return zero chapters from parseNovel (down from 15 in round 1 and 10 in round 3): A Sword Master Childhood Friend Power Harassed Me Harshly; Sword Art Online Progressive Light Novel; We Live in Dragons Peak; I Became the Strongest With The Failure Frame; I'm the Evil Lord of an Intergalactic Empire!. This is the known gap recorded in commit 08fc0c6. The user must decide whether to ship with it or fix it.
  • 🚨 live validation verdict: no-go (7 of 7 scenarios were driven live against the product); failed: Adversarial: every Popular catalog series parses to a non-empty chapter list
  • Live validation: ❌ no-go - 7 of 7 scenarios driven live against the product
Scenario Result Live Evidence
Popular tab lists the Grensia catalog after Fetch ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-1-popular.png
Parse Novel for MAGICAL★EXPLORER shows cover, metadata, and 137 chapters ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-2-parse-magical.png
Parse Novel for the Hero Summoning series (previously zero chapters) lists 227 chapters ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-3-parse-hero-summoning.png
Search for 'Hero Summoning' returns the series by its catalog title ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-4-search-hero-summoning.png
Parse Chapter renders readable Indonesian post text for a Grensia chapter ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-6-parse-chapter.png
Adversarial: Parse Novel for the Orc Eiyuu series (known gap in earlier rounds) lists chapters ✅ pass live ~/.no-mistakes/evidence/01M4ZV1934NK3XCYHECY9AVRRW/grensia-5-parse-orc-known-gap.png
Adversarial: every Popular catalog series parses to a non-empty chapter list ❌ fail live Adversarial sweep output recorded in tested: 33 of 38 non-empty, 5 zero (A Sword Master Childhood Friend Power Harassed Me Harshly; Sword Art Online Progressive Light Novel; We Live in Dragons Peak; I…
  • node scripts/live-check-plugin.js plugins/indonesian/grensia.ts (baseline, all four checks PASS)
  • npx vite --port 3000 (playground dev server, real product), then headless Chromium with chrome-devtools-axi attached via CHROME_DEVTOOLS_AXI_BROWSER_URL
  • Playground: Popular tab, Fetch, screenshot of catalog
  • Playground: Parse Novel for MAGICAL★EXPLORER path, screenshot
  • Playground: Parse Novel for I Was Caught up in a Hero Summoning, but That World Is at Peace, screenshot (227 chapters)
  • Playground: Search tab, term 'Hero Summoning', screenshot (series returned)
  • Playground: Parse Novel for Orc Eiyuu Monogatari Sontaku Retsuden (60 chapters)
  • Playground: Parse Chapter for /2019/10/magicalexplorer-chapter-1-prologue.html, screenshot (12490 characters)
  • Adversarial sweep: bundled grensia.ts with esbuild (same options as live-check) and ran popularNovels(1) then parseNovel for each of 38 series against the live site: 33 non-empty, 5 zero (A Sword Master Childhood Friend Power Harassed Me Harshly; Sword Art Online Progressive Light Novel; We Live in Dragons Peak; I Became the Strongest With The Failure Frame; I'm the Evil Lord of an Intergalactic Empire!)
  • Teardown: stopped vite and the headless Chromium, removed scratch files; git status clean in the worktree
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

RibatTRW and others added 5 commits October 15, 2026 20:00
Add a standalone Indonesian source for grensia.blogspot.com (Blogger).

- Catalog: the site's own "List Novel" index (label novel).
- Chapters: the reader's HTML search for the series name, followed
  through the "Older Posts" pages, filtered to the matching series.
- Search: site search grouped by series name, so series missing from
  the List Novel (e.g. Isekai wa Heiwa deshita) are still found.
- Chapter text is the post body.

Known gap: 15 of the 38 listed series have titles that do not match
their chapter posts on the site, so they show no chapters.

Co-Authored-By: Claude <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] Adds a new content source plugin for Indonesian novels.

The PR appears safe to merge with non-blocking fixes recommended for search coverage and exported covers.

Findings

  1. P2 Search hides matching novels ▶
  2. P2 Exported books lose their covers ▶

Summary

Adds Grensia as an Indonesian source with a source icon.

  • Readers can find Grensia novels in its catalog or search for them.
  • Opening a Grensia novel shows its chapters in order and readable text.

Acknowledged issues excluded from this review: RibatTRW's PR description records catalog-name gaps, previously declined empty-term search behavior, and a known near-duplicate search result.

Reviews (1) · Last reviewed commit: "no-mistakes(document): no docs stale; pr..." · Reviewed by Greptile

Comment on lines +241 to +245
if (pageNo > 1) return [];

const posts = await readAll(
`${BASE}/search?q=${encodeURIComponent(searchTerm)}&max-results=${SEARCH_PAGE_SIZE}`,
1,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Search hides matching novels

searchNovels reads only the first 150 matching posts and returns nothing for later pages. These are chapter posts, not distinct novels, so a long series can fill that page and hide other matching series. Follow the older-post links or support pageNo so users can reach those results.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +273 to +274
resolveUrl = (path: string, isNovel?: boolean) =>
isNovel ? `${BASE}/search?q=${path}` : BASE + path;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Exported books lose their covers

resolveUrl turns an absolute cover URL into a Blogger search URL when the playground exports an EPUB. useEpubExport calls it with sourceNovel.cover and true, so the export fetches a search page instead of artwork. Preserve absolute image URLs before building the novel search URL.

Suggested change
resolveUrl = (path: string, isNovel?: boolean) =>
isNovel ? `${BASE}/search?q=${path}` : BASE + path;
resolveUrl = (path: string, isNovel?: boolean) =>
/^https?:\/\//i.test(path)
? path
: isNovel
? `${BASE}/search?q=${path}`
: BASE + path;

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.

Grensia

1 participant