Skip to content

milestone 2.0.0 - #73

Closed
flier268 wants to merge 134 commits into
masterfrom
migrate-to-nodejs
Closed

flier268 wants to merge 134 commits into
masterfrom
migrate-to-nodejs

Conversation

@flier268

@flier268 flier268 commented Aug 14, 2026 •

Copy link
Copy Markdown
Owner

ConvertZZ 2.0.0

自 1.0.0.8(WPF/Windows 限定)起的第一個公開預發行版。

2.0 以 Vue 3、Element Plus、Tauri 2 與 Rust 轉換核心重寫,正式支援 Windows x64 與 Linux x64。

這是預發行版,供測試與回饋。正式版前行為與安裝流程仍可能調整。

使用者不需要另外安裝 Node.js、FFmpeg 或 TagLib。

相較 1.0.0.8 的主要變化

架構與平台

  • 由單一 Windows WPF 應用改為跨平台桌面程式;轉換核心與桌面層同程序,發行包不含外部 Node.js 執行檔。
  • Linux 可使用 AppImage、DEB、RPM;乾淨環境不需建置用 *-dev 套件即可執行。
  • 保留單一執行個體、系統托盤、獨立浮動球、全域快捷鍵與舊版命令列語意。

轉換引擎

  • 預設引擎改為新式分詞(ws-segment-rs + cjk-convert-rs);簡轉繁會做同義詞最佳化。
  • 舊版字典仍讀取 UTF-8 BOM 六欄 Dictionary.csv,保留啟用欄位、優先權、長詞優先與 9999 保護詞。
  • ZhConvert 改呼叫官方 /convert,快取 /service-info 二十四小時;網路失敗時不會自動切換引擎。
  • 空白、換行、標點與未知片段盡量保持原位;長文會在安全邊界分段。

檔案與寫入安全(刻意與舊版不同)

  • 檔案內容、檔名與音訊標籤作業都會先預覽,確認後才寫入。
  • 檔名衝突預設略過;覆寫需額外確認。
  • 內容先寫入同目錄暫存檔,驗證成功後才取代;檔名採兩階段重新命名,失敗時嘗試回復。
  • 遞迴處理不跟隨符號連結。
  • 轉換前預設建立 .bak 備份(可用設定或 /b:f 關閉)。
  • 舊命令列參數大多相容,但不再提供無確認直接寫入。

音訊標籤

  • MP3:ID3v1/ID3v2.3/ID3v2.4(Rust id3);ID3v1 可修復 Big5/GBK 損壞文字。
  • APE:APEv2;OGG/OGA/Opus:Vorbis Comment(Rust lofty)。
  • 未選欄位、未知欄位、二進位欄位與封面不變;不會重新編碼音訊內容。
  • 離線即可掃描 APE/OGG,不在執行時下載 WASM。

設定與字典

  • 首次發現舊版 ConvertZZ.json 會詢問;同意後只讀取並另存為 2.0 設定,不修改來源。
  • 儲存 Dictionary.csv 前會詢問,並先建立不覆蓋的時間戳備份。

自動更新

  • Windows 安裝程式與 Linux AppImage 支援應用程式內更新,並以 minisign 公鑰驗證。
  • DEB/RPM 不會就地覆寫;檢查更新時會改開啟 GitHub Releases。
  • 預設只檢查正式版;設定中可開啟「檢查開發/預發佈版本」才會看到本 beta。

已知限制與平台差異

  • Linux Wayland:全域快捷鍵與自動複製貼上於本版停用;浮動球置頂依合成器能力而定。
  • Linux 托盤通常需要 AppIndicator/StatusNotifier;缺少時主視窗仍可使用。Tauri 在 Linux 不提供托盤左鍵事件,請用選單開啟主視窗。
  • ZhConvert API 金鑰優先存入作業系統憑證庫;Linux 缺少 Secret Service 時只保留於目前工作階段。
  • 少數字形結果可能與舊版 Windows LCMapStringEx 不同。
  • 編碼工具改為明確指定編碼,不再跟隨舊版 Encoding.Default 系統碼頁。

回報問題

請到 GitHub Issues,並附上作業系統、桌面環境(X11/Wayland)、安裝格式與重現步驟。

移除硬編碼的雙擊轉繁與右鍵轉簡。左鍵無輔助鍵只拖曳,輔助鍵加點擊執行設定動作,右鍵開啟與舊版相同的選單。
托盤改列與舊懸浮球相同的轉換、工具與視窗項目,並一律送出 app://legacy-action。同步修正 AppImage 驗收測試字串。
更新已取得證據的項目狀態,並寫入 2026-08-14 的本機驗收紀錄。
開發與 CI 改用 ffmpeg-static 與 tests/fixtures,不再下載遠端樣本或依賴系統 ffmpeg。
該 ffmpeg 不打進發行包。
驗收人已確認關於頁會開啟 GitHub Issues 與 Releases。
主視窗預設不可見。設定新增「啟動時顯示主視窗」,命令列參數或發現更新時仍會顯示。
設定頁快捷鍵欄位改為唯讀並攔截鍵盤事件,不再讓使用者手打加速鍵字串。
首次開啟會顯示系統導覽,其中一步詢問是否匯入 ConvertZZ.json。設定頁移除此匯入按鈕,關於頁可重看導覽。
移除設定頁頂部儲存按鈕。有未儲存變更時,改在畫面底部顯示提示與儲存按鈕。
啟動時先隱藏主視窗與懸浮球,定位後再顯示。
轉換完成改為獨立 Toast,顯示在游標附近,不再裁切於懸浮球內。
補上 ID3v1 Big5/GBK、多值標籤、設定備份失敗與四種音訊副檔名案例,並更新對應驗收狀態。
以 QEMU 安裝 DEB,確認沒有 Node.js 與開發套件,並離線掃描 APE/OGG。映像優先從台灣鏡像下載。
依 test:qemu 通過結果,將 B-03、I-09、J-09、J-10、J-13 標為已通過。
視窗背景改為透明,球體填滿視窗,並停用文字選取。
保留襯線 Z 與上標 2,配色改為 2.0 青綠。懸浮球、側邊欄與關於頁共用同一份路徑圖示,避免字型把 2 畫成 z,並把浮動視窗鎖回 72×72。
存檔與 commit 前會執行 rustfmt 與 Prettier,並套用現有原始碼格式。
Vue Test Utils 的 get() 會省略 exists,導致 vue-tsc 失敗。
將套件管理員改為 pnpm 11,build script 設定改到 pnpm-workspace.yaml。
TypeScript 升到 6.0.3,並依官方建議移除已棄用的 baseUrl。
補上目錄責任、層級邊界與套件更新方式,供後續代理依專案慣例修改。
讓 CI 與 Release 使用 pnpm/action-setup@v6,不再寫死 10.26.1。
依 ID3 標頭擷取 MP3 音訊,讓 2.3/UTF-16 寫回通過驗證。
建立 SettingsV2 驗收表,並在備份失敗時顯示錯誤且不覆寫設定。
以本機正式建置驗證 /file 預覽、APE/OGG 標籤畫面、浮動球拖動與關閉後仍留在背景。
去掉結尾 .app,避免與 macOS 套件副檔名衝突,並同步憑證庫服務名稱。
Windows 安裝程式與 Linux AppImage 會先確認再下載安裝。
發行工作流程會簽署產物並產生 latest.json。
DEB 與 RPM 仍改開啟 GitHub Releases。
舊版 ConvertZZ.json 本來就不會被改寫,結果會另存為 2.0 設定。
關閉 store 自動存檔,載入時先重讀磁碟。浮動球移動改走 patchSavedSettings,避免用過期記憶體覆寫快捷鍵。
只註冊已啟用且有組合鍵的項目;已填但未啟用時提出警告。錯誤改走應用程式通知。
進度文字改到進度條下方;檔案清單、差異檢視、工具編輯區、字典表與設定分頁改吃剩餘高度,避免整頁過長。
pin 與 word=/word^= 的整詞在載入分詞器時釘入,轉換繁體時仍套用 skip/s2t-multi。
和牛、胜肽、里長等固定整詞改由 rules.txt 維護,extra-correction 只保留語料同義。
roundtrip-dict 改從 specials 寫回保護詞,並加入 merge-extra 與單字鄰居粘詞。
從國土測繪中心下載鄉/里正名,分詞時整詞保護,簡轉繁拉回正名。
roundtrip-dict 寫回 extra 分詞表時一併參照。不收鎮/市/區/村。
place-names 由鄉/里擴及縣、市(含縣轄市)與鎮;仍不收區/村或單字。
分詞釘整詞,簡轉繁拉回正名,roundtrip-dict 一併參照。
補充分詞單字並調高權重
同步 package.json、tauri.conf、Cargo 清單、e2e 模擬與更新/免安裝測試版本字串,並新增 beta7 發行說明稿。
無頭在 GUI/single-instance 之前結束,預設不讀設定;可用 --globalconfig 或 --config,明確參數覆寫設定。寫入需 --yes 或是/否確認。
浮動球改為點擊/拖入矩陣;關於頁並排差異卡,內容超出時才出現捲軸。
- 預設檔案篩選移除音訊類型;舊的內建預設載入時自動更新
- prepare_file 與 preview 加入二進位判斷(檔頭 magic、NUL、U+FFFD 比例)
- 判定為二進位或解碼有錯誤時不寫回內容:both 只改檔名,content 不寫入,結果帶警告
- 新增自製正弦波 MP3 fixture(含 ID3 與純 MPEG 幀),驗證位元組不變與檔名轉換

Fixes #76
- 遷移 C# v1 預設篩選(「音頻文件|*.mp3」,來自 00c2e90)與含音訊群組的舊預設
- UTF-16 奇數長度與落單 surrogate 視為解碼錯誤,不寫回
- 檔頭判斷驗證版本/form type/brand,避免「caffeine」「MAC 地址」等純文字誤判
- MPEG 幀同步排除無效 bitrate/sample-rate,並驗證下一幀;無 BOM UTF-16BE「¥」不再誤判
- U+FFFD 比例檢查只用於 UTF-16
- 前端多則略過警告合併為「已略過 N 個檔案的內容轉換」
- 補齊對應 Rust 與前端測試

Refs #76
功能分支只靠 pull_request 觸發 CI,略過 tags;並為 CI/Release 加上 concurrency 取消舊執行。
- C# 1.0.0.0–1.0.0.3 的舊格式(e7c3aeb、03204e6 的 Settings.cs)不含 <,
  照 C# Settings.Reload 的 Contains("<") 規則重設為預設,避免資料夾掃描收進所有檔案
- 移除音訊群組時只拿掉格式完整的 <名稱|樣式>;<junk>、未閉合 < 兩邊都保留比較,
  修正 {預設}/<junk> 在 TS 被重設、Rust 保留的不一致
- 新增共用測試向量 tests/fixtures/type-filter-migration.json,Rust 與 Vitest 逐條跑
- 新增遷移後 visit_files 不收 .mp3/.wav 的測試

Refs #76
- 檔案對話框固定在「支援的檔案」之後加入「所有檔案」(["*"]),不寫入設定字串
- parseLegacyFileFilters 保留自訂 *.* / *;設定頁可「加入所有檔案」寫入 <所有檔案|*.*>
- 資料夾掃描:篩選含 * 時省略 allowedExtensions(Rust None = 所有檔案);
  解析不到副檔名時送空陣列,資料夾掃描不收任何檔,不再等於所有檔案
- 直接指定的檔案一律收(對話框不回報選了哪個篩選),自訂副檔名純文字可轉換
- headless 同步:*.* / * 為所有檔案,無法解析為空清單,缺欄位用預設
- 測試:自訂副檔名轉換、所有檔案模式掃描、MP3 在所有檔案模式 content/both 位元組不變、空清單

Refs #76
- beta1–8 清空篩選器會存成空字串(當時代表所有檔案),現在空清單代表資料夾掃描
  不收任何檔案。Rust 與 TS 遷移都把空字串改回預設,共用向量新增空字串案例。
- appendAllFilesTypeFilter 遇到結尾未閉合的群組(例如 <所有檔案|*.*)先補上 >,
  不再產生 <所有檔案|*.*/<所有檔案|*.*> 這種壞字串。
記憶體:
- 內容檢查先只讀前 64 KiB 判斷檔頭 magic 與 NUL,是二進位就不再讀整個檔案。
- 文字檔超過 64 MiB 略過內容轉換並警告,不整檔讀入。
- verify_stage 改成串流逐塊比對,不再把暫存檔與來源整檔讀進記憶體。
- 內容不變只改名(例如 both 模式的二進位檔)時,同一磁碟區直接 rename;
  跨磁碟區才串流複製、串流比對後再 rename。

資料夾掃描:
- 遞迴掃描略過 .git、.svn、.hg、.bzr 與其他以點開頭的資料夾(檔案與子資料夾改名都不收)。
- 直接指定版本控制資料夾或其中的路徑時預設略過並列在計畫的 ignoredInputs;
  GUI 跳出確認視窗,確認後以 includeIgnored 重建計畫,取消則從來源清單移除。
  無頭模式印出警告,加上 --include-ignored 才處理。
- 空的副檔名清單不再收子資料夾,both/檔名模式不會改名子資料夾。
- 直接指定的資料夾掃描到 0 個檔案時,計畫加上警告;GUI 另外跳提示,無頭印出警告。
… 依標籤分組 (#76)

- release.yml:Linux job 在打包前跑 cargo test --workspace(並安裝 ffmpeg,音訊測試需要)。
- ci.yml:push 也監聽 migrate-to-nodejs(beta 標籤從這個分支打)。
- release.yml:concurrency 群組改成 workflow-標籤,手動觸發時同一分支先後發兩個標籤不會互相取消。
還原 a118dcd 加入的 migrate-to-nodejs push 監聽(回到 312ecf7 的原意);Release 的 cargo test 與 concurrency 保留。
還原 1131b37 只監聽 master 的做法。push 監聽改為所有分支(branches: "**",仍不監聽 tags);pull_request 保留,但每個 job 以 if 只讓 fork 來的 PR 執行,同一個 commit 不會被 push 與 PR #73 各跑一次。
同步 package.json、tauri.conf、Cargo 清單、e2e 模擬與更新/免安裝測試版本字串,並新增 beta9 發行說明稿(回應 #76)。
- commit_unchanged_content 先試 rename(source, output);遇到 CrossesDevices/EXDEV
  才分段複製到 stage、串流比對,通過後才把來源移成 original,再把 stage 改成
  output,最後刪除 original。來源移開前失敗或取消時刪除 stage,來源留在原位。
- 先搬開來源只保留給同一磁碟區、只差大小寫的改名;validator 改傳仍存在的來源。
- 分段複製(1 MiB)每塊之間檢查取消。
- 掃描略過 .convertzz- 開頭的交易殘留檔。
- 遞迴時讀不到的子資料夾略過並記成帶路徑的警告;頂層讀不到仍報錯。
- merge_warning 不重複接同一句。
- 發行說明補上 Linux 對話框會把 * 變成 *.* 的限制。
@flier268 flier268 closed this Oct 13, 2026
@flier268
flier268 deleted the migrate-to-nodejs branch October 13, 2026 06:22
@flier268 flier268 mentioned this pull request Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant