BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2,或任何藍牙控制器搭配 MyWhoosh、Rouvy、Zwift 等。可於 iOS、Android、Windows 與 macOS 免費試用。
AI 翻譯
Stage-by-stage GC, sprint and KOM analytics for the Tour de France, Giro d'Italia and Vuelta a España, plus 11 one-day monuments and classics and 6 American gravel and MTB races — 1892–2026.
翻譯準備中
運動與健身Python · TypeScriptGitHub @eshiflet上線中營運者未確認
試用過了嗎? 點一下就好,不需要登入。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Stage-by-stage cycling analytics: the Tour de France, Giro d'Italia and Vuelta a España, 11 one-day classics and 7 gravel races — 1892 to 2026, 786,787 results
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Stage-by-stage results for professional road cycling, charted — every edition of the Tour de France, the Giro d'Italia and the Vuelta a España, eleven one-day classics, and seven gravel and mountain-bike races. Every value is traced to a source in data_provenance. DATA_SOURCES.md lists each one — procyclingstats, bikeraceinfo, cyclingflash, Athlinks, sportmaniacs, tretzesports — with its URLs, how to reach it, and what it is and is not good for.檢視完整 README ↗
Stage-by-stage results for professional road cycling, charted — every edition of the Tour de France, the Giro d'Italia and the Vuelta a España, eleven one-day classics, and seven gravel and mountain-bike races.
Live: ericshiflet.com/tdf-analytics
21 races · 1,365 race-years · 1892–2026 · 19,023 riders · 786,870 stage results
Every value is traced to a source in data_provenance. DATA_SOURCES.md lists each one — procyclingstats, bikeraceinfo, cyclingflash, Athlinks, sportmaniacs, tretzesports — with its URLs, how to reach it, and what it is and is not good for.
| path | what it holds |
|---|---|
cycling-app/ | the site: TypeScript, D3, Vite. No framework. Deployed to GitHub Pages. |
cycling-app/src/data/ | exported JSON, one file per race-year — what the site actually loads |
pipeline/ | scrapers, ingest, validators and exporters (Python, standard library only) |
pipeline/*_scrapes/ | raw scraped JSON, tracked in git — the source of truth |
ai-context.md | the long-form record: every defect found, why it happened, what the fix was |
architecture.md | data model, module map, CI/CD flow |
cycling.db is not in git and not regenerable from scratch — some values
in it came from sources that no longer answer. Back it up with
python3 pipeline/db_backup.py.
cd cycling-app && npm install && npm run dev # the site, on :5173
cd pipeline && python3 -m unittest discover -p 'test_*.py'
The pipeline needs no dependencies at all — Python 3 and the standard library. The site needs Node 20.
A typical data change is scrape → ingest → export → validate:
python3 scrape_race.py --race tour 1985 # writes tour_scrapes/1985/
python3 preview_reingest.py --race tour 1985 # what the ingest WOULD change
python3 ingest_race.py --race tour 1985
python3 export_gc.py --race tdf --year 1985
python3 validate_db.py && python3 validate_exports.py
preview_reingest.py is worth the habit: it copies the database, ingests into
the copy and reports the diff, counting fills, overwrites and clears
separately. A rebuild that loses rows is the one to stop for.
Cycling data is wrong in quiet ways. A parser that stops matching returns nothing, which becomes a NULL column and a blank chart rather than an error — so the failures here are silent by default, and most of them look plausible. Some real examples, all fixed:
21:47.870 and the pattern allowed no fraction.ai-context.md records each one with the evidence, because the expensive part
is never the fix — it is working out that anything is wrong.
Results come from procyclingstats.com, with
Wikipedia and bikeraceinfo.com used to cross-check distances and classification
totals. Every stored value carries provenance: data_provenance records the
source and the URL for each field, and unknown is a real answer that means
nobody recorded where a number came from.