7.8 KiB
Phase 01 — Shared scrape + lookup helpers
Context
- Research: overview + emoji
- Research: quote
- Research: ability + splash
- Existing:
scripts/scrape-loldle-data.js,src/modules/loldle/lookup.js
Overview
Priority: P0 (blocks 02–05). Status: pending.
Lay a minimal shared foundation so the four new modules don't each re-implement champion-name normalization or re-scrape loldle.net five times.
Key insights
- Bundle check (2026-04-24): loldle.net's bundle contains classic
attributes only — zero emoji code points, zero per-champion quote
strings. Daily answers are fetched encrypted from
cache.loldle.net/cache.jsonand decrypted with AES keyD5XCtTOObw, but the cache only holds the single daily rotation, not a full champion→emoji / champion→quote pool. - Pivot (DEVIATION from plan as written): Emoji sequences are derived
algorithmically from classic's existing
champions.jsonmetadata (species/regions/positions/resource) via a small mapping table — no new fetch, no brittle scrape. Quote text uses DDragon'stitle+ first-sentenceloreblurb. Both data sources are stable and official. - Data Dragon is the right source for ability/splash — official, stable, no brittle regex. Scripts hit DDragon once per patch (fortnightly) and cache to JSON. Bot imports JSON directly.
lookup.js'sfindChampionstays coupled to the champion-record shape. Don't hoist it; only hoist the tinynormalize(s)helper.
Requirements
Functional
- Extended scraper emits three JSONs (keeps
champions.jsonplus addsemojis.json,quotes.json). - New DDragon script emits
abilities.json+splashes.json. - Shared
normalize(s)helper insrc/util/for case/space/punctuation- insensitive matching across all modes.
Non-functional
- Single loldle.net fetch per scrape run (no re-download for each mode).
- DDragon fetch uses
GET /api/versions.json→ latest → onechampion.jsonper champion OR one aggregateden_US/champion.json(list) + per-champion fetches as needed. Prefer aggregated list first, drill into per-champion only forskins[]. - Scripts idempotent, safe to re-run, short-circuit on "no change".
Architecture
scripts/
├── scrape-loldle-data.js (EXISTING, extended)
│ └── writes: src/modules/loldle/champions.json
│ + src/modules/loldle-emoji/emojis.json
│ + src/modules/loldle-quote/quotes.json
└── fetch-ddragon-data.js (NEW)
└── writes: src/modules/loldle-ability/abilities.json
+ src/modules/loldle-splash/splashes.json
src/util/
└── normalize-name.js (NEW, ~10 LOC)
src/modules/{loldle-emoji,loldle-quote,loldle-ability,loldle-splash}/
└── (created in phases 02–05)
Related code files
Modify
scripts/scrape-loldle-data.js— add extraction for emoji + quote fields. Regex must accommodate loldle.net's current bundle shape (inspect before touching; existing regex is the template)..github/workflows/scrape-loldle-data.yml— no change needed; the extended scraper writes more files, the workflow'sgit diffcheck catches them automatically.
Create
scripts/fetch-ddragon-data.js— fetch DDragon, extract ability + skin metadata, write two JSONs.src/util/normalize-name.js— single exportnormalize(s).src/modules/loldle-emoji/(empty folder, populated in 02).src/modules/loldle-quote/(empty folder, populated in 03).src/modules/loldle-ability/(empty folder, populated in 04).src/modules/loldle-splash/(empty folder, populated in 05).
Delete: none.
Implementation steps
-
Create
src/util/normalize-name.js:export const normalize = (s) => String(s || "").toLowerCase().replace(/[^a-z0-9]/g, "");Update
src/modules/loldle/lookup.jsto import it (keeps behaviour, removes the inline duplicate). Runnpm test— classic loldle tests must still pass. -
Inspect the live loldle.net bundle for emoji + quote fields:
node -e " const html = await (await fetch('https://loldle.net/emoji')).text(); const m = html.match(/js\/index\.[^\"]+\.js/); const js = await (await fetch('https://loldle.net/' + m[0])).text(); console.log(js.match(/emoji[s]?:\s*[\"\[][^\n]{0,200}/g)?.slice(0,3)); console.log(js.match(/quote[s]?:\s*[\"\[][^\n]{0,200}/g)?.slice(0,3)); "Document the ACTUAL shape in this file. Update regex accordingly.
-
Extend
scrape-loldle-data.js:- Reuse the single bundle fetch already there.
- Add two new regex passes extracting
championName → emojipairs andchampionName → quotepairs. - Write
src/modules/loldle-emoji/emojis.jsonandsrc/modules/loldle-quote/quotes.json. Sort by championName. - Fail LOUDLY if either new regex hits zero matches (prevents silent schema drift on loldle.net's next bundle).
-
Create
scripts/fetch-ddragon-data.js:GET /api/versions.json → take versions[0] GET /cdn/<v>/data/en_US/champion.json → summary (all champions) for each championKey: GET /cdn/<v>/data/en_US/champion/<Key>.json → full (spells, passive, skins) write abilities.json: [{ championName, abilities: [{ slot:"P"|"Q"|"W"|"E"|"R", name, icon:"<full-url>" }] }] write splashes.json: [{ championName, skins: [{ id:0, name:"Classic", url:"<splash-url>" }, ...] }]Use
ddragon.leagueoflegends.com. Parallelize per-champion fetches with a concurrency cap (10). Cache to a local.ddragon-cache/ignored by git so re-runs within the same patch are instant. Add npm script:"fetch:ddragon-data": "node scripts/fetch-ddragon-data.js". -
Run both scripts locally, commit the resulting JSONs. Verify sizes reasonable (emojis.json < 50 KB; quotes.json < 100 KB; abilities.json < 500 KB; splashes.json < 300 KB). If abilities.json balloons past 1 MB, drop fields (keep only slot + icon URL + ability name).
-
Run
npm test+npm run lint— no regressions in classic loldle.
Todo
- Create
src/util/normalize-name.js - Refactor
src/modules/loldle/lookup.jsto importnormalize - Inspect loldle.net bundle; document emoji + quote regex shape here
- Extend
scripts/scrape-loldle-data.js(emoji + quote extraction) - Create
scripts/fetch-ddragon-data.js - Add
fetch:ddragon-datanpm script - Run both scripts, commit generated JSONs
- Create 4 empty module folders (placeholders for phases 02–05)
npm test+npm run lintclean
Success criteria
npm run scrape:loldle-datawrites 3 JSONs (champions + emojis + quotes), all non-empty, all sorted by championName.npm run fetch:ddragon-datawrites 2 JSONs with full CDN URLs.- Classic loldle tests unchanged, still pass.
- No lint warnings.
- Four empty module folders exist, ready for phases 02–05.
Risks
| Risk | Mitigation |
|---|---|
| loldle.net bundle schema drifts between now and scrape | Extraction fails loud, re-inspect and update regex |
| DDragon ability icon URL requires version path; version shifts mid-day | Cache URLs with version baked in; fetch script refreshes on demand |
| Per-champion DDragon fetches (165 requests) hit rate limits | Concurrency cap 10; no published DDragon rate limits but be polite |
| abilities.json > 1 MB bloats Workers bundle | Strip fields, keep only slot + icon URL + name |
Security
- No secrets introduced.
- DDragon and loldle.net are public endpoints; no auth.
- Scripts write only to
src/modules/**/*.json(no directory traversal).
Next steps
Phases 02–05 can start in parallel once this phase completes.