Skip to content

fix(madara): list coin-locked Tangerine Archive chapters with an honest locked notice - #5

Closed
RibatTRW wants to merge 1 commit into
fm/lnreader-plugins-2555-tangerinefrom
fm/tangerine-premium-nav-continuity
Closed

RibatTRW wants to merge 1 commit into
fm/lnreader-plugins-2555-tangerinefrom
fm/tangerine-premium-nav-continuity

Conversation

@RibatTRW

@RibatTRW RibatTRW commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Stacked candidate fix for lnreader#2564 (base is that PR's branch fm/lnreader-plugins-2555-tangerine, not the default branch).

Fixes the gap PR 2564 documented: premium (coin-locked) chapters were left out of the chapter list. They now appear, marked as locked, and opening one gives an honest locked notice instead of a blank chapter - so reader prev/next steps through them instead of skipping them.

What changed

plugins/multisrc/madara/template.ts (additive and flag-gated; other Madara sources take the old code path unchanged):

  • New listLockedChapters option in MadaraOptions.

  • parseNovel: locked rows (premium-block, href="#") are kept. Their canonical /series/<slug>/chapter-<n>/ URL is rebuilt from the row's chapter number (Chapter 175 -> chapter-175/, dots become dashes, Chapter 176 🔞 -> chapter-176-🔞 when a non-ASCII token is part of the slug), the existing 🔒 prefix is kept, and chapterNumber/order stay aligned with the full live inventory. The non-ASCII rule was checked against the real hrefs of 1036 free rows on the live site (1035 exact, the single miss being a duplicate title that has a real href and is never reconstructed).

  • Locked rows' releaseTime comes from the site's own unlock countdown: "Unlocked in 4 weeks" becomes the future date it names (as YYYY-MM-DD); "TBA" claims no date. The template's parseData would have subtracted instead and reported a date in the past.

  • New parseChapter helper parseLockedChapter: when the fetched page contains .reading-content .content-blocked, it returns e.g.

    🔒 This chapter is locked on Tangerine Archive.
    It costs 10 coins to unlock.
    Unlocked in 4 weeks.
    

    Price is read from the block's coin-<N> class; the countdown is read from the series chapter-list ajax (the only place the site renders it) by chapter id, with a price-only fallback if that lookup fails.

  • A derived URL can land on the series page when the real slug is not chapter-<n> (peer-verified cases: emoji-suffixed titles, duplicate chapter numbers). Those rows now return an explicit "could not be loaded" notice instead of coming back empty.

plugins/multisrc/madara/sources.json + plugins/multisrc/madara/README.md: tangerinearchive opts in with listLockedChapters, the existing hasLocked setting (so users can hide locked chapters again), and versionIncrements: 1 (version 2.2.1).

Chapter name metadata in the list is deliberately unchanged beyond the existing 🔒 marker.

What was probed (anonymous, read-only; no cookies, no login, no purchase, no bypass)

  • POST /series/<slug>/ajax/chapters/ is the full inventory in one response; premium rows are li.premium.coin-N.data-chapter-<id>.premium-block with href="#" and a countdown or TBA. Built the URL rule from the row's visible number and verified derived URLs against the row's data-chapter-<id> (#wp-manga-current-chap data-id on the fetched page) across 5 series.
  • Premium pages answer 200 with .reading-content .content-blocked and no body; free pages have real prose (~6.4k-10.5k chars) and zero content-blocked. Countdown is absent from the chapter page, present only in the list.
  • Verified free -> locked -> free walks live in both directions, e.g. 159 -> 160 -> 161 -> 162 -> 161 -> 160 (garden-of-may) and 51 -> 52 -> 53 -> 54 -> 53 -> 52 (i-thought-i-was-the-monster-dukes-fake-tranquilizer): free chapters return prose, locked ones return the notice.
  • Plugin chapter counts now equal the live ajax inventory: garden-of-may 212 (160 free + 52 locked), i-thought... 173 (53 + 120), me-the-weakest... 198 (148 + 50). Before the change the plugin returned only the free counts.
  • Edge cases verified live: the emoji-suffixed premium rows Chapter 175 🔞 / Chapter 176 🔞 now reconstruct to /chapter-175-%F0%9F%94%9E/ and /chapter-176-%F0%9F%94%9E/, whose pages carry the row's own data-id (16719 / 16720) and return the locked notice; Chapter 242 - 🔞 stays plain /chapter-242/ (a dash makes the emoji a title, not a slug token); a deliberately wrong path (/chapter-176/) returns the "could not be loaded" notice instead of a blank chapter; the duplicate Chapter 166 row returns a locked notice, never free prose.
  • hideLocked verified both ways with a stubbed storage: off -> 212 chapters / 52 locked, on -> 160 chapters / 0 locked.

Validation

  • npm run build:multisrc and npm run build:compile pass.
  • npm run check:plugin -- 'plugins/english/TangerineArchive[madara].ts' passes all four steps (popularNovels 12, searchNovels pass, parseNovel 173 chapters, parseChapter 14497 chars).
  • Custom plugin-level probe: 54/54 checks pass (counts, derived URLs, notices, release times, both-direction walks); edge-case probe 6/6.
  • Shared-template guard: SleepyTranslations[madara] passes all four checks identically on base and head. ZetroTranslation[madara] popularNovels fails on the base commit too (dead site), and BoxNovel/NovelNice/LunarLetters/WooksTeahouse are site-level unreachable - none caused by this change.
  • prettier --check and eslint on the changed file pass (repo-wide eslint has pre-existing errors in untouched files).

Not tested

  • No entitled-session test. Nothing here attempts to bypass, purchase, or log in around the coin-lock: locked bodies are server-gated and the plugin only reports that they are locked. The unlock flow was not exercised with a registered account or coins, so the notice is verified as an honest locked state, not as a post-unlock read.
  • Reader-app rendering of the notice (verified at plugin API level only).
  • The site's own countdown rounding: the list's unlock date is derived from "Unlocked in N ..." and can differ from the exact unlock time by up to a day or two.

Related: lnreader#2564, lnreader#2555

@RibatTRW
RibatTRW force-pushed the fm/tangerine-premium-nav-continuity branch from 65aa49c to 8ae4d84 Compare September 23, 2026 12:01
Tangerine Archive's coin-locked (premium) chapters have href="#" in the
chapter list, so the Madara template dropped them from novel.chapters and
the reader's prev/next jumped straight past them. Their bodies are
server-gated behind login + coins, so they cannot be read anonymously.

Add a flag-gated `listLockedChapters` source option (only tangerinearchive
opts in) that:
- keeps locked rows in the list, rebuilding their canonical
  /series/<slug>/chapter-<n>/ URL from the row's chapter number, including
  the slug token when a non-ASCII suffix is part of it ("Chapter 176 🔞" ->
  chapter-176-🔞, verified against the real hrefs of 1036 free rows);
- derives locked rows' unlock date from the site's "Unlocked in N ..."
  countdown and claims none for "TBA", instead of parseData's backwards
  subtraction reporting a past date;
- returns an honest locked notice from parseChapter (price from the page's
  coin-N class, unlock countdown read from the series chapter list) instead
  of blank text, plus an explicit "could not be loaded" notice when a
  derived URL lands on the series page (duplicate chapter numbers).

Tangerine Archive also gets the existing "Hide locked chapters" setting
(`hasLocked`) and a version bump to 2.2.1. Sources without the flag keep
the previous code path unchanged.

Co-Authored-By: firstmate-crewmate <crewmate@firstmate.local>
@RibatTRW
RibatTRW force-pushed the fm/tangerine-premium-nav-continuity branch from 8ae4d84 to e1e4477 Compare September 23, 2026 12:04
@RibatTRW RibatTRW closed this Sep 23, 2026
@RibatTRW
RibatTRW deleted the fm/tangerine-premium-nav-continuity branch September 24, 2026 01:06
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.

1 participant