改用 Node.js 實作,並將其封裝成一個在 Windows 上雙擊即可執行、免安裝 Node.js 環境的獨立 .exe 檔,可以使用 webdav-server 套件來架設伺服器,並搭配 pkg 工具來進行封裝。
步驟 1:初始化專案與安裝套件
- 在 Windows 上建立一個新資料夾(例如
music-server)。 - 打開命令提示字元 (CMD) 或 PowerShell,切換到該資料夾:
cd C:\path\to\music-server- 初始化 Node.js 專案並安裝必要的套件(
webdav-server用於架設服務,pkg用於打包成 exe):
npm init -y
npm install webdav-server
npm install -g pkg步驟 2:撰寫 Node.js 核心程式 (server.js)
在資料夾中建立一個名為 server.js 的檔案,並寫入以下程式碼。這段程式會自動偵測執行檔所在目錄下的 Music 資料夾,這樣你未來移動 .exe 檔時,只要旁邊有放音樂資料夾就能直接啟動。
const webdav = require('webdav-server').v2;
const path = require('path');
const os = require('os');
const fs = require('fs');
// ==================== 設定區 ====================
const PORT = 8010;
// 自動抓取執行檔所在目錄下的 "Music" 資料夾
// 如果是開發階段 (node server.js),則會抓取當前專案目錄下的 Music 資料夾
const baseDir = process.pkg ? path.dirname(process.execPath) : __dirname;
const MUSIC_FOLDER = path.join(baseDir, 'Music');
// ================================================
// 自動建立音樂資料夾(如果不存在的話)
if (!fs.existsSync(MUSIC_FOLDER)) {
fs.mkdirSync(MUSIC_FOLDER, { recursive: true });
}
// 取得本機 192.168.X.X 的區域網路 IP
function getLocalIP() {
const interfaces = os.networkInterfaces();
for (const devName in interfaces) {
const iface = interfaces[devName];
for (let i = 0; i < iface.length; i++) {
const alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '128.0.0.1' && !alias.internal) {
return alias.address;
}
}
}
return '127.0.0.1';
}
const localIP = getLocalIP();
// 建立 WebDAV 伺服器
const server = new webdav.WebDAVServer({
port: PORT
});
// 將實體音樂資料夾映射到 WebDAV 的根目錄 (/)
server.setFileSystem('/', new webdav.PhysicalFileSystem(MUSIC_FOLDER), (status) => {
console.log("==================================================");
console.log(" 🎵 Node.js Windows 個人音樂維護伺服器已啟動!");
console.log(` 📂 正在分享資料夾: ${MUSIC_FOLDER}`);
console.log(` 🌐 請在 iPhone App (如 Evermusic) 中輸入此 WebDAV 網址:`);
console.log(` http://${localIP}:${PORT}`);
console.log("==================================================");
console.log("提示:請保持此視窗開啟。若要關閉,請直接關閉視窗或按 Ctrl + C。");
});
// 啟動伺服器
server.start(() => {
// 伺服器成功在指定 Port 監聽
});
步驟 3:封裝成 Windows 獨立執行檔 (.exe)
在 CMD 中執行 pkg 指令,將剛才寫好的 server.js 打包。指定目標為 Windows 的 64 位元架構 (win-x64):
pkg server.js --target node18-win-x64 --output music-server.exe(備註:node18 代表使用 Node.js v18 的環境來封裝,pkg 會自動下載對應的基礎檔,第一次打包會稍慢,之後就很快。)
打包完成後,你的資料夾內就會出現一個 music-server.exe 檔案。
步驟 4:如何部署與使用
- 將產出的 music-server.exe 複製到你想放置的任何地方(例如 D:\iPhone音樂維護\)。
- 在 music-server.exe 的同一個資料夾底下,建立一個名為 Music 的資料夾。
- 把你的 MP3、AAC 音樂檔案全部丟進這個
Music資料夾中(可以自由分類資料夾,如建立「周杰倫」、「健身歌單」等)。 - 雙擊執行 music-server.exe,畫面上就會跳出黑底白字的視窗,顯示你目前的電腦 IP 以及給 iPhone 連線的網址。
- 手機打開 Wi-Fi 並連接同一個路由器,開啟 Evermusic App,按照前一次提到的步驟連線到 http://你的IP:8010,就能直接瀏覽並一鍵將音樂整批下載到 iPhone 離線收聽了!
如何驗證與連線?
不需要在 Windows 瀏覽器看它,請直接依照下列方式使用:
測試方式 A:直接用 iPhone 連線(推薦)
請確保手機與電腦在同一個 Wi-Fi 下:
- 打開 iPhone 的 Evermusic App。
- 進入「連線 (Connections)」->「新增連線」-> 選擇 WebDAV。
- URL 輸入你在黑視窗畫面上看到的 IP 地址(例如 http://192.168.1.100:8010),帳密留空。
- 點擊連線,你就會看到資料夾裡的音樂,並且可以開始下載。
測試方式 B:在 Windows 本機掛載成網路磁碟機
如果你想在 Windows 本機測試它是否運作正常:
- 打開 Windows 的「本機(我的電腦)」。
- 在上方選單點選「連線網路磁碟機」(Map network drive)。
- 資料夾欄位輸入:http://localhost:8010/
- 點擊完成,它就會變成一個像隨身碟一樣的槽位,能直接點進去讀寫檔案。
進階修改:瀏覽器也能直接看(讓 GET 請求正常工作)
如果希望在 Windows 瀏覽器輸入網址時,能直接看到檔案清單網頁,只需要在 server.js 程式碼中加入一個瀏覽器外掛(Browser Middleware)。
請將原本的 server.js 程式碼修改為以下版本(加入第 29 行的 Writter 瀏覽器支援):
// ==================== 設定區 ====================
const webdav = require('webdav-server').v2;
const http = require('http');
const path = require('path');
const os = require('os');
const fs = require('fs');
const PORT = 8010; // 伺服器監聽的 port
// 自動抓取執行檔所在目錄下的 "Music" 資料夾
// 如果是開發階段 (node server.js),則會抓取當前專案目錄下的 Music 資料夾
const baseDir = process.pkg ? path.dirname(process.execPath) : __dirname;
const MUSIC_FOLDER = path.join(baseDir, 'Music');
// 自動建立音樂資料夾(如果不存在的話)
if (!fs.existsSync(MUSIC_FOLDER)) {
fs.mkdirSync(MUSIC_FOLDER, { recursive: true });
}
// 取得本機 192.168.X.X 的區域網路 IP
function getLocalIP() {
const interfaces = os.networkInterfaces();
for (const devName in interfaces) {
const iface = interfaces[devName];
for (let i = 0; i < iface.length; i++) {
const alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
return alias.address;
}
}
}
return '127.0.0.1';
}
const localIP = getLocalIP();
// 建立 WebDAV 伺服器
// 1. 建立純淨的 WebDAV 核心實例 (不帶任何 port 參數,不讓它自己開伺服器)
const davServer = new webdav.WebDAVServer();
// 將實體音樂資料夾映射到 WebDAV 的根目錄 (/)
davServer.setFileSystem('/', new webdav.PhysicalFileSystem(MUSIC_FOLDER), (status) => {
// 檔案系統掛載成功
});
// 2. 使用 Node.js 內建的 http 模組來掌控最外層的請求
const httpServer = http.createServer((req, res) => {
// 如果是網頁瀏覽器發送的標準 GET 請求,且直接瀏覽根目錄
if (req.method === 'GET' && req.url === '/') {
fs.readdir(MUSIC_FOLDER, (err, files) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h2>🎵 Windows 個人音樂維護伺服器</h2><ul>');
if (err || files.length === 0) {
res.write('<li>目前資料夾內沒有歌曲,請放入 MP3 檔案。</li>');
} else {
files.forEach(file => {
res.write(`<li>📌 ${file}</li>`);
});
}
res.write('</ul><p>iPhone 傳輸專用,請保持此視窗開啟。</p>');
res.end();
});
} else {
// 3. 所有其他請求(例如 iPhone App 發出的 WebDAV 專屬指令)全部轉交給 WebDAV 核心處理
davServer.execute(req, res);
}
});
// 3. 啟動伺服器監聽
httpServer.listen(PORT, () => {
console.log("==================================================");
console.log(" 🎵 Node.js Windows 個人音樂維護伺服器已成功啟動!");
console.log(` 📂 正在分享資料夾: ${MUSIC_FOLDER}`);
console.log(` 🌐 網頁/iPhone App 皆可連線:`);
console.log(` http://${localIP}:${PORT}`);
console.log("==================================================");
console.log("提示:請保持此視窗開啟。若要關閉,請直接按 Ctrl + C。");
});這個架構利用原生 http.createServer 做路由分流。瀏覽器的 GET / 請求會走內建的 fs.readdir 流程列出檔案,完全不經過 webdav-server;而 iPhone App(如 Evermusic)連線時所發出的 PROPFIND、OPTIONS 請求則會被 else 區塊捕獲,並由 davServer.execute(req, res) 接手處理。這完全繞過了第三方套件內建網頁外掛的相容性錯誤。
修改完畢後,重新用 pkg 打包成 .exe。這時候你再用 Chrome 瀏覽器打開 http://localhost:8010/,就不會再報 405 錯誤,而是會看到一個純文字的檔案清單網頁了!
如何在 Visual Studio Code 偵錯
建立 VS Code 偵錯設定檔 (launch.json)
VS Code 需要一個設定檔來知道如何啟動 Node.js 的偵錯模式。
- 點擊 VS Code 左側工具列的 「執行與偵錯」圖示(一個播放鍵加一隻小蟲的圖標🐞),或直接按快速鍵
Ctrl + Shift + D。 - 點擊畫面上的 「建立 launch.json 檔案」 (create a launch.json file) 連結。
- 在上方彈出的下拉選單中選擇 Node.js。
- VS Code 會自動在專案中建立一個
.vscode/launch.json檔案。請將其內容修改並替換為以下設定:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "測試執行並偵錯音樂伺服器",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/server.js",
"restart": true,
"console": "integratedTerminal"
}
]
}
如何開始進行「中斷點偵錯」
- 打開你的 server.js。
- 設定中斷點:將滑鼠移到程式碼左側的行號旁邊(例如 const server = new webdav.WebDAVServer… 那幾行),點擊一下會出現一個紅點。這代表程式執行到這一行時會暫停,讓你檢查變數值。
- 啟動偵錯:按下鍵盤上的
F5,或者點擊左側偵錯面板上方的 綠色播放按鈕(測試執行並偵錯音樂伺服器)。 - 觀察 VS Code 下方的「終端機 (Terminal)」面板,你會看到 Node.js 成功啟動,並印出你的伺服器 IP 與網址。
- 此時你可以用 iPhone App 或瀏覽器連線測試。如果觸發了你設紅點的那幾行程式,VS Code 會自動暫停,你可以將滑鼠移到變數(例如 MUSIC_FOLDER)上方查看當前路徑是否正確。
確保「偵錯階段」與「打包後」路徑一致
在偵錯時,有一點需要特別注意:在 server.js 中使用了 process.pkg 來判斷是否處於打包狀態。
為了確保在 VS Code 中測試時(process.pkg 為 false),程式抓到的 Music 資料夾路徑,跟未來變成 .exe 時完全一樣,請檢查路徑邏輯。使用先前寫的這段邏輯是完全沒問題的:
// 如果是被 pkg 打包了,抓 .exe 所在目錄;如果是 VS Code 偵錯,抓目前專案目錄
const baseDir = process.pkg ? path.dirname(process.execPath) : __dirname;
const MUSIC_FOLDER = path.join(baseDir, 'Music');Python 與 Nodejs 的比較
| 開發目標 | 推薦首選 | 原因 |
|---|---|---|
| 重視外觀、需要漂亮 UI 的桌面軟體 | 🥇 Node.js (Electron / Tauri) | 用網頁技術刻介面最快最美,封裝生態系極度成熟。 |
| 純背景執行、Excel 處理、自動化爬蟲腳本 | 🥇 Python (PyInstaller) | 語法直覺、第三方自動化與數據庫極其強大,打包檔案輕量。 |
| 小工具(簡單介面 + 自動化邏輯) | 🥈 兩者皆可 | 可以用 Python + CustomTkinter,或 Node.js + Tauri,看您對哪種語言比較熟悉。 |
為什麼 Node.js 更適合開發 WebDAV 音樂伺服器?
要讓 iPhone 的現成音樂 App(如 Marvis Pro、Evermusic、Flacbox 等)透過 WebDAV 進行全自動同步, Windows 端程式本質上是一個 「常駐的 Web 伺服器」。
- WebDAV 協議的高效處理
- Node.js 的核心強項就是處理高併發的 HTTP 請求。音樂檔案通常很大(尤其是無損格式如 FLAC、WAV),Node.js 內建的 Stream(串流)機制極其強大,可以用極低的記憶體消耗,把 Windows 電腦裡的音樂串流傳輸到 iPhone 上,不會因為多人連線或傳輸大檔案而崩潰。
- Python 雖然也能做(如使用 Flask 或 FastAPI),但在處理大檔案串流與高併發請求時,Node.js 的事件驅動非阻塞 I/O 表現更為直覺且高效。
- 成熟的 WebDAV 生態系
- Node.js 有非常成熟的開源 WebDAV 伺服器套件(例如 webdav-server),幾行程式碼就能在 Windows 內建一個支援權限管理、檔案讀寫的 WebDAV 服務。
- 桌面端封裝與使用者體驗 (UI)
- 因為是給一般 Windows 用戶使用的 .exe,您一定需要一個介面讓使用者「點擊開啟服務」、「設定音樂資料夾路徑」、「顯示目前連線狀態」或「產生 QR Code 讓 iPhone 掃描連線」。
- 使用 Node.js + Tauri 或 Electron,您可以輕鬆用網頁前端技術做出極其美觀、現代化的 Windows 控制台介面,並一鍵打包成獨立的 .exe。
Node.js 與 Python 可以整合嗎?
可以,而且非常常見!
在軟體開發中,這叫作微服務架構(Microservices)或多語言協作。在這個情境中,完美的結合方式是:
- Node.js 擔任「對外窗口」(主程式):負責 UI 介面、WebDAV 伺服器、監聽 HTTP 請求、串流傳輸音樂給 iPhone。
- Python 擔任「幕後工具人」(子程序):負責音樂檔案的元數據(Metadata)處理。
為什麼背景需要 Python?
Python 在處理音樂檔案(如 MP3、FLAC)的標籤(ID3 Tag、封面圖片、歌詞、自動分類)以及音訊轉碼(如使用 pydub 或呼叫 FFmpeg 將不支援的格式轉為 AAC)時,擁有比 Node.js 更豐富且強大的第三方庫(如 mutagen)。
兩者整合的架構與打包方式
如果決定同時使用兩者,將它們打包成「單一獨立 .exe」的實務作法如下:
- 開發階段(溝通橋樑):
- Node.js 主程式會使用內建的 child_process.spawn() 模組,在背景偷偷啟動 Python 程式。
- 兩者之間可以透過 標準輸入輸出 (stdin/stdout) 或內部的 本地本地 API (Local localhost API) 來傳遞資料(例如 Node.js 告訴 Python:「幫我解析這首 MP3 的封面圖片」,Python 處理完後回傳給 Node.js)。
- 封裝打包階段(變成單一 .exe):
- 您可以使用 Python (PyInstaller) 先將 Python 的核心邏輯打包成一個私有的 backend.exe(不帶介面,純背景運作)。
- 接著,使用 Node.js (Tauri 或 Electron) 打包主程式時,將這個 backend.exe 作為「資源檔案 (Resources/Sidecar)」一起包進去。
- 當使用者執行您的最終 .exe 時,Node.js 介面開啟的瞬間,會自動在背景呼叫那個包在裡面的 Python 程式。對使用者而言,他們只看到一個軟體,完全感覺不到裡面有 Python。



