# pokemon-radar-api 把 twpkinfo.com 的寶可夢雷達資料包成 Redis-backed 的 HTTP API,給前端 / n8n 呼叫。 - 上手操作:`QUICKSTART.md` - 設計脈絡與演進:`SUMMARY.md` - Claude Code 指引:`CLAUDE.md` 本檔為參考手冊:組件一覽、指令、環境變數、HTTP API、Redis schema。 --- ## 組件 | 檔案 | 角色 | |---|---| | `radar_fetcher.py` | **現行 fetcher**:呼叫 Function Server 抓資料 → 篩選 → 寫入 Redis(`SETEX`,預設 TTL 300s) | | `pokemon_radar_api.py` | **FastAPI 服務**(`:8008`):`/ping`、`/scan`;從 Redis 讀取,依 request 參數即時二次篩選 | | `twpk_radar.mjs` | Function Server 上跑的 Puppeteer worker,負責開瀏覽器拉 `twpkinfo.com/ipoke.aspx` 的資料 | | `pokemon_location_fetcher.py` | **舊版 CLI**:直接呼叫 Function Server,輸出本地 `pokemon_data.{json,csv}` + `screenshot.png`。API 仍重用它的 `PokemonRadarClient.postprocess` 做二次篩選 | | `pokemon_radar_example.py` | 舊 CLI 的 Python 範例程式(非 CLI argparse 介面) | | `reader.py` | 從 Redis 讀取並用 `rich` 表格顯示目前快取內容 | | `check_redis.py` | 從 Redis 讀取並 dump 原始 JSON | | `fetch_and_upload.sh` | 生產環境 cron:以 `flock` 鎖定,呼叫**舊 CLI**產 `pokemon_data.json` 後 `scp` 到 `192.168.42.104:/opt/caddy/www/pokemon/spots.json` | | `run_pokemon_radar_api.sh` | 啟動 FastAPI(`uvicorn`,port 8008)的 shell 腳本 | | `state.json` | twpkinfo.com 登入後的 cookies / localStorage / UA / langs 快照,注入到 MJS 繞人機驗證 | | `logging.ini` | uvicorn 的 logging 設定 | ## 執行指令 全部以 `uv` 跑(Python 3.12,見 `.python-version`、`pyproject.toml`)。 | 目的 | 指令 | |---|---| | 啟動 API | `./run_pokemon_radar_api.sh`(= `uv run uvicorn pokemon_radar_api:app --host 0.0.0.0 --port 8008 --log-config logging.ini`) | | 跑 fetcher(寫入 Redis) | `uv run python radar_fetcher.py` | | 跑舊 CLI(輸出本地檔案) | `uv run python pokemon_location_fetcher.py --script twpk_radar.mjs --lat 25.0478 --lng 121.5170 --zoom 16 --state state.json --ua-from-state --min-remaining 300 --min-iv 90` | | 查 Redis 內容(表格) | `uv run python reader.py` | | 查 Redis 內容(raw JSON) | `uv run python check_redis.py` | | 生產排程(含 scp 上傳) | `./fetch_and_upload.sh` | 本專案沒有 test / lint / build 流程。 ## 環境變數(`.env`) | 變數 | 預設 | 誰用 | 說明 | |---|---|---|---| | `FUNCTION_URL` | `http://192.168.42.124:13000/function` | `radar_fetcher` | Function Server endpoint | | `FUNCTION_TOKEN` | (必填) | `radar_fetcher` | 未設會直接 `raise` | | `SCRIPT_PATH` | `twpk_radar.mjs` | `radar_fetcher` | JS worker 檔名 | | `STATE_PATH` | `state.json` | `radar_fetcher` | 登入狀態快照路徑 | | `UA_FROM_STATE` | `true` | `radar_fetcher` | 是否從 state 帶 UA / langs | | `RADAR_LAT` / `RADAR_LNG` | `25.0478` / `121.5170` | `radar_fetcher` | 掃描中心座標 | | `RADAR_ZOOM` | `11` | `radar_fetcher` | 地圖縮放 | | `RADAR_SHOT` | `false` | `radar_fetcher` | 是否擷取畫面(base64) | | `MIN_REMAINING` | `300` | `radar_fetcher` | 剩餘秒數門檻 | | `MIN_IV` | 空 | `radar_fetcher` | IV% 下限 | | `PERFECT_ONLY` | `false` | `radar_fetcher` | 只保留 100% IV | | `SPECIES` | 空 | `radar_fetcher` | 逗號分隔的 dex id 或名稱關鍵字(例:`133,伊布`) | | `HTTP_TIMEOUT` | `160` | `radar_fetcher` | 呼叫 Function Server 的 HTTP timeout(秒) | | `REDIS_HOST` | `localhost`(fetcher)/ `192.168.42.211`(API、reader) | 全部 | 注意兩邊預設不同,統一在 `.env` 指定 | | `REDIS_PORT` | `6379` | 全部 | | | `REDIS_DB` | `0` | 全部 | | | `REDIS_PASSWORD` | 空 | 全部 | 空字串視為無密碼 | | `REDIS_TTL` | `300` | `radar_fetcher` | 寫入 TTL | | `REDIS_KEY` | `pokemon:radar:latest` | 全部 | | ## HTTP API ### `GET /ping` ``` 200 → {"status":"ok","backend":"redis"} ``` ### `POST /scan` 從 Redis 讀取目前快取,依 body 篩選後回傳。**永遠回 200**,Redis 連不上或空資料都回空陣列,不會 500。 **Request body** | 欄位 | 型別 | 說明 | |---|---|---| | `lat`, `lng`, `zoom`, `shot`, `state_path`, `ua_from_state`, `save_files` | — | 相容性欄位,Redis 模式下**忽略** | | `min_remaining` | `int ≥ 0` | 剩餘秒數下限 | | `min_iv` | `int 0-100` | IV% 下限 | | `perfect_only` | `bool` | 只保留 100% IV | | `species` | `str` | 逗號分隔 dex id 或名稱關鍵字 | **Response** | 欄位 | 說明 | |---|---| | `source` | `"redis"` / `"redis (empty)"` / `"redis (unreachable)"` | | `ttl` | Redis key 剩餘秒數 | | `count_raw` | Redis 內筆數 | | `count_filtered` | 經 request 參數篩選後筆數 | | `items` | 物件陣列,見下 | | `debug` | 含 `notes`(MJS 輸出)、`redis_ttl`、`note`(錯誤訊息) | **`items[]` 欄位** `id / name / gender / remaining / expire_time / expire_at / latitude / longitude / iv_pct / iv_atk / iv_def / iv_sta / cp / level / is_perfect / fast_move / charge_move` ## Redis schema | 項目 | 值 | |---|---| | Key | `pokemon:radar:latest` | | 型別 | String(JSON) | | TTL | `REDIS_TTL`(預設 300s) | | Writer | `radar_fetcher.py` | | Readers | `pokemon_radar_api.py`、`reader.py`、`check_redis.py` | **Value 結構** ```json { "source": "fetcher", "generated_at": "2026-04-20T09:06:36+08:00", "count_raw": 120, "count_filtered": 79, "items": [ /* 同上方 items[] */ ], "debug": { "notes": ["..."], "api_source": "Fresh from Function Server" } } ```