Conversation
Madara sites that use the wp-manga-chapter-coin plugin hide the premium rows from the chapter list (href="#") while the chapter itself is still served at /series/<slug>/chapter-<number>/ with only a "This chapter is locked!" notice in .reading-content. Excluding those rows makes the list understate the novel and hides which chapters exist. Add an opt-in includeLockedChapters source option (default off) that: - rebuilds a premium row's /chapter-<number>/ path from its title and keeps the row listed next to the free chapters; - throws a clear "chapter is locked" error in parseChapter (including the coin price from the page's coin-N class) instead of returning an empty chapter, and also fails loud when a rebuilt URL lands on a page with no chapter body at all; - reports no releaseTime for rebuilt rows, because the site only shows a countdown or "TBA" (never a publication date). tangerinearchive opts in and its plugin version is incremented to 2.2.1. The locked body stays server-gated: no anonymous path returns it, so the listed premium chapters remain unreadable and now say so honestly. Co-Authored-By: pi <pi@local>
The site keeps a non-ASCII token that follows the chapter number in the
chapter slug ("Chapter 176 🔞" -> /chapter-176-%F0%9F%94%9E/) while a
" - subtitle" is dropped ("Chapter 242 - 🔞" -> /chapter-242/). Without
that rule the two emoji chapters listed by the option resolved to the
series page instead of their own locked page.
Verified against the free rows of 14 series (1904 rows): the rule matches
1886 slugs exactly, 17 more differ only by percent-encoding case, and the
single miss is a WordPress duplicate-slug uniquifier (chapter-55_1) whose
premium equivalent is the already-documented duplicate-number collision.
Co-Authored-By: pi <pi@local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked candidate fix for lnreader#2564 (base:
fm/lnreader-plugins-2555-tangerine). PR lnreader#2564 deliberatelyomits coin-locked chapters; this PR lists them and gives them an honest locked experience instead of
a blank chapter. The locked body stays server-gated — nothing here bypasses the coin-lock.
What changed (3 files, flag-gated)
plugins/multisrc/madara/template.ts— new opt-inincludeLockedChapterssource option, default off:parseNovel, when the option is on and a row ispremium-blockwithhref="#", the/series/<slug>/chapter-<number>/path is rebuilt from the chapter number in the row title, so therow is listed with the free chapters. The slug follows the site's own rules, verified against the
free rows:
Chapter 27.2→chapter-27-2; a non-ASCII token straight after the number is part ofthe slug (
Chapter 176 🔞→chapter-176-%F0%9F%94%9E); a- subtitleis dropped(
Chapter 242 - 🔞→chapter-242). Rows whose title has no number are still skipped.releaseTimeisnullfor rebuilt rows because the site only shows a countdown orTBA, never apublication date (the template's
parseDatawould otherwise turn "Unlocked in 4 weeks" into a bogusdate four weeks in the past).
parseChapter, when the option is on: a lock notice inside.reading-content(
.content-blocked/.premium-block/ "chapter is locked") throwsThis chapter is locked and costs <n> coins. Unlock it with a site account to read it here.;a page with no
.reading-contentat all (e.g. a rebuilt URL that falls back to the series page)throws a clear "no readable content" error instead of returning
''(blank).Detection is scoped to
.reading-content, because free chapter pages carry adiv.nav-next.premium...premium-blockoutside it that would otherwise look locked.It is decided from the fetched page, not from the list class, so a row the list marks free but
whose page is still gated is covered too.
plugins/multisrc/madara/sources.json—tangerinearchiveopts in (includeLockedChapters: true)and
versionIncrements: 1(plugin 2.2.1).plugins/multisrc/madara/README.md— documents the new option.Verified anonymously, read-only (no login, no cookies, no purchase, no unlock request)
garden-of-mayparses 212 = 52 premium + 160 free andvillain-let-me-touch-youparses 191 = 46 premium + 145 free, both exactly matching anindependent anonymous
POST /series/<slug>/ajax/chapters/. Every premium row's rebuilt path matchesits number; free chapters still parse (chapter-1 7120 chars, chapter-160 6538 chars).
parseChapter:garden-of-may/chapter-161/and/chapter-212/(10 coins) throw the locked error;it-seems-like-.../chapter-244/(12 coins) throws with the right price; the previously-failingemoji rows now resolve to their own gated pages (
villain-let-me-touch-you/chapter-176-%F0%9F%94%9E/and
.../chapter-175-%F0%9F%94%9E/) and throw the locked error; free chapters return prose.holy-night-my-husband-is-definitely-a-paladin/chapter-359/is listed as a free row with a real href on the site, but its page is gated
(
premium coin-12 ... content-blocked). With this change it throws the locked error ("costs 12 coins")instead of returning blank/leaking anything.
17 differ only by percent-encoding case, and the single miss is a WordPress duplicate-slug uniquifier
(
chapter-55_1) whose premium equivalent is the documented duplicate-number case below.#wp-manga-current-chap[data-id]== the ajax row'sdata-chapter-<id>. Every row now resolves to itsown gated page except
villain-let-me-touch-you's duplicateChapter 166pair (two rows, one/chapter-166/path; both are locked and show the same notice — the colliding row's own slug isundiscoverable). An offline census of 2486 rows found no free↔premium number collision, so a
premium row cannot surface free prose, and
parseChapterrefuses any page without a chapter body.(
/amp/,/print/,/feed/,/embed/,?amp,?print=1,?feed=rss2,?preview=,?style=,?_format=json,?output=,?ajax=1,?nocache=,?display=full) either return the same gatedpage or a series-page soft-404; oEmbed returns series metadata only;
/wp-json/exposes no chapterroute (
wp/v2has no chapter CPT,wp-manga/v1only has a cache-stats route);/wp-sitemap.xmlandthe
wp-manga-chapters-sitemap{1..8}.xmlfamily list only free chapters (2289 URLs, no premium URL);manga_get_reading_navwith the theme's own params returns all 212 options but every one of the 52premium options carries
data-redirect="#"; chapter pages arecf-cache-status: DYNAMICwithno-store, and crawler user agents get the same gated page (Googlebot: 403). There is no anonymousroute to the locked body, so this PR does not look for one.
Checks run
npm run build:multisrcandnpm run build:compilepass.npm run check:plugin -- 'plugins/english/TangerineArchive[madara].ts'passes (popularNovels 12,searchNovels PASS, parseNovel 173 chapters — the same novel returned 53 before — parseChapter
14497 chars on a free chapter).
includeLockedChaptersis referenced only in the template and thetangerinearchiveentry (git grep), and unrelatednpm run check:plugin -- 'plugins/english/SleepyTranslations[madara].ts'passes all four checks(16 novels / 44 chapters / 9872 chars).
Not tested / not claimed
coins, so this PR does not read it and does not claim to. The listed premium chapters remain
server-gated and now fail loudly instead of returning blank text.
releaseTime: 'LL'for Tangerine's free chapters is a pre-existing shared-template issue(
dayjs().format('LL')withoutlocalizedFormat) and is intentionally left out of scope.Authored with an AI agent, per the repository's commit guidance (
Co-Authored-By: pi <pi@local>).