# mplayer **Repository Path**: mh-code/mplayer ## Basic Information - **Project Name**: mplayer - **Description**: 一款本地音乐播放器 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: ai/reset-clear-cache - **Homepage**: http://mplayer.1234n.cn/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-25 - **Last Updated**: 2026-09-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: Mplayer是一个纯本地的音乐播放器 ## README # Mplayer 本地音乐播放器,界面与主题复刻 `E:\meizu\Videos\music.mp4` 中演示的播放器(Salt Player 风格浅色主题), 使用 **Electron 33 + Vite 7 + Vue 3 + Naive UI + TypeScript + Pinia + SCSS** 从零实现。 > 程序名已从 **Z Music** 全量改为 **Mplayer**:侧边栏品牌、窗口标题、托盘提示、任务栏、 > 关于页、打包产物名与 `package.json`(`name` / `productName` / `appId` / `author`)全部同步。 > 数据目录随之从 `%APPDATA%/Z Music/` 变为 `%APPDATA%/Mplayer/`,启动时会**一次性自动迁移** > (同盘直接改名,跨盘或被占用时退化为复制,连复制都失败则回退到旧目录继续用), > 见 `electron/main/legacy-userdata.ts`。 ## 功能 **曲库** - 扫描任意音乐文件夹(MP3 / FLAC / WAV / OGG / M4A / AAC / OPUS / AIFF / APE / WMA / DSD 等) - **文件夹管理**:音乐库里一个文件夹一行,可单独移除;添加时自动去重(忽略大小写/结尾分隔符,已被父级包含的子目录会跳过,新加的父目录会顶掉旧的子目录) - **扫描过滤**:可指定只扫描哪些格式(不选 = 不限格式,想排除 DSD 之类的不勾即可),另有「忽略时长不足的音频」 (**默认 30 秒**,填 0 = 不限制;老配置里没改过的 0 会在升级时一次性升到 30)与「忽略体积过小的文件」 两项,用来把铃声、试听片段挡在曲库外;改完条件后点「过滤条件」那一行的 **应用并重新扫描**按钮才生效(本色渐变按钮,扫描中图标转动并显示进度百分比) - 读取标签、内嵌封面(缓存到 `%APPDATA%/Mplayer/covers`)、时长、码率、采样率、位深 - 歌曲 / 曲风 / 专辑 / 艺术家 四种维度均可下钻到详情页;文件夹页只有两层 —— 列出已添加的音乐文件夹(一行一个、显示完整路径),点进去直接看这个文件夹下的全部音乐(含所有子目录) - 搜索(`Ctrl + F` 聚焦)、排序(工具栏「排序」下拉:标题/艺术家/专辑/时长/文件名 + 升/降序)、点击行内艺术家或专辑直接过滤 - **音乐信息分析**(音乐库页):总体积、平均比特率、无损/有损比例、格式分布、时长分布、采样率与位深分布、封面/不可读文件的完整度 - 音乐库页顶部的四张统计卡(歌曲 / 曲风 / 专辑 / 艺术家)可直接点击,跳到对应的浏览页面; 卡片是干净的实底卡(**没有顶部本色粗边、也没有本色光晕** —— 按需求去掉,太抢眼), 色相只落在图标底板、数量与进入箭头上;统计页的四张概览卡与它保持同一套外观 - **歌曲详细信息**(右键菜单 / 全屏播放页 CD 中心):标签、音频参数、**完整歌词**(有就整段按行列出 + 一键复制,没有就一句「这首歌没有歌词」(不显示行数 / 来源统计);打开的就是正在播放的那首时,同步歌词会标出播放到的那一行)、文件路径与**中文标签帧清单** (帧名换成人话,只列能看懂 / 含义明确的;认不出来的一律不显示,悬停可看原始帧名;歌词帧不重复列,上面歌词区已经显示过) - **统计**(侧边栏独立页面,原「听歌统计」):总播放次数与累计时长、近 14 天趋势、最常听的歌曲与艺术家、按天记录 **播放** - 列表循环 / 单曲循环 / 随机播放 / 顺序播放 - 播放队列抽屉:跳播、移除、清空 - 迷你播放器(封面 + 标题 + 进度 + 传输控制 + 音量),**控制栏实时显示当前歌词行**(前奏阶段显示即将开始的一句,点歌词打开全屏播放页) - 全屏播放页:封面模糊背景 + LRC 歌词滚动高亮,**歌词读取优先级:内嵌歌词 → 外部 .lrc 文件**: 1. 音频文件内嵌歌词 —— 先看 music-metadata 归一化后的 `common.lyrics`(ID3v2 `USLT` / `SYLT`、Vorbis `LYRICS` / `UNSYNCEDLYRICS`、MP4 `©lyr`、APE `Lyrics` 等) 2. 内嵌歌词兜底 —— 直接翻原生标签帧:任何 id 里含 `LYRIC` / `歌词` 的帧都算,覆盖 `TXXX:LYRICS`(千千静听 / foobar / 酷狗等常见写法)、`LYRICS_ZH`、`UNSYNCED LYRICS`、`©lyr` 等命名差异;再退一步,任何**取值里带 LRC 时间轴**的帧、以及带时间轴的注释(`COMM`)也会被当作歌词 3. 没有内嵌歌词时,才读歌曲同目录的同名 `.lrc` 文件(UTF-8 读不动时自动按 GBK 再解一次,老歌词文件不乱码) 4. 标签里只有「纯音乐,敬请欣赏」「此歌曲为没有填词的纯音乐,请您欣赏」这类**占位文案**时不算歌词(继续找 `.lrc`,都没有就显示「暂无歌词」),不会再把占位文字当成歌词显示 5. **同一个标签往往给两份表示**:`text`(时间轴被丢掉的整段文字)与 `syncText`(`[{ timestamp(毫秒), text }]` 结构化时间轴),原生 LRC 帧又是第三份。提取时**把所有候选按"有没有时间轴"排序再挑**,不再撞上 `text` 就返回 —— "歌词读到了、时间轴没了"就是这个原因 6. 末尾 `[99:00.xx]本歌曲来自某平台` 这类**宣传语时间戳**(超过 30 分钟)直接丢弃,否则滚动条会跑到歌外 7. 译文写在前、原文写在后的双语文案(俄语歌配中文译文)会自动把原文换回主行 - 有时间轴 → 逐行滚动高亮,**正在播放的那一行行首带一颗青→紫→粉的圆点标记**(播放中轻轻呼吸, 暂停时保持常亮);**没有时间轴的纯文本内嵌歌词也能正常整段显示**(不再被当作"暂无歌词"丢掉) - 全屏页左上角标注来源(「内嵌歌词」/「本地歌词文件」) - 开头的 `[ti:]/[ar:]/[by:]/[offset:]` 元信息行,以及 `[00:00.00]作词 : …` 这类**署名 / 歌名行**都会剥掉(只在开头 6 秒内、最多看 5 行,正文里出现「作曲」二字不会误删),从第一句正文开始显示 - 界面只给三种状态:正常显示歌词 / **歌词不可用**(读取失败)/ **暂无歌词**(文件里没有),不出现「无时间轴」这类技术提示 - 歌词接口 `no-store`、所有响应带 `Vary: Origin`:补了同名 `.lrc` 或重新打了标签切回来立刻生效, 也避免同源(打包版)缓存下来「没有 CORS 头」的响应把开发模式的请求挡在 CORS 外面(症状正是"这首歌没歌词") - 全局媒体键(播放/暂停、上一首、下一首),后台也生效 - 歌单:新建 / 重命名 / 删除、内置「爱听」收藏歌单、右键菜单批量加入 **窗口 / 托盘** - 无边框自绘标题栏(折叠侧边栏 / 最小化 / 最大化 / 关闭),窗口大小与位置记忆; 标题栏**不显示软件名称**(名字只在左侧边栏品牌区),左侧只保留「N 个音轨无法读取」的琥珀色警告药丸 - 系统托盘:左键显示主界面,右键菜单可播放/暂停、上一首、下一首、退出 - **后台运行开关**(设置 → 后台运行,**默认开启**) - 开启(默认):点击关闭按钮 → **隐藏到系统托盘**,音乐继续播放;从托盘菜单「退出」结束进程 - 关闭:点击关闭按钮 → **彻底退出应用** **帮助** - 设置 → 帮助:上手指引、歌词/封面为什么没显示、关闭按钮为什么不退出、快捷键速查、数据目录与常见问题 ## 运行 ```bash npm install # 安装依赖(首次会下载 Electron 运行时) npm run dev # 开发模式:Vite dev server + Electron 热重载 npm run dev:debug # 同上,但带调试模式(自动开开发者工具 + 转发渲染层日志) npm run build # 构建主进程(esbuild)+ 渲染层(vite build) npm start # 构建后以生产模式启动 npm run start:debug # 同上,但带调试模式 npm run typecheck # 渲染层类型检查(vue-tsc) npm run typecheck:node # 主进程 / preload 类型检查 npm run dist # 打包 Windows 安装包(electron-builder → release/) npm run dist:linux # 打包 Linux AppImage + deb npm run dist:mac # 打包 macOS dmg ``` 关于页的版本号直接取自 `package.json`,发行日期在构建时生成:`vite.config.ts` 用 `define` 注入 `__APP_VERSION__` / `__BUILD_DATE__`;`npm run dist` 会先构建渲染层,所以打出来的日期就是打包当天。 界面里不再有任何写死的版本号。 **终端中文乱码**:Windows 控制台默认代码页是 936(GBK),而 Node 写的是 UTF-8 字节,控制台会把 每个字节当成一个 GBK 字解码,日志就成了「鏂版鏁版嵁」。`npm run dev` / `build:main` / 主进程启动时 都会先读一次控制台代码页(`scripts/console-utf8.mjs`、`electron/main/console-utf8.ts`): - 代码页是 65001(UTF-8 终端)→ 什么都不做; - 是其它代码页 → 把日志文本**编成该代码页的字节**再写出去(Node 的 `TextEncoder` 不支持 gbk, 所以用内置 `TextDecoder` 反建了一张字符→字节表); - 日志重定向到文件(`npm run dev > log.txt`)→ 保持 UTF-8,文件不会变成 GBK。 临时排障可以用 `ZMUSIC_CONSOLE_CP=936` 强制指定代码页。 调试模式(`electron/main/debug.ts`): - **开启**:仅开发运行(`npm run dev` / `npm start`)可启用;`npm run dev:debug` / `npm run start:debug`、`--debug` 参数或 `ZMUSIC_DEBUG=1` 环境变量均有效 - **开启后**:窗口加载完成自动打开开发者工具(独立窗口),渲染层的 `console` 会带级别与 来源打到终端,另外转发 `did-fail-load` / 渲染进程崩溃 / 窗口无响应事件,并在启动时打印 数据目录、渲染层地址、媒体服务地址、音乐文件夹、曲库曲目数与控制台编码 - **打包后的正式版禁止调试**:`app.isPackaged` 时忽略 `--debug` / `ZMUSIC_DEBUG=1`, `F12` / `Ctrl+Shift+I` 也不会打开开发者工具(设置界面里同样不出现开发/技术信息) 歌词读取自检(不需要启动应用): ```bash python scripts/make-lyric-fixtures.py # 用 ffmpeg 合成 7 个测试文件到 %TEMP%(内嵌 USLT / TXXX:LYRICS / FLAC Vorbis / 外部 .lrc 等) npm run test:lyric # 直接跑 electron/main/lyric-extract.ts 的真实实现并断言来源优先级 npm run test:lyric:placeholder # 「纯音乐,敬请欣赏」这类占位文案的识别(真歌词不许被误判) npm run test:lyric:parse # 渲染层解析:时间戳换算、双语原文/译文配对、99:00 宣传语丢弃 ``` 首次启动是空的:应用不内置任何歌曲,在「音乐库」里点「添加音乐文件夹」选择自己的音乐目录后开始扫描。 ## 目录结构 ``` electron/main/ 主进程:窗口、托盘、扫描器、本地媒体服务、IPC、设置持久化、调试模式 electron/preload/ contextBridge 暴露 window.zmusic(唯一桥接层) shared/ 主进程与渲染层共享的类型与 IPC 通道常量 src/renderer/ components/ TitleBar / Sidebar / NavIcon / MiniPlayer / NowPlaying / QueuePanel / TrackList / SortMenu / PageHeader / ActionButton / EmptyState / Settings* / PlaylistCreateModal / TrackDetailsModal views/ 歌曲 曲风 专辑 艺术家 文件夹 音乐库 歌单 设置(含 7 个子页) store/ settings / library / player 三个 Pinia store utils/ media / format / loop / palette(多彩取色) styles/ 主题 token 与多彩调色板(global.scss)、SCSS 变量与 mixin、Naive UI 主题覆盖 docs/ 设计契约、视频界面规格、参考项目笔记 ``` 数据目录:`%APPDATA%/Mplayer/`(`config/config.json` 设置、`library.json` 曲库缓存、`stats.json` 统计、`covers/` 封面缓存) 主题四选一:浅色 / 深色 / **液态玻璃** / 跟随系统。液态玻璃是 iOS Liquid Glass 那一挂 —— 面层压到 0.18~0.5 的半透明、`backdrop-filter: blur(48px) saturate(1.95) brightness(1.07)` 做折射, 再叠一层**镜面圈**(顶边一条细亮线 + 四周玻璃边 + 内侧透光)和**面层反光**(左上高光 + 斜向淡反射), 背后的彩色底光也调得更亮、暗角更轻(玻璃背后得有东西可看);模糊、镜面圈、反光三个材质参数收在 `--glass-blur / --glass-rim / --glass-sheen` 里,规则统一引用,不各写各的。 详见 `styles/global.scss` 的 `data-theme='glass'` 段。 ## 主题(取自视频逐像素采样) | 用途 | 颜色 | | --- | --- | | 窗口底色 | `#f6f6f6` | | 侧边栏 | `#f3f3f3` | | 内容区 | `#f8f8f8` | | 卡片 / 迷你播放器 | `#ffffff` / `#fdfdfd` | | 主色(强调色) | `#0370e5`(可换,14 个预设 + 自定义取色),多彩配色另有 12 色相调色板 | | 侧边栏选中药丸 | `#e9e9e9` + 加粗(左侧 4px 主色标记按需求去掉) | | 界面字体 | 默认系统字体栈(雅黑 UI → 雅黑 → 苹方 → Segoe UI → system-ui,本机预装、零下载、加载最快),缺字回退内置 CJK 字体;可在「设置 → 外观 → 界面字体」换成系统里的任意字体 | | 主文字 / 次要 / 弱 | `#1b1b1b` / `#5c5c5c` / `#8b8b8b` | 侧边栏几何:宽 216px(视频实测 275px,按需求两次收窄)、条目高 45px、条目间距 48px(45 + 3px 间隔, 按需求从 51px 收紧)、分组分隔线上下留白 9px(原 15px)、图标 22px 彩色实心、标签距左 68px; 顶部品牌区为 26px 紫→青渐变方块(内侧高光 + 本色描边 + 本色柔光,鼠标移上去轻轻歪一下) + 「Mplayer」渐变文字,折叠时只留方块并居中; 页面大标题 20px(视频实测 24px,按需求收小); 条目鼠标移入放大 1.035(图标 1.08),移出自动缩回,`prefers-reduced-motion` 下只留背景变化。 歌曲列表按需求整体用紧凑小尺寸:行高 64px、封面 38px + 1px 边框与占位底色、行内序号播放键 22px、 爱听心形 18px(内部图标 11 / 13px,比常规小一档)、标题 13px、标题与艺术家行距 3px、 固定列宽(序号 36 / 封面 38 / 专辑 220 / 时长 72,标题列自适应),专辑列与时长列右对齐 (序号列按「放得下四位数」留宽:曲库上千首时 12px 字号下 `1808` 实测 28.2px, 播放队列的序号列同理 32px / 11px 字号 25.8px)。 设置里的开关统一用 Naive 的小号(轨道 40×22px、圆钮 18px,`naive-theme.ts` 里的 `*Small` 档位): 后台运行、全局媒体键、显示翻译歌词、无法读取音轨警告四处一致。 ## 多彩配色 整体是多色风格,不是"灰底 + 一个主色": - **调色板**:`global.scss` 里 12 个色相(blue / sky / cyan / teal / green / lime / amber / orange / rose / pink / violet / indigo)× 4 档(实色 / 浅底上的文字色 / 浅底 / 更浅底), 由 Sass `@each` 展开成 `--c-blue`、`--c-blue-ink`、`--c-blue-soft`、`--c-blue-softer`, 浅色与深色主题各一套(深色用更亮的实色 + 更重的透明度)。 - **取色统一走 `src/renderer/utils/palette.ts`**,组件里不写死颜色: - `hueOf(名字)` / `colorOf(名字)`:曲风、歌单、专辑、艺术家、文件夹、格式名 → **稳定**色相, 同一个名字在任何页面都是同一个颜色 - `hueAt(下标)` / `colorAt(下标)`:卡片、柱状图、队列这类有序列表按顺序轮转上色 - `tintVars()`:一次给出 `--tint / --tint-ink / --tint-soft / --tint-softer`,直接绑到 `:style` - `gradientOf()`:双色渐变,用于没有封面时的占位图 - **落到哪些地方**:页面标题渐变装饰条与彩色数量药丸、侧边栏每项的悬停本色底与彩色实心图标、 设置页每行图标、设置首页「后台运行」卡片(青色系:图标渐变底板 + 右上状态药丸, 关闭时图标退回浅底描边色;卡片本身是干净的实底卡 —— 左侧那条本色细光条与左上角的径向光 按需求去掉了,它们渲染出来像是左边多了一道边框色)、音乐库四张统计卡与信息分析卡/条形图、 格式标签按编码家族上色(圆点实心=无损 / 空心=有损,选中后只把标签文字变深色、不出现对勾图标)、 统计(概览卡 / 14 天柱状图 / 前三名名次)、曲风卡、 专辑与艺术家占位封面及悬停色、歌单封面与标题、队列序号、播放进度条(蓝→紫→粉渐变)、 全屏播放页的彩色极光背景、窗口顶端 12 色相首尾相连的多色细线、 顶部两抹本色光晕(**从窗口最顶端 y=0 开始铺**,跨过标题栏一路淡进内容区)、 设置分组标题的本色圆点与渐隐细线 + 卡片顶边本色高光、 歌曲页工具栏各 chip(循环紫 / 排序天蓝 / 刷新绿 / 过滤按艺术家琥珀·专辑粉)、 队列抽屉标题、列表里没有封面时的按行色相渐变占位、侧边栏顶部品牌区、 文件夹页(按磁盘分组的文件夹卡片:封面堆叠 + 本色短竖条文件夹名 + 父级路径 + 本色数量药丸 + 悬停抬起·封面张开·本色圆底箭头,卡片本身是干净的实底卡 —— 左缘本色光条与上半部本色柔光按需求去掉了,同样是因为看起来像左边多了一道边框色; 磁盘分组抬头是本色圆角徽标 + 渐隐细线 + 可折叠箭头;详情页顶部是完整路径条 + 四项统计条)。 - **选中态不再有深色描边**:所有 `选中/聚焦` 状态的描边与聚焦环统一用柔和本色 (新 token `--select-border` / `--select-ring`:浅色 `rgba(3,112,229,.34)`、深色 `rgba(61,139,242,.45)`), 不再用强调色实色、本色实色或 `--border-strong` 深灰。改到的地方:音乐库「指定扫描的音乐格式」 勾选后的标签描边、设置→外观的 14 个强调色圆点选中环、当前强调色圆点外环、浅色/深色/跟随系统 三张主题卡片、文件夹卡片与曲风卡的悬停描边、音乐库统计卡与设置功能卡的悬停描边、 专辑页 chip、标签页路径按钮、所有按钮的 `:focus-visible` 环、文件夹卡片与统计卡的聚焦环。 强调色换色时这两个 token 不跟着变(固定柔和蓝),只表达"被选中",避免与强调色抢眼。 - **所有按钮统一成一个组件**(`components/ActionButton.vue`):应用里已经没有 ``, 也不再各页面自己写「返回」这类按钮样式。三种角色:`primary` 实心强调色渐变(播放全部 / 刷新曲库库 / 添加音乐文件夹 / 应用并重新扫描 / 确认保存)、`secondary` 白底细描边(随机播放 / 加入队列 / 排序 / 打开目录 / 读取标签 / 返回列表)、`quiet` 无底色只在悬停浮出浅底(取消 / 移除 / 重命名 / 返回 / 列表行内小图标)。**按钮配色只有强调色这一套**:不再有"本色淡底的按钮"(绿底刷新 + 蓝底播放 在同一排里不搭,已按需求收敛),页面自己的色相只留给图标、chip、卡片这些非按钮元素。 尺寸只有 30px(`sm`)与 34px(`md`)两档,只有图标时自动收成正方形。 统一交互:悬停抬起 1px + 阴影变大、按下落回并压暗、键盘聚焦有柔和本色环、 `loading` 时左侧图标匀速旋转、`prefers-reduced-motion` 下取消位移与旋转。 - **空状态统一成 `EmptyState.vue`**:图标底板与文字颜色由「主文案散列出的色相」决定 (也能用 `hue` 手动指定),所以「曲库为空」「没有匹配结果」这类文案在每个页面颜色都不同, 但同一个页面每次进来颜色稳定;按钮放进默认插槽(前往音乐库 / 返回列表等)。 - **窗口顶部的背景是连成一片的**(标题栏不再是一条独立色带): `.app-main` 用 `--bg-content` + 顶端两抹本色光打底,`TitleBar` 的 `background` 改成 `transparent`,光晕从 y=0 起铺、跨过标题栏淡进内容区;左侧栏顶部 50px 用 `linear-gradient(180deg, var(--bg-app), var(--bg-sidebar) v.$titlebar-h)` 从标题栏色 渐变到侧边栏色,所以左右两个上角都不会在标题栏交界处出现横向色阶。 窗口最顶端那条 12 色相细线仍叠在最上层。 - **系统消息提示固定在窗口顶部居中**(复制成功、扫描完成、设置已保存这类反馈): `NMessageProvider` 用 `placement="top"`,并让容器整块下移一个标题栏高度(`App.vue` 里 `top: calc(50px + 8px)`,50px 取自 `v.$titlebar-h`),因为 Naive 默认的 12px 会被 50px 高的 标题栏压住;提示条本身 `-webkit-app-region: no-drag`,不会占掉标题栏的拖拽区域。 容器是 teleport 到 `` 的,所以这条样式写在 body 上(选择器带 `n-message-container--top` 完整类名,不会影响到别处)。 - 强调色(设置 → 外观):**14 个预设**(12 个色相取自调色板实色档 + 正红 / 石墨)**+ 自定义取色** (原生取色器,确认后写入设置);下方显示当前强调色的名字与色值,右侧可一键「恢复默认」。 强调色只管交互色(按钮、开关、选中态、进度条等),彩色调色板(曲风 / 专辑 / 统计等)与它互不干扰。 - **默认界面字体走系统字体栈,加载最快**:`DEFAULT_FONT_STACK` 依次是雅黑 UI → 雅黑 → 苹方 → Segoe UI → system-ui,全是本机预装、零下载,首屏直接按最终字形画出来(不做字体 swap); 随包分发的内置 CJK 字体(MiSans / 阿里巴巴普惠体,woff2 每个字重 ~4.6-5MB,只留 Regular + Bold) 排在系统字体**后面兜底**,只有系统凑不出某个字时才会回退下载它们 (原鸿蒙 19.7MB TTF 与两套字体的 Medium 字重已按包体优化移除), 泛型族 `sans-serif` 必须排在最后。默认栈在 `utils/font.ts`、`styles/_variables.scss` 各一份,两边保持一致。 - **界面字体可选,且是全应用统一的**(设置 → 外观 → 界面字体):下拉里列出系统已安装的字体家族和内置字体, 可搜索;选中后**整个界面**都换成该字体 —— 侧边栏、标题栏、歌曲列表(含歌名 / 艺术家 / 专辑 / 时长)、歌词、迷你播放器与全屏播放页、设置页、空状态,以及 Naive UI 的下拉 / 弹窗 / 消息提示 (由 `naive-theme.ts` 的 `common.fontFamily` 同步)。 实现上 `applyFont()` 把字体同时写到 `` 的 `--font-family` 变量与 `` 的内联 `font-family`,样式表里只有 `html,body,#app { font-family: var(--font-family, …) }` 一处声明, 其余 `font-family` 全部是 `inherit`(表单控件必须显式 inherit,浏览器默认不继承), 所以不存在"只对部分界面生效"的情况;设置页里的预览块用的也是同一个字体。 字体清单来自主进程读 Windows 字体注册表 (`HKLM` + `HKCU` 的 `...\CurrentVersion\Fonts`,见 `electron/main/fonts.ts`):去掉 `(TrueType)` 之类的后缀与 `Bold`/`Italic` 等样式后缀、`A & B` 这种合并条目只取第一个,去重后缓存;读不到时 回退到内置清单。选中的字体后面会自动接上默认字体栈(系统字体优先 + 内置字体兜底),缺字按顺序回退,不会出现方框。 ## 与视频的差异(有意为之) - 歌曲列表只保留「标题前的爱听图标」,视频里悬停出现的行内操作按钮全部去掉,详情、加歌单、 复制路径等操作统一走鼠标右键菜单(右键任意一行)。 - **点击歌曲名 = 复制歌名**(光标是 `copy`,悬停变主色 + 虚线,复制后弹出「已复制歌曲名称:…」): 走 `clipboard:write` 这条 IPC 落到主进程的 `clipboard.writeText`,不依赖渲染进程的 Clipboard API 与权限提示;名字点击不再触发播放(行本身的单击 / 双击照旧播放)。 - 歌曲列表顶部不放表头(列名行),排序改成工具栏 / 歌单页的「排序」下拉,列的宽度与含义不变。 - 整个应用**不显示滚动条**(原生滚动条与 Naive 自绘滚动条都隐藏):列表、设置页、歌词区域用 滚轮 / 触控板滚动,因此内容也不再为滚动条留出边距,左右留白对称。 - **「打开目录」= 在系统文件资源管理器里打开当前文件夹**:走 `library:open-folder` 这条 IPC 落到 主进程的 `shell.openPath`(返回空串表示成功,否则把失败原因弹成错误提示), 取代了原先的「复制文件夹名称」;文件夹路径的复制仍然保留(路径条右侧的复制图标按钮)。 - **文件夹页只做两层**:根目录按磁盘分组,每个「已添加的音乐文件夹」一张卡片 (封面堆叠最多三张封面、文件夹名、去掉盘符后的完整路径、`N 首 · 总时长 · 主要格式`, 磁盘抬头显示该盘的文件夹数与歌曲数,可点击折叠),点进去直接列出这个文件夹下的**全部音乐** (递归含所有子目录),不再显示子文件夹层级 —— 面包屑、「根」按钮、「子文件夹」小节、 子文件夹聚合逻辑全部移除。详情页顶部是一条完整路径条(盘符徽标 + 淡色父级 + 本色文件夹名, 右侧一个复制路径的图标按钮),下面跟一条统计条(歌曲数 / 总时长 / 专辑数 / 主要格式 + 右侧「打开目录」——在系统文件资源管理器里打开这个文件夹,走 `library.openFolder` → 主进程 `shell.openPath`), 工具栏有「播放全部 / 随机播放」与「返回文件夹列表」。 - 视频是"灰底 + 单一蓝色强调色",本项目按需求改成上文的多彩风格。 - 视频中「设置」列出了 14 项(无障碍、创意工坊、实验室、第三方 App、CD 工具箱、节能、帮助与反馈等), 但演示里从未被点击、也不产生任何状态变化,按「不可点击的就不要了」的要求只保留有实际功能的项 (外观 / 歌词 / 音频引擎(含音轨信息)/ 键盘快捷键 / 帮助 / 关于)+ 后台运行开关。 其中「关于」里能查看本次更新内容(首页首次打开某个新版本时也会弹一次,文案写在 `src/renderer/utils/changelog.ts`)。 - 音乐库页的「安全移除」「详细了解音乐库功能」等纯展示项同样未实现。 - 迷你播放器在视频中只显示封面 / 标题 / 艺术家,本项目补上了可点击的进度条与传输控制 (否则播放无法操作),外壳尺寸、圆角、阴影与配色与视频一致。 - 视频只有浅色主题;本项目额外提供深色主题与跟随系统(设置 → 外观)。 ## 设置项取舍 只保留**真正生效**的设置,凡是无法实现或改了没有任何效果的选项一律不放进界面: | 已移除 | 原因 | | --- | --- | | 语言(9 种语言) | 界面只有简体中文一套文案,切换语言不会改变任何内容;等做了 i18n 再加回来 | | Windows 音频会话 API 独占模式 | Electron/Chromium 的 `