70 lines
4.6 KiB
Markdown
70 lines
4.6 KiB
Markdown
---
|
||
status: approved
|
||
---
|
||
|
||
# 003 — Tapas source
|
||
|
||
A second source (spec 001 §4.1): covers of a [Tapas](https://tapas.io) series, comics and novels. Design approved
|
||
by the user in chat on 2026-10-15 ("Comics and novels"). Everything else — inspection, dedupe, Wayback history,
|
||
hosting, download, history — is the existing pipeline.
|
||
|
||
## 1. Verified facts (2026-10-15)
|
||
|
||
Checked against *Villains Are Destined to Die* (comic, id 186414) and its novel (id 266599), a mature series
|
||
(id 286112) and Wayback captures since 2020-10. Fixtures in `test/fixtures/tapas/` and `test/fixtures/wayback/tapas-*`.
|
||
|
||
- **Series page:** `https://tapas.io/series/<slug>/info` (its own canonical URL). `/series/<slug>` serves the
|
||
episode reader (canonical `/episode/<id>`). `/series/<id>/info` redirects to the slug form. Slugs may contain
|
||
capitals and underscores (`/series/RU_Screwed`).
|
||
- **Series id:** on the info page `pageMeta : { id: <id>, type: 'series_id' }`; on the reader `seriesId: <id>`.
|
||
- **Comic or novel:** the stats row links `/static-landing/genre?category=COMIC` or `…=NOVEL`. `og:type` is
|
||
`comicpanda:webcomic_series` for both.
|
||
- **Title:** the cover image's `alt` in `.thumb-wrapper`; `og:title` is "Read <title> | Tapas Web Comics".
|
||
- **Images** (`us-a.tapas.io/sa/<xx>/<uuid>[_<size>].<ext>`, no token, no Referer needed):
|
||
- **Portrait cover:** the `<img>` in `.thumb-wrapper` (both the info page and the 2020 reader page),
|
||
`…_z.jpg` = 400×600. Without the suffix: the original, 960×1440.
|
||
- **Banner:** `og:image` (also the `js-top-banner` / `header-layer` background), 1280×460, no suffix.
|
||
- Lists use `_m` (180 px) of other images; `pc/…` images are signed promotions of other series. Neither is used.
|
||
- Older pages use `d30womf5coomej.cloudfront.net/sa/…`; the same paths answer on `us-a.tapas.io`.
|
||
- **Mature series:** without a signed-in, age-verified account, `/series/…/info` redirects to
|
||
`/account/verify-age?from=https://tapas.io/series/<slug>/info`, a page with no series data. The userscript's
|
||
`GM_xmlhttpRequest` sends the user's own tapas.io cookies, so a signed-in adult gets the real page there.
|
||
- **Language:** English only (MangaBaka `en`).
|
||
- **Wayback:** `tapas.io/series/<slug>` captured about monthly since 2020; the prefix also matches
|
||
`<slug>-novel` and other longer slugs.
|
||
|
||
## 2. Behaviour
|
||
|
||
- **Links accepted:** `tapas.io/series/<slug>`, `…/info`, `…/<id>`, `…/<id>/info`, and `tapas.io/episode/<id>`
|
||
(the reader page names its series id). `www.` and `m.` hosts too. Fetched as `https://tapas.io/series/<slug or
|
||
id>/info`; an episode link first fetches the episode page for its series id.
|
||
- **Series:** `externalId` = the numeric id, `title`, `language: "en"`, `canonicalUrl` =
|
||
`https://tapas.io/series/<slug>/info`, `flags.novel`, `archiveUrls` = [`tapas.io/series/<slug>`].
|
||
- **Current covers:** portrait (role `poster`, suffix removed) and banner (role `banner`). The poster is the
|
||
suggested main cover as for Webtoons.
|
||
- **Mature (age check):** the series is resolved from the `from=` link (slug; title from the slug), `mature: true`,
|
||
no current covers, and a warning: Tapas shows this series only to signed-in adults; use the userscript while
|
||
signed in, or tick the Wayback history. History still runs.
|
||
- **Image URLs:** `normalizeImageUrl` maps both image hosts to `us-a.tapas.io`, drops `_<letters>` size suffixes
|
||
after the UUID and any query.
|
||
- **Same series:** a link is the same series when it is a tapas.io `/series/<slug>[/info][/]` with the same slug
|
||
(case-insensitive) or `/series/<id>[/info]` with the same id. This also filters Wayback rows (`-novel`).
|
||
- **Hosts:** fetch `tapas.io`, `www.tapas.io`, `m.tapas.io`, `us-a.tapas.io`, `d30womf5coomej.cloudfront.net`;
|
||
images `us-a.tapas.io`, `d30womf5coomej.cloudfront.net`. The userscript `@connect`s `tapas.io` and the
|
||
CloudFront host.
|
||
- **Chrome:** source-neutral where it named WEBTOON: the link hint ("WEBTOON or Tapas for now"), the
|
||
"No rehosting" warning ("the source's own image URL"), the userscript description.
|
||
|
||
## 3. Testing
|
||
|
||
Unit tests on the captured pages, no network: link parsing (every form, rejects), page parsing (comic, novel,
|
||
reader, 2020 archive, age check), URL normalisation, same-series (slug, id, `-novel` rejected), and the source
|
||
end to end through the fake transport (info page, episode link, age check, `/series/<id>` redirect).
|
||
Then a real run in headless Chrome for one comic and one novel.
|
||
|
||
## 4. Risks
|
||
|
||
- Tapas markup changes; the parser looks for two stable hooks (`thumb-wrapper`, `og:image`) and the page type link.
|
||
- The info page may show a mature badge to signed-in users that we never saw; mature is only known from the
|
||
age check.
|