import { ipcMain, dialog, BrowserWindow, shell } from 'electron' import { IPC } from '@shared/ipc/channels' import { getStore } from '../services/store' import { dbQuery, dbExec } from '../services/database' import { startFileServer, stopFileServer, getFileServerStatus } from '../services/fileServer' import { getLanIps } from '../services/lanInfo' import { fetchJson, fetchText } from '../services/network' import { syncLibrary } from '../services/library' import { convertFlacToWav, stopConvert } from '../services/transcode' import { startMusicServer, stopMusicServer, sendMusicCmd } from '../services/musicServer' import { startDataServer, stopDataServer, sendDataCmd } from '../services/dataServer' import { toggleDesktopLyric, updateDesktopLyric, setLyricIgnoreMouse } from '../window/desktopLyricWindow' import { checkUpdate } from '../services/update' import { exportSongs, type ExportItem } from '../services/export' import { cleanIosWavFile, ensureIosWavFiles, type WifiAudioRef } from '../services/wifiTransfer' function broadcast(channel: string, payload: unknown): void { BrowserWindow.getAllWindows().forEach((w) => w.webContents.send(channel, payload)) } export function registerIpc(): void { /* ---------- 配置 ---------- */ const store = getStore() ipcMain.handle(IPC.STORE_GET, (_e, key: string) => store.get(key as never)) ipcMain.handle(IPC.STORE_SET, (_e, key: string, value: unknown) => store.set(key as never, value as never) ) ipcMain.handle(IPC.STORE_DELETE, (_e, key: string) => store.delete(key as never)) /* ---------- 数据库 ---------- */ ipcMain.handle(IPC.DB_QUERY, (_e, sql: string, params: unknown[]) => dbQuery(sql, params)) ipcMain.handle(IPC.DB_EXEC, (_e, sql: string, params: unknown[]) => { const r = dbExec(sql, params) return { changes: r.changes, lastInsertRowid: Number(r.lastInsertRowid) } }) /* ---------- HTTP 文件服务 ---------- */ ipcMain.handle(IPC.HTTP_START, async (_e, root: string, port: number) => startFileServer(root, port) ) ipcMain.handle(IPC.HTTP_STOP, async () => { await stopFileServer() return true }) ipcMain.handle(IPC.HTTP_STATUS, () => getFileServerStatus()) /* ---------- 局域网 ---------- */ ipcMain.handle(IPC.NET_LAN_IPS, () => getLanIps()) /* ---------- OSS 元数据 ---------- */ ipcMain.handle(IPC.NET_FETCH_JSON, (_e, url: string) => fetchJson(url)) ipcMain.handle(IPC.NET_FETCH_TEXT, (_e, url: string) => fetchText(url)) /* ---------- 曲库同步 ---------- */ ipcMain.handle(IPC.LIBRARY_SYNC, async () => { const result = await syncLibrary() store.set('dataVersion', String(result.version)) return result }) ipcMain.handle(IPC.LIBRARY_DATA_VERSION, () => store.get('dataVersion')) /* ---------- 转码 ---------- */ ipcMain.handle(IPC.CONVERT_START, async (_e, input: string, output: string) => { await convertFlacToWav({ input, output, onProgress: (p) => broadcast(IPC.CONVERT_PROGRESS, { input, progress: p }) }) broadcast(IPC.CONVERT_DONE, { input, output }) return true }) ipcMain.handle(IPC.CONVERT_STOP, () => { stopConvert() return true }) ipcMain.handle(IPC.WIFI_ENSURE_IOS_WAV, async (_e, items: WifiAudioRef[]) => { await ensureIosWavFiles(items || []) return true }) ipcMain.handle(IPC.WIFI_CLEAN_IOS_WAV, (_e, item: WifiAudioRef) => { cleanIosWavFile(item) return true }) /* ---------- 传歌服务(4388) ---------- */ ipcMain.handle(IPC.MUSIC_SERVER_START, () => { startMusicServer((e) => broadcast(IPC.MUSIC_SERVER_EVENT, e)) return true }) ipcMain.handle(IPC.MUSIC_SERVER_STOP, () => { stopMusicServer() return true }) ipcMain.handle(IPC.MUSIC_SERVER_SEND, (_e, cmd: string, body: string) => sendMusicCmd(cmd, body) ) /* ---------- 数据同步服务(4389) ---------- */ ipcMain.handle(IPC.DATA_SERVER_START, () => { startDataServer((e) => broadcast(IPC.DATA_SERVER_EVENT, e)) return true }) ipcMain.handle(IPC.DATA_SERVER_STOP, () => { stopDataServer() return true }) ipcMain.handle(IPC.DATA_SERVER_SEND, (_e, cmd: string, body: string) => sendDataCmd(cmd, body) ) /* ---------- 对话框 ---------- */ ipcMain.handle(IPC.DIALOG_OPEN_DIR, async () => { const r = await dialog.showOpenDialog({ properties: ['openDirectory'] }) return r.canceled ? null : r.filePaths[0] }) ipcMain.handle(IPC.DIALOG_OPEN_FILE, async () => { const r = await dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }) return r.canceled ? null : r.filePaths }) /* ---------- 桌面歌词 ---------- */ ipcMain.handle(IPC.LYRIC_TOGGLE, (_e, show: boolean) => { toggleDesktopLyric(show) broadcast(IPC.LYRIC_STATE, show) return true }) ipcMain.on(IPC.LYRIC_UPDATE, (_e, payload) => updateDesktopLyric(payload)) ipcMain.on(IPC.LYRIC_SET_IGNORE_MOUSE, (_e, ignore: boolean) => setLyricIgnoreMouse(ignore)) /* ---------- 窗口控制 ---------- */ ipcMain.on(IPC.WIN_MIN, (e) => BrowserWindow.fromWebContents(e.sender)?.minimize()) ipcMain.on(IPC.WIN_MAX, (e) => { const w = BrowserWindow.fromWebContents(e.sender) if (!w) return w.isMaximized() ? w.unmaximize() : w.maximize() }) ipcMain.on(IPC.WIN_CLOSE, (e) => BrowserWindow.fromWebContents(e.sender)?.close()) /* ---------- 导出歌曲 ---------- */ ipcMain.handle( IPC.EXPORT_SONGS, async (_e, dest: string, platform: 'android' | 'ios', list: ExportItem[]) => exportSongs(dest, platform, list, (p) => broadcast(IPC.EXPORT_PROGRESS, p)) ) /* ---------- 更新 ---------- */ ipcMain.handle(IPC.UPDATE_CHECK, () => checkUpdate()) ipcMain.handle(IPC.UPDATE_OPEN_DOWNLOAD, (_e, url: string) => { if (url) shell.openExternal(url) return true }) }