Terminal split-flap (Solari) departure board for JR / Tokyo Metro / Toei lines.
Project description
🚉 JR / Tokyo Metro Split-Flap Board
終端機裡的 JR/東京地鐵 翻牌式(split-flap / Solari board)時刻表站牌模擬器。
每次刷新會先像老火車站、航站樓的機械翻牌那樣亂數翻滾,再逐格鎖定成真實的到站資訊。 20 條路線、資料驅動、可接 ODPT 即時資料,並提供可嵌入 Claude Code 狀態列的單行跑馬燈模式。
+----------------------------------------------------------+
| JY 山手線 Yamanote Line |
| JY 17 新 宿 |
| しんじゅく Shinjuku |
| ◀ 新大久保 ■ 代々木 ▶ |
| < Shin-Okubo Shinjuku Yoyogi > |
+----------------------------------------------------------+
| 時刻 | 種別 | 行先 (方面) | 番線 |
|----------------------------------------------------------|
| 15:45 | 各駅停車 | 品川・渋谷方面 | 1 |
| 15:45 | 各駅停車 | 上野・池袋方面 | 2 |
| 15:50 | 各駅停車 | 品川・渋谷方面 | 1 |
| ... | ... | ... | ... |
|----------------------------------------------------------|
| Yamanote Line src: STATIC |
+----------------------------------------------------------+
終端機實際輸出帶有各線的官方代表色(山手線綠、銀座線橘、丸ノ内線紅⋯⋯)。
✨ 功能
- 真實資料:可接 ODPT(公共交通開放資料平台)即時時刻表;未設定金鑰時自動回退到內建的真實靜態時刻表。站牌右下角誠實標示資料來源
src: ODPT/src: STATIC。 - 20 條路線可切換,全部資料驅動(見下方路線表)。
- 翻牌動畫:經典 split-flap / Solari board 效果,速度可調。
- 單行跑馬燈模式:站名釘住、班次捲動,可嵌入 Claude Code 狀態列。
- CJK 對齊:以
east_asian_width處理日文全形字佔 2 格的問題,每行精準對齊到固定視覺寬度。
🚀 快速開始
# (選用)只有要接 ODPT 即時資料時才需要
pip install requests
# 列出全部 20 條路線與站點
python3 main.py --list
# 全站牌 + 翻牌動畫(預設山手線新宿,每 10 秒刷新;Ctrl-C 結束)
python3 main.py
--station 接受英文名、站號或站 id,大小寫不拘(例:--station shinjuku、--station 17、--station JY17)。
# 指定路線/站點,渲染一次就結束
python3 main.py --once --line ginza --station ginza
python3 main.py --once --line keihintohoku --station tokyo --no-flap
# 翻牌速度微調
python3 main.py --line yamanote --station shinjuku --flap-delay 0.15 # 更慢、更機械感
python3 main.py --line yamanote --station shinjuku --flap-steps 8 # 更少格、更俐落
# 單行跑馬燈
python3 main.py --mode statusline --line oedo --station tochomae --columns 70
python3 main.py --mode statusline --line marunouchi --station tokyo --columns 70 --scroll-all
🧩 更多模式:TUI、番茄鐘、通勤守門員、行事曆
除了站牌與跑馬燈,同一支 CLI 還提供四種附加模式(所有舊旗標行為不變,這些都是選用)。
# 互動式 curses 瀏覽器:左邊是「依城市分組」的路線清單(各線官方色,
# j/k 移動、/ 模糊搜尋、h/l 切換站點、f 收藏、q 離開),右邊是即時彩色站牌
# (切換線/站時會播翻牌動畫)
python3 main.py --tui
# 番茄鐘=一趟電車旅程:把專注計時畫成從起點到終點的乘車。會在路線上
# 自動挑兩站(或用 --from/--to 指定),先播翻牌動畫,之後每秒重繪,
# 直到「とうちゃく」(抵達)。
python3 main.py --pomodoro 25 --line yamanote
python3 main.py --pomodoro 25 --line yamanote --from shinjuku --to tokyo
python3 main.py --pomodoro 1 --line yamanote --once # 只畫一格就結束
# 通勤守門員:「我幾點要出門才趕得上下一班車?」需要在設定檔填
# [commute] home/work(見下)。早上 → 家→公司,下午/晚上 → 公司→家。
python3 main.py --commute # 完整站牌
python3 main.py --commute --mode statusline # 精簡單行
# 行事曆來源:用本機 .ics 檔當作發車來源(標籤 AGENDA),把接下來的
# 會議當成電車顯示,而非時刻表。
python3 main.py --feed-ics ~/cal.ics --once
python3 main.py --feed-ics ~/cal.ics --mode statusline --columns 70
設定檔
設定讀自 ~/.config/jrboard/config.toml(會尊重 XDG_CONFIG_HOME)。檔案缺失或格式錯誤會直接忽略——一律套用預設值,而 CLI 旗標永遠覆寫設定檔。
[board]
line = "oedo"
station = "tochomae"
columns = 50
width = 60
flap_steps = 22
flap_delay = 0.08
[commute]
home = ["yamanote", "shinjuku"]
work = ["yamanote", "tokyo"]
leave_buffer_min = 7 # 走到車站的緩衝分鐘數
在 TUI 中切換的收藏會存到 ~/.config/jrboard/favorites.txt(每行一組 line_key,station_key)。
安裝/進入點
pip install -e . # 安裝 `jrboard` 命令列腳本
jrboard --list # 與 `python3 main.py` 相同的 CLI
jrboard --tui
🚇 路線一覽(20 條)
| 代碼 | --line key |
路線 | 站數 | 範例站 |
|---|---|---|---|---|
| JY | yamanote |
山手線(環狀) | 30 | shinjuku |
| JC | chuo |
中央線快速 | 24 | tokyo |
| JB | sobu |
中央・総武線各駅停車 | 39 | akihabara |
| JK | keihintohoku |
京浜東北・根岸線 | 47 | tokyo |
| JA | saikyo |
埼京線 | 19 | osaki |
| JS | shonanshinjuku |
湘南新宿ライン | 19 | shinjuku |
| JO | yokosuka |
横須賀線 | 19 | yokohama |
| G | ginza |
東京メトロ銀座線 | 19 | ginza |
| M | marunouchi |
東京メトロ丸ノ内線 | 25 | tokyo |
| H | hibiya |
東京メトロ日比谷線 | 22 | naka-meguro |
| T | tozai |
東京メトロ東西線 | 23 | otemachi |
| C | chiyoda |
東京メトロ千代田線 | 19 | yoyogi-uehara |
| Y | yurakucho |
東京メトロ有楽町線 | 24 | wakoshi |
| Z | hanzomon |
東京メトロ半蔵門線 | 14 | shibuya |
| N | namboku |
東京メトロ南北線 | 19 | meguro |
| F | fukutoshin |
東京メトロ副都心線 | 16 | wakoshi |
| A | asakusa |
都営浅草線 | 20 | asakusa |
| I | mita |
都営三田線 | 27 | meguro |
| S | shinjuku |
都営新宿線 | 21 | shinjuku |
| E | oedo |
都営大江戸線 | 39 | tochomae |
--line shinjuku指的是都營新宿線(地鐵);JR 線各有獨立 key(chuo/sobu/…)。
🌏 其他城市(京都/大阪/札幌/小樽)
用 --city 篩選城市:python3 main.py --list --city Osaka;--rotate --city Osaka 只在大阪境內隨機巡迴。
| key | 城市 | 路線 | 站數 |
|---|---|---|---|
osaka-loop |
大阪 | JR 大阪環狀線(環狀) | 19 |
osaka-midosuji |
大阪 | 御堂筋線 | 20 |
osaka-tanimachi |
大阪 | 谷町線 | 26 |
kyoto-karasuma |
京都 | 地下鐵烏丸線 | 15 |
kyoto-tozai |
京都 | 地下鐵東西線 | 17 |
kyoto-randen |
京都 | 嵐電 嵐山本線(路面電車) | 13 |
kyoto-sagano |
京都 | JR 嵯峨野線(山陰本線) | 15 |
kyoto-keihan |
京都 | 京阪本線 | 42 |
sapporo-namboku |
札幌 | 南北線 | 16 |
sapporo-tozai |
札幌 | 東西線 | 19 |
sapporo-toho |
札幌 | 東豊線 | 14 |
otaru-hakodate |
小樽 | JR 函館本線(小樽—札幌) | 15 |
🛰️ 接 ODPT 即時資料
- 到 https://developer.odpt.org/ 免費申請 consumer key。
- 設環境變數後執行:
export ODPT_KEY="你的金鑰"
python3 main.py --line yamanote --station shinjuku # 站牌右下角會顯示 src: ODPT
抓不到(無金鑰、API 錯誤、空資料)時會自動回退靜態時刻表並在 stderr 記錄原因,站牌顯示 src: STATIC。
🔐 金鑰請勿寫進程式或 commit,用環境變數即可(
.env已被.gitignore忽略)。
📟 接進 Claude Code 狀態列(statusLine)
多行站牌不適合狀態列(會佔 16 行),請用單行 statusline 模式。它會把站名釘在最左、班次像燈條捲過去:
[JY] 17 新宿 ▸ 15:45 品川・渋谷方面 15:45 上野・池袋方面 15:50 …
在 ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "python3 /Users/minghsuan/Downloads/JR-timetable/main.py --mode statusline --line yamanote --station shinjuku --columns 80"
}
}
兩個狀態列的本質限制(已在設計內處理):
- 非 TTY:statusLine 指令沒有終端寬度,必須用
--columns N明確給寬度,跑馬燈才會捲動。 - 非計時器驅動:Claude Code 只在 render(有活動)時才重跑指令,所以跑馬燈是「每次刷新前進一格」而非閒置時平滑流動。捲動偏移量由當前時間推導,因此每次刷新位置都不同。
--scroll-all 可改成整行一起捲動(連站名一起跑)。
用 csl 主題(推薦,會動的跑馬燈)
若你用 csl 狀態列主題管理器,本專案附了一個現成主題 integrations/csl/jr-board.sh(+ manifest)。它覆寫 render() 呼叫上面的跑馬燈,並靠 settings.json 的 refreshInterval: 1 達成每秒前進一格的真實捲動:
# 安裝主題到 user-tier 後啟用
cp integrations/csl/jr-board.* ~/.config/csl/themes/
csl preview jr-board # 先試跑一次
csl set jr-board # 啟用(自動改寫 settings.json 並備份)
csl set bastille-day # 隨時切回原本的主題
在 jr-board.sh 頂部可調 JR_LINE / JR_STATION / JR_COLUMNS(越窄越會捲)/ JR_SCROLL_ALL。
🎞️ 翻牌動畫調校
| 旗標 | 預設 | 效果 |
|---|---|---|
--no-flap |
— | 跳過動畫,直接畫出結果 |
--flap-steps N |
22 | 從全亂到解出的影格數;越大越漸進 |
--flap-delay S |
0.08 | 每影格停留秒數;越大越慢 |
預設整段動畫約 2 秒。動畫「以什麼順序鎖定」由 jrboard/flap.py 的 lock_threshold() 決定(目前是由左往右擦除+微抖動),想改成隨機落定或 ease-out 收尾,調這個函式即可,其他模組不用動。
🏗️ 架構
資料驅動:引擎與路線無關,新增路線 = 在 jrboard/data/ 丟一個 <key>.json,不必改任何程式。
| 模組 | 職責 |
|---|---|
jrboard/width.py |
CJK 全形字 / ANSI 視覺寬度計算與對齊 |
jrboard/model.py |
Line / Station 資料模型,載入 data/*.json |
jrboard/sources.py |
時刻表來源(ODPT + 靜態備援,repository pattern) |
jrboard/flap.py |
split-flap 翻牌動畫引擎(純函式、可測) |
jrboard/render.py |
站牌 + 時刻表 ANSI 渲染 |
jrboard/statusline.py |
單行跑馬燈 |
jrboard/cli.py |
argparse CLI 與刷新排程 |
jrboard/data/*.json |
各路線的站點 + 時刻表資料 |
新增一條路線
在 jrboard/data/ 放一個 <key>.json,照既有檔的結構填:
{
"key": "tokaido",
"name_jp": "東海道線", "name_en": "Tokaido Line",
"symbol": "JT",
"color": { "name": "...", "ansi_fg": "[38;5;208m",
"ansi_bg": "[48;5;208m[38;5;232m", "hex": "#F68B1E" },
"operator": "JR-East",
"odpt_railway": "odpt.Railway:JR-East.Tokaido",
"loop": false,
"stations": [
{ "id": "JT01", "number": "01", "name_jp": "東京", "kana": "とうきょう",
"name_en": "Tokyo", "odpt_station": "odpt.Station:JR-East.Tokaido.Tokyo" }
],
"timetable": {
"first_train": "04:30", "last_train": "00:30",
"headway_min": { "weekday": { "7": 5, "8": 4, "...": 0 }, "holiday": { "...": 0 } },
"directions": [
{ "id": "down", "name_jp": "熱海方面", "via_jp": "横浜方面", "track": "1" },
{ "id": "up", "name_jp": "東京方面", "via_jp": "品川方面", "track": "2" }
]
}
}
存檔後 python3 main.py --list 立刻就會出現這條線。
✅ 測試
python3 -m pytest tests -q # 47 tests
涵蓋:視覺寬度(CJK+ANSI)、資料模型(載入/找站/環狀鄰站)、時刻表來源(靜態產生與 ODPT 備援切換)、翻牌(寬度保持、最後一幀完全解出)、狀態列(站名釘住、跑馬燈隨時間前進)。
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tokyo_train_board-0.1.0.tar.gz.
File metadata
- Download URL: tokyo_train_board-0.1.0.tar.gz
- Upload date:
- Size: 102.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dafd142e7692ee2766f7e21ad5facdae3be15b94d504c43d2b2fafd871bb06ed
|
|
| MD5 |
5ba92b8fff08a4e021a0135232e48676
|
|
| BLAKE2b-256 |
bb71bf53b77685f2c3ba2c0187097b3a6d533ef3512ad198a62e07e6bcf45f95
|
File details
Details for the file tokyo_train_board-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tokyo_train_board-0.1.0-py3-none-any.whl
- Upload date:
- Size: 109.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf72c08d26f006b76816f9e19d095a421ed34a23cbaa08a71538cd0e6d6d669b
|
|
| MD5 |
9c63b84597095f6d8922fc6449dd28e8
|
|
| BLAKE2b-256 |
88f743dc876ebd6d3f2efa2bb181540c9a8140e58eea97fceeb89aea0bfbb052
|