playlist-admin 2.6.81 → 2.6.82

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.
@@ -0,0 +1,50 @@
1
+ """把沒有對應 .txt 的 .srt 字幕轉成 .txt (去除時間軸),供向量庫補索引
2
+ 用法: python rag/srt_to_txt.py
3
+ """
4
+ import os
5
+ import re
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
10
+
11
+ from _resolve import podcast_downloads_dir
12
+
13
+
14
+ def srt_to_text(srt_path: Path) -> str:
15
+ text = srt_path.read_text(encoding="utf-8-sig", errors="replace")
16
+ # 移除 srt 索引行 (純數字行)
17
+ text = re.sub(r"^\d+\s*$", "", text, flags=re.MULTILINE)
18
+ # 移除時間軸行 (00:00:00,000 --> 00:00:01,000)
19
+ text = re.sub(
20
+ r"\d{1,2}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.]\d{3}",
21
+ "",
22
+ text,
23
+ )
24
+ lines = [ln.strip() for ln in text.splitlines() if ln.strip()]
25
+ return "\n".join(lines)
26
+
27
+
28
+ def main() -> None:
29
+ root = podcast_downloads_dir()
30
+ converted = 0
31
+ for srt in sorted(root.rglob("*.srt")):
32
+ name = srt.name
33
+ if ".zh-TW.srt" in name or ".zh-Hans.srt" in name or ".zh-Hant.srt" in name:
34
+ continue
35
+ txt = srt.with_suffix(".txt")
36
+ if txt.exists():
37
+ continue
38
+ try:
39
+ content = srt_to_text(srt)
40
+ except Exception as e:
41
+ print(f"!! 失敗 {srt.name}: {e}")
42
+ continue
43
+ txt.write_text(content, encoding="utf-8")
44
+ print(f"轉換: {srt.parent.name}/{srt.stem[:50]}")
45
+ converted += 1
46
+ print(f"完成! 轉換 {converted} 個 srt -> txt")
47
+
48
+
49
+ if __name__ == "__main__":
50
+ main()
package/COMMANDS.md DELETED
@@ -1,263 +0,0 @@
1
-
2
- # Playlist Administrator 指令說明書
3
-
4
- ## Node.js CLI(npm)
5
-
6
- Node CLI 以 Node.js 完整實作(`cli/` 目錄),與 Dart CLI 相同指令介面:
7
-
8
- ```bash
9
- npm run pipeline # 完整流程(轉檔 → 爬取 → 清理 → 分類 → metadata → LUFS)
10
- npm run pipeline -- --step 3 # 從第 3 步開始
11
- npm run podcast # Podcast Pipeline(RSS → YouTube 字幕 → Groq 逐字稿)
12
- npm run status # 顯示狀態
13
- npm run spotube-download -- <name> # 下載單一歌單
14
- npm run spotube-download-all # 下載所有歌單
15
- npm run spotube-move # 搬移 M4A
16
- npm run spotube-cleanup # 清除孤兒 MP3
17
- ```
18
-
19
- 也可全域安裝使用 `playlist-admin` 指令:
20
-
21
- ```bash
22
- npm install -g .
23
- playlist-admin status
24
- ```
25
-
26
- 不需要任何 npm 依賴;需要系統有 `ffmpeg` / `ffprobe` / `yt-dlp`(與 Python/Dart 版相同)。
27
- Spotube 自動化透過 PowerShell P/Invoke(user32.dll)實作,不需要額外套件。
28
-
29
- ## CLI 指令(Dart)
30
-
31
- ### 完整流程
32
-
33
- ```bash
34
- dart run lib/cli_main.dart pipeline
35
- ```
36
-
37
- 依序執行:轉檔 → 爬取 Spotify → 清理遺失歌曲 → 分類未收錄歌曲 → 增強 Metadata。
38
-
39
- ### 只看狀態
40
-
41
- ```bash
42
- dart run lib/cli_main.dart status
43
- ```
44
-
45
- 顯示:
46
- - 資料庫歌曲總數(MP3 / M4A / FLAC)
47
- - 各歌單的匹配狀況(已完成 / 缺少)
48
- - 空間節省統計
49
-
50
- ### 爬取 Spotify 歌單
51
-
52
- ```bash
53
- dart run lib/cli_main.dart scrape
54
- ```
55
-
56
- 爬取 `config.json` 中所有 Spotify URL,比對本地檔案,輸出 M3U8 播放清單。
57
-
58
- ### 轉檔 M4A → MP3
59
-
60
- ```bash
61
- dart run lib/cli_main.dart convert
62
- ```
63
-
64
- 掃描 Music/m4a 目錄,將尚未有對應 MP3 的 M4A 轉檔(需要 ffmpeg)。
65
-
66
- ### 清理遺失歌曲
67
-
68
- ```bash
69
- dart run lib/cli_main.dart prune
70
- ```
71
-
72
- 檢查 M3U8 歌單中所有檔案是否存在磁碟,移除已刪除的條目。
73
-
74
- ### 整理未分類歌曲
75
-
76
- ```bash
77
- dart run lib/cli_main.dart unsorted
78
- ```
79
-
80
- 掃描音樂庫中所有未被任何歌單收錄的歌曲,寫入 `_Unsorted.m3u8`。
81
-
82
- ---
83
-
84
- ## Spotube 自動化
85
-
86
- Spotube 自動化透過 Win32 API 操作 Spotube GUI 來自動下載歌單。
87
-
88
- ### 校準點擊座標(必要步驟)
89
-
90
- 由於每個人的螢幕解析度、視窗位置不同,Spotube 操作需要先校準按鈕位置。
91
-
92
- **方法一:Python 校準工具(建議)**
93
-
94
- ```bash
95
- pip install pywin32
96
- python tools/spotube_calibrate.py
97
- ```
98
-
99
- 依序將滑鼠移到 9 個目標元素上,按下 Enter 記錄位置:
100
-
101
- | 步驟 | 名稱 | 目標元素 |
102
- |---|---|---|
103
- | 1 | `sidebar_library` | 側邊欄 Library 圖示 |
104
- | 2 | `library_filter` | Library 頁面搜尋/過濾輸入框 |
105
- | 3 | `first_playlist_card` | 過濾後出現的第一個歌單卡片 |
106
- | 4 | `three_dot_menu` | 歌單頁面右上角的三點選單(⋯) |
107
- | 5 | `download_all_offset` | 選單中的「下載全部」(自動計算偏移) |
108
- | 6 | `confirm_button` | 確認對話框的「同意/Download」 |
109
- | 7 | `skip_detect` | 跳過對話框上一個明顯的白色像素(用於偵測) |
110
- | 8 | `skip` |「略過 / Skip」按鈕 |
111
- | 9 | `skip_all` |「全部略過 / Skip All」按鈕 |
112
-
113
- 完成後座標自動寫入 `config.json` 的 `spotube_coords`。
114
-
115
- **方法二:Flutter 內建校準**
116
-
117
- ```bash
118
- dart run lib/calibrate.dart
119
- ```
120
-
121
- ### 下載單一歌單
122
-
123
- ```bash
124
- dart run lib/cli_main.dart spotube-download "Daily Mix 1"
125
- ```
126
-
127
- 程式會:
128
- 1. 啟動/啟用 Spotube
129
- 2. 最大化視窗
130
- 3. 點擊側邊欄 Library
131
- 4. 在搜尋框輸入歌單名稱
132
- 5. 點擊第一個結果
133
- 6. 點擊三點選單 → 下載全部 → 確認
134
- 7. 監測跳過對話框(最多 30 秒),自動按 Skip → Skip All
135
- 8. 下載完成後最小化
136
-
137
- ### 下載所有歌單
138
-
139
- ```bash
140
- dart run lib/cli_main.dart spotube-download-all
141
- ```
142
-
143
- 依序對 `config.json` 中所有 `urlNames` 執行下載。
144
- 已下載過的歌單會記錄在 `lastUpdated`,不會重複下載。
145
-
146
- ### 搬移下載檔案
147
-
148
- ```bash
149
- dart run lib/cli_main.dart spotube-move
150
- ```
151
-
152
- 將 Spotube 預設下載目錄 `%USERPROFILE%/Downloads/Spotube` 中的音檔搬到 `Music/m4a`。
153
-
154
- ### 重置下載紀錄
155
-
156
- ```bash
157
- dart run lib/cli_main.dart spotube-reset
158
- ```
159
-
160
- 清除所有下載記錄,讓所有歌單可以被重新下載。
161
-
162
- ---
163
-
164
- ## 設定檔說明
165
-
166
- 主設定檔位置:`{base_path}/config.json`
167
-
168
- ### 主要欄位
169
-
170
- | 欄位 | 類型 | 說明 |
171
- |---|---|---|
172
- | `base_path` | string | 資料庫根目錄 |
173
- | `library_path` | string | 音樂庫目錄(預設 `{base_path}/Music`) |
174
- | `playlists_path` | string | M3U8 歌單目錄(預設 `{base_path}/Playlists`) |
175
- | `url_names` | object | Spotify URL → 歌單名稱 對應表 |
176
- | `search_names` | object | 搜尋別名對應表(中文/英文) |
177
- | `spotube_coords` | object | Spotube 自動化按鈕座標 |
178
- | `last_updated` | object | 各歌單最後同步日期 |
179
- | `audio_format` | string | 目標音檔格式(`mp3`, `flac`) |
180
- | `max_threads` | int | 轉檔執行緒數 |
181
- | `ffmpeg_path` | string | FFmpeg 執行檔路徑 |
182
- | `spotube_exe_path` | string | Spotube 執行檔路徑 |
183
- | `spotube_exact_match` | bool | 是否要求檔名與 Spotify 完全一致 |
184
- | `enable_metadata_enrichment` | bool | 是否啟用 Metadata 增強(重新命名檔案) |
185
-
186
- ### 搜尋別名(search_names)
187
-
188
- 用於中英文歌名/藝人名的模糊比對。例如:
189
-
190
- ```json
191
- {
192
- "search_names": {
193
- "日本流行樂合輯": "J-Pop Mix",
194
- "韓國流行樂合輯": "K-Pop Mix",
195
- "每週新發現": "Discover Daily"
196
- }
197
- }
198
- ```
199
-
200
- 可在設定頁面「搜尋別名」區塊編輯。
201
-
202
- ---
203
-
204
- ## M3U8 格式
205
-
206
- 所有歌單儲存為 UTF-8 編碼的 `.m3u8` 檔案:
207
-
208
- ```
209
- #EXTM3U
210
- #EXTINF:-1,YOASOBI - 夜に駆ける
211
- ../Music/YOASOBI - 夜に駆ける.mp3
212
- #EXTINF:-1,Ado - 唱
213
- ../Music/Ado - 唱.mp3
214
- ```
215
-
216
- - 路徑為**相對路徑**(相對於 Playlists 目錄)
217
- - 使用**正斜線 `/`** 作為路徑分隔符號
218
- - 只有**匹配到的歌曲**才會寫入(unmatched 不會被寫入)
219
- - 換行使用 LF(`\n`)
220
-
221
- ---
222
-
223
- ## 開發用指令
224
-
225
- ### Flutter 分析
226
-
227
- ```bash
228
- flutter analyze
229
- ```
230
-
231
- ### 編譯 Windows Release
232
-
233
- ```bash
234
- flutter build windows --release
235
- ```
236
-
237
- 輸出:`build/windows/x64/runner/Release/playlist_administrator.exe`
238
-
239
- ### 編譯 Windows Debug
240
-
241
- ```bash
242
- flutter build windows --debug
243
- ```
244
-
245
- 輸出:`build/windows/x64/runner/Debug/playlist_administrator.exe`
246
-
247
- ### 版本標籤
248
-
249
- 發版只推 tag 即可,**不需**更新 pubspec.yaml 或任何檔案,
250
- GitHub Actions 會自動從 tag 讀取版本號填入編譯:
251
-
252
- ```bash
253
- # 1. 先 commit 程式碼修正(不用動版本號)
254
- git commit -am "修復 xxx"
255
-
256
- # 2. 直接打 tag 並推送
257
- git tag v2.6.66
258
- git push origin v2.6.66
259
- ```
260
-
261
- - tag 名稱格式:`vX.Y.Z`(例如 `v2.6.66`)
262
- - 推送後 CI 會自動:`flutter build windows --release --dart-define=APP_VERSION=<版本號>` → Inno Setup 打包 → 上傳 GitHub Release
263
- - `pubspec.yaml` 的 `version` 欄位僅供分支推播(非 tag)時備用,發版流程可忽略