Skip to content

feat(english/asianfanfics): add Asianfanfics plugin - #2616

Open
RibatTRW wants to merge 3 commits into
lnreader:masterfrom
RibatTRW:fm/lnreader-asianfanfics-2383
Open

RibatTRW wants to merge 3 commits into
lnreader:masterfrom
RibatTRW:fm/lnreader-asianfanfics-2383

Conversation

@RibatTRW

@RibatTRW RibatTRW commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Closes #2383

Adds a standalone plugin for Asianfanfics (plugins/english/asianfanfics.ts) and its 96x96 icon (the site's own favicon-96x96.png).

What it supports

  • popularNovels: paged browse lists, with a Sort filter (Trending (default), Latest, Newest, Completed, One Shots, Featured, Views, Subscriptions, Commented) and a Language filter (the site's story-language list). "Latest" in the app uses the site's Latest list.
  • searchNovels: the site's keyword search, paged.
  • parseNovel: title, cover (defaultCover when the story has none), author, tags as genres, Completed/Ongoing status, description, and the full chapter list from the table of contents. The "Foreword" entry is left out because it is the story page itself.
  • parseChapter: chapter text, with scripts, stylesheets (<style>/<link>), inline style attributes, iframes/forms, on* attributes and javascript: URLs removed. Chapter bodies are author-written, so inline styles could otherwise lay content over the reader.

The site renders listings, descriptions and chapter text as HTMX fragments (/htmx/...) after the page loads, so the plugin requests those fragments directly. The search fragment only answers with a Referer header, which the plugin sends.

What it can't read without an account

Logged-out readers only see what the site shows them ("Sign in to see every story"). Many stories are marked Members Only, Subscribers Only or Friends Only. Their story pages and chapter lists are public, but chapter text is not. For those chapters the plugin returns the site's own notice (for example "Please log in to read further chapters.") with a note that the chapter needs an Asianfanfics account, plus the public teaser the site shows when there is one. The plugin has no login or credential handling and does not try to get around these restrictions.

Testing

  • npx eslint plugins/english/asianfanfics.ts, npx prettier --check plugins/english/asianfanfics.ts and npm run build:compile pass locally. CI Lint Check and Format Check pass.
  • CI Plugin Live Check: INCONCLUSIVE (run https://github.com/lnreader/lnreader-plugins/actions/runs/36697237354): popularNovels | INCONCLUSIVE | HTTP 403 (Cloudflare). On the first commit this check was FAIL (run https://github.com/lnreader/lnreader-plugins/actions/runs/36696977845). The runner got past the site probe, but the fragment request got the same 403. The plugin was throwing a plain Error with no status, so the checker couldn't tell it was a block. The follow-up commit keeps status/response on the thrown error, the way dragonholic/daotekno do. The checker was not changed.
  • Diagnosis: from plain Node fetch (undici), both / and /htmx/browse/en/trending?page=1 return 403 with cf-mitigated: challenge, with or without a browser User-Agent, HX-Request or Referer. curl gets 200 on the same URLs. So this is Cloudflare's bot check on the client, not a header the plugin is missing.
  • Locally, npm run check:plugin -- plugins/english/asianfanfics.ts reports INCONCLUSIVE at siteReachability (HTTP 403, Cloudflare). A local, uncommitted copy of the checker with the site probe skipped (as on the runner) reports popularNovels INCONCLUSIVE (HTTP 403, Cloudflare) after the fix.
  • To exercise the plugin anyway, I ran a local, uncommitted copy of the checker that sends Node's fetch through curl. It passed: popularNovels 30 novels, searchNovels found the novel, parseNovel 12 chapters, parseChapter 14334 chars (a subscribers-only chapter: notice plus teaser).
  • Checked by hand with the same curl-backed setup: popular pages 1 and 2 differ; the Latest sort; the Language filter (ko on Latest returns 30 stories; some sorts such as Trending have no stories for some languages, and the site says so); search pages 1 and 2 differ; a public chapter returns the full text; a members-only chapter returns the notice plus teaser; a completed story reports Completed; the sanitizer strips onclick/onerror and javascript: hrefs on a synthetic sample. After the style fix (fbcc780): a synthetic chapter with position:fixed; z-index overlays and <style>/<link> tags comes back with no styles while keeping em/strong/br/img; a live public chapter still returns its full text (1292 paragraphs) with no style attributes; the curl-backed checker copy passes again (popularNovels 30, parseNovel 12 chapters, parseChapter 14334 chars).
  • Not tested in the LNReader app or the playground. Whether the app's own network stack gets past Cloudflare here the way curl does is unverified.

This PR was written by an AI agent (Claude); no human has reviewed it yet.

Carry the response status on thrown fetch errors so a Cloudflare block
is reported as a block instead of a plugin failure.
@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Adds a new content-scraping plugin for a fanfiction site.

The PR appears safe to merge, but chapter styles should be stripped so story content cannot cover preview controls.

Findings

  1. P2 Security Chapter content can cover controls ▶

Summary

Adds an Asianfanfics plugin and icon so readers can browse and search stories, view story details, and read public chapters in LNReader.

  • Browse lists include sort and language filters and load page by page.
  • Story pages provide descriptions and a de-duplicated chapter list; restricted chapters show the site's notice and any available teaser.

Reviews (1) · Last reviewed commit: "feat(english/asianfanfics): add Asianfan..."

Comment on lines +175 to +179
if (
name.toLowerCase().startsWith('on') ||
value.startsWith('javascript:')
) {
$(ele).removeAttr(name);

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 security Chapter content can cover controls

cleanHtml keeps inline style attributes in chapters and teasers. A story author can use one to place content over the preview’s controls, because the preview inserts the returned HTML directly into the page. Strip inline styles before returning the HTML.

How this was verified: Author-controlled chapter HTML keeps style attributes and is inserted directly into the chapter preview.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in fbcc780: cleanHtml now drops every inline style attribute (.find('[style]').removeAttr('style'), as lightnovelworld.ts does) and removes <link>/<meta> along with <style>, for both chapter and teaser HTML. I checked it on a synthetic chapter with position:fixed; z-index overlays (the styles are removed; em/strong/br/img are kept) and on a live public chapter (the text is intact). (Reply by an AI agent.)

Chapter and teaser bodies are author-written; drop style attributes and
link/meta tags so content cannot be positioned over the reader.

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.

asianfanfics: Plugin Request

1 participant