docs: spec 004 (KakaoPage source), its plan, and captured KakaoPage fixtures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
80185210ac
commit
899e8a0d54
10 files changed
+255
No files matched your search
@@ -0,0 +1,34 @@
|
||||
# KakaoPage source — implementation plan
|
||||
|
||||
> superpowers:executing-plans (native). **Spec:** [`docs/specs/004-kakaopage.md`](../specs/004-kakaopage.md).
|
||||
|
||||
**Goal:** a `kakaopage` Source registered next to `webtoons` and `tapas`, plus per-host request headers.
|
||||
|
||||
## Global constraints
|
||||
`src/core` pure; tests offline on captured fixtures (done); no new dependencies.
|
||||
|
||||
## Review focus
|
||||
1. `seriesId=N` must not match `N0` in Wayback rows. → Task 1 test, Task 4 history test.
|
||||
2. A series without `land_thumbnail` (19+ edition) → one cover, no crash. → Task 3 test.
|
||||
3. Old `dn-img-page.kakao.com …&filename=th3` URLs normalise to the original. → Task 1 test.
|
||||
4. The Referer reaches `bff-page.kakao.com` through both the server proxy and the userscript. → Task 2 tests.
|
||||
5. An unknown id gives a clear error. → Task 4 test.
|
||||
|
||||
### Task 1: URLs (`kakaopage/urls.ts`)
|
||||
- [ ] Links (`/content/N`, `/home?seriesId=N`, `m.`), rejects; `normalizeImageUrl`; `isSameKakaoSeries`;
|
||||
`overviewUrl(id)`. RED → GREEN → commit.
|
||||
|
||||
### Task 2: Request headers (`core/transport.ts`, `server/app.ts`, `userscript/gm.ts`)
|
||||
- [ ] `requestHeadersFor(url)`; the server proxy and `gmTransport` send it (tests on both). RED → GREEN → commit.
|
||||
|
||||
### Task 3: Parsing (`kakaopage/parse.ts`)
|
||||
- [ ] `parseOverview(json)` (comic, novel, 19+ without land thumbnail, error body); `extractCovers(html, pageUrl)`
|
||||
for 2020/2022/2024 captures. RED → GREEN → commit.
|
||||
|
||||
### Task 4: Source and registry
|
||||
- [ ] `kakaopage` Source through `FakeTransport` (resolve, currentCovers, unknown id, Wayback over both CDX
|
||||
fixtures keeps only this id); registry, allowlists, `@connect`, hint copy; README, ARCHITECTURE, DECISIONS.
|
||||
RED → GREEN → commit.
|
||||
|
||||
### Task 5: Verify and finish
|
||||
- [ ] Real run in headless Chrome; final review; remove this plan; merge; push.
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
status: approved
|
||||
---
|
||||
|
||||
# 004 — KakaoPage source
|
||||
|
||||
A third source (spec 001 §4.1): covers of a [KakaoPage](https://page.kakao.com) series, comics (웹툰) and
|
||||
novels (웹소설). Design approved by the user in chat on 2026-10-15. Kakao Webtoon (`webtoon.kakao.com`) is a
|
||||
different site and out of scope.
|
||||
|
||||
## 1. Verified facts (2026-10-15)
|
||||
|
||||
Checked against *악역의 엔딩은 죽음뿐* (Villains Are Destined to Die; comic 54845189, novel 52654302) and
|
||||
*울프 인더 하우스 [19세 완전판]* (63659962, 19+). Fixtures in `test/fixtures/kakaopage/` and
|
||||
`test/fixtures/wayback/kakaopage-*`.
|
||||
|
||||
- **Pages are rendered in the browser.** `page.kakao.com/content/<id>` is an 11 KB shell with a generic
|
||||
`og:image`; the data comes from
|
||||
`GET https://bff-page.kakao.com/api/gateway/api/v1/content/overview?series_id=<id>`.
|
||||
- **That endpoint needs a `page.kakao.com` Referer (or Origin)**; without one it answers 403. It answers 19+
|
||||
series without a login.
|
||||
- **Its `result.content`:** `series_id`, `title`, `category` (`웹툰` / `웹소설`), `age_grade` (0, 12, 15, 19),
|
||||
`lang` (`ko`), `thumbnail` (portrait key, e.g. 720×1030), `land_thumbnail` (landscape key, 540×370; may be null).
|
||||
An unknown id answers with an error (`상품 정보를 찾을 수 없습니다`, "product not found").
|
||||
- **Images:** `https://page-images.kakaoentcdn.com/download/resource?kid=<key>&filename=o1` is the original
|
||||
(`th2`, `th3` and `/dims/resize/…` are smaller). No Referer needed. Older pages use `dn-img-page.kakao.com` with
|
||||
the same query; old keys answer on the new host.
|
||||
- **Wayback:** `page.kakao.com/home?seriesId=<id>` (the old address, 2020–2022) and `page.kakao.com/content/<id>`
|
||||
(2022 on) are captured server-rendered. Every capture's `og:image` is this series' image (landscape in 2020–22,
|
||||
portrait in 2024). 2020 captures also hold `props.initialState.series.series.thumbnailUrl` and
|
||||
`landThumbnailUrl` in `__NEXT_DATA__`. Other images on the page (`sameSeriesList`, comments) are other series
|
||||
or users.
|
||||
|
||||
## 2. Behaviour
|
||||
|
||||
- **Links:** `page.kakao.com/content/<id>` (with or without a trailing path/query) and
|
||||
`page.kakao.com/home?seriesId=<id>`; `m.` hosts too.
|
||||
- **Series:** from the overview endpoint: `externalId` = id, `title`, `language` = `lang` (`ko`),
|
||||
`canonicalUrl` = `https://page.kakao.com/content/<id>`, `mature` = `age_grade >= 15` (the rating warning),
|
||||
`flags.novel`, `archiveUrls` = [`page.kakao.com/content/<id>`, `page.kakao.com/home?seriesId=<id>`].
|
||||
- **Current covers:** `thumbnail` → role `poster` (the suggested main cover), `land_thumbnail` → role `banner`.
|
||||
- **History:** from a capture: `og:image` (role `other`: portrait or landscape, the shape decides the type) and,
|
||||
when present, the series' own `thumbnailUrl` (`poster`) and `landThumbnailUrl` (`banner`).
|
||||
- **Same series:** a link is the same series when its id (`/content/<id>` or `seriesId=<id>`) equals ours exactly,
|
||||
so `seriesId=548451890` is another series.
|
||||
- **Image URLs:** both hosts → `page-images.kakaoentcdn.com`, `filename=o1`, the `kid` kept, any `/dims/…`
|
||||
dropped.
|
||||
- **Request headers per host:** `requestHeadersFor(url)` in `core/transport.ts` (User-Agent as before, plus
|
||||
`Referer: https://page.kakao.com/` for `bff-page.kakao.com`). The server proxy and the userscript send them.
|
||||
- **Hosts:** fetch `page.kakao.com`, `m.page.kakao.com`, `bff-page.kakao.com`, `page-images.kakaoentcdn.com`,
|
||||
`dn-img-page.kakao.com`; images the last two. The userscript `@connect`s `kakao.com` and `kakaoentcdn.com`.
|
||||
- **Chrome:** the link hint names "WEBTOON, Tapas or KakaoPage".
|
||||
|
||||
## 3. Testing
|
||||
|
||||
Offline unit tests on the captures: link parsing, URL normalisation, same-series, overview parsing (comic,
|
||||
novel, 19+, unknown id), archived pages (2020, 2022, 2024), Wayback rows through both prefixes, request headers.
|
||||
Then a real run in headless Chrome (current covers, then yearly history).
|
||||
|
||||
## 4. Risks
|
||||
|
||||
- The overview endpoint is an internal API: its shape or its Referer check can change.
|
||||
- Sending a `page.kakao.com` Referer is what KakaoPage's own page sends; like the browser User-Agent for
|
||||
Webtoons, it is a browser-like header, not an identity.
|
||||
Reference in new issue
Block a user