Conversation
Tangerine Archive's coin-locked chapters carry href="#" in the chapter
list, so the shared Madara template dropped them and the reader's
prev/next skipped straight over them. Their bodies are server-gated
behind login + coins and stay that way; this change only keeps the
navigation continuous and the outcome honest.
Flag-gated `listLockedChapters` (only tangerinearchive opts in, plus
`hasLocked` for the existing "Hide locked chapters" switch):
- rebuild each locked row's /series/<slug>/chapter-<n>/ URL from the
chapter number in its title, with the non-ASCII slug token when it is
part of the slug ("Chapter 176 🔞" -> chapter-176-%F0%9F%94%9E) and
without a " - title" suffix ("Chapter 242 - 🔞" -> chapter-242);
verified against the real hrefs of 3289 free rows (3271 exact, 17
percent-encoding case only, 1 WordPress `_1` duplicate);
- label locked rows with price and unlock state ("10 coins, TBA" /
"12 coins, 2 weeks") and set releaseTime from the site's countdown
(null for TBA) instead of a backwards-derived past date;
- resolve duplicate derived URLs against the site: keep only the row
whose own data-chapter id is the post that URL serves (villain lnreader#166),
and drop a rebuilt URL that collides with a free chapter, so a listed
locked row can never resolve to different text than its name claims;
- parseChapter returns an honest locked notice (price + countdown/TBA,
named post) instead of blank text, refuses a rebuilt URL that renders
the series page (soft 404), and only treats a page as locked when the
reading body has no prose of its own - so an entitled session's prose
is never masked by the (hidden) gate block;
- a free-labelled row whose page is still gated (holy-night lnreader#359) is
reported from the fetched page, not from the list class.
Verified live, anonymous, read-only (no login, cookies, nonce replay or
purchase): all 20 series, 4073 chapters = 3289 free + 784 locked,
matching the ajax inventory exactly (785 premium rows minus the one
duplicate whose URL is undiscoverable); free -> locked -> free boundary
walks in both directions on garden-of-may, holy-night, in-the-doghouse
and me-the-weakest...; edge cases (emoji slug, " - 🔞" slug, duplicate
lnreader#166, soft 404, hideLocked both ways). check:plugin Tangerine PASS,
unrelated Madara sources (SleepyTranslations, Lovelyblossoms) PASS with
the flag off, eslint/prettier/build:compile/build:multisrc pass.
The locked prose itself was NOT obtained: every credential-free route
(re-checked sitemaps, wp-json index, WP Abilities API, coin plugin
assets, route aliases, series-page render) returns the gate or nothing.
An entitled-session probe is ready and runs one command when an
owner-authorized session exists.
Co-Authored-By: pi (AI agent) <noreply@pi.dev>
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 PR lnreader#2564 (base is that PR's branch
fm/lnreader-plugins-2555-tangerine, not the default branch). Wave-2 replica of thetangerine-premium-nav-continuitylane; it is a fresh implementation on the same base, not a copy of PR 5.Tangerine Archive's coin-locked (premium) chapters carry
href="#", so the Madara template dropped them fromnovel.chaptersand the reader's prev/next jumped straight past them. The bodies are server-gated behind login + coins and stay that way. This change keeps the navigation continuous and the outcome honest.What changed
plugins/multisrc/madara/template.ts- additive, flag-gated; sources without the flag take the old code path:/series/<slug>/chapter-<n>/, with the non-ASCII slug token when it is part of the slug (Chapter 176 🔞->chapter-176-%F0%9F%94%9E) and without a" - title"suffix (Chapter 242 - 🔞->chapter-242). Rule validated against the real hrefs of 3289 free rows: 3271 exact, 17 differ only by percent-encoding case, 1 is a WordPress_1duplicate that is never reconstructed.🔒 Chapter 212 (10 coins, TBA)/🔒 Chapter 161 (10 coins, 1 day);releaseTimecomes from the site's own countdown asYYYY-MM-DD, ornullfor TBA (never a backwards-derived past date, never the literalLL).data-chapter-<id>is the post that URL really serves -villain-let-me-touch-youChapter 166now lists one honest row (Chapter 166 - Secret, id 16700) instead of two rows sharing a lying path. If the lookup fails, the colliding rows are dropped rather than guessed. A rebuilt URL colliding with a free chapter's real href is dropped too (0 today).parseChapterreturns an honest notice instead of blank text for a gated page: coin price from the page'scoin-Nclass, unlock countdown/TBA and the row's own title read from the series chapter list by the page'sdata-id; an explicit "could not be loaded" notice when a rebuilt URL renders the series page (soft 404); and a prose-masking guard - a page is only treated as locked when.reading-contentcarries the gate block and no prose of its own, so an entitled session's prose is never hidden behind the (hidden) gate block.holy-night chapter-359is listedfree-chapwith a real href but its page is gated; it is reported from the fetched page (costs 12 coins, and since its row carriestitle="1 hour ago"with no countdown,The site lists this chapter as released (1 hour ago) but still serves it locked.), not from the list class.plugins/multisrc/madara/sources.json:tangerinearchiveopts in withlistLockedChapters: true,hasLocked: true(the existing "Hide locked chapters" switch) andversionIncrements: 1(plugin 2.2.1).README.mddocuments both options.What was probed (all anonymous, read-only - no login, cookies, nonce replay or purchase)
parseNovelvs an independent fetch of the same ajax endpoint - 4073 chapters = 3289 free + 784 locked, every series matching exactly (785 live premium rows minus the one duplicate whose URL is undiscoverable). 42/42 checks." - 🔞"slug (it-seems 242 -> plainchapter-242, page id 16942), duplicate ReaperScans not showing novels lnreader/lnreader-plugins#166 (one row, page id 16700, notice namesChapter 166 - Secret), fabricated/chapter-9999/-> "could not be loaded",hideLockedboth ways (212/52 off, 160/0 on).wp-manga/v1/cache/stats401,wp/v2/wp-manga-chapter404)./wp-json/wp-abilities/v1/abilities-> 401), coin plugin file inventory (directory 403,readme.txt404, only modal-onlyfrontend.jspublic), route aliases (/manga/,/comics/,/novel/-> 404), series-page server render (one chapter href, newest premium id with no href).npm run check:pluginTangerineArchive PASS (173 chapters, 14497 chars). Shared-template guard:SleepyTranslations[madara]PASS (16/44/9872) andLovelyblossoms[madara]PASS (16/5/15373) with the flag off - identical numbers to the base commit.eslint,prettier,build:compile,build:multisrcpass; no newtscerrors (23 pre-existing repo-wide, unchanged).What was NOT tested
.scratch/entitled-probe.mjs, not committed) runs one command when an owner-authorized session exists and specifically fails if the plugin returns the locked notice while the site serves prose - it is validated in refusal mode (no creds -> exit 2; dummy cookie -> exit 1 "still gated").releaseTime: 'LL'bug for free rows (dayjs().format('LL')withoutlocalizedFormat) is untouched and out of scope.This PR was authored by an AI agent (Firstmate crewmate); the probes above are reproducible from the commands in the commit message and the shared findings board.