Conversation
Tangerine Archive lists its coin-locked (premium) chapters with href="#" and replaces the chapter body with a "This chapter is locked!" block, so the source dropped them from the chapter list entirely and their URLs returned an empty chapter. Add an opt-in lockedChapterPlaceholder option to the Madara template and enable it for tangerinearchive: - locked rows whose title is exactly "Chapter <n>" get a URL rebuilt from the pattern the free rows of the same list use, instead of href="#"; - parseChapter recognises a gated body (content-blocked/premium-block in .reading-content) and returns a readable lock notice with the chapter title, the coin price and the unlock countdown/TBA from the chapter list, instead of blank text. No story prose is ever synthesized and the coin-lock is never bypassed; sources without the flag keep the previous behaviour. Co-Authored-By: pi crewmate (AI agent) <crewmate@firstmate.local>
Follow-ups from a fleet-wide probe of Tangerine Archive's locked rows:
- Slug the row title the way the site does (leading number, dots become
dashes, and a non-ASCII token glued straight onto the number stays in
the slug, e.g. "Chapter 176 🔞" -> chapter-176-%F0%9F%94%9E), instead
of only accepting titles that are exactly "Chapter <n>". Measured
against the real hrefs of 1509 free rows: 1508 exact, the single miss
being a WordPress duplicate-slug "_1" that no rule can predict. This
lists the 12 premium rows with title suffixes/subtitles and the two
emoji-suffixed rows that were previously skipped.
- Never return a blank chapter: when the fetched page has no chapter body
at all (a derived URL that falls back to the series page) return an
explicit "page could not be found" notice.
- releaseTime is null for locked rows: their date span holds the unlock
state ("Unlocked in 4 weeks" / "TBA"), which the app renders as
"Invalid Date" if passed through as a release date.
- Never mask real prose: the lock notice now also requires the readable
body to be empty, so an entitled session (or a chapter whose window
just ended) keeps its real text even though the coin block is still in
the markup.
Co-Authored-By: pi crewmate (AI agent) <crewmate@firstmate.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 on lnreader#2564 (
fm/lnreader-plugins-2555-tangerine) — this closes the one gap that PR documents: premium (coin-locked) chapters were dropped from the chapter list because their rows link tohref="#", and their URLs returned an empty chapter.What changed
Two files, additive and flag-gated:
plugins/multisrc/madara/sources.json— thetangerinearchiveentry gainslockedChapterPlaceholder: true,hasLocked: true(exposes the template's existing "Hide locked chapters" switch) andversionIncrements: 1(plugin version 2.2.1).plugins/multisrc/madara/template.ts— new opt-inlockedChapterPlaceholderoption:#, built from the row title on the same URL base the list's free rows use. The title is slugged the way the site does: leading number, dots become dashes, and a non-ASCII token glued straight onto the number stays in the slug (Chapter 176 🔞→chapter-176-%F0%9F%94%9E), while a- Subtitlesuffix is dropped (Chapter 434 - (Special Side Story End)→chapter-434).releaseTimeisnullfor locked rows — their date span holds the unlock state (Unlocked in 4 weeks/TBA), which the app renders as "Invalid Date".parseChapterreturns a labelled notice instead of blank text in the two cases where there is no body to show:.reading-content .content-blocked/.premium-block) → chapter title,Premium chapter - locked behind <N> coins., and the unlock countdown orTBAfrom the series chapter list;The notice is only used when the readable body is empty, so an entitled session — or a chapter whose early-access window just ended — always keeps its real prose even though the coin block is still in the markup.
Why the URL is derived from the title, not the row position
The template's
chapterNumberistotalChapters - index, which is wrong for at least one Tangerine series:i-thought-i-was-the-monster-dukes-fake-tranquilizerhas 173 rows titledChapter 0 - Prologue…Chapter 172, so every position-derived URL is off by one —/chapter-173/is a soft 404 (HTTP 200, series page, no lock marker), while/chapter-172/is the real page.What was probed (anonymous, read-only, no login, no purchase)
POST /series/<slug>/ajax/chapters/: locked rows carrydata-chapter-<id>,span.coin= 10 andspan.chapter-release-date=TBAorUnlocked in N days/weeks; the locked chapter page is HTTP 200 with.reading-content > div.premium.coin-10.content-blocked.premium-blockholding onlyThis chapter is locked!, while free pages have.reading-content > .text-leftwith prose._1that no rule can predict. The rule also resolves all 28 non-exact premium titles:- Subtitlesuffixes are dropped and a glued non-ASCII token stays in the slug.npm run build:compile,npm run build:multisrcandnpm run check:pluginon the generated plugin all pass (Tangerine: 173 chapters, parseChapter 14497 chars).eslintandprettier --checkare clean on both changed files; the 3 lint errors and 10 format warnings elsewhere in the repo are pre-existing in untouched files.Locked-row verification (live, plugin-level)
Counts match the live lists exactly and paths are unique except one known site-side collision:
chapter-21-%f0%9f%94%9elisted; one duplicate-number collision (below)parseChapter: garden locked 212 → notice withTBA; locked 169 → notice withUnlocked in 4 weeks; free 160 → 6538 chars of prose; villain free 144 → 7859 chars; villain emoji slug → lock notice; villain/chapter-176/(soft-404 slug) → "page could not be found" notice instead of a blank chapter. Read-time detection also covers rows the list labels free but the site serves gated:holy-night-my-husband-is-definitely-a-paladin/chapter-359/is list-marked free with a real href, yet returns the lock notice ("locked behind 12 coins") whilechapter-358/returns 6827 chars of prose.Known site-side collision:
villain-let-me-touch-youhas two locked rows,Chapter 166andChapter 166 - Secret, which both slug tochapter-166; the site serves post id 16700 there. I checkedchapter-166_1andchapter-166-2— neither exists, so the second post is not reachable by any predictable slug. Both rows stay listed and the notice names the site's own chapter at that address rather than guessing.Regression guard for other Madara sources
CitrusAurora, DuskBlossoms, TranslatinOtaku and SonicMTL all still pass
check:pluginwith this template change. ZetroTranslation'spopularNovelsFAIL reproduces identically on the base commitf2f3e4a, so it is pre-existing.What was NOT tested
_format/output/raw/preview/style variants, RSS/Atom/RDF feeds, oEmbed,wp-json+wp-manga/v1+rest_route, the sitemap family, header/cache variants, and the wholeadmin-ajaxaction family taken from the site's own JS bundles) found no route that returns a locked body — every >200-char "hit" was a soft-404 fallback to the series page or an unrelated site feed. So the lock really is entitlement-only; there is nothing to parse around.Unlocked in 4 weeksflips on schedule). The template picks a chapter up as free as soon as the site serves it with a real href.