tokyo-train-board 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tokyo_train_board-0.1.0/PKG-INFO +331 -0
- tokyo_train_board-0.1.0/README.md +307 -0
- tokyo_train_board-0.1.0/jrboard/__init__.py +20 -0
- tokyo_train_board-0.1.0/jrboard/cli.py +611 -0
- tokyo_train_board-0.1.0/jrboard/commute.py +389 -0
- tokyo_train_board-0.1.0/jrboard/config.py +258 -0
- tokyo_train_board-0.1.0/jrboard/data/asakusa.json +243 -0
- tokyo_train_board-0.1.0/jrboard/data/chiyoda.json +235 -0
- tokyo_train_board-0.1.0/jrboard/data/chuo.json +275 -0
- tokyo_train_board-0.1.0/jrboard/data/fukutoshin.json +211 -0
- tokyo_train_board-0.1.0/jrboard/data/ginza.json +235 -0
- tokyo_train_board-0.1.0/jrboard/data/hanzomon.json +195 -0
- tokyo_train_board-0.1.0/jrboard/data/hibiya.json +259 -0
- tokyo_train_board-0.1.0/jrboard/data/keihintohoku.json +459 -0
- tokyo_train_board-0.1.0/jrboard/data/kyoto-karasuma.json +204 -0
- tokyo_train_board-0.1.0/jrboard/data/kyoto-keihan.json +420 -0
- tokyo_train_board-0.1.0/jrboard/data/kyoto-randen.json +188 -0
- tokyo_train_board-0.1.0/jrboard/data/kyoto-sagano.json +204 -0
- tokyo_train_board-0.1.0/jrboard/data/kyoto-tozai.json +220 -0
- tokyo_train_board-0.1.0/jrboard/data/marunouchi.json +283 -0
- tokyo_train_board-0.1.0/jrboard/data/mita.json +299 -0
- tokyo_train_board-0.1.0/jrboard/data/namboku.json +235 -0
- tokyo_train_board-0.1.0/jrboard/data/oedo.json +395 -0
- tokyo_train_board-0.1.0/jrboard/data/osaka-loop.json +236 -0
- tokyo_train_board-0.1.0/jrboard/data/osaka-midosuji.json +244 -0
- tokyo_train_board-0.1.0/jrboard/data/osaka-tanimachi.json +292 -0
- tokyo_train_board-0.1.0/jrboard/data/otaru-hakodate.json +204 -0
- tokyo_train_board-0.1.0/jrboard/data/saikyo.json +235 -0
- tokyo_train_board-0.1.0/jrboard/data/sapporo-namboku.json +212 -0
- tokyo_train_board-0.1.0/jrboard/data/sapporo-toho.json +196 -0
- tokyo_train_board-0.1.0/jrboard/data/sapporo-tozai.json +236 -0
- tokyo_train_board-0.1.0/jrboard/data/shinjuku.json +251 -0
- tokyo_train_board-0.1.0/jrboard/data/shonanshinjuku.json +235 -0
- tokyo_train_board-0.1.0/jrboard/data/sobu.json +395 -0
- tokyo_train_board-0.1.0/jrboard/data/tozai.json +267 -0
- tokyo_train_board-0.1.0/jrboard/data/yamanote.json +323 -0
- tokyo_train_board-0.1.0/jrboard/data/yokosuka.json +235 -0
- tokyo_train_board-0.1.0/jrboard/data/yurakucho.json +275 -0
- tokyo_train_board-0.1.0/jrboard/feeds.py +190 -0
- tokyo_train_board-0.1.0/jrboard/flap.py +236 -0
- tokyo_train_board-0.1.0/jrboard/journey.py +368 -0
- tokyo_train_board-0.1.0/jrboard/model.py +247 -0
- tokyo_train_board-0.1.0/jrboard/render.py +271 -0
- tokyo_train_board-0.1.0/jrboard/sources.py +414 -0
- tokyo_train_board-0.1.0/jrboard/statusline.py +370 -0
- tokyo_train_board-0.1.0/jrboard/tui.py +805 -0
- tokyo_train_board-0.1.0/jrboard/width.py +77 -0
- tokyo_train_board-0.1.0/pyproject.toml +42 -0
- tokyo_train_board-0.1.0/setup.cfg +4 -0
- tokyo_train_board-0.1.0/tests/test_commute.py +390 -0
- tokyo_train_board-0.1.0/tests/test_config.py +137 -0
- tokyo_train_board-0.1.0/tests/test_feeds.py +88 -0
- tokyo_train_board-0.1.0/tests/test_flap.py +81 -0
- tokyo_train_board-0.1.0/tests/test_journey.py +263 -0
- tokyo_train_board-0.1.0/tests/test_model.py +102 -0
- tokyo_train_board-0.1.0/tests/test_render_golden.py +97 -0
- tokyo_train_board-0.1.0/tests/test_sources.py +102 -0
- tokyo_train_board-0.1.0/tests/test_statusline.py +127 -0
- tokyo_train_board-0.1.0/tests/test_tui.py +204 -0
- tokyo_train_board-0.1.0/tests/test_tui_extra.py +78 -0
- tokyo_train_board-0.1.0/tests/test_width.py +67 -0
- tokyo_train_board-0.1.0/tokyo_train_board.egg-info/PKG-INFO +331 -0
- tokyo_train_board-0.1.0/tokyo_train_board.egg-info/SOURCES.txt +65 -0
- tokyo_train_board-0.1.0/tokyo_train_board.egg-info/dependency_links.txt +1 -0
- tokyo_train_board-0.1.0/tokyo_train_board.egg-info/entry_points.txt +2 -0
- tokyo_train_board-0.1.0/tokyo_train_board.egg-info/requires.txt +3 -0
- tokyo_train_board-0.1.0/tokyo_train_board.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tokyo-train-board
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Terminal split-flap (Solari) departure board for JR / Tokyo Metro / Toei lines.
|
|
5
|
+
Author: jrboard contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/JaeggerJose/tokyo-train-board
|
|
8
|
+
Project-URL: Repository, https://github.com/JaeggerJose/tokyo-train-board
|
|
9
|
+
Project-URL: Issues, https://github.com/JaeggerJose/tokyo-train-board/issues
|
|
10
|
+
Keywords: terminal,tui,ansi,split-flap,jr,tokyo-metro,timetable
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Terminals
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Provides-Extra: live
|
|
23
|
+
Requires-Dist: requests; extra == "live"
|
|
24
|
+
|
|
25
|
+
# 🚉 JR / Tokyo Metro Split-Flap Board
|
|
26
|
+
|
|
27
|
+
[English](README.en.md) · **繁體中文** · [日本語](README.ja.md)
|
|
28
|
+
|
|
29
|
+
終端機裡的 JR/東京地鐵 **翻牌式(split-flap / Solari board)時刻表站牌**模擬器。
|
|
30
|
+
|
|
31
|
+
每次刷新會先像老火車站、航站樓的機械翻牌那樣亂數翻滾,再逐格鎖定成真實的到站資訊。
|
|
32
|
+
20 條路線、資料驅動、可接 ODPT 即時資料,並提供可嵌入 Claude Code 狀態列的單行跑馬燈模式。
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
+----------------------------------------------------------+
|
|
38
|
+
| JY 山手線 Yamanote Line |
|
|
39
|
+
| JY 17 新 宿 |
|
|
40
|
+
| しんじゅく Shinjuku |
|
|
41
|
+
| ◀ 新大久保 ■ 代々木 ▶ |
|
|
42
|
+
| < Shin-Okubo Shinjuku Yoyogi > |
|
|
43
|
+
+----------------------------------------------------------+
|
|
44
|
+
| 時刻 | 種別 | 行先 (方面) | 番線 |
|
|
45
|
+
|----------------------------------------------------------|
|
|
46
|
+
| 15:45 | 各駅停車 | 品川・渋谷方面 | 1 |
|
|
47
|
+
| 15:45 | 各駅停車 | 上野・池袋方面 | 2 |
|
|
48
|
+
| 15:50 | 各駅停車 | 品川・渋谷方面 | 1 |
|
|
49
|
+
| ... | ... | ... | ... |
|
|
50
|
+
|----------------------------------------------------------|
|
|
51
|
+
| Yamanote Line src: STATIC |
|
|
52
|
+
+----------------------------------------------------------+
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> 終端機實際輸出帶有各線的官方代表色(山手線綠、銀座線橘、丸ノ内線紅⋯⋯)。
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## ✨ 功能
|
|
60
|
+
|
|
61
|
+
- **真實資料**:可接 [ODPT](https://www.odpt.org/)(公共交通開放資料平台)即時時刻表;未設定金鑰時自動回退到內建的真實靜態時刻表。站牌右下角誠實標示資料來源 `src: ODPT` / `src: STATIC`。
|
|
62
|
+
- **20 條路線可切換**,全部資料驅動(見下方路線表)。
|
|
63
|
+
- **翻牌動畫**:經典 split-flap / Solari board 效果,速度可調。
|
|
64
|
+
- **單行跑馬燈模式**:站名釘住、班次捲動,可嵌入 Claude Code 狀態列。
|
|
65
|
+
- **CJK 對齊**:以 `east_asian_width` 處理日文全形字佔 2 格的問題,每行精準對齊到固定視覺寬度。
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 🚀 快速開始
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# (選用)只有要接 ODPT 即時資料時才需要
|
|
73
|
+
pip install requests
|
|
74
|
+
|
|
75
|
+
# 列出全部 20 條路線與站點
|
|
76
|
+
python3 main.py --list
|
|
77
|
+
|
|
78
|
+
# 全站牌 + 翻牌動畫(預設山手線新宿,每 10 秒刷新;Ctrl-C 結束)
|
|
79
|
+
python3 main.py
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`--station` 接受**英文名、站號或站 id**,大小寫不拘(例:`--station shinjuku`、`--station 17`、`--station JY17`)。
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# 指定路線/站點,渲染一次就結束
|
|
86
|
+
python3 main.py --once --line ginza --station ginza
|
|
87
|
+
python3 main.py --once --line keihintohoku --station tokyo --no-flap
|
|
88
|
+
|
|
89
|
+
# 翻牌速度微調
|
|
90
|
+
python3 main.py --line yamanote --station shinjuku --flap-delay 0.15 # 更慢、更機械感
|
|
91
|
+
python3 main.py --line yamanote --station shinjuku --flap-steps 8 # 更少格、更俐落
|
|
92
|
+
|
|
93
|
+
# 單行跑馬燈
|
|
94
|
+
python3 main.py --mode statusline --line oedo --station tochomae --columns 70
|
|
95
|
+
python3 main.py --mode statusline --line marunouchi --station tokyo --columns 70 --scroll-all
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 🧩 更多模式:TUI、番茄鐘、通勤守門員、行事曆
|
|
101
|
+
|
|
102
|
+
除了站牌與跑馬燈,同一支 CLI 還提供四種附加模式(所有舊旗標行為不變,這些都是選用)。
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# 互動式 curses 瀏覽器:左邊是「依城市分組」的路線清單(各線官方色,
|
|
106
|
+
# j/k 移動、/ 模糊搜尋、h/l 切換站點、f 收藏、q 離開),右邊是即時彩色站牌
|
|
107
|
+
# (切換線/站時會播翻牌動畫)
|
|
108
|
+
python3 main.py --tui
|
|
109
|
+
|
|
110
|
+
# 番茄鐘=一趟電車旅程:把專注計時畫成從起點到終點的乘車。會在路線上
|
|
111
|
+
# 自動挑兩站(或用 --from/--to 指定),先播翻牌動畫,之後每秒重繪,
|
|
112
|
+
# 直到「とうちゃく」(抵達)。
|
|
113
|
+
python3 main.py --pomodoro 25 --line yamanote
|
|
114
|
+
python3 main.py --pomodoro 25 --line yamanote --from shinjuku --to tokyo
|
|
115
|
+
python3 main.py --pomodoro 1 --line yamanote --once # 只畫一格就結束
|
|
116
|
+
|
|
117
|
+
# 通勤守門員:「我幾點要出門才趕得上下一班車?」需要在設定檔填
|
|
118
|
+
# [commute] home/work(見下)。早上 → 家→公司,下午/晚上 → 公司→家。
|
|
119
|
+
python3 main.py --commute # 完整站牌
|
|
120
|
+
python3 main.py --commute --mode statusline # 精簡單行
|
|
121
|
+
|
|
122
|
+
# 行事曆來源:用本機 .ics 檔當作發車來源(標籤 AGENDA),把接下來的
|
|
123
|
+
# 會議當成電車顯示,而非時刻表。
|
|
124
|
+
python3 main.py --feed-ics ~/cal.ics --once
|
|
125
|
+
python3 main.py --feed-ics ~/cal.ics --mode statusline --columns 70
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 設定檔
|
|
129
|
+
|
|
130
|
+
設定讀自 `~/.config/jrboard/config.toml`(會尊重 `XDG_CONFIG_HOME`)。檔案缺失或格式錯誤會直接忽略——一律套用預設值,而 CLI 旗標永遠覆寫設定檔。
|
|
131
|
+
|
|
132
|
+
```toml
|
|
133
|
+
[board]
|
|
134
|
+
line = "oedo"
|
|
135
|
+
station = "tochomae"
|
|
136
|
+
columns = 50
|
|
137
|
+
width = 60
|
|
138
|
+
flap_steps = 22
|
|
139
|
+
flap_delay = 0.08
|
|
140
|
+
|
|
141
|
+
[commute]
|
|
142
|
+
home = ["yamanote", "shinjuku"]
|
|
143
|
+
work = ["yamanote", "tokyo"]
|
|
144
|
+
leave_buffer_min = 7 # 走到車站的緩衝分鐘數
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
在 TUI 中切換的收藏會存到 `~/.config/jrboard/favorites.txt`(每行一組 `line_key,station_key`)。
|
|
148
|
+
|
|
149
|
+
### 安裝/進入點
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
pip install -e . # 安裝 `jrboard` 命令列腳本
|
|
153
|
+
jrboard --list # 與 `python3 main.py` 相同的 CLI
|
|
154
|
+
jrboard --tui
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 🚇 路線一覽(20 條)
|
|
160
|
+
|
|
161
|
+
| 代碼 | `--line` key | 路線 | 站數 | 範例站 |
|
|
162
|
+
|:----:|------|------|:----:|------|
|
|
163
|
+
| JY | `yamanote` | 山手線(環狀)| 30 | `shinjuku` |
|
|
164
|
+
| JC | `chuo` | 中央線快速 | 24 | `tokyo` |
|
|
165
|
+
| JB | `sobu` | 中央・総武線各駅停車 | 39 | `akihabara` |
|
|
166
|
+
| JK | `keihintohoku` | 京浜東北・根岸線 | 47 | `tokyo` |
|
|
167
|
+
| JA | `saikyo` | 埼京線 | 19 | `osaki` |
|
|
168
|
+
| JS | `shonanshinjuku` | 湘南新宿ライン | 19 | `shinjuku` |
|
|
169
|
+
| JO | `yokosuka` | 横須賀線 | 19 | `yokohama` |
|
|
170
|
+
| G | `ginza` | 東京メトロ銀座線 | 19 | `ginza` |
|
|
171
|
+
| M | `marunouchi` | 東京メトロ丸ノ内線 | 25 | `tokyo` |
|
|
172
|
+
| H | `hibiya` | 東京メトロ日比谷線 | 22 | `naka-meguro` |
|
|
173
|
+
| T | `tozai` | 東京メトロ東西線 | 23 | `otemachi` |
|
|
174
|
+
| C | `chiyoda` | 東京メトロ千代田線 | 19 | `yoyogi-uehara` |
|
|
175
|
+
| Y | `yurakucho` | 東京メトロ有楽町線 | 24 | `wakoshi` |
|
|
176
|
+
| Z | `hanzomon` | 東京メトロ半蔵門線 | 14 | `shibuya` |
|
|
177
|
+
| N | `namboku` | 東京メトロ南北線 | 19 | `meguro` |
|
|
178
|
+
| F | `fukutoshin` | 東京メトロ副都心線 | 16 | `wakoshi` |
|
|
179
|
+
| A | `asakusa` | 都営浅草線 | 20 | `asakusa` |
|
|
180
|
+
| I | `mita` | 都営三田線 | 27 | `meguro` |
|
|
181
|
+
| S | `shinjuku` | 都営新宿線 | 21 | `shinjuku` |
|
|
182
|
+
| E | `oedo` | 都営大江戸線 | 39 | `tochomae` |
|
|
183
|
+
|
|
184
|
+
> `--line shinjuku` 指的是**都營新宿線**(地鐵);JR 線各有獨立 key(`chuo`/`sobu`/…)。
|
|
185
|
+
|
|
186
|
+
### 🌏 其他城市(京都/大阪/札幌/小樽)
|
|
187
|
+
|
|
188
|
+
用 `--city` 篩選城市:`python3 main.py --list --city Osaka`;`--rotate --city Osaka` 只在大阪境內隨機巡迴。
|
|
189
|
+
|
|
190
|
+
| key | 城市 | 路線 | 站數 |
|
|
191
|
+
|------|:----:|------|:----:|
|
|
192
|
+
| `osaka-loop` | 大阪 | JR 大阪環狀線(環狀)| 19 |
|
|
193
|
+
| `osaka-midosuji` | 大阪 | 御堂筋線 | 20 |
|
|
194
|
+
| `osaka-tanimachi` | 大阪 | 谷町線 | 26 |
|
|
195
|
+
| `kyoto-karasuma` | 京都 | 地下鐵烏丸線 | 15 |
|
|
196
|
+
| `kyoto-tozai` | 京都 | 地下鐵東西線 | 17 |
|
|
197
|
+
| `kyoto-randen` | 京都 | 嵐電 嵐山本線(路面電車)| 13 |
|
|
198
|
+
| `kyoto-sagano` | 京都 | JR 嵯峨野線(山陰本線)| 15 |
|
|
199
|
+
| `kyoto-keihan` | 京都 | 京阪本線 | 42 |
|
|
200
|
+
| `sapporo-namboku` | 札幌 | 南北線 | 16 |
|
|
201
|
+
| `sapporo-tozai` | 札幌 | 東西線 | 19 |
|
|
202
|
+
| `sapporo-toho` | 札幌 | 東豊線 | 14 |
|
|
203
|
+
| `otaru-hakodate` | 小樽 | JR 函館本線(小樽—札幌)| 15 |
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 🛰️ 接 ODPT 即時資料
|
|
208
|
+
|
|
209
|
+
1. 到 <https://developer.odpt.org/> 免費申請 consumer key。
|
|
210
|
+
2. 設環境變數後執行:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
export ODPT_KEY="你的金鑰"
|
|
214
|
+
python3 main.py --line yamanote --station shinjuku # 站牌右下角會顯示 src: ODPT
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
抓不到(無金鑰、API 錯誤、空資料)時會自動回退靜態時刻表並在 stderr 記錄原因,站牌顯示 `src: STATIC`。
|
|
218
|
+
|
|
219
|
+
> 🔐 金鑰請勿寫進程式或 commit,用環境變數即可(`.env` 已被 `.gitignore` 忽略)。
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 📟 接進 Claude Code 狀態列(statusLine)
|
|
224
|
+
|
|
225
|
+
多行站牌**不適合**狀態列(會佔 16 行),請用單行 `statusline` 模式。它會把站名釘在最左、班次像燈條捲過去:
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
[JY] 17 新宿 ▸ 15:45 品川・渋谷方面 15:45 上野・池袋方面 15:50 …
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
在 `~/.claude/settings.json`:
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"statusLine": {
|
|
236
|
+
"type": "command",
|
|
237
|
+
"command": "python3 /Users/minghsuan/Downloads/JR-timetable/main.py --mode statusline --line yamanote --station shinjuku --columns 80"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
兩個狀態列的本質限制(已在設計內處理):
|
|
243
|
+
|
|
244
|
+
1. **非 TTY**:statusLine 指令沒有終端寬度,**必須用 `--columns N` 明確給寬度**,跑馬燈才會捲動。
|
|
245
|
+
2. **非計時器驅動**:Claude Code 只在 render(有活動)時才重跑指令,所以跑馬燈是「每次刷新前進一格」而非閒置時平滑流動。捲動偏移量由當前時間推導,因此每次刷新位置都不同。
|
|
246
|
+
|
|
247
|
+
`--scroll-all` 可改成整行一起捲動(連站名一起跑)。
|
|
248
|
+
|
|
249
|
+
### 用 csl 主題(推薦,會動的跑馬燈)
|
|
250
|
+
|
|
251
|
+
若你用 [`csl`](https://) 狀態列主題管理器,本專案附了一個現成主題 `integrations/csl/jr-board.sh`(+ manifest)。它覆寫 `render()` 呼叫上面的跑馬燈,並靠 `settings.json` 的 `refreshInterval: 1` 達成**每秒前進一格的真實捲動**:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# 安裝主題到 user-tier 後啟用
|
|
255
|
+
cp integrations/csl/jr-board.* ~/.config/csl/themes/
|
|
256
|
+
csl preview jr-board # 先試跑一次
|
|
257
|
+
csl set jr-board # 啟用(自動改寫 settings.json 並備份)
|
|
258
|
+
csl set bastille-day # 隨時切回原本的主題
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
在 `jr-board.sh` 頂部可調 `JR_LINE` / `JR_STATION` / `JR_COLUMNS`(越窄越會捲)/ `JR_SCROLL_ALL`。
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 🎞️ 翻牌動畫調校
|
|
266
|
+
|
|
267
|
+
| 旗標 | 預設 | 效果 |
|
|
268
|
+
|------|:----:|------|
|
|
269
|
+
| `--no-flap` | — | 跳過動畫,直接畫出結果 |
|
|
270
|
+
| `--flap-steps N` | 22 | 從全亂到解出的影格數;越大越漸進 |
|
|
271
|
+
| `--flap-delay S` | 0.08 | 每影格停留秒數;越大越慢 |
|
|
272
|
+
|
|
273
|
+
預設整段動畫約 2 秒。動畫「以什麼順序鎖定」由 `jrboard/flap.py` 的 `lock_threshold()` 決定(目前是由左往右擦除+微抖動),想改成隨機落定或 ease-out 收尾,調這個函式即可,其他模組不用動。
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 🏗️ 架構
|
|
278
|
+
|
|
279
|
+
**資料驅動**:引擎與路線無關,**新增路線 = 在 `jrboard/data/` 丟一個 `<key>.json`,不必改任何程式**。
|
|
280
|
+
|
|
281
|
+
| 模組 | 職責 |
|
|
282
|
+
|------|------|
|
|
283
|
+
| `jrboard/width.py` | CJK 全形字 / ANSI 視覺寬度計算與對齊 |
|
|
284
|
+
| `jrboard/model.py` | `Line` / `Station` 資料模型,載入 `data/*.json` |
|
|
285
|
+
| `jrboard/sources.py` | 時刻表來源(ODPT + 靜態備援,repository pattern)|
|
|
286
|
+
| `jrboard/flap.py` | split-flap 翻牌動畫引擎(純函式、可測)|
|
|
287
|
+
| `jrboard/render.py` | 站牌 + 時刻表 ANSI 渲染 |
|
|
288
|
+
| `jrboard/statusline.py` | 單行跑馬燈 |
|
|
289
|
+
| `jrboard/cli.py` | argparse CLI 與刷新排程 |
|
|
290
|
+
| `jrboard/data/*.json` | 各路線的站點 + 時刻表資料 |
|
|
291
|
+
|
|
292
|
+
### 新增一條路線
|
|
293
|
+
|
|
294
|
+
在 `jrboard/data/` 放一個 `<key>.json`,照既有檔的結構填:
|
|
295
|
+
|
|
296
|
+
```jsonc
|
|
297
|
+
{
|
|
298
|
+
"key": "tokaido",
|
|
299
|
+
"name_jp": "東海道線", "name_en": "Tokaido Line",
|
|
300
|
+
"symbol": "JT",
|
|
301
|
+
"color": { "name": "...", "ansi_fg": "[38;5;208m",
|
|
302
|
+
"ansi_bg": "[48;5;208m[38;5;232m", "hex": "#F68B1E" },
|
|
303
|
+
"operator": "JR-East",
|
|
304
|
+
"odpt_railway": "odpt.Railway:JR-East.Tokaido",
|
|
305
|
+
"loop": false,
|
|
306
|
+
"stations": [
|
|
307
|
+
{ "id": "JT01", "number": "01", "name_jp": "東京", "kana": "とうきょう",
|
|
308
|
+
"name_en": "Tokyo", "odpt_station": "odpt.Station:JR-East.Tokaido.Tokyo" }
|
|
309
|
+
],
|
|
310
|
+
"timetable": {
|
|
311
|
+
"first_train": "04:30", "last_train": "00:30",
|
|
312
|
+
"headway_min": { "weekday": { "7": 5, "8": 4, "...": 0 }, "holiday": { "...": 0 } },
|
|
313
|
+
"directions": [
|
|
314
|
+
{ "id": "down", "name_jp": "熱海方面", "via_jp": "横浜方面", "track": "1" },
|
|
315
|
+
{ "id": "up", "name_jp": "東京方面", "via_jp": "品川方面", "track": "2" }
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
存檔後 `python3 main.py --list` 立刻就會出現這條線。
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## ✅ 測試
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
python3 -m pytest tests -q # 47 tests
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
涵蓋:視覺寬度(CJK+ANSI)、資料模型(載入/找站/環狀鄰站)、時刻表來源(靜態產生與 ODPT 備援切換)、翻牌(寬度保持、最後一幀完全解出)、狀態列(站名釘住、跑馬燈隨時間前進)。
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# 🚉 JR / Tokyo Metro Split-Flap Board
|
|
2
|
+
|
|
3
|
+
[English](README.en.md) · **繁體中文** · [日本語](README.ja.md)
|
|
4
|
+
|
|
5
|
+
終端機裡的 JR/東京地鐵 **翻牌式(split-flap / Solari board)時刻表站牌**模擬器。
|
|
6
|
+
|
|
7
|
+
每次刷新會先像老火車站、航站樓的機械翻牌那樣亂數翻滾,再逐格鎖定成真實的到站資訊。
|
|
8
|
+
20 條路線、資料驅動、可接 ODPT 即時資料,並提供可嵌入 Claude Code 狀態列的單行跑馬燈模式。
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
+----------------------------------------------------------+
|
|
14
|
+
| JY 山手線 Yamanote Line |
|
|
15
|
+
| JY 17 新 宿 |
|
|
16
|
+
| しんじゅく Shinjuku |
|
|
17
|
+
| ◀ 新大久保 ■ 代々木 ▶ |
|
|
18
|
+
| < Shin-Okubo Shinjuku Yoyogi > |
|
|
19
|
+
+----------------------------------------------------------+
|
|
20
|
+
| 時刻 | 種別 | 行先 (方面) | 番線 |
|
|
21
|
+
|----------------------------------------------------------|
|
|
22
|
+
| 15:45 | 各駅停車 | 品川・渋谷方面 | 1 |
|
|
23
|
+
| 15:45 | 各駅停車 | 上野・池袋方面 | 2 |
|
|
24
|
+
| 15:50 | 各駅停車 | 品川・渋谷方面 | 1 |
|
|
25
|
+
| ... | ... | ... | ... |
|
|
26
|
+
|----------------------------------------------------------|
|
|
27
|
+
| Yamanote Line src: STATIC |
|
|
28
|
+
+----------------------------------------------------------+
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> 終端機實際輸出帶有各線的官方代表色(山手線綠、銀座線橘、丸ノ内線紅⋯⋯)。
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ✨ 功能
|
|
36
|
+
|
|
37
|
+
- **真實資料**:可接 [ODPT](https://www.odpt.org/)(公共交通開放資料平台)即時時刻表;未設定金鑰時自動回退到內建的真實靜態時刻表。站牌右下角誠實標示資料來源 `src: ODPT` / `src: STATIC`。
|
|
38
|
+
- **20 條路線可切換**,全部資料驅動(見下方路線表)。
|
|
39
|
+
- **翻牌動畫**:經典 split-flap / Solari board 效果,速度可調。
|
|
40
|
+
- **單行跑馬燈模式**:站名釘住、班次捲動,可嵌入 Claude Code 狀態列。
|
|
41
|
+
- **CJK 對齊**:以 `east_asian_width` 處理日文全形字佔 2 格的問題,每行精準對齊到固定視覺寬度。
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 🚀 快速開始
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# (選用)只有要接 ODPT 即時資料時才需要
|
|
49
|
+
pip install requests
|
|
50
|
+
|
|
51
|
+
# 列出全部 20 條路線與站點
|
|
52
|
+
python3 main.py --list
|
|
53
|
+
|
|
54
|
+
# 全站牌 + 翻牌動畫(預設山手線新宿,每 10 秒刷新;Ctrl-C 結束)
|
|
55
|
+
python3 main.py
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`--station` 接受**英文名、站號或站 id**,大小寫不拘(例:`--station shinjuku`、`--station 17`、`--station JY17`)。
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 指定路線/站點,渲染一次就結束
|
|
62
|
+
python3 main.py --once --line ginza --station ginza
|
|
63
|
+
python3 main.py --once --line keihintohoku --station tokyo --no-flap
|
|
64
|
+
|
|
65
|
+
# 翻牌速度微調
|
|
66
|
+
python3 main.py --line yamanote --station shinjuku --flap-delay 0.15 # 更慢、更機械感
|
|
67
|
+
python3 main.py --line yamanote --station shinjuku --flap-steps 8 # 更少格、更俐落
|
|
68
|
+
|
|
69
|
+
# 單行跑馬燈
|
|
70
|
+
python3 main.py --mode statusline --line oedo --station tochomae --columns 70
|
|
71
|
+
python3 main.py --mode statusline --line marunouchi --station tokyo --columns 70 --scroll-all
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 🧩 更多模式:TUI、番茄鐘、通勤守門員、行事曆
|
|
77
|
+
|
|
78
|
+
除了站牌與跑馬燈,同一支 CLI 還提供四種附加模式(所有舊旗標行為不變,這些都是選用)。
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# 互動式 curses 瀏覽器:左邊是「依城市分組」的路線清單(各線官方色,
|
|
82
|
+
# j/k 移動、/ 模糊搜尋、h/l 切換站點、f 收藏、q 離開),右邊是即時彩色站牌
|
|
83
|
+
# (切換線/站時會播翻牌動畫)
|
|
84
|
+
python3 main.py --tui
|
|
85
|
+
|
|
86
|
+
# 番茄鐘=一趟電車旅程:把專注計時畫成從起點到終點的乘車。會在路線上
|
|
87
|
+
# 自動挑兩站(或用 --from/--to 指定),先播翻牌動畫,之後每秒重繪,
|
|
88
|
+
# 直到「とうちゃく」(抵達)。
|
|
89
|
+
python3 main.py --pomodoro 25 --line yamanote
|
|
90
|
+
python3 main.py --pomodoro 25 --line yamanote --from shinjuku --to tokyo
|
|
91
|
+
python3 main.py --pomodoro 1 --line yamanote --once # 只畫一格就結束
|
|
92
|
+
|
|
93
|
+
# 通勤守門員:「我幾點要出門才趕得上下一班車?」需要在設定檔填
|
|
94
|
+
# [commute] home/work(見下)。早上 → 家→公司,下午/晚上 → 公司→家。
|
|
95
|
+
python3 main.py --commute # 完整站牌
|
|
96
|
+
python3 main.py --commute --mode statusline # 精簡單行
|
|
97
|
+
|
|
98
|
+
# 行事曆來源:用本機 .ics 檔當作發車來源(標籤 AGENDA),把接下來的
|
|
99
|
+
# 會議當成電車顯示,而非時刻表。
|
|
100
|
+
python3 main.py --feed-ics ~/cal.ics --once
|
|
101
|
+
python3 main.py --feed-ics ~/cal.ics --mode statusline --columns 70
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 設定檔
|
|
105
|
+
|
|
106
|
+
設定讀自 `~/.config/jrboard/config.toml`(會尊重 `XDG_CONFIG_HOME`)。檔案缺失或格式錯誤會直接忽略——一律套用預設值,而 CLI 旗標永遠覆寫設定檔。
|
|
107
|
+
|
|
108
|
+
```toml
|
|
109
|
+
[board]
|
|
110
|
+
line = "oedo"
|
|
111
|
+
station = "tochomae"
|
|
112
|
+
columns = 50
|
|
113
|
+
width = 60
|
|
114
|
+
flap_steps = 22
|
|
115
|
+
flap_delay = 0.08
|
|
116
|
+
|
|
117
|
+
[commute]
|
|
118
|
+
home = ["yamanote", "shinjuku"]
|
|
119
|
+
work = ["yamanote", "tokyo"]
|
|
120
|
+
leave_buffer_min = 7 # 走到車站的緩衝分鐘數
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
在 TUI 中切換的收藏會存到 `~/.config/jrboard/favorites.txt`(每行一組 `line_key,station_key`)。
|
|
124
|
+
|
|
125
|
+
### 安裝/進入點
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pip install -e . # 安裝 `jrboard` 命令列腳本
|
|
129
|
+
jrboard --list # 與 `python3 main.py` 相同的 CLI
|
|
130
|
+
jrboard --tui
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 🚇 路線一覽(20 條)
|
|
136
|
+
|
|
137
|
+
| 代碼 | `--line` key | 路線 | 站數 | 範例站 |
|
|
138
|
+
|:----:|------|------|:----:|------|
|
|
139
|
+
| JY | `yamanote` | 山手線(環狀)| 30 | `shinjuku` |
|
|
140
|
+
| JC | `chuo` | 中央線快速 | 24 | `tokyo` |
|
|
141
|
+
| JB | `sobu` | 中央・総武線各駅停車 | 39 | `akihabara` |
|
|
142
|
+
| JK | `keihintohoku` | 京浜東北・根岸線 | 47 | `tokyo` |
|
|
143
|
+
| JA | `saikyo` | 埼京線 | 19 | `osaki` |
|
|
144
|
+
| JS | `shonanshinjuku` | 湘南新宿ライン | 19 | `shinjuku` |
|
|
145
|
+
| JO | `yokosuka` | 横須賀線 | 19 | `yokohama` |
|
|
146
|
+
| G | `ginza` | 東京メトロ銀座線 | 19 | `ginza` |
|
|
147
|
+
| M | `marunouchi` | 東京メトロ丸ノ内線 | 25 | `tokyo` |
|
|
148
|
+
| H | `hibiya` | 東京メトロ日比谷線 | 22 | `naka-meguro` |
|
|
149
|
+
| T | `tozai` | 東京メトロ東西線 | 23 | `otemachi` |
|
|
150
|
+
| C | `chiyoda` | 東京メトロ千代田線 | 19 | `yoyogi-uehara` |
|
|
151
|
+
| Y | `yurakucho` | 東京メトロ有楽町線 | 24 | `wakoshi` |
|
|
152
|
+
| Z | `hanzomon` | 東京メトロ半蔵門線 | 14 | `shibuya` |
|
|
153
|
+
| N | `namboku` | 東京メトロ南北線 | 19 | `meguro` |
|
|
154
|
+
| F | `fukutoshin` | 東京メトロ副都心線 | 16 | `wakoshi` |
|
|
155
|
+
| A | `asakusa` | 都営浅草線 | 20 | `asakusa` |
|
|
156
|
+
| I | `mita` | 都営三田線 | 27 | `meguro` |
|
|
157
|
+
| S | `shinjuku` | 都営新宿線 | 21 | `shinjuku` |
|
|
158
|
+
| E | `oedo` | 都営大江戸線 | 39 | `tochomae` |
|
|
159
|
+
|
|
160
|
+
> `--line shinjuku` 指的是**都營新宿線**(地鐵);JR 線各有獨立 key(`chuo`/`sobu`/…)。
|
|
161
|
+
|
|
162
|
+
### 🌏 其他城市(京都/大阪/札幌/小樽)
|
|
163
|
+
|
|
164
|
+
用 `--city` 篩選城市:`python3 main.py --list --city Osaka`;`--rotate --city Osaka` 只在大阪境內隨機巡迴。
|
|
165
|
+
|
|
166
|
+
| key | 城市 | 路線 | 站數 |
|
|
167
|
+
|------|:----:|------|:----:|
|
|
168
|
+
| `osaka-loop` | 大阪 | JR 大阪環狀線(環狀)| 19 |
|
|
169
|
+
| `osaka-midosuji` | 大阪 | 御堂筋線 | 20 |
|
|
170
|
+
| `osaka-tanimachi` | 大阪 | 谷町線 | 26 |
|
|
171
|
+
| `kyoto-karasuma` | 京都 | 地下鐵烏丸線 | 15 |
|
|
172
|
+
| `kyoto-tozai` | 京都 | 地下鐵東西線 | 17 |
|
|
173
|
+
| `kyoto-randen` | 京都 | 嵐電 嵐山本線(路面電車)| 13 |
|
|
174
|
+
| `kyoto-sagano` | 京都 | JR 嵯峨野線(山陰本線)| 15 |
|
|
175
|
+
| `kyoto-keihan` | 京都 | 京阪本線 | 42 |
|
|
176
|
+
| `sapporo-namboku` | 札幌 | 南北線 | 16 |
|
|
177
|
+
| `sapporo-tozai` | 札幌 | 東西線 | 19 |
|
|
178
|
+
| `sapporo-toho` | 札幌 | 東豊線 | 14 |
|
|
179
|
+
| `otaru-hakodate` | 小樽 | JR 函館本線(小樽—札幌)| 15 |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🛰️ 接 ODPT 即時資料
|
|
184
|
+
|
|
185
|
+
1. 到 <https://developer.odpt.org/> 免費申請 consumer key。
|
|
186
|
+
2. 設環境變數後執行:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
export ODPT_KEY="你的金鑰"
|
|
190
|
+
python3 main.py --line yamanote --station shinjuku # 站牌右下角會顯示 src: ODPT
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
抓不到(無金鑰、API 錯誤、空資料)時會自動回退靜態時刻表並在 stderr 記錄原因,站牌顯示 `src: STATIC`。
|
|
194
|
+
|
|
195
|
+
> 🔐 金鑰請勿寫進程式或 commit,用環境變數即可(`.env` 已被 `.gitignore` 忽略)。
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 📟 接進 Claude Code 狀態列(statusLine)
|
|
200
|
+
|
|
201
|
+
多行站牌**不適合**狀態列(會佔 16 行),請用單行 `statusline` 模式。它會把站名釘在最左、班次像燈條捲過去:
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
[JY] 17 新宿 ▸ 15:45 品川・渋谷方面 15:45 上野・池袋方面 15:50 …
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
在 `~/.claude/settings.json`:
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"statusLine": {
|
|
212
|
+
"type": "command",
|
|
213
|
+
"command": "python3 /Users/minghsuan/Downloads/JR-timetable/main.py --mode statusline --line yamanote --station shinjuku --columns 80"
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
兩個狀態列的本質限制(已在設計內處理):
|
|
219
|
+
|
|
220
|
+
1. **非 TTY**:statusLine 指令沒有終端寬度,**必須用 `--columns N` 明確給寬度**,跑馬燈才會捲動。
|
|
221
|
+
2. **非計時器驅動**:Claude Code 只在 render(有活動)時才重跑指令,所以跑馬燈是「每次刷新前進一格」而非閒置時平滑流動。捲動偏移量由當前時間推導,因此每次刷新位置都不同。
|
|
222
|
+
|
|
223
|
+
`--scroll-all` 可改成整行一起捲動(連站名一起跑)。
|
|
224
|
+
|
|
225
|
+
### 用 csl 主題(推薦,會動的跑馬燈)
|
|
226
|
+
|
|
227
|
+
若你用 [`csl`](https://) 狀態列主題管理器,本專案附了一個現成主題 `integrations/csl/jr-board.sh`(+ manifest)。它覆寫 `render()` 呼叫上面的跑馬燈,並靠 `settings.json` 的 `refreshInterval: 1` 達成**每秒前進一格的真實捲動**:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# 安裝主題到 user-tier 後啟用
|
|
231
|
+
cp integrations/csl/jr-board.* ~/.config/csl/themes/
|
|
232
|
+
csl preview jr-board # 先試跑一次
|
|
233
|
+
csl set jr-board # 啟用(自動改寫 settings.json 並備份)
|
|
234
|
+
csl set bastille-day # 隨時切回原本的主題
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
在 `jr-board.sh` 頂部可調 `JR_LINE` / `JR_STATION` / `JR_COLUMNS`(越窄越會捲)/ `JR_SCROLL_ALL`。
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 🎞️ 翻牌動畫調校
|
|
242
|
+
|
|
243
|
+
| 旗標 | 預設 | 效果 |
|
|
244
|
+
|------|:----:|------|
|
|
245
|
+
| `--no-flap` | — | 跳過動畫,直接畫出結果 |
|
|
246
|
+
| `--flap-steps N` | 22 | 從全亂到解出的影格數;越大越漸進 |
|
|
247
|
+
| `--flap-delay S` | 0.08 | 每影格停留秒數;越大越慢 |
|
|
248
|
+
|
|
249
|
+
預設整段動畫約 2 秒。動畫「以什麼順序鎖定」由 `jrboard/flap.py` 的 `lock_threshold()` 決定(目前是由左往右擦除+微抖動),想改成隨機落定或 ease-out 收尾,調這個函式即可,其他模組不用動。
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 🏗️ 架構
|
|
254
|
+
|
|
255
|
+
**資料驅動**:引擎與路線無關,**新增路線 = 在 `jrboard/data/` 丟一個 `<key>.json`,不必改任何程式**。
|
|
256
|
+
|
|
257
|
+
| 模組 | 職責 |
|
|
258
|
+
|------|------|
|
|
259
|
+
| `jrboard/width.py` | CJK 全形字 / ANSI 視覺寬度計算與對齊 |
|
|
260
|
+
| `jrboard/model.py` | `Line` / `Station` 資料模型,載入 `data/*.json` |
|
|
261
|
+
| `jrboard/sources.py` | 時刻表來源(ODPT + 靜態備援,repository pattern)|
|
|
262
|
+
| `jrboard/flap.py` | split-flap 翻牌動畫引擎(純函式、可測)|
|
|
263
|
+
| `jrboard/render.py` | 站牌 + 時刻表 ANSI 渲染 |
|
|
264
|
+
| `jrboard/statusline.py` | 單行跑馬燈 |
|
|
265
|
+
| `jrboard/cli.py` | argparse CLI 與刷新排程 |
|
|
266
|
+
| `jrboard/data/*.json` | 各路線的站點 + 時刻表資料 |
|
|
267
|
+
|
|
268
|
+
### 新增一條路線
|
|
269
|
+
|
|
270
|
+
在 `jrboard/data/` 放一個 `<key>.json`,照既有檔的結構填:
|
|
271
|
+
|
|
272
|
+
```jsonc
|
|
273
|
+
{
|
|
274
|
+
"key": "tokaido",
|
|
275
|
+
"name_jp": "東海道線", "name_en": "Tokaido Line",
|
|
276
|
+
"symbol": "JT",
|
|
277
|
+
"color": { "name": "...", "ansi_fg": "[38;5;208m",
|
|
278
|
+
"ansi_bg": "[48;5;208m[38;5;232m", "hex": "#F68B1E" },
|
|
279
|
+
"operator": "JR-East",
|
|
280
|
+
"odpt_railway": "odpt.Railway:JR-East.Tokaido",
|
|
281
|
+
"loop": false,
|
|
282
|
+
"stations": [
|
|
283
|
+
{ "id": "JT01", "number": "01", "name_jp": "東京", "kana": "とうきょう",
|
|
284
|
+
"name_en": "Tokyo", "odpt_station": "odpt.Station:JR-East.Tokaido.Tokyo" }
|
|
285
|
+
],
|
|
286
|
+
"timetable": {
|
|
287
|
+
"first_train": "04:30", "last_train": "00:30",
|
|
288
|
+
"headway_min": { "weekday": { "7": 5, "8": 4, "...": 0 }, "holiday": { "...": 0 } },
|
|
289
|
+
"directions": [
|
|
290
|
+
{ "id": "down", "name_jp": "熱海方面", "via_jp": "横浜方面", "track": "1" },
|
|
291
|
+
{ "id": "up", "name_jp": "東京方面", "via_jp": "品川方面", "track": "2" }
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
存檔後 `python3 main.py --list` 立刻就會出現這條線。
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## ✅ 測試
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
python3 -m pytest tests -q # 47 tests
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
涵蓋:視覺寬度(CJK+ANSI)、資料模型(載入/找站/環狀鄰站)、時刻表來源(靜態產生與 ODPT 備援切換)、翻牌(寬度保持、最後一幀完全解出)、狀態列(站名釘住、跑馬燈隨時間前進)。
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""jrboard: a terminal split-flap (Solari) JR / Toei departure board.
|
|
2
|
+
|
|
3
|
+
The package is intentionally lightweight at import time. Heavy work (JSON
|
|
4
|
+
loading, network access, rendering) lives in submodules that callers import
|
|
5
|
+
explicitly:
|
|
6
|
+
|
|
7
|
+
- :mod:`jrboard.width` visual width / ANSI-aware padding helpers
|
|
8
|
+
- :mod:`jrboard.model` frozen value objects + JSON loading
|
|
9
|
+
- :mod:`jrboard.sources` departure repositories (ODPT / static fallback)
|
|
10
|
+
- :mod:`jrboard.flap` pure split-flap animation engine
|
|
11
|
+
- :mod:`jrboard.render` ANSI board renderer
|
|
12
|
+
- :mod:`jrboard.statusline` single-line marquee for Claude Code statusLine
|
|
13
|
+
- :mod:`jrboard.cli` argparse entry point (``main``)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
__version__ = "1.0.0"
|
|
19
|
+
|
|
20
|
+
__all__ = ["__version__"]
|