Compare commits

...

174 Commits

Author SHA1 Message Date
alger
939dc85d7d fix: 修复 Windows 安装时 uninstallericon.ico 写入报错并优化 NSIS 配置 2025-12-21 10:43:00 +08:00
alger
c4831966c1 chore: bump version to 5.0.0 2025-12-20 20:04:15 +08:00
alger
50aebcf8de feat(update): 支持 macOS 分架构下载 (x64/arm64) 2025-12-20 20:01:39 +08:00
alger
75d1225b40 feat: v5.0.0 2025-12-20 19:47:38 +08:00
alger
c251ec9dcf fix: 修复榜单 loading 2025-12-20 19:45:41 +08:00
alger
00a251b5b6 feat: mac 添加权限 2025-12-20 18:32:14 +08:00
algerkong
7e59cfee05 feat: 补全国际化 2025-12-20 14:20:25 +08:00
algerkong
c3dd03cc13 feat: 优化歌词颜色检测逻辑 2025-12-20 14:18:27 +08:00
algerkong
999cd6526b feat: 优化播放检测逻辑 2025-12-20 14:16:32 +08:00
algerkong
77bb06c0d6 feat: 添加歌词字体粗细控制并修复 i18n 缺失 2025-12-20 14:09:57 +08:00
alger
85302c611a feat:优化音源配置 2025-12-20 02:30:09 +08:00
alger
0f42bfc6cb fix:修复随机播放问题 2025-12-20 02:29:43 +08:00
alger
5bcef29f10 feat:优化lx音源问题 2025-12-20 02:29:22 +08:00
alger
a9fb487332 feat:添加国际化 2025-12-19 00:24:26 +08:00
alger
8e1259d2aa feat:针对移动端优化 2025-12-19 00:23:24 +08:00
alger
70f1044dd9 feat: 优化设置页面 2025-12-19 00:22:22 +08:00
alger
e2ebbe12e4 feat:优化全屏歌词界面 添加背景和宽度设置 2025-12-19 00:14:24 +08:00
alger
af9117ee5f feat: 优化预加载逻辑和继续播放功能 2025-12-17 15:05:40 +08:00
alger
6bc168c5bd feat: 优化播放错误处理 2025-12-17 13:19:10 +08:00
alger
89c6b11110 feat: 添加 lx 音源导入 2025-12-13 15:00:38 +08:00
alger
b9287e1c36 fix: 修复音源解析致命性错误 2025-12-13 14:46:15 +08:00
alger
1a0e449e13 feat: 一系列播放优化 2025-12-13 11:31:49 +08:00
algerkong
07f6152c56 fix: 修复预加载问题 2025-12-13 11:31:49 +08:00
alger
56adac0d4e feat: 优化 tray 标题长度 2025-11-08 17:37:27 +08:00
alger
452e1d1129 feat: 去除构建麦克风权限 2025-11-08 14:26:59 +08:00
alger
34ba2250bf feat: 重构播放 store 2025-11-08 14:26:04 +08:00
alger
1005718c07 feat: 封面图预先加载 2025-11-08 14:22:44 +08:00
alger
3527da17da feat: 添加心动模式播放 2025-10-22 22:48:52 +08:00
alger
9bf513d35d feat: 添加历史日推功能 2025-10-22 21:52:22 +08:00
alger
35b798b69e fix: 修复远程控制关闭无法保存问题 2025-10-22 21:52:00 +08:00
alger
9535183405 feat: 添加播放记录热力图显示功能 2025-10-22 21:51:45 +08:00
alger
6d7ba6dbae feat: 历史记录页面 添加本地和云端两种记录支持,支持歌曲、歌单、专辑 2025-10-22 21:51:16 +08:00
alger
a9adb6be36 feat: 用户页面添加收藏专辑展示 2025-10-22 21:50:20 +08:00
alger
bee5445b6e fix: 修复mini播放栏主题颜色问题 将mini播放栏设为默认 2025-10-22 21:49:53 +08:00
alger
316d5932e3 feat: 移动端歌词点击跳转 优化国际化和移动端逐字歌词 2025-10-12 17:38:45 +08:00
alger
a5d3ff359c feat: 优化逐字歌词效果,桌面歌词添加逐字歌词效果 2025-10-12 17:11:48 +08:00
alger
77f3069e67 fix: 修复逐字歌词 字间距问题 2025-10-12 13:02:56 +08:00
alger
f3a9f8b979 feat: 自动隐藏menu滚动条 2025-10-11 20:27:15 +08:00
alger
29ba231a7d feat: 平板模式 2025-10-11 20:24:11 +08:00
alger
cb2baeadf5 feat: 逐字歌词 2025-10-11 20:23:54 +08:00
alger
4575e4f26d fix: 重新解析功能修复缓存问题 2025-10-11 20:23:36 +08:00
alger
dc8957dcf2 fix: 修复桌面歌词不透明显示标题栏的问题 2025-10-11 20:23:15 +08:00
algerkong
c83ad48ef4 feat(config): 添加GPU加速设置支持 2025-09-20 16:51:47 +08:00
algerkong
67370b9072 feat: bili播放优化 2025-09-20 16:40:45 +08:00
algerkong
93022691e2 fix: 修复优化bili解析搜索和播放问题 2025-09-20 15:38:35 +08:00
algerkong
0df86b583b fix: 修复节点问题 2025-09-20 15:37:44 +08:00
algerkong
df3a7994cb feat: 优化翻译 2025-09-20 15:12:54 +08:00
Alger
8fb4c4df68 Merge pull request #477 from lekoOwO/feature/lyric-translation 2025-09-20 15:07:29 +08:00
Leko
56922caa40 feat: 新增歌詞翻譯模組和 OpenCC 翻譯引擎 2025-09-14 17:16:53 +08:00
Leko
abbbf7e771 fix: 修復 vue-eslint-parser 不在 dev dependency 的問題 2025-09-14 16:05:44 +08:00
Leko
6d9235902a fix: 相容 pnpm 包管理器設置項 2025-09-14 14:45:00 +08:00
alger
659c9f9a4c feat: 优化解析功能,添加缓存 2025-09-14 01:03:29 +08:00
alger
8f0728d9db feat: 登录状态校验功能修改 2025-09-14 00:34:54 +08:00
alger
8f9c989815 feat: 优化代码提交流程 添加lint-staged 2025-09-14 00:21:07 +08:00
alger
d8734f8302 feat: 格式化代码 2025-09-14 00:19:41 +08:00
Alger
74b9d73241 Merge pull request #472 from souvenp/feat/menu-expand
feat: 左上角菜单展开状态持久保存
2025-09-14 00:00:54 +08:00
Alger
10421fa4d2 Merge branch 'main' into feat/menu-expand 2025-09-14 00:00:46 +08:00
Alger
d05a63c5e3 Merge pull request #471 from souvenp/feat/dislike-improvement
feat: 日推不感兴趣调用官方接口并返回新歌
2025-09-13 23:59:46 +08:00
Alger
a9f76c7952 Merge branch 'main' into feat/dislike-improvement 2025-09-13 23:59:40 +08:00
alger
70677dfb14 fix: 不喜欢的操作只有每日推荐歌曲才请求接口,去除不喜欢的提示 2025-09-13 23:58:33 +08:00
Alger
e9ef7123e7 Merge pull request #470 from souvenp/feat/search-suggestions
feat: search suggestions
2025-09-13 23:41:37 +08:00
Alger
5fbe4c3ad4 Merge branch 'main' into feat/search-suggestions 2025-09-13 23:41:26 +08:00
alger
bce02532ef fix: electron环境使用kg, 其他环境使用 wy api,独立kg搜索提示 API 到otherApi.ts 2025-09-13 23:40:01 +08:00
alger
9003de8d4b fix: 优化音源设置国际化 2025-09-13 23:16:07 +08:00
Alger
c98f5bb608 Merge pull request #468 from souvenp/fix/hires-download-bug
fix: 下载无损格式会返回hires音质的问题
2025-09-13 22:55:11 +08:00
Alger
6e67263766 Merge pull request #465 from souvenp/feat/add-custom-api 2025-09-13 22:53:37 +08:00
alger
e91667a2e6 fix: 修改国际化问题 和 音源优先级以及音源解析错误处理 2025-09-13 22:52:37 +08:00
Alger
7306722fcf Merge pull request #464 from souvenp/feat/flac-tags
feat: flac tags support and optimize cover images
2025-09-13 22:22:13 +08:00
alger
76db7e3ad6 feat: 添加3D封面组件并优化顶部按钮hover逻辑 2025-09-13 22:21:11 +08:00
shano
8aaabf4b65 feat: 菜单展开设置 2025-09-10 20:15:39 +08:00
shano
292ab56be8 feat: 菜单状态保存 2025-09-10 20:05:59 +08:00
shano
5ab3143fdd fix: 下载无损格式会返回hires音质的问题 2025-09-10 19:13:19 +08:00
shano
08f7e5adfe feat: electron only 2025-09-10 18:55:02 +08:00
shano
2a8d0f2066 feat: 搜索建议添加 2025-09-10 13:15:58 +08:00
shano
fb8b4c9341 feat: 日推不感兴趣调用官方接口 2025-09-10 13:13:17 +08:00
shano
dc99331911 Merge remote-tracking branch 'origin/feat/add-custom-api' into feat/add-custom-api 2025-09-10 09:58:04 +08:00
shano
7ae6e041b5 fix 2025-09-10 09:55:47 +08:00
shano
1171e0f9e7 feat: add custom api 2025-09-09 22:09:44 +08:00
shano
df236e491c feat: add custom api 2025-09-09 22:05:48 +08:00
shano
4368c05b80 feat: Flac metadata and optimize cover images 2025-09-07 17:57:19 +08:00
alger
d24d3d63b8 feat: 添加统计脚本 2025-08-12 20:50:10 +08:00
alger
ad57673129 feat: 优化音源逻辑 2025-08-12 19:54:20 +08:00
alger
ad51f57bd7 🦄 refactor: 重构播放列表逻辑 优化随机播放功能
feated: #368 #353
2025-08-12 19:51:29 +08:00
alger
88e1c2cd81 feat: 更新至4.9.0 2025-08-07 23:26:28 +08:00
alger
18853d401f feat: 替换Token设置弹窗为Cookie设置弹窗,并优化Token保存逻辑 2025-08-07 23:24:43 +08:00
alger
6b27116584 feat: 添加登录类型条件渲染 2025-08-07 23:11:25 +08:00
alger
283a123590 feat: 更新文本 2025-08-07 23:05:33 +08:00
alger
1597fbf108 feat: 修改Cookie文字 2025-08-07 22:57:37 +08:00
alger
3ba85f34ed feat: 优化类型处理 2025-08-07 22:57:17 +08:00
alger
daa8e7514d feat: 优化登录功能 添加UID登录功能 2025-08-07 22:57:02 +08:00
alger
aeb7f0361d feat: 播放速度设置弹窗标题添加速度显示 2025-08-07 22:56:41 +08:00
alger
16aeaf2948 feat: 添加Cookie登录功能及自动获取等相关管理设置
feat: #413 #424
2025-08-06 22:36:30 +08:00
alger
09ccd9f2a6 fix: 修复菜单显示不全的问题 添加滚动条
fixed(#328): 页面左侧菜单行高问题
2025-07-29 22:57:09 +08:00
alger
679089eda9 fix: 修复音量调整不同步的问题
fixed(#331):  软件存在两套音量调整逻辑,快捷键调整和音量条调整音量不一致
2025-07-29 22:19:34 +08:00
Alger
f2eba9a6d0 Merge pull request #403 from Hellodwadawd12312312/main
feat: 使用滑块增强播放速度控制并改进空安全
2025-07-26 23:51:06 +08:00
algerkong
306215669d feat: 添加日语和韩语国际化,并且优化语言相关代码 2025-07-26 23:32:58 +08:00
algerkong
b7a58a0073 fix: 修复歌曲初始化问题 2025-07-26 23:29:53 +08:00
Qumo
8fb382e21f feat: enhance playback speed controls with slider and improve null safety for playMusic 2025-07-24 08:22:03 +02:00
alger
c08c2cbf19 refactor: 更新 eslint 和 prettier 配置 格式化代码 2025-07-23 23:54:35 +08:00
alger
d1f5c8af84 feat: 桌面歌词添加主题颜色面板组件 2025-07-23 22:47:22 +08:00
alger
d5ba218b10 feat: 添加主题根据系统切换功能
feat: #387
2025-07-23 22:45:47 +08:00
alger
e489ab46b5 fix: 修复歌单列表页面翻页类型问题
fixed: #398
2025-07-23 22:43:59 +08:00
alger
9b3019d04b fix: 修复mini窗口恢复时导致的应用窗口变小问题 2025-07-22 00:40:34 +08:00
Alger
1e213388c1 Merge pull request #396 from algerkong/fix/mac-window-close
🐞 fix: 修复mac快捷键关闭窗口报错的问题
2025-07-21 23:51:43 +08:00
alger
67ef4d7221 🐞 fix: 修复mac快捷键关闭窗口报错的问题 2025-07-21 23:49:21 +08:00
alger
62a504e7d3 feat: 托盘菜单添加繁体中文设置 2025-07-21 23:35:48 +08:00
Alger
386db7384d Merge pull request #392 from dongguacute/main
feat(i18n): add Traditional Chinese (zh-Hant) localization support
2025-07-21 23:33:50 +08:00
dongguacute
2cc03cb080 feat(i18n): add Traditional Chinese (zh-Hant) localization support
add Traditional Chinese translations for all application strings
include new language files for artist, history, donation, favorite, login, search, user, common, download, player, settings, comp components
update main i18n configuration to include zh-Hant language
add zh-Hant option to language switcher component
2025-07-20 22:53:25 +08:00
algerkong
7891bf45fd feat: 更新版本至 4.8.2 2025-06-28 18:16:19 +08:00
algerkong
2f339b1373 🐞 fix: 修复在歌词界面添加到歌单抽屉被遮挡问题 2025-06-28 17:46:24 +08:00
algerkong
749a2a69c4 feat: 重新设计歌词页面的迷你播放栏 2025-06-28 17:40:57 +08:00
algerkong
5b97010b32 🐞 fix: 修复解析错误问题, 优化播放效果 2025-06-28 17:31:37 +08:00
algerkong
694dff425b feat: 添加清除自定义音源功能 2025-06-28 17:26:07 +08:00
algerkong
e8cf253567 feat: 更新版本至 4.8.1 2025-06-27 18:59:40 +08:00
algerkong
4d831777f1 🔧 chore: 移除统计,更新支持的音乐源列表 2025-06-27 18:49:37 +08:00
algerkong
95c255d2ba 🐞 fix: 修复网页端和快捷键无法调整音量的问题 2025-06-23 20:58:08 +08:00
algerkong
d739a6701b feat: 添加通知抽屉组件,优化用户体验并支持多平台提示 2025-06-23 20:56:50 +08:00
alger
d7169efcf5 feat: 更新版本至 4.8.0 2025-06-20 23:32:29 +08:00
alger
a7cce28050 feat: 在构建配置中添加对 Linux RPM 包的支持 2025-06-20 23:32:08 +08:00
alger
e99385c512 feat: 添加版本号比较函数,优化更新检查逻辑 2025-06-20 23:17:16 +08:00
alger
72c11eef6c 🎨 style: 更新歌词区域按钮样式,修复歌词时间调整按钮不显示问题 2025-06-20 23:06:57 +08:00
alger
facb03d3e1 feat: 添加 linux rpm 构建目标支持 2025-06-20 22:27:48 +08:00
alger
902feff2fb 🔧 chore: 降级 electron 版本至 35.2.0 2025-06-20 22:23:56 +08:00
alger
426cafd54c feat: 更新 AppMenu 组件,增加移动端适配,优化工具提示的禁用条件 2025-06-20 21:15:13 +08:00
alger
e4ed089085 chore: 更新 .gitignore 文件,添加 android/app/release 目录以排除构建文件 2025-06-20 21:08:43 +08:00
alger
7f6e11e508 feat: 移除代理配置,简化构建命令,更新环境变量设置 2025-06-20 21:08:26 +08:00
alger
81b61e4575 feat: 增强移动端播放页面效果,优化横屏效果,添加播放列表功能 2025-06-20 21:07:17 +08:00
Alger
66aa6b7aff Merge pull request #326 from hecai84/main
添加任务栏缩略图控制按钮
2025-06-20 17:49:09 +08:00
hecai
58ab9906cc 启动默认显示缩略图控制按钮。
(cherry picked from commit 1f438e391ab7bb37e38a31ec571724d33f35310b)
2025-06-19 09:26:28 +08:00
hecai
9bec67ebf9 添加任务栏缩略图控制按钮
(cherry picked from commit e0ddb7cb4821b5b48ed3ffb99a44c00c8cb4d46e)
2025-06-18 15:52:37 +08:00
Alger
386c9c7067 Merge pull request #320 from Hellodwadawd12312312/feature
修复音频初始化音量问题,完善翻译
2025-06-17 11:34:26 +08:00
Felix
b95f5e1b2f small fix 2025-06-16 08:44:50 +02:00
Qumo
090103bf1a Update audioService.ts 2025-06-16 07:47:40 +02:00
Qumo
5ee60d751e Update audioService.ts 2025-06-16 07:39:35 +02:00
Qumo
a85b5ff58b Merge branch 'algerkong:main' into feature 2025-06-16 07:28:28 +02:00
alger
58922dc91b feat: 更新类型定义文件路径,移除旧的 auto-imports 和 components 定义文件 2025-06-12 22:58:01 +08:00
alger
0d89e15e01 feat: 添加横屏模式支持,优化歌词和播放控制布局 2025-06-12 22:57:24 +08:00
algerkong
b9c38d257a feat: 重构播放控制逻辑,添加播放进度恢复功能并清理无用代码 2025-06-11 20:12:52 +08:00
algerkong
d227ac8b34 feat: 优化播放栏无法控制隐藏问题 2025-06-11 20:10:33 +08:00
algerkong
f9d85f11ad feat: 去除无用代码 2025-06-11 20:05:43 +08:00
Felix
49595ef57f more translation 2025-06-10 13:31:33 +02:00
Alger
cceb1de3fb Merge pull request #304 from Hellodwadawd12312312/feature
添加搜索类型的翻译
2025-06-09 10:41:25 +08:00
Felix
f59b5d5602 translation 2025-06-08 14:49:24 +02:00
alger
fabcf289dc feat: 优化歌曲列表组件布局,添加底部间距以提升视觉效果 2025-06-07 22:47:34 +08:00
alger
934580552d feat: 优化歌词组件和移动端界面设计 2025-06-07 22:30:39 +08:00
alger
6f1909a028 🐞 fix: 修复刷新后第一次播放出现的无法播放问题 2025-06-07 22:10:55 +08:00
alger
c5d71cf53c feat: 添加 Vite 配置文件并更新 package.json,支持开发模式下的 Web 预览 2025-06-07 21:34:19 +08:00
alger
21b2fc08be feat: 优化移动端界面设计以及歌词界面设计 添加播放模式选择 2025-06-07 10:48:54 +08:00
alger
155bdf246c feat: 优化提示组件,支持位置和图标显示选项 2025-06-06 23:37:24 +08:00
alger
e46df8a04e feat: 优化窗口大小管理功能,优化窗口状态保存与恢复逻辑
- 引入窗口大小管理器,初始化窗口大小管理
- 优化窗口状态保存与恢复,确保在迷你模式下正确应用窗口大小
- 移除不必要的代码,简化窗口管理逻辑
- 更新窗口创建逻辑,确保窗口大小和位置的正确性
2025-06-06 23:37:06 +08:00
alger
b203077cad feat: 添加下载设置功能,支持自定义文件名格式和下载路径配置
- 新增下载设置抽屉,允许用户设置下载路径和文件名格式
- 支持多种文件名格式预设和自定义格式
- 实现下载项的显示名称格式化
- 优化下载管理逻辑,避免重复通知
2025-06-05 23:02:41 +08:00
alger
a08fbf1ec8 style: 优化播放列表抽屉样式,调整标题和按钮颜色以提升可读性 2025-06-05 22:19:55 +08:00
alger
edd393c8ac feat: 新增歌单导入功能
添加歌单导入功能,支持通过链接、文本和元数据三种方式导入歌单
- 实现链接导入、文本导入和元数据导入三种方式
- 添加导入状态检查和显示功能
2025-06-04 22:53:49 +08:00
alger
8988cdb082 feat: 在音乐列表页面中添加 Electron 环境判断,优化多选下载操作的显示逻辑 2025-06-04 22:46:35 +08:00
alger
1221101821 feat: 列表添加多选下载功能,支持批量选择和下载音乐 2025-06-04 20:19:44 +08:00
alger
3ac3159058 feat: 添加下载管理页面, 引入文件类型检测库以支持多种音频格式 2025-06-03 22:35:04 +08:00
Alger
bfaa06b0d5 Merge pull request #281 from algerkong/feat/window-auto-size
feat: 添加主窗口自适应大小功能,页面缩放功能,支持缩放因子的调整和重置,并在搜索栏中提供缩放控制
2025-05-28 22:12:29 +08:00
alger
61700473b9 feat: 添加主窗口自适应大小功能,页面缩放功能,支持缩放因子的调整和重置,并在搜索栏中提供缩放控制 2025-05-28 22:08:17 +08:00
alger
bf4bcfcde6 chore: 更新 .gitignore 文件 2025-05-28 22:06:13 +08:00
Alger
475d7d2595 Merge pull request #280 from algerkong/fix/day-list
feat: 重构每日推荐数据加载逻辑,提取为独立函数并优化用户状态判断
2025-05-28 22:04:14 +08:00
alger
5e704a1f3c feat: 重构每日推荐数据加载逻辑,提取为独立函数并优化用户状态判断 2025-05-28 22:02:59 +08:00
Alger
6faab820da Merge pull request #279 from algerkong/fix/volume-color
feat: 添加mini播放栏鼠标滚轮调整音量 并优化音量滑块数字不展示问题
2025-05-28 22:01:07 +08:00
alger
5c7278544a feat: 添加mini播放栏鼠标滚轮调整音量 并优化音量滑块数字不展示问题 2025-05-28 21:58:32 +08:00
Alger
4c24bb9257 feat: Update README.md 2025-05-27 15:18:42 +08:00
alger
c975344dd0 feat: 添加歌词矫正功能,支持增加和减少矫正时间 2025-05-26 22:58:42 +08:00
Alger
08a14359a5 Merge pull request #268 from algerkong/fix/modal-zindex
fix: 修复更多设置弹窗被歌词窗口遮挡问题 并优化为互斥弹窗, 优化样式
2025-05-25 19:28:54 +08:00
alger
62e5166953 fix: 修复更多设置弹窗被歌词窗口遮挡问题 并优化为互斥弹窗, 优化样式 2025-05-25 19:26:24 +08:00
alger
7685ad3939 feat: 在配置中添加 publicDir 选项以指定资源目录 2025-05-25 11:35:16 +08:00
alger
d7c06586d6 feat: 在 EQControl 组件标题中添加桌面版可用提示标签 2025-05-25 11:07:06 +08:00
alger
5070a085e9 feat: 优化收藏和历史列表组件,添加加载状态管理和动画效果 2025-05-24 19:23:38 +08:00
alger
e5adb8aa72 fix: 修复设置页面动画速度滑块样式和文本错误 2025-05-24 19:23:13 +08:00
alger
d08439c99e feat:v4.7.1 2025-05-24 10:11:50 +08:00
alger
dee4515cb3 fix: 修复切换收藏和不喜欢状态时事件处理逻辑 2025-05-24 10:11:29 +08:00
alger
53bc1774ff fix: 修复下载请求中的音乐 URL 处理逻辑 2025-05-24 10:02:15 +08:00
298 changed files with 34574 additions and 9028 deletions

View File

@@ -1,92 +0,0 @@
---
description: 这个规则是项目描述
globs:
alwaysApply: false
---
您是 TypeScript、Node.js、Vue3、Electron、naive-ui、VueUse 和 Tailwind 方面的专家。
项目结构
- 这是 Electron 项目,使用 Vue3 和 Pinia 进行开发的第三方网易云音乐播放器。
- 使用 Vue3 和 Pinia 进行开发。
- 使用 Pinia 进行状态管理。
- 使用 VueUse 进行状态管理。
- 使用 naive-ui 进行 UI 设计。
- 使用 Tailwind 进行样式设计。
- 使用 remixicon 进行图标设计。
- 使用 vite 进行项目构建。
- 使用 electron-builder 进行项目打包。
- 使用 electron-vite 进行项目开发。
- 使用 netease-cloud-music-api 进行网易云音乐接口调用。
- 使用 electron-store 进行本地数据存储。
- 使用 axios 进行网络请求。
- 使用 @unblockneteasemusic/server 进行网易云音乐解锁。
- 使用 vue-i18n 进行国际化。目录为 src/i18n
代码风格和结构
- 编写简洁、技术性的 TypeScript 代码,并提供准确示例。
- 使用组合 API 和声明性编程模式;避免使用选项 API。
- 优先使用迭代和模块化,而不是代码重复。
- 使用带有助动词的描述性变量名称(例如 isLoading、hasError
- 结构文件:导出的组件、可组合项、帮助程序、静态内容、类型。
命名约定
- 使用带破折号的小写字母表示目录(例如 components/auth-wizard
- 使用 PascalCase 表示组件名称(例如 AuthWizard.vue
- 使用 camelCase 表示可组合项(例如 useAuthState.ts
TypeScript 用法
- 对所有代码使用 TypeScript优先使用类型而不是接口。
- 避免使用枚举;改用 const 对象。
- 将 Vue 3 与 TypeScript 结合使用,利用 defineComponent 和 PropType。
语法和格式
- 对方法和计算属性使用箭头函数。
- 避免在条件中使用不必要的花括号;对简单语句使用简洁的语法。
- 使用模板语法进行声明式渲染。
UI 和样式
- 使用 naive-ui 和 Tailwind 进行组件和样式设计。
- 使用 Tailwind CSS 实现响应式设计;采用移动优先方法。
图标
- 使用 remixicon 作为图标库。
性能优化
- 对异步组件使用 Suspense。
- 为路由和组件实现延迟加载。
关键约定
- 对常见可组合项和实用函数使用 VueUse。
- 使用 Pinia 进行状态管理。
- 优化 Web VitalsLCP、CLS、FID
Vue 3 和 Composition API 最佳实践
- 使用 <script setup lang="ts"> 语法进行简洁的组件定义。
- 利用 ref、reactive 和 computed 进行反应状态管理。
- 在适当的情况下使用 provide/inject 进行依赖注入。
- 实现自定义可组合项以实现可重用逻辑。
Electron 最佳实践
- 使用 Electron 和 Vue.js 进行跨平台桌面应用程序开发。
- 使用 Electron 的 API 和 Vue.js 的组合 API 进行开发。
- 实现自定义可组合项以实现可重用逻辑。
组件导入
- 使用 auto-import 进行组件导入。
- naive-ui 组件自动导入 不需要手动导入。
关注官方 Electron 和 Vue.js 文档,了解有关数据获取、渲染和路由的最新最佳实践。
问题修复
- 思考 5-7 种可能导致问题的来源,并根据可能性、对功能的影响以及在类似问题中的出现频率进行优先排序。仅考虑与错误日志、最近代码变更和系统约束相匹配的来源。忽略外部依赖,除非日志明确指向它们。
- 一旦缩小到 1-2 个最可能的来源,将其与历史错误日志、相关系统状态和预期行为进行交叉验证。如果发现不一致,调整你的假设。
- 在添加日志时,确保它们被策略性地放置,以便同时确认或排除多个潜在原因。如果日志不支持你的假设,请先提出替代的调试策略,再继续深入分析。
- 在实施修复之前,先总结问题现象、经过验证的假设,以及预期的日志输出,以确认问题是否真正得到解决。

View File

@@ -1,148 +0,0 @@
---
description: 这个规则是项目结构
globs:
alwaysApply: false
---
# AlgerMusicPlayer 项目结构
AlgerMusicPlayer 是一个基于 Electron、Vue 3、TypeScript 开发的网易云音乐第三方播放器。
## 技术栈
- **前端框架**Vue 3 + TypeScript
- **UI 组件库**naive-ui
- **样式框架**Tailwind CSS
- **图标库**remixicon
- **状态管理**Pinia
- **工具库**VueUse
- **构建工具**Vite, electron-vite
- **打包工具**electron-builder
- **国际化**vue-i18n
- **HTTP 客户端**axios
- **本地存储**electron-store localstorage
- **网易云音乐 API**netease-cloud-music-api
- **音乐解锁**@unblockneteasemusic/server
## 项目结构
```
AlgerMusicPlayer/
├── build/ # 构建相关文件
├── docs/ # 项目文档
├── node_modules/ # 依赖包
├── out/ # 构建输出目录
├── resources/ # 资源文件
├── src/ # 源代码
│ ├── i18n/ # 国际化配置
│ │ ├── lang/ # 语言包
│ │ ├── main.ts # 主进程国际化入口
│ │ └── renderer.ts # 渲染进程国际化入口
│ ├── main/ # Electron 主进程
│ │ ├── modules/ # 主进程模块
│ │ ├── index.ts # 主进程入口
│ │ ├── lyric.ts # 歌词处理
│ │ ├── server.ts # 服务器
│ │ ├── set.json # 设置
│ │ └── unblockMusic.ts # 音乐解锁
│ ├── preload/ # 预加载脚本
│ │ ├── index.ts # 预加载脚本入口
│ │ └── index.d.ts # 预加载脚本类型声明
│ └── renderer/ # Vue 渲染进程
│ ├── api/ # API 请求
│ ├── assets/ # 静态资源
│ ├── components/ # 组件
│ │ ├── common/ # 通用组件
│ │ ├── home/ # 首页组件
│ │ ├── lyric/ # 歌词组件
│ │ ├── settings/ # 设置组件
│ │ └── ... # 其他组件
│ ├── const/ # 常量定义
│ ├── directive/ # 自定义指令
│ ├── hooks/ # 自定义 Hooks
│ ├── layout/ # 布局组件
│ ├── router/ # 路由配置
│ ├── services/ # 服务
│ ├── store/ # Pinia 状态管理
│ │ ├── modules/ # Pinia 模块
│ │ └── index.ts # Pinia 入口
│ ├── type/ # 类型定义
│ ├── types/ # 更多类型定义
│ ├── utils/ # 工具函数
│ ├── views/ # 页面视图
│ ├── App.vue # 根组件
│ ├── index.css # 全局样式
│ ├── index.html # HTML 模板
│ ├── main.ts # 渲染进程入口
│ └── ... # 其他文件
├── .env.development # 开发环境变量
├── .env.development.local # 本地开发环境变量
├── .env.production.local # 本地生产环境变量
├── .eslintrc.cjs # ESLint 配置
├── .gitignore # Git 忽略文件
├── .prettierrc.yaml # Prettier 配置
├── electron-builder.yml # electron-builder 配置
├── electron.vite.config.ts # electron-vite 配置
├── package.json # 项目配置
├── postcss.config.js # PostCSS 配置
├── tailwind.config.js # Tailwind 配置
├── tsconfig.json # TypeScript 配置
├── tsconfig.node.json # 节点 TypeScript 配置
└── tsconfig.web.json # Web TypeScript 配置
```
## 主要组件说明
### 主进程 (src/main)
主进程负责创建窗口、处理系统层面的交互以及与渲染进程的通信。
- **index.ts**: 应用主入口,负责创建窗口和应用生命周期管理
- **lyric.ts**: 歌词解析和处理
- **unblockMusic.ts**: 网易云音乐解锁功能
- **server.ts**: 本地服务器
### 预加载脚本 (src/preload)
预加载脚本在渲染进程加载前执行,提供了渲染进程和主进程之间的桥接功能。
### 渲染进程 (src/renderer)
渲染进程是基于 Vue 3 的前端应用,负责 UI 渲染和用户交互。
- **components/**: 包含各种 UI 组件
- **common/**: 通用组件
- **home/**: 首页相关组件
- **lyric/**: 歌词显示组件
- **settings/**: 设置界面组件
- **MusicList.vue**: 音乐列表组件
- **MvPlayer.vue**: MV 播放器
- **EQControl.vue**: 均衡器控制
- **...**: 其他组件
- **store/**: Pinia 状态管理
- **modules/**: 各功能模块的状态管理
- **index.ts**: 状态管理入口
- **views/**: 页面视图组件
- **router/**: 路由配置
- **api/**: API 请求封装
- **utils/**: 工具函数
## 开发指南
### 命名约定
- 目录使用 kebab-case (如: components/auth-wizard)
- 组件文件名使用 PascalCase (如: AuthWizard.vue)
- 可组合式函数使用 camelCase (如: useAuthState.ts)
### 代码风格
- 使用 Composition API 和 `<script setup>` 语法
- 使用 TypeScript 类型系统
- 优先使用类型而非接口
- 避免使用枚举,使用 const 对象代替
- 使用 tailwind 实现响应式设计

View File

@@ -1,9 +1,4 @@
# 你的接口地址 (必填)
VITE_API = http://127.0.0.1:30488
# 音乐破解接口地址 web端
VITE_API_MUSIC = ***
# 本地运行代理地址
VITE_API_LOCAL = /api
VITE_API_MUSIC_PROXY = /music
VITE_API_MUSIC = ***

View File

@@ -1,4 +0,0 @@
node_modules
dist
out
.gitignore

View File

@@ -1,137 +0,0 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution');
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'@vue/typescript/recommended',
'plugin:vue/vue3-recommended',
'plugin:vue-scoped-css/base',
'@electron-toolkit',
'@electron-toolkit/eslint-config-ts/eslint-recommended',
'plugin:prettier/recommended'
],
env: {
browser: true,
node: true,
jest: true,
es6: true
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly'
},
plugins: ['vue', '@typescript-eslint', 'simple-import-sort'],
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module',
allowImportExportEverywhere: true,
ecmaFeatures: {
jsx: true
}
},
settings: {
'import/extensions': ['.js', '.jsx', '.ts', '.tsx']
},
rules: {
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'no-underscore-dangle': 'off',
'no-nested-ternary': 'off',
'no-console': 'off',
'no-await-in-loop': 'off',
'no-continue': 'off',
'no-restricted-syntax': 'off',
'no-return-assign': 'off',
'no-unused-expressions': 'off',
'no-return-await': 'off',
'no-plusplus': 'off',
'no-param-reassign': 'off',
'no-shadow': 'off',
'guard-for-in': 'off',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'import/prefer-default-export': 'off',
'import/first': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'vue/first-attribute-linebreak': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}
],
'no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}
],
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'class-methods-use-this': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error'
},
overrides: [
{
files: ['*.vue'],
rules: {
'vue/component-name-in-template-casing': [2, 'kebab-case'],
'vue/require-default-prop': 0,
'vue/multi-word-component-names': 0,
'vue/no-reserved-props': 0,
'vue/no-v-html': 0,
'vue-scoped-css/enforce-style-type': [
'error',
{
allows: ['scoped']
}
],
'@typescript-eslint/explicit-function-return-type': 'off',
// 需要行尾分号
'prettier/prettier': ['error', { endOfLine: 'auto' }]
}
},
{
files: ['*.ts', '*.tsx'],
rules: {
'max-classes-per-file': 'off',
'no-await-in-loop': 'off',
'dot-notation': 'off',
'constructor-super': 'off',
'getter-return': 'off',
'no-const-assign': 'off',
'no-dupe-args': 'off',
'no-dupe-class-members': 'off',
'no-dupe-keys': 'off',
'no-func-assign': 'off',
'no-import-assign': 'off',
'no-new-symbol': 'off',
'no-obj-calls': 'off',
'no-redeclare': 'off',
'no-setter-return': 'off',
'no-this-before-super': 'off',
'no-undef': 'off',
'no-unreachable': 'off',
'no-unsafe-negation': 'off',
'no-var': 'error',
'prefer-const': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'valid-typeof': 'off',
'consistent-return': 'off',
'no-promise-executor-return': 'off',
'prefer-promise-reject-errors': 'off',
'@typescript-eslint/explicit-function-return-type': 'off'
}
}
]
};

View File

@@ -1,6 +1,6 @@
name: 反馈 Bug
description: 通过 github 模板进行 Bug 反馈。
title: "描述问题的标题"
title: '描述问题的标题'
body:
- type: markdown
attributes:

View File

@@ -1,5 +1,5 @@
blank_issues_enabled: true
contact_links:
- name:
url:
about:
- name:
url:
about:

View File

@@ -1,6 +1,6 @@
name: 反馈新功能
description: 通过 github 模板进行新功能反馈。
title: "描述问题的标题"
title: '描述问题的标题'
body:
- type: markdown
attributes:

View File

@@ -1,4 +1,5 @@
## IssueShoot
- 预估时长: {{ .duration }}
- 期望完成时间: {{ .deadline }}
- 开发难度: {{ .level }}

View File

@@ -8,11 +8,11 @@ on:
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v4
@@ -77,6 +77,7 @@ jobs:
dist/*.dmg
dist/*.exe
dist/*.deb
dist/*.rpm
dist/*.AppImage
dist/latest*.yml
dist/*.blockmap
@@ -84,4 +85,4 @@ jobs:
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -16,7 +16,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: '18'
- name: 创建环境变量文件
run: |
echo "VITE_API=${{ secrets.VITE_API }}" > .env.production.local
@@ -36,7 +36,7 @@ jobs:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.DEPLOY_KEY }}
source: "out/renderer/*"
source: 'out/renderer/*'
target: ${{ secrets.DEPLOY_PATH }}
strip_components: 2
@@ -48,4 +48,4 @@ jobs:
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd ${{ secrets.DEPLOY_PATH }}
echo "部署完成于 $(date)"
echo "部署完成于 $(date)"

14
.gitignore vendored
View File

@@ -26,4 +26,16 @@ out
.github/deploy_keys
resources/android/**/*
resources/android/**/*
android/app/release
.cursor
.windsurf
.agent
.auto-imports.d.ts
.components.d.ts
src/renderer/auto-imports.d.ts
src/renderer/components.d.ts

View File

@@ -1,2 +1,7 @@
echo "对已暂存文件运行 lint-staged..."
npx lint-staged
echo "运行类型检查..."
npm run typecheck
npm run typecheck
echo "所有检查通过,准备提交..."

View File

@@ -1,2 +1,7 @@
echo "对已暂存文件运行 lint-staged..."
npx lint-staged
echo "运行类型检查..."
npm run typecheck
npm run typecheck
echo "所有检查通过,准备提交..."

View File

@@ -1,5 +0,0 @@
singleQuote: true
semi: true
printWidth: 100
trailingComma: none
endOfLine: auto

View File

@@ -1,58 +1,64 @@
# 更新日志
## v4.7.0
> 如果更新遇到问题,请前往 <a href="http://donate.alger.fun/download" target="_blank">下载 AlgerMusicPlayer</a>
> 请我喝咖啡(支持作者) ☕️ <a href="http://donate.alger.fun/donate" target="_blank" style="color: red; font-weight: bold;">赏你</a>
> 帮我点个 star <a href="https://github.com/algerkong/AlgerMusicPlayer" target="_blank">github star</a>
> QQ频道 <a href="https://pd.qq.com/s/cs056n33q?b=5" target="_blank">加入频道</a>
## v5.0.0
### ✨ 新功能
- 替换扁平风格图标 ([c8e6db1](https://github.com/algerkong/AlgerMusicPlayer/commit/c8e6db1))
- 添加双击歌曲播放功能 ([258828f](https://github.com/algerkong/AlgerMusicPlayer/commit/258828f))
- 添加排行榜页面 ([a8010c8](https://github.com/algerkong/AlgerMusicPlayer/commit/a8010c8))
- 添加播放速度控制功能 ([6554736](https://github.com/algerkong/AlgerMusicPlayer/commit/6554736)) (#241) [感谢Java-wyx的 PR](https://github.com/Java-wyx)
- 修改播放列表展示形式,添加清空播放列表功能 ([2e96161](https://github.com/algerkong/AlgerMusicPlayer/commit/2e96161))
- 歌单列表添加布局切换、播放全部、收藏、添加到播放列表功能 ([b32408b](https://github.com/algerkong/AlgerMusicPlayer/commit/b32408b))
- 优化播放栏,整合高级控制菜单([f5f0dbb](https://github.com/algerkong/AlgerMusicPlayer/commit/f5f0dbb))
- 添加顶部定时显示,定时器过期检查功能, ([2dd4535](https://github.com/algerkong/AlgerMusicPlayer/commit/2dd4535))([170ac45](https://github.com/algerkong/AlgerMusicPlayer/commit/170ac45))
- 添加 mac 状态栏播放按键控制功能开关 ([2476fbd](https://github.com/algerkong/AlgerMusicPlayer/commit/2476fbd))
- 收藏列表添加升序降序排列 ([2803d40](https://github.com/algerkong/AlgerMusicPlayer/commit/2803d40))
- 为歌曲下拉菜单添加圆角样式,优化歌曲预览布局 ([5bef0e4](https://github.com/algerkong/AlgerMusicPlayer/commit/5bef0e4))
- 在用户歌单中添加"我创建的"标签,优化获取用户歌单的逻辑 ([d56a25e](https://github.com/algerkong/AlgerMusicPlayer/commit/d56a25e))
- 在歌手详情页添加歌曲操作工具栏,支持播放全部、添加到播放列表和搜索功能 ([6048e24](https://github.com/algerkong/AlgerMusicPlayer/commit/6048e24))
- 添加所有用户的关注和粉丝列表点击,优化播放排行获取和无权限展示 ([0c74291](https://github.com/algerkong/AlgerMusicPlayer/commit/0c74291))
- 添加 macOS 下点击 Dock 图标激活主窗口的功能 ([7fa0fa5](https://github.com/algerkong/AlgerMusicPlayer/commit/7fa0fa5))
- 添加鼠标滚轮调整音量功能,并显示音量百分比 ([95af222](https://github.com/algerkong/AlgerMusicPlayer/commit/95af222))
- 添加歌曲右键不喜欢功能以过滤每日推荐歌曲 ([a0935c7](https://github.com/algerkong/AlgerMusicPlayer/commit/a0935c7))
- 添加音乐平台链接,优化移动端样式 ([01a3a7a](https://github.com/algerkong/AlgerMusicPlayer/commit/01a3a7a))
- 在应用菜单中添加工具提示功能 ([5084da3](https://github.com/algerkong/AlgerMusicPlayer/commit/5084da3))
- LX Music 音源脚本导入
- 逐字歌词,支持全屏歌词和桌面歌词同步显示
- 心动模式播放
- 移动设备整体页面风格和效果优化
- 移动端添加平板模式设置
- 歌词页面样式控制优化 支持背景、宽度、字体粗细等个性化设置
- 历史日推查看
- 播放记录热力图
- 历史记录支持本地和云端记录
- 用户页面收藏专辑展示
- 添加 GPU 硬件加速设置
- 菜单展开状态保存 - 感谢 [harenchi](https://github.com/souvenp) 的贡献
- 搜索建议 - 感谢 [harenchi](https://github.com/souvenp) 的贡献
- 歌词繁体中文翻译模块,集成 OpenCC 引擎 - 感谢 [Leko](https://github.com/lekoOwO) 的贡献
- 自定义 API源 支持 [自定义源文档](https://github.com/algerkong/AlgerMusicPlayer/blob/main/docs/custom-api-readme.md) - 感谢 [harenchi](https://github.com/souvenp) 的贡献
### 🐛 Bug 修复
- 修复播放音乐时 URL 未正确更新的问题 ([91b1ff7](https://github.com/algerkong/AlgerMusicPlayer/commit/91b1ff7))
- 修复播放状态判断逻辑 ([e9fe900](https://github.com/algerkong/AlgerMusicPlayer/commit/e9fe900))
- 修复收藏歌曲功能未同步问题 ([69b1e54](https://github.com/algerkong/AlgerMusicPlayer/commit/69b1e54))
- 优化下载列表显示 ([df5ecb6](https://github.com/algerkong/AlgerMusicPlayer/commit/df5ecb6))
- 修复随机播放顺序异常
- 修复音源解析错误处理
- 修复 Mini 播放栏主题颜色问题
- 修复桌面歌词透明模式标题栏显示
- 修复逐字歌词字间距
- 修复远程控制设置无法保存
- 修复下载无损格式返回 HiRes 音质 - 感谢 [harenchi](https://github.com/souvenp) 的贡献
- 兼容 pnpm 包管理器 - 感谢 [Leko](https://github.com/lekoOwO) 的贡献
### 🎨 优化
- 添加 husky 预提交和预推送钩子,运行类型检查以确保代码质量 ([a449b74](https://github.com/algerkong/AlgerMusicPlayer/commit/a449b74))
- 重构歌曲组件,添加基础组件和多种样式,优化播放列表抽屉功能 ([ad7b504](https://github.com/algerkong/AlgerMusicPlayer/commit/ad7b504))
- 将下载逻辑提取优化([ca51020](https://github.com/algerkong/AlgerMusicPlayer/commit/ca51020))
- 优化B站音频解析功能 ([e47c84e](https://github.com/algerkong/AlgerMusicPlayer/commit/e47c84e))
- 统一音源选项的标签格式 ([54cbb84](https://github.com/algerkong/AlgerMusicPlayer/commit/54cbb84))
- 移动端去除定时关闭功能 ([f7951ec](https://github.com/algerkong/AlgerMusicPlayer/commit/f7951ec))
- 优化网页端下载程序功能 ([56b3ecf](https://github.com/algerkong/AlgerMusicPlayer/commit/56b3ecf))
- 退出登录时刷新页面 ([54f82d3](https://github.com/algerkong/AlgerMusicPlayer/commit/54f82d3))
### 其他优化
([ae1a7c9](https://github.com/algerkong/AlgerMusicPlayer/commit/ae1a7c9))
([f68f499](https://github.com/algerkong/AlgerMusicPlayer/commit/f68f499))
([6d4e6ef](https://github.com/algerkong/AlgerMusicPlayer/commit/6d4e6ef))
([2379b2c](https://github.com/algerkong/AlgerMusicPlayer/commit/2379b2c))
([33a1057](https://github.com/algerkong/AlgerMusicPlayer/commit/33a1057))
([54d66d0](https://github.com/algerkong/AlgerMusicPlayer/commit/54d66d0))
([3c792ce](https://github.com/algerkong/AlgerMusicPlayer/commit/3c792ce))
([35b84f3](https://github.com/algerkong/AlgerMusicPlayer/commit/35b84f3))
([278db37](https://github.com/algerkong/AlgerMusicPlayer/commit/278db37))
- 音源解析缓存
- 完善多语言国际化
- 优化播放检测和错误处理
- FLAC 元数据和封面图片处理 - 感谢 [harenchi](https://github.com/souvenp) 的贡献
- 日推不感兴趣调用官方接口 - 感谢 [harenchi](https://github.com/souvenp) 的贡献
- 代码提交流程优化,添加 lint-staged
## 赞赏支持☕️
[赞赏列表](https://donate.alger.fun/donate)
<table>
<tr>
<th style="text-align:center">微信赞赏</th>
<th style="width:100px"></th>
<th style="text-align:center">支付宝赞赏</th>
</tr>
<tr>
<td align="center">
<img src="https://github.com/algerkong/algerkong/blob/main/wechat.jpg?raw=true" alt="WeChat QRcode" width="200"><br>
<h6>☕️喝点咖啡继续干</h6>
</td>
<td></td>
<td align="center">
<img src="https://github.com/algerkong/algerkong/blob/main/alipay.jpg?raw=true" alt="Alipay QRcode" width="200"><br>
<h6>🍔来个汉堡</h6>
</td>
</tr>
</table>

198
DEV.md Normal file
View File

@@ -0,0 +1,198 @@
# Alger Music Player 开发文档
## 项目结构
### 技术栈
- **前端框架**Vue 3 + TypeScript
- **UI 组件库**naive-ui
- **样式框架**Tailwind CSS
- **图标库**remixicon
- **状态管理**Pinia
- **工具库**VueUse
- **构建工具**Vite, electron-vite
- **打包工具**electron-builder
- **国际化**vue-i18n
- **HTTP 客户端**axios
- **本地存储**electron-store localstorage
- **网易云音乐 API**netease-cloud-music-api
- **音乐解锁**@unblockneteasemusic/server
### 项目结构
```
AlgerMusicPlayer/
├── build/                  # 构建相关文件
├── docs/                   # 项目文档
├── node_modules/           # 依赖包
├── out/                    # 构建输出目录
├── resources/              # 资源文件
├── src/                    # 源代码
  ├── i18n/               # 国际化配置
   ├── lang/           # 语言包
   ├── main.ts         # 主进程国际化入口
   └── renderer.ts     # 渲染进程国际化入口
  ├── main/               # Electron 主进程
   ├── modules/        # 主进程模块
   ├── index.ts        # 主进程入口
   ├── lyric.ts        # 歌词处理
   ├── server.ts       # 服务器
   ├── set.json        # 设置
   └── unblockMusic.ts # 音乐解锁
  ├── preload/            # 预加载脚本
   ├── index.ts        # 预加载脚本入口
   └── index.d.ts      # 预加载脚本类型声明
  └── renderer/           # Vue 渲染进程
      ├── api/            # API 请求
      ├── assets/         # 静态资源
      ├── components/     # 组件
       ├── common/     # 通用组件
       ├── home/       # 首页组件
       ├── lyric/      # 歌词组件
       ├── settings/   # 设置组件
       └── ...         # 其他组件
      ├── const/          # 常量定义
      ├── directive/      # 自定义指令
      ├── hooks/          # 自定义 Hooks
      ├── layout/         # 布局组件
      ├── router/         # 路由配置
      ├── services/       # 服务
      ├── store/          # Pinia 状态管理
       ├── modules/    # Pinia 模块
       └── index.ts    # Pinia 入口
      ├── type/           # 类型定义
      ├── types/          # 更多类型定义
      ├── utils/          # 工具函数
      ├── views/          # 页面视图
      ├── App.vue         # 根组件
      ├── index.css       # 全局样式
      ├── index.html      # HTML 模板
      ├── main.ts         # 渲染进程入口
      └── ...             # 其他文件
├── .env.development        # 开发环境变量
├── .env.development.local  # 本地开发环境变量
├── .env.production.local   # 本地生产环境变量
├── .eslintrc.cjs           # ESLint 配置
├── .gitignore              # Git 忽略文件
├── .prettierrc.yaml        # Prettier 配置
├── electron-builder.yml    # electron-builder 配置
├── electron.vite.config.ts # electron-vite 配置
├── package.json            # 项目配置
├── postcss.config.js       # PostCSS 配置
├── tailwind.config.js      # Tailwind 配置
├── tsconfig.json           # TypeScript 配置
├── tsconfig.node.json      # 节点 TypeScript 配置
└── tsconfig.web.json       # Web TypeScript 配置
```
### 主要组件说明
#### 主进程 (src/main)
主进程负责创建窗口、处理系统层面的交互以及与渲染进程的通信。
- **index.ts**: 应用主入口,负责创建窗口和应用生命周期管理
- **lyric.ts**: 歌词解析和处理
- **unblockMusic.ts**: 网易云音乐解锁功能
- **server.ts**: 本地服务器
#### 预加载脚本 (src/preload)
预加载脚本在渲染进程加载前执行,提供了渲染进程和主进程之间的桥接功能。
#### 渲染进程 (src/renderer)
渲染进程是基于 Vue 3 的前端应用,负责 UI 渲染和用户交互。
- **components/**: 包含各种 UI 组件
  - **common/**: 通用组件
  - **home/**: 首页相关组件
  - **lyric/**: 歌词显示组件
  - **settings/**: 设置界面组件
  - **MusicList.vue**: 音乐列表组件
  - **MvPlayer.vue**: MV 播放器
  - **EQControl.vue**: 均衡器控制
  - **...**: 其他组件
- **store/**: Pinia 状态管理
  - **modules/**: 各功能模块的状态管理
  - **index.ts**: 状态管理入口
- **views/**: 页面视图组件
- **router/**: 路由配置
- **api/**: API 请求封装
- **utils/**: 工具函数
### 开发指南
#### 命名约定
- 目录使用 kebab-case (如: components/auth-wizard)
- 组件文件名使用 PascalCase (如: AuthWizard.vue)
- 可组合式函数使用 camelCase (如: useAuthState.ts)
#### 代码风格
- 使用 Composition API 和 `<script setup>` 语法
- 使用 TypeScript 类型系统
- 优先使用类型而非接口
- 避免使用枚举,使用 const 对象代替
- 使用 tailwind 实现响应式设计
### 如何启动?
安装依赖最好使用node18+
```
npm install
```
#### 桌面端开发
启动桌面端开发:
```
npm run dev
```
#### 网页端开发
如果只启动网页端开发,需要自己部署服务 netease-cloud-music-api
需要复制一份 `.env.development.local``src/renderer`
```
# .env.development.local
# 你的接口地址 (必填)
VITE_API = ***
# 音乐破解接口地址
VITE_API_MUSIC = ***
```
启动web端开发
```
npm run dev:web
```
### 打包
打包桌面端:
```
npm run build:win
```
打包后的文件在 /dist 下
打包网页端:
```
npm run build
```
打包后的文件在 /out/renderer 下

View File

@@ -1,4 +1,3 @@
<h2 align="center">🎵 Alger Music Player</h2>
<div align="center">
<div align="center">
@@ -23,7 +22,10 @@
<a href="https://hellogithub.com/repository/607b849c598d48e08fe38789d156ebdc" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=607b849c598d48e08fe38789d156ebdc&claim_uid=ObuMXUfeHBmk9TI&theme=neutral" alt="FeaturedHelloGitHub" width="160" height="32" /></a>
</div>
[项目下安装以及常用问题文档](https://www.yuque.com/alger-pfg5q/ip4f1a/bmgmfmghnhgwghkm?singleDoc#)
主要功能如下
- 🎵 音乐推荐
- 🔐 网易云账号登录与同步
- 📝 功能
@@ -38,15 +40,13 @@
- 迷你模式
- 状态栏控制
- 多语言支持
- 🎼 音乐功能
- 支持歌单、MV、专辑等完整音乐服务
- 灰色音乐资源解析(基于 @unblockneteasemusic/server
- 音乐单独解析
- 音乐资源解析(基于 @unblockneteasemusic/server
- EQ均衡器
- 定时播放 远程控制播放 倍速播放
- 高品质音乐
- 音乐文件下载(支持右键下载和批量下载, 附带歌词封面等信息)
- 音乐文件下载
- 搜索 MV 音乐 专辑 歌单 bilibili
- 音乐单独选择音源解析
- 🚀 技术特性
@@ -54,12 +54,15 @@
- 全平台适配Desktop & Web & Mobile Web & Android<测试> & ios<后续>
## 项目简介
一个第三方音乐播放器、本地服务、桌面歌词、音乐下载、最高音质
一个第三方音乐播放器、本地服务、桌面歌词、音乐下载、最高音质
## 预览地址
[http://music.alger.fun/](http://music.alger.fun/)
## 软件截图
![首页白](./docs/image.png)
![首页黑](./docs/image3.png)
![歌词](./docs/image6.png)
@@ -68,37 +71,31 @@
![音乐远程控制](./docs/image5.png)
## 项目启动
```bash
npm install
npm run dev
```
## 项目打包
```bash
# web
npm run build
# win
npm run build:win
# mac
npm run build:mac
# linux
npm run build:linux
```
## 开发文档
点击这里[开发文档](./DEV.md)
## 赞赏☕️
[赞赏列表](http://donate.alger.fun/)
| 微信赞赏 | 支付宝赞赏 |
| 微信赞赏 | 支付宝赞赏 |
| :--------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: |
| <img src="https://github.com/algerkong/algerkong/blob/main/wechat.jpg?raw=true" alt="WeChat QRcode" width=200> <br><small>喝点咖啡继续干</small> | <img src="https://github.com/algerkong/algerkong/blob/main/alipay.jpg?raw=true" alt="Wechat QRcode" width=200> <br><small>来包辣条吧~</small> |
## 项目统计
[![Stargazers over time](https://starchart.cc/algerkong/AlgerMusicPlayer.svg?variant=adaptive)](https://starchart.cc/algerkong/AlgerMusicPlayer)
![Alt](https://repobeats.axiom.co/api/embed/c4d01b3632e241c90cdec9508dfde86a7f54c9f5.svg "Repobeats analytics image")
![Alt](https://repobeats.axiom.co/api/embed/c4d01b3632e241c90cdec9508dfde86a7f54c9f5.svg 'Repobeats analytics image')
## 欢迎提Issues
## 免责声明
## 声明
本软件仅用于学习交流,禁止用于商业用途,否则后果自负。
希望大家还是要多多支持官方正版,此软件仅用作开发教学。

90
auto-imports.d.ts vendored
View File

@@ -1,90 +0,0 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: (typeof import('vue'))['EffectScope'];
const computed: (typeof import('vue'))['computed'];
const createApp: (typeof import('vue'))['createApp'];
const customRef: (typeof import('vue'))['customRef'];
const defineAsyncComponent: (typeof import('vue'))['defineAsyncComponent'];
const defineComponent: (typeof import('vue'))['defineComponent'];
const effectScope: (typeof import('vue'))['effectScope'];
const getCurrentInstance: (typeof import('vue'))['getCurrentInstance'];
const getCurrentScope: (typeof import('vue'))['getCurrentScope'];
const h: (typeof import('vue'))['h'];
const inject: (typeof import('vue'))['inject'];
const isProxy: (typeof import('vue'))['isProxy'];
const isReactive: (typeof import('vue'))['isReactive'];
const isReadonly: (typeof import('vue'))['isReadonly'];
const isRef: (typeof import('vue'))['isRef'];
const markRaw: (typeof import('vue'))['markRaw'];
const nextTick: (typeof import('vue'))['nextTick'];
const onActivated: (typeof import('vue'))['onActivated'];
const onBeforeMount: (typeof import('vue'))['onBeforeMount'];
const onBeforeUnmount: (typeof import('vue'))['onBeforeUnmount'];
const onBeforeUpdate: (typeof import('vue'))['onBeforeUpdate'];
const onDeactivated: (typeof import('vue'))['onDeactivated'];
const onErrorCaptured: (typeof import('vue'))['onErrorCaptured'];
const onMounted: (typeof import('vue'))['onMounted'];
const onRenderTracked: (typeof import('vue'))['onRenderTracked'];
const onRenderTriggered: (typeof import('vue'))['onRenderTriggered'];
const onScopeDispose: (typeof import('vue'))['onScopeDispose'];
const onServerPrefetch: (typeof import('vue'))['onServerPrefetch'];
const onUnmounted: (typeof import('vue'))['onUnmounted'];
const onUpdated: (typeof import('vue'))['onUpdated'];
const onWatcherCleanup: (typeof import('vue'))['onWatcherCleanup'];
const provide: (typeof import('vue'))['provide'];
const reactive: (typeof import('vue'))['reactive'];
const readonly: (typeof import('vue'))['readonly'];
const ref: (typeof import('vue'))['ref'];
const resolveComponent: (typeof import('vue'))['resolveComponent'];
const shallowReactive: (typeof import('vue'))['shallowReactive'];
const shallowReadonly: (typeof import('vue'))['shallowReadonly'];
const shallowRef: (typeof import('vue'))['shallowRef'];
const toRaw: (typeof import('vue'))['toRaw'];
const toRef: (typeof import('vue'))['toRef'];
const toRefs: (typeof import('vue'))['toRefs'];
const toValue: (typeof import('vue'))['toValue'];
const triggerRef: (typeof import('vue'))['triggerRef'];
const unref: (typeof import('vue'))['unref'];
const useAttrs: (typeof import('vue'))['useAttrs'];
const useCssModule: (typeof import('vue'))['useCssModule'];
const useCssVars: (typeof import('vue'))['useCssVars'];
const useDialog: (typeof import('naive-ui'))['useDialog'];
const useId: (typeof import('vue'))['useId'];
const useLoadingBar: (typeof import('naive-ui'))['useLoadingBar'];
const useMessage: (typeof import('naive-ui'))['useMessage'];
const useModel: (typeof import('vue'))['useModel'];
const useNotification: (typeof import('naive-ui'))['useNotification'];
const useSlots: (typeof import('vue'))['useSlots'];
const useTemplateRef: (typeof import('vue'))['useTemplateRef'];
const watch: (typeof import('vue'))['watch'];
const watchEffect: (typeof import('vue'))['watchEffect'];
const watchPostEffect: (typeof import('vue'))['watchPostEffect'];
const watchSyncEffect: (typeof import('vue'))['watchSyncEffect'];
}
// for type re-export
declare global {
// @ts-ignore
export type {
Component,
ComponentPublicInstance,
ComputedRef,
DirectiveBinding,
ExtractDefaultPropTypes,
ExtractPropTypes,
ExtractPublicPropTypes,
InjectionKey,
PropType,
Ref,
MaybeRef,
MaybeRefOrGetter,
VNode,
WritableComputedRef
} from 'vue';
import('vue');
}

View File

@@ -16,5 +16,7 @@
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
</dict>
</plist>

33
components.d.ts vendored
View File

@@ -1,33 +0,0 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {};
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
NAvatar: typeof import('naive-ui')['NAvatar']
NButton: typeof import('naive-ui')['NButton']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
NDrawer: typeof import('naive-ui')['NDrawer']
NDropdown: typeof import('naive-ui')['NDropdown']
NEllipsis: typeof import('naive-ui')['NEllipsis']
NEmpty: typeof import('naive-ui')['NEmpty']
NImage: typeof import('naive-ui')['NImage']
NInput: typeof import('naive-ui')['NInput']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NLayout: typeof import('naive-ui')['NLayout']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NPopover: typeof import('naive-ui')['NPopover']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSlider: typeof import('naive-ui')['NSlider']
NSpin: typeof import('naive-ui')['NSpin']
NSwitch: typeof import('naive-ui')['NSwitch']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}

62
docs/custom-api-readme.md Normal file
View File

@@ -0,0 +1,62 @@
## 🎵 自定义音源API配置
现在支持通过导入一个简单的 JSON 配置文件来对接第三方的音乐解析 API。这将提供极大的灵活性可以接入任意第三方音源。
### 如何使用
1. 前往 **设置 -> 播放设置 -> 音源设置**
2.**自定义 API 设置** 区域,点击 **“导入 JSON 配置”** 按钮。
3. 选择你已经编写好的 `xxx.json` 配置文件。
4. 导入成功后,程序将优先使用你的自定义 API 进行解析。
### JSON 配置文件格式说明
导入的配置文件必须是一个合法的 JSON 文件,并包含以下字段:
| 字段名 | 类型 | 是否必须 | 描述 |
| ----------------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `name` | `string` | 是 | API 名称,将显示在应用的 UI 界面上。 |
| `apiUrl` | `string` | 是 | API 的基础请求地址。 |
| `method` | `string` | 否 | HTTP 请求方法。可以是 `"GET"``"POST"`。**如果省略,默认为 "GET"**。 |
| `params` | `object` | 是 | 请求时需要发送的参数。对于 `GET` 请求,它们会作为查询字符串;对于 `POST` 请求,它们会作为请求体。 |
| `qualityMapping` | `object` | 否 | **音质映射表**。用于将应用内部的音质值(如 `"lossless"`)翻译成你的 API 需要的特定值。如果省略,则直接使用应用内部值。 |
| `responseUrlPath` | `string` | 是 | **URL提取路径**。用于从 API 返回的 JSON 响应中找到最终可播放的音乐链接。支持点 `.` 和方括号 `[]` 语法来访问嵌套对象和数组。 |
#### 占位符
`params` 对象的值中,你可以使用以下占位符,程序在请求时会自动替换它们:
- `{songId}`: 将被替换为当前歌曲的 ID。
- `{quality}`: 将被替换为当前用户设置的音质字符串 (例如, `"higher"`, `"lossless"`)。
#### 音质值列表
应用内部使用的音质值如下,你可以在 `qualityMapping` 中使用它们作为**键**
`standard`, `higher`, `exhigh`, `lossless`, `hires`, `jyeffect`, `sky`, `dolby`, `jymaster`
### 示例
假设有一个 API 如下:
`https://api.example.com/music?song_id=12345&bitrate=320000`
它返回的 JSON 是:
`{ "code": 200, "data": { "play_url": "http://..." } }`
那么对应的 JSON 配置文件应该是:
```json
{
"name": "Example API",
"apiUrl": "https://api.example.com/music",
"method": "GET",
"params": {
"song_id": "{songId}",
"bitrate": "{quality}"
},
"qualityMapping": {
"higher": "128000",
"exhigh": "320000",
"lossless": "999000"
},
"responseUrlPath": "data.play_url"
}
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -1,45 +0,0 @@
appId: com.electron.app
productName: electron-lan-file
directories:
buildResources: build
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
asarUnpack:
- resources/**
win:
executableName: electron-lan-file
nsis:
artifactName: ${name}-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://example.com/auto-updates
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/

View File

@@ -1,5 +1,5 @@
import vue from '@vitejs/plugin-vue';
import { defineConfig, externalizeDepsPlugin } from 'electron-vite';
import { defineConfig } from 'electron-vite';
import { resolve } from 'path';
import AutoImport from 'unplugin-auto-import/vite';
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
@@ -8,17 +8,14 @@ import viteCompression from 'vite-plugin-compression';
import VueDevTools from 'vite-plugin-vue-devtools';
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()]
},
preload: {
plugins: [externalizeDepsPlugin()]
},
main: {},
preload: {},
renderer: {
resolve: {
alias: {
'@': resolve('src/renderer'),
'@renderer': resolve('src/renderer')
'@renderer': resolve('src/renderer'),
'@i18n': resolve('src/i18n')
}
},
plugins: [
@@ -37,25 +34,10 @@ export default defineConfig({
resolvers: [NaiveUiResolver()]
})
],
publicDir: resolve('resources'),
server: {
proxy: {
// with options
[process.env.VITE_API_LOCAL as string]: {
target: process.env.VITE_API,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${process.env.VITE_API_LOCAL}`), '')
},
[process.env.VITE_API_MUSIC_PROXY as string]: {
target: process.env.VITE_API_MUSIC,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${process.env.VITE_API_MUSIC_PROXY}`), '')
},
[process.env.VITE_API_PROXY_MUSIC as string]: {
target: process.env.VITE_API_PROXY,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${process.env.VITE_API_PROXY_MUSIC}`), '')
}
}
host: '0.0.0.0',
port: 2389
}
}
});

237
eslint.config.mjs Normal file
View File

@@ -0,0 +1,237 @@
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
import vue from 'eslint-plugin-vue';
import vueParser from 'vue-eslint-parser';
import prettier from 'eslint-plugin-prettier';
import simpleImportSort from 'eslint-plugin-simple-import-sort';
import vueScopedCss from 'eslint-plugin-vue-scoped-css';
import globals from 'globals';
export default [
// 忽略文件配置
{
ignores: ['node_modules/**', 'dist/**', 'out/**', '.gitignore']
},
// 基础 JavaScript 配置
js.configs.recommended,
// JavaScript 文件配置
{
files: ['**/*.js', '**/*.cjs', '**/*.mjs'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.node,
...globals.browser
}
},
rules: {
'no-console': 'off',
'no-undef': 'error'
}
},
// TypeScript 文件配置
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: typescriptParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
allowImportExportEverywhere: true,
ecmaFeatures: {
jsx: true
}
},
globals: {
...globals.node,
...globals.browser,
// Vue 3 特定全局变量
defineProps: 'readonly',
defineEmits: 'readonly',
// TypeScript 全局类型
NodeJS: 'readonly',
ScrollBehavior: 'readonly'
}
},
plugins: {
'@typescript-eslint': typescript,
'simple-import-sort': simpleImportSort
},
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
// we are only using this rule to check for unused arguments since TS
// catches unused variables but not args.
{ varsIgnorePattern: '.*', args: 'none' }
],
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'no-console': 'off',
'no-unused-vars': [
'error',
// we are only using this rule to check for unused arguments since TS
// catches unused variables but not args.
{ varsIgnorePattern: '.*', args: 'none' }
],
'no-use-before-define': 'off',
'max-classes-per-file': 'off',
'no-await-in-loop': 'off',
'dot-notation': 'off',
'constructor-super': 'off',
'getter-return': 'off',
'no-const-assign': 'off',
'no-dupe-args': 'off',
'no-dupe-class-members': 'off',
'no-dupe-keys': 'off',
'no-func-assign': 'off',
'no-import-assign': 'off',
'no-new-symbol': 'off',
'no-obj-calls': 'off',
'no-redeclare': 'off',
'no-setter-return': 'off',
'no-this-before-super': 'off',
'no-undef': 'off',
'no-unreachable': 'off',
'no-unsafe-negation': 'off',
'no-var': 'error',
'prefer-const': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'valid-typeof': 'off',
'consistent-return': 'off',
'no-promise-executor-return': 'off',
'prefer-promise-reject-errors': 'off'
}
},
// Vue 文件配置
{
files: ['**/*.vue'],
languageOptions: {
parser: vueParser,
parserOptions: {
parser: typescriptParser,
ecmaVersion: 'latest',
sourceType: 'module',
allowImportExportEverywhere: true
},
globals: {
...globals.browser,
// Vue 3 特定全局变量
defineProps: 'readonly',
defineEmits: 'readonly',
// Vue 3 Composition API (如果使用了 unplugin-auto-import)
ref: 'readonly',
reactive: 'readonly',
computed: 'readonly',
watch: 'readonly',
watchEffect: 'readonly',
onMounted: 'readonly',
onUnmounted: 'readonly',
onBeforeUnmount: 'readonly',
nextTick: 'readonly',
inject: 'readonly',
provide: 'readonly',
// Naive UI (如果使用了 unplugin-auto-import)
useDialog: 'readonly',
useMessage: 'readonly',
// TypeScript 全局类型
NodeJS: 'readonly',
ScrollBehavior: 'readonly'
}
},
plugins: {
vue,
'@typescript-eslint': typescript,
prettier,
'simple-import-sort': simpleImportSort,
'vue-scoped-css': vueScopedCss
},
rules: {
// Vue 3 推荐规则
'vue/no-unused-vars': 'error',
'vue/no-unused-components': 'error',
'vue/no-multiple-template-root': 'off',
'vue/no-v-model-argument': 'off',
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/component-name-in-template-casing': ['error', 'kebab-case'],
'vue/no-reserved-props': 'off',
'vue/no-v-html': 'off',
'vue/first-attribute-linebreak': 'off',
'vue-scoped-css/enforce-style-type': [
'error',
{
allows: ['scoped']
}
],
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'prettier/prettier': 'error',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error'
}
},
// TypeScript 类型定义文件配置
{
files: ['**/*.d.ts'],
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-interface': 'off'
}
},
// JavaScript 第三方库文件配置
{
files: ['**/assets/**/*.js', '**/vendor/**/*.js', '**/lib/**/*.js'],
rules: {
'no-unused-vars': 'off',
'no-redeclare': 'off',
'no-self-assign': 'off',
'no-undef': 'off'
}
},
// 通用规则
{
files: ['**/*.js', '**/*.ts', '**/*.vue'],
rules: {
'no-console': 'off',
'no-underscore-dangle': 'off',
'no-nested-ternary': 'off',
'no-await-in-loop': 'off',
'no-continue': 'off',
'no-restricted-syntax': 'off',
'no-return-assign': 'off',
'no-unused-expressions': 'off',
'no-return-await': 'off',
'no-plusplus': 'off',
'no-param-reassign': 'off',
'no-shadow': 'off',
'guard-for-in': 'off',
'class-methods-use-this': 'off',
'no-case-declarations': 'off',
'no-unused-vars': [
'error',
// we are only using this rule to check for unused arguments since TS
// catches unused variables but not args.
{ varsIgnorePattern: '.*', args: 'none' }
]
}
}
];

View File

@@ -1,95 +1,118 @@
{
"name": "AlgerMusicPlayer",
"version": "4.7.0",
"version": "5.0.0",
"description": "Alger Music Player",
"author": "Alger <algerkc@qq.com>",
"main": "./out/main/index.js",
"homepage": "https://github.com/algerkong/AlgerMusicPlayer",
"scripts": {
"prepare": "husky",
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix",
"format": "prettier --write ./src",
"lint": "eslint ./src --fix",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"build": "npm run typecheck && electron-vite build",
"dev:web": "vite dev",
"build": "electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win",
"build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux"
},
"lint-staged": {
"*.{ts,tsx,vue,js}": [
"eslint --fix"
],
"*.{ts,tsx,vue,js,css,scss,md,json}": [
"prettier --write"
]
},
"dependencies": {
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/preload": "^3.0.2",
"@electron-toolkit/utils": "^4.0.0",
"@unblockneteasemusic/server": "^0.27.8-patch.1",
"@unblockneteasemusic/server": "^0.27.10",
"cors": "^2.8.5",
"electron-store": "^8.1.0",
"crypto-js": "^4.2.0",
"electron-store": "^8.2.0",
"electron-updater": "^6.6.2",
"express": "^4.18.2",
"font-list": "^1.5.1",
"electron-window-state": "^5.0.3",
"express": "^4.22.1",
"file-type": "^21.1.1",
"flac-tagger": "^1.0.7",
"font-list": "^1.6.0",
"form-data": "^4.0.5",
"husky": "^9.1.7",
"jsencrypt": "^3.5.4",
"music-metadata": "^11.10.3",
"netease-cloud-music-api-alger": "^4.26.1",
"node-fetch": "^2.7.0",
"node-id3": "^0.2.9",
"node-machine-id": "^1.1.12",
"vue-i18n": "^11.1.3"
"pinia-plugin-persistedstate": "^4.7.1",
"sharp": "^0.34.5",
"vue-i18n": "^11.2.2"
},
"devDependencies": {
"@electron-toolkit/eslint-config": "^2.1.0",
"@electron-toolkit/eslint-config-ts": "^3.1.0",
"@electron-toolkit/tsconfig": "^1.0.1",
"@rushstack/eslint-patch": "^1.10.3",
"@tailwindcss/postcss7-compat": "^2.2.4",
"@eslint/js": "^9.39.2",
"@rushstack/eslint-patch": "^1.15.0",
"@types/howler": "^2.2.12",
"@types/node": "^20.14.8",
"@types/node": "^20.19.26",
"@types/node-fetch": "^2.6.13",
"@types/tinycolor2": "^1.4.6",
"@typescript-eslint/eslint-plugin": "^8.30.1",
"@typescript-eslint/parser": "^8.30.1",
"@vitejs/plugin-vue": "^5.0.5",
"@vue/compiler-sfc": "^3.5.0",
"@typescript-eslint/eslint-plugin": "^8.49.0",
"@typescript-eslint/parser": "^8.49.0",
"@vitejs/plugin-vue": "^5.2.4",
"@vue/compiler-sfc": "^3.5.25",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.5.0",
"@vue/runtime-core": "^3.5.0",
"@vue/eslint-config-typescript": "^14.6.0",
"@vue/runtime-core": "^3.5.25",
"@vueuse/core": "^11.3.0",
"@vueuse/electron": "^11.3.0",
"@vueuse/electron": "^13.9.0",
"animate.css": "^4.1.1",
"autoprefixer": "^10.4.20",
"axios": "^1.7.7",
"autoprefixer": "^10.4.22",
"axios": "^1.13.2",
"cross-env": "^7.0.3",
"electron": "^36.2.0",
"electron-builder": "^25.1.8",
"electron-vite": "^3.1.0",
"eslint": "^9.0.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-simple-import-sort": "^12.0.0",
"eslint-plugin-vue": "^10.0.0",
"eslint-plugin-vue-scoped-css": "^2.9.0",
"electron": "^39.2.7",
"electron-builder": "^26.0.12",
"electron-vite": "^5.0.0",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-vue": "^10.6.2",
"eslint-plugin-vue-scoped-css": "^2.12.0",
"globals": "^16.5.0",
"howler": "^2.2.4",
"lint-staged": "^15.5.2",
"lodash": "^4.17.21",
"marked": "^15.0.4",
"naive-ui": "^2.41.0",
"pinia": "^3.0.1",
"pinyin-match": "^1.2.6",
"postcss": "^8.5.3",
"prettier": "^3.3.2",
"remixicon": "^4.6.0",
"sass": "^1.86.0",
"tailwindcss": "^3.4.17",
"marked": "^15.0.12",
"naive-ui": "^2.43.2",
"pinia": "^3.0.4",
"pinyin-match": "^1.2.10",
"postcss": "^8.5.6",
"prettier": "^3.7.4",
"remixicon": "^4.7.0",
"sass": "^1.96.0",
"tailwindcss": "^3.4.19",
"tinycolor2": "^1.6.0",
"tunajs": "^1.0.15",
"typescript": "^5.5.2",
"unplugin-auto-import": "^19.1.1",
"unplugin-vue-components": "^28.4.1",
"vite": "^6.2.2",
"typescript": "^5.9.3",
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.8.0",
"vite": "^6.4.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-vue-devtools": "7.7.2",
"vue": "^3.5.13",
"vue-router": "^4.5.0",
"vue-tsc": "^2.0.22"
"vue": "^3.5.25",
"vue-eslint-parser": "^10.2.0",
"vue-router": "^4.6.4",
"vue-tsc": "^2.2.12"
},
"build": {
"appId": "com.alger.music",
@@ -126,6 +149,12 @@
"gatekeeperAssess": false,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist",
"extendInfo": {
"NSMicrophoneUsageDescription": "AlgerMusicPlayer needs access to the microphone for audio visualization.",
"NSCameraUsageDescription": "Application requests access to the device's camera.",
"NSDocumentsFolderUsageDescription": "Application requests access to the user's Documents folder.",
"NSDownloadsFolderUsageDescription": "Application requests access to the user's Downloads folder."
},
"notarize": false,
"identity": null,
"type": "distribution",
@@ -164,6 +193,13 @@
"x64",
"arm64"
]
},
{
"target": "rpm",
"arch": [
"x64",
"arm64"
]
}
],
"artifactName": "${productName}-${version}-linux-${arch}.${ext}",
@@ -178,7 +214,15 @@
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "AlgerMusicPlayer",
"include": "build/installer.nsh"
"include": "build/installer.nsh",
"deleteAppDataOnUninstall": true,
"uninstallDisplayName": "AlgerMusicPlayer"
}
},
"pnpm": {
"onlyBuiltDependencies": [
"electron",
"esbuild"
]
}
}

10
prettier.config.js Normal file
View File

@@ -0,0 +1,10 @@
/**
* @type {import('prettier').Config}
*/
module.exports = {
singleQuote: true,
semi: true,
printWidth: 100,
trailingComma: 'none',
endOfLine: 'auto'
};

View File

@@ -1,486 +1,505 @@
<!DOCTYPE html>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>AlgerMusicPlayer 远程控制</title>
<style>
:root {
--primary-color: #007AFF;
--secondary-color: #5AC8FA;
--success-color: #4CD964;
--danger-color: #FF3B30;
--warning-color: #FF9500;
--light-gray: #F2F2F7;
--medium-gray: #E5E5EA;
--dark-gray: #8E8E93;
--text-color: #000000;
--text-secondary: #6C6C6C;
--background-color: #FFFFFF;
}
@media (prefers-color-scheme: dark) {
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<title>AlgerMusicPlayer 远程控制</title>
<style>
:root {
--primary-color: #0A84FF;
--secondary-color: #64D2FF;
--success-color: #30D158;
--danger-color: #FF453A;
--warning-color: #FF9F0A;
--light-gray: #1C1C1E;
--medium-gray: #2C2C2E;
--dark-gray: #8E8E93;
--text-color: #FFFFFF;
--text-secondary: #AEAEB2;
--background-color: #000000;
--primary-color: #007aff;
--secondary-color: #5ac8fa;
--success-color: #4cd964;
--danger-color: #ff3b30;
--warning-color: #ff9500;
--light-gray: #f2f2f7;
--medium-gray: #e5e5ea;
--dark-gray: #8e8e93;
--text-color: #000000;
--text-secondary: #6c6c6c;
--background-color: #ffffff;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: var(--text-color);
background-color: var(--light-gray);
display: flex;
flex-direction: column;
min-height: 100vh;
padding: 0;
margin: 0;
}
.header {
position: sticky;
top: 0;
z-index: 100;
background-color: var(--background-color);
padding: 12px 16px;
text-align: center;
border-bottom: 1px solid var(--medium-gray);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.header h1 {
font-size: 18px;
font-weight: 600;
margin: 0;
}
.container {
max-width: 540px;
margin: 0 auto;
padding: 16px;
width: 100%;
flex: 1;
}
.card {
background-color: var(--background-color);
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.song-info {
display: flex;
align-items: center;
padding-bottom: 16px;
}
.song-cover {
width: 72px;
height: 72px;
border-radius: 8px;
object-fit: cover;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
background-color: var(--medium-gray);
}
.song-details {
margin-left: 16px;
flex: 1;
}
.song-details h2 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: var(--text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.song-details p {
margin: 4px 0 0;
font-size: 15px;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.play-state {
font-size: 14px;
color: var(--primary-color);
margin-top: 4px;
display: flex;
align-items: center;
}
.play-state::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
}
.playing .play-state::before {
background-color: var(--success-color);
}
.paused .play-state::before {
background-color: var(--warning-color);
}
.controls {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 16px;
}
.extra-controls {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: var(--background-color);
color: var(--primary-color);
border: 1px solid var(--medium-gray);
padding: 16px 0;
border-radius: 12px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
user-select: none;
position: relative;
overflow: hidden;
}
.btn:active {
transform: scale(0.97);
opacity: 0.7;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--primary-color);
opacity: 0;
transition: opacity 0.2s ease;
z-index: -1;
}
.btn:active::before {
opacity: 0.1;
}
.btn svg {
margin-bottom: 8px;
width: 24px;
height: 24px;
fill: var(--primary-color);
}
.btn-play svg {
width: 28px;
height: 28px;
margin-bottom: 6px;
}
.status-bar {
text-align: center;
padding: 8px 16px;
font-size: 14px;
color: var(--text-secondary);
background-color: var(--background-color);
border-top: 1px solid var(--medium-gray);
position: sticky;
bottom: 0;
}
.status-message {
display: inline-block;
transition: opacity 0.3s ease;
}
.status-message.fade {
opacity: 0;
}
.refresh-button {
color: var(--primary-color);
background: none;
border: none;
font-size: 14px;
cursor: pointer;
padding: 0;
margin-left: 8px;
}
@media (max-width: 350px) {
.controls, .extra-controls {
gap: 8px;
@media (prefers-color-scheme: dark) {
:root {
--primary-color: #0a84ff;
--secondary-color: #64d2ff;
--success-color: #30d158;
--danger-color: #ff453a;
--warning-color: #ff9f0a;
--light-gray: #1c1c1e;
--medium-gray: #2c2c2e;
--dark-gray: #8e8e93;
--text-color: #ffffff;
--text-secondary: #aeaeb2;
--background-color: #000000;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
font-family:
-apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: var(--text-color);
background-color: var(--light-gray);
display: flex;
flex-direction: column;
min-height: 100vh;
padding: 0;
margin: 0;
}
.header {
position: sticky;
top: 0;
z-index: 100;
background-color: var(--background-color);
padding: 12px 16px;
text-align: center;
border-bottom: 1px solid var(--medium-gray);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.header h1 {
font-size: 18px;
font-weight: 600;
margin: 0;
}
.container {
max-width: 540px;
margin: 0 auto;
padding: 16px;
width: 100%;
flex: 1;
}
.card {
background-color: var(--background-color);
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.song-info {
display: flex;
align-items: center;
padding-bottom: 16px;
}
.song-cover {
width: 72px;
height: 72px;
border-radius: 8px;
object-fit: cover;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
background-color: var(--medium-gray);
}
.song-details {
margin-left: 16px;
flex: 1;
}
.song-details h2 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: var(--text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.song-details p {
margin: 4px 0 0;
font-size: 15px;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.play-state {
font-size: 14px;
color: var(--primary-color);
margin-top: 4px;
display: flex;
align-items: center;
}
.play-state::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
}
.playing .play-state::before {
background-color: var(--success-color);
}
.paused .play-state::before {
background-color: var(--warning-color);
}
.controls {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 16px;
}
.extra-controls {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.btn {
padding: 12px 0;
font-size: 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: var(--background-color);
color: var(--primary-color);
border: 1px solid var(--medium-gray);
padding: 16px 0;
border-radius: 12px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
user-select: none;
position: relative;
overflow: hidden;
}
.btn:active {
transform: scale(0.97);
opacity: 0.7;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--primary-color);
opacity: 0;
transition: opacity 0.2s ease;
z-index: -1;
}
.btn:active::before {
opacity: 0.1;
}
.btn svg {
width: 20px;
height: 20px;
margin-bottom: 8px;
width: 24px;
height: 24px;
fill: var(--primary-color);
}
.btn-play svg {
width: 28px;
height: 28px;
margin-bottom: 6px;
}
}
</style>
</head>
<body>
<div class="header">
<h1>AlgerMusicPlayer 远程控制</h1>
</div>
<div class="container">
<div class="card" id="songInfoCard">
<div class="song-info">
<img id="songCover" class="song-cover" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%238E8E93'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-5.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z'/%3E%3C/svg%3E" alt="封面">
<div class="song-details">
<h2 id="songTitle">未在播放</h2>
<p id="songArtist">--</p>
<div class="play-state" id="playState">未播放</div>
.status-bar {
text-align: center;
padding: 8px 16px;
font-size: 14px;
color: var(--text-secondary);
background-color: var(--background-color);
border-top: 1px solid var(--medium-gray);
position: sticky;
bottom: 0;
}
.status-message {
display: inline-block;
transition: opacity 0.3s ease;
}
.status-message.fade {
opacity: 0;
}
.refresh-button {
color: var(--primary-color);
background: none;
border: none;
font-size: 14px;
cursor: pointer;
padding: 0;
margin-left: 8px;
}
@media (max-width: 350px) {
.controls,
.extra-controls {
gap: 8px;
}
.btn {
padding: 12px 0;
font-size: 12px;
}
.btn svg {
width: 20px;
height: 20px;
margin-bottom: 6px;
}
}
</style>
</head>
<body>
<div class="header">
<h1>AlgerMusicPlayer 远程控制</h1>
</div>
<div class="container">
<div class="card" id="songInfoCard">
<div class="song-info">
<img
id="songCover"
class="song-cover"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%238E8E93'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-5.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z'/%3E%3C/svg%3E"
alt="封面"
/>
<div class="song-details">
<h2 id="songTitle">未在播放</h2>
<p id="songArtist">--</p>
<div class="play-state" id="playState">未播放</div>
</div>
</div>
</div>
<div class="card">
<div class="controls">
<button id="prevBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M6 6h2v12H6zm3.5 6l8.5 6V6z" />
</svg>
上一首
</button>
<button id="playBtn" class="btn btn-play">
<svg id="playIcon" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z" />
</svg>
播放/暂停
</button>
<button id="nextBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" />
</svg>
下一首
</button>
</div>
<div class="extra-controls">
<button id="volumeDownBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"
/>
</svg>
音量-
</button>
<button id="volumeUpBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"
/>
</svg>
音量+
</button>
</div>
</div>
<div class="card">
<div class="extra-controls">
<button id="favoriteBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
/>
</svg>
收藏
</button>
<button id="refreshBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"
/>
</svg>
刷新
</button>
</div>
</div>
</div>
<div class="card">
<div class="controls">
<button id="prevBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/>
</svg>
上一首
</button>
<button id="playBtn" class="btn btn-play">
<svg id="playIcon" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
播放/暂停
</button>
<button id="nextBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/>
</svg>
下一首
</button>
</div>
<div class="extra-controls">
<button id="volumeDownBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/>
</svg>
音量-
</button>
<button id="volumeUpBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>
</svg>
音量+
</button>
</div>
<div class="status-bar">
<span id="status" class="status-message">准备就绪</span>
</div>
<div class="card">
<div class="extra-controls">
<button id="favoriteBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
收藏
</button>
<button id="refreshBtn" class="btn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
</svg>
刷新
</button>
</div>
</div>
</div>
<script>
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', () => {
// 获取DOM元素
const songInfoCard = document.getElementById('songInfoCard');
const songTitle = document.getElementById('songTitle');
const songArtist = document.getElementById('songArtist');
const songCover = document.getElementById('songCover');
const playState = document.getElementById('playState');
const playBtn = document.getElementById('playBtn');
const playIcon = document.getElementById('playIcon');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const favoriteBtn = document.getElementById('favoriteBtn');
const volumeUpBtn = document.getElementById('volumeUpBtn');
const volumeDownBtn = document.getElementById('volumeDownBtn');
const refreshBtn = document.getElementById('refreshBtn');
const status = document.getElementById('status');
<div class="status-bar">
<span id="status" class="status-message">准备就绪</span>
</div>
let isPlaying = false;
<script>
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', () => {
// 获取DOM元素
const songInfoCard = document.getElementById('songInfoCard');
const songTitle = document.getElementById('songTitle');
const songArtist = document.getElementById('songArtist');
const songCover = document.getElementById('songCover');
const playState = document.getElementById('playState');
const playBtn = document.getElementById('playBtn');
const playIcon = document.getElementById('playIcon');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const favoriteBtn = document.getElementById('favoriteBtn');
const volumeUpBtn = document.getElementById('volumeUpBtn');
const volumeDownBtn = document.getElementById('volumeDownBtn');
const refreshBtn = document.getElementById('refreshBtn');
const status = document.getElementById('status');
let isPlaying = false;
// 显示状态消息并淡出
function showStatus(message, autoClear = true) {
status.textContent = message;
status.classList.remove('fade');
if (autoClear) {
setTimeout(() => {
status.classList.add('fade');
}, 2000);
}
}
// 更新播放/暂停图标
function updatePlayIcon() {
if (isPlaying) {
playIcon.innerHTML = '<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>';
} else {
playIcon.innerHTML = '<path d="M8 5v14l11-7z"/>';
}
}
// 更新状态的函数
async function updateStatus() {
try {
showStatus('获取播放状态...', false);
const response = await fetch('/api/status');
const data = await response.json();
// 更新播放状态
isPlaying = data.isPlaying;
updatePlayIcon();
// 更新UI
if (data.currentSong) {
songTitle.textContent = data.currentSong.name || '未知歌曲';
if (data.currentSong.ar && data.currentSong.ar.length) {
songArtist.textContent = data.currentSong.ar.map(a => a.name).join(', ');
} else if (data.currentSong.artists && data.currentSong.artists.length) {
songArtist.textContent = data.currentSong.artists.map(a => a.name).join(', ');
} else {
songArtist.textContent = '未知艺术家';
}
if (data.currentSong.picUrl) {
songCover.src = data.currentSong.picUrl;
}
} else {
songTitle.textContent = '未在播放';
songArtist.textContent = '--';
songCover.src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%238E8E93'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-5.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z'/%3E%3C/svg%3E";
// 显示状态消息并淡出
function showStatus(message, autoClear = true) {
status.textContent = message;
status.classList.remove('fade');
if (autoClear) {
setTimeout(() => {
status.classList.add('fade');
}, 2000);
}
// 更新播放状态
playState.textContent = isPlaying ? '正在播放' : '已暂停';
songInfoCard.className = isPlaying ? 'card playing' : 'card paused';
showStatus('已更新', true);
} catch (error) {
console.error('获取状态失败:', error);
showStatus('获取状态失败');
}
}
// 发送命令的函数
async function sendCommand(endpoint) {
try {
showStatus('发送命令中...', false);
const response = await fetch('/api/' + endpoint, { method: 'POST' });
const data = await response.json();
showStatus(data.message || '命令已发送');
// 稍等后更新状态
setTimeout(updateStatus, 500);
} catch (error) {
console.error('发送命令失败:', error);
showStatus('发送命令失败');
}
}
// 绑定按钮事件
playBtn.addEventListener('click', () => sendCommand('toggle-play'));
prevBtn.addEventListener('click', () => sendCommand('prev'));
nextBtn.addEventListener('click', () => sendCommand('next'));
favoriteBtn.addEventListener('click', () => sendCommand('toggle-favorite'));
volumeUpBtn.addEventListener('click', () => sendCommand('volume-up'));
volumeDownBtn.addEventListener('click', () => sendCommand('volume-down'));
refreshBtn.addEventListener('click', updateStatus);
// 初始加载状态
updateStatus();
// 每1秒更新一次状态
setInterval(updateStatus, 1000);
// 添加触摸反馈
const buttons = document.querySelectorAll('.btn');
buttons.forEach(btn => {
btn.addEventListener('touchstart', function() {
this.style.transform = 'scale(0.97)';
this.style.opacity = '0.7';
});
btn.addEventListener('touchend', function() {
this.style.transform = 'scale(1)';
this.style.opacity = '1';
});
});
// 检测深色模式变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
// 更新播放/暂停图标
function updatePlayIcon() {
if (isPlaying) {
playIcon.innerHTML = '<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>';
} else {
playIcon.innerHTML = '<path d="M8 5v14l11-7z"/>';
}
}
// 更新状态的函数
async function updateStatus() {
try {
showStatus('获取播放状态...', false);
const response = await fetch('/api/status');
const data = await response.json();
// 更新播放状态
isPlaying = data.isPlaying;
updatePlayIcon();
// 更新UI
if (data.currentSong) {
songTitle.textContent = data.currentSong.name || '未知歌曲';
if (data.currentSong.ar && data.currentSong.ar.length) {
songArtist.textContent = data.currentSong.ar.map((a) => a.name).join(', ');
} else if (data.currentSong.artists && data.currentSong.artists.length) {
songArtist.textContent = data.currentSong.artists.map((a) => a.name).join(', ');
} else {
songArtist.textContent = '未知艺术家';
}
if (data.currentSong.picUrl) {
songCover.src = data.currentSong.picUrl;
}
} else {
songTitle.textContent = '未在播放';
songArtist.textContent = '--';
songCover.src =
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%238E8E93'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14.5c-2.49 0-4.5-2.01-4.5-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5-2.01 4.5-4.5 4.5zm0-5.5c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z'/%3E%3C/svg%3E";
}
// 更新播放状态
playState.textContent = isPlaying ? '正在播放' : '已暂停';
songInfoCard.className = isPlaying ? 'card playing' : 'card paused';
showStatus('已更新', true);
} catch (error) {
console.error('获取状态失败:', error);
showStatus('获取状态失败');
}
}
// 发送命令的函数
async function sendCommand(endpoint) {
try {
showStatus('发送命令中...', false);
const response = await fetch('/api/' + endpoint, { method: 'POST' });
const data = await response.json();
showStatus(data.message || '命令已发送');
// 稍等后更新状态
setTimeout(updateStatus, 500);
} catch (error) {
console.error('发送命令失败:', error);
showStatus('发送命令失败');
}
}
// 绑定按钮事件
playBtn.addEventListener('click', () => sendCommand('toggle-play'));
prevBtn.addEventListener('click', () => sendCommand('prev'));
nextBtn.addEventListener('click', () => sendCommand('next'));
favoriteBtn.addEventListener('click', () => sendCommand('toggle-favorite'));
volumeUpBtn.addEventListener('click', () => sendCommand('volume-up'));
volumeDownBtn.addEventListener('click', () => sendCommand('volume-down'));
refreshBtn.addEventListener('click', updateStatus);
// 初始加载状态
updateStatus();
// 每1秒更新一次状态
setInterval(updateStatus, 1000);
// 添加触摸反馈
const buttons = document.querySelectorAll('.btn');
buttons.forEach((btn) => {
btn.addEventListener('touchstart', function () {
this.style.transform = 'scale(0.97)';
this.style.opacity = '0.7';
});
btn.addEventListener('touchend', function () {
this.style.transform = 'scale(1)';
this.style.opacity = '1';
});
});
// 检测深色模式变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
updateStatus();
});
});
});
</script>
</body>
</html>
</script>
</body>
</html>

View File

@@ -0,0 +1,51 @@
export default {
player: {
loading: 'Loading audio...',
retry: 'Retry',
playNow: 'Play Now',
loadingTitle: 'Loading...',
totalDuration: 'Total Duration: {duration}',
partsList: 'Parts List ({count} episodes)',
playStarted: 'Playback started',
switchingPart: 'Switching to part: {part}',
preloadingNext: 'Preloading next part: {part}',
playingCurrent: 'Playing current selected part: {name}',
num: 'M',
errors: {
invalidVideoId: 'Invalid video ID',
loadVideoDetailFailed: 'Failed to load video details',
loadPartInfoFailed: 'Unable to load video part information',
loadAudioUrlFailed: 'Failed to get audio playback URL',
videoDetailNotLoaded: 'Video details not loaded',
missingParams: 'Missing required parameters',
noAvailableAudioUrl: 'No available audio URL found',
loadPartAudioFailed: 'Failed to load part audio URL',
audioListEmpty: 'Audio list is empty, please retry',
currentPartNotFound: 'Current part audio not found',
audioUrlFailed: 'Failed to get audio URL',
playFailed: 'Playback failed, please retry',
getAudioUrlFailed: 'Failed to get audio URL, please retry',
audioNotFound: 'Corresponding audio not found, please retry',
preloadFailed: 'Failed to preload next part',
switchPartFailed: 'Failed to load audio URL when switching parts'
},
console: {
loadingDetail: 'Loading Bilibili video details',
detailData: 'Bilibili video detail data',
multipleParts: 'Video has multiple parts, total {count}',
noPartsData: 'Video has no parts or part data is empty',
loadingAudioSource: 'Loading audio source',
generatedAudioList: 'Generated audio list, total {count}',
getDashAudioUrl: 'Got dash audio URL',
getDurlAudioUrl: 'Got durl audio URL',
loadingPartAudio: 'Loading part audio URL: {part}, cid: {cid}',
loadPartAudioFailed: 'Failed to load part audio URL: {part}',
switchToPart: 'Switching to part: {part}',
audioNotFoundInList: 'Corresponding audio item not found',
preparingToPlay: 'Preparing to play current selected part: {name}',
preloadingNextPart: 'Preloading next part: {part}',
playingSelectedPart: 'Playing current selected part: {name}, audio URL: {url}',
preloadNextFailed: 'Failed to preload next part'
}
}
};

View File

@@ -27,6 +27,7 @@ export default {
refresh: 'Refresh',
retry: 'Retry',
reset: 'Reset',
back: 'Back',
copySuccess: 'Copied to clipboard',
copyFailed: 'Copy failed',
validation: {
@@ -39,9 +40,13 @@ export default {
},
viewMore: 'View More',
noMore: 'No more',
selectAll: 'Select All',
expand: 'Expand',
collapse: 'Collapse',
songCount: '{count} songs',
language: 'Language',
today: 'Today',
yesterday: 'Yesterday',
tray: {
show: 'Show',
quit: 'Quit',
@@ -51,6 +56,5 @@ export default {
pause: 'Pause',
play: 'Play',
favorite: 'Favorite'
},
language: 'Language'
}
};

View File

@@ -52,6 +52,31 @@ export default {
copyFailed: 'Copy failed',
backgroundDownload: 'Background Download'
},
disclaimer: {
title: 'Terms of Use',
warning:
'This application is a development test version. Functions are not yet perfect, and there may be many problems and bugs. It is for learning and exchange only.',
item1:
'This application is for personal learning, research and technical exchange only. Please do not use it for any commercial purposes.',
item2:
'Please delete it within 24 hours after downloading. If you need to use it for a long time, please support the genuine music service.',
item3:
'By using this application, you understand and assume the relevant risks. The developer is not responsible for any loss.',
agree: 'I have read and agree',
disagree: 'Disagree and Exit'
},
donate: {
title: 'Support Developer',
subtitle: 'Your support is my motivation',
tip: 'Donation is completely voluntary. All functions can be used normally without donation. Thank you for your understanding and support!',
wechat: 'WeChat',
alipay: 'Alipay',
wechatQR: 'WeChat QR Code',
alipayQR: 'Alipay QR Code',
scanTip: 'Please use your phone to scan the QR code above to donate',
enterApp: 'Enter App',
noForce: 'No forced donation, click to enter'
},
coffee: {
title: 'Buy me a coffee',
alipay: 'Alipay',
@@ -60,7 +85,7 @@ export default {
wechatQR: 'Wechat QR code',
coffeeDesc: 'A cup of coffee, a support',
coffeeDescLinkText: 'View more',
qqGroup: 'QQ group: algermusic',
groupText: 'Wechat Public Account: AlgerMusic',
messages: {
copySuccess: 'Copied to clipboard'
},
@@ -85,12 +110,16 @@ export default {
login: 'Login',
toLogin: 'To Login',
logout: 'Logout',
set: 'Set',
set: 'Settings',
theme: 'Theme',
restart: 'Restart',
refresh: 'Refresh',
currentVersion: 'Current Version',
searchPlaceholder: 'Search for something...'
searchPlaceholder: 'Search for something...',
zoom: 'Zoom',
zoom100: 'Zoom 100%',
resetZoom: 'Reset Zoom',
zoomDefault: 'Default Zoom'
},
titleBar: {
closeTitle: 'Choose how to close',
@@ -115,6 +144,79 @@ export default {
addToPlaylist: 'Add to Playlist',
addToPlaylistSuccess: 'Add to Playlist Success',
operationFailed: 'Operation Failed',
songsAlreadyInPlaylist: 'Songs already in playlist'
}
songsAlreadyInPlaylist: 'Songs already in playlist',
historyRecommend: 'Daily History',
fetchDatesFailed: 'Failed to fetch dates',
fetchSongsFailed: 'Failed to fetch songs',
noSongs: 'No songs'
},
playlist: {
import: {
button: 'Import Playlist',
title: 'Import Playlist',
description: 'Import playlists via metadata, text, or links',
linkTab: 'Import by Link',
textTab: 'Import by Text',
localTab: 'Import by Metadata',
linkPlaceholder: 'Enter playlist links, one per line',
textPlaceholder: 'Enter song information in format: Song Name Artist Name',
localPlaceholder: 'Enter song metadata in JSON format',
linkTips: 'Supported link sources:',
linkTip1: 'Copy links after sharing playlists to WeChat/Weibo/QQ',
linkTip2: 'Directly copy playlist/profile links',
linkTip3: 'Directly copy article links',
textTips: 'Enter song information, one song per line',
textFormat: 'Format: Song Name Artist Name',
localTips: 'Add song metadata',
localFormat: 'Format example:',
songNamePlaceholder: 'Song Name',
artistNamePlaceholder: 'Artist Name',
albumNamePlaceholder: 'Album Name',
addSongButton: 'Add Song',
addLinkButton: 'Add Link',
importToStarPlaylist: 'Import to My Favorite Music',
playlistNamePlaceholder: 'Enter playlist name',
importButton: 'Start Import',
emptyLinkWarning: 'Please enter playlist links',
emptyTextWarning: 'Please enter song information',
emptyLocalWarning: 'Please enter song metadata',
invalidJsonFormat: 'Invalid JSON format',
importSuccess: 'Import task created successfully',
importFailed: 'Import failed',
importStatus: 'Import Status',
refresh: 'Refresh',
taskId: 'Task ID',
status: 'Status',
successCount: 'Success Count',
failReason: 'Failure Reason',
unknownError: 'Unknown error',
statusPending: 'Pending',
statusProcessing: 'Processing',
statusSuccess: 'Success',
statusFailed: 'Failed',
statusUnknown: 'Unknown',
taskList: 'Task List',
taskListTitle: 'Import Task List',
action: 'Action',
select: 'Select',
fetchTaskListFailed: 'Failed to fetch task list',
noTasks: 'No import tasks',
clearTasks: 'Clear Tasks',
clearTasksConfirmTitle: 'Confirm Clear',
clearTasksConfirmContent:
'Are you sure you want to clear all import task records? This action cannot be undone.',
confirm: 'Confirm',
cancel: 'Cancel',
clearTasksSuccess: 'Task list cleared',
clearTasksFailed: 'Failed to clear task list'
}
},
settings: 'Settings',
user: 'User',
toplist: 'Toplist',
history: 'History',
list: 'Playlist',
mv: 'MV',
home: 'Home',
search: 'Search'
};

View File

@@ -3,17 +3,20 @@ export default {
localMusic: 'Local Music',
count: '{count} songs in total',
clearAll: 'Clear All',
settings: 'Settings',
tabs: {
downloading: 'Downloading',
downloaded: 'Downloaded'
},
empty: {
noTasks: 'No download tasks',
noDownloaded: 'No downloaded songs'
noDownloaded: 'No downloaded songs',
noDownloadedHint: 'Download your favorite songs to listen offline'
},
progress: {
total: 'Total Progress: {progress}%'
},
items: 'items',
status: {
downloading: 'Downloading',
completed: 'Completed',
@@ -43,7 +46,46 @@ export default {
},
message: {
downloadComplete: '{filename} download completed',
downloadFailed: '{filename} download failed: {error}'
downloadFailed: '{filename} download failed: {error}',
alreadyDownloading: '{filename} is already downloading'
},
loading: 'Loading...'
loading: 'Loading...',
playStarted: 'Play started: {name}',
playFailed: 'Play failed: {name}',
path: {
copied: 'Path copied to clipboard',
copyFailed: 'Failed to copy path'
},
settingsPanel: {
title: 'Download Settings',
path: 'Download Location',
pathDesc: 'Set where your music files will be saved',
pathPlaceholder: 'Please select download path',
noPathSelected: 'Please select download path first',
select: 'Select Folder',
open: 'Open Folder',
fileFormat: 'Filename Format',
fileFormatDesc: 'Set how downloaded music files will be named',
customFormat: 'Custom Format',
separator: 'Separator',
separators: {
dash: 'Space-dash-space',
underscore: 'Underscore',
space: 'Space'
},
dragToArrange: 'Sort or use arrow buttons to arrange:',
formatVariables: 'Available variables',
preview: 'Preview:',
saveSuccess: 'Download settings saved',
presets: {
songArtist: 'Song - Artist',
artistSong: 'Artist - Song',
songOnly: 'Song only'
},
components: {
songName: 'Song name',
artistName: 'Artist name',
albumName: 'Album name'
}
}
};

View File

@@ -1,5 +1,45 @@
export default {
title: 'Play History',
heatmapTitle: 'Heatmap',
playCount: '{count}',
getHistoryFailed: 'Failed to get play history'
getHistoryFailed: 'Failed to get play history',
categoryTabs: {
songs: 'Songs',
playlists: 'Playlists',
albums: 'Albums'
},
tabs: {
all: 'All Records',
local: 'Local Records',
cloud: 'Cloud Records'
},
getCloudRecordFailed: 'Failed to get cloud records',
needLogin: 'Please login with cookie to view cloud records',
merging: 'Merging records...',
noDescription: 'No description',
noData: 'No records',
newKey: 'New translation',
heatmap: {
title: 'Play Heatmap',
loading: 'Loading data...',
unit: 'plays',
footerText: 'Hover to view details',
playCount: 'Played {count} times',
topSongs: 'Top songs of the day',
times: 'times',
totalPlays: 'Total Plays',
activeDays: 'Active Days',
noData: 'No play records',
colorTheme: 'Color Theme',
colors: {
green: 'Green',
blue: 'Blue',
orange: 'Orange',
purple: 'Purple',
red: 'Red'
},
mostPlayedSong: 'Most Played Song',
mostActiveDay: 'Most Active Day',
latestNightSong: 'Latest Night Song'
}
};

View File

@@ -1,29 +0,0 @@
import artist from './artist';
import common from './common';
import comp from './comp';
import donation from './donation';
import download from './download';
import favorite from './favorite';
import history from './history';
import login from './login';
import player from './player';
import search from './search';
import settings from './settings';
import songItem from './songItem';
import user from './user';
export default {
common,
donation,
favorite,
history,
login,
player,
search,
settings,
songItem,
user,
download,
comp,
artist
};

View File

@@ -1,22 +1,64 @@
export default {
title: {
qr: 'QR Code Login',
phone: 'Phone Login'
phone: 'Phone Login',
cookie: 'Cookie Login',
uid: 'UID Login'
},
qrTip: 'Scan with NetEase Cloud Music APP',
phoneTip: 'Login with NetEase Cloud account',
tokenTip: 'Enter a valid NetEase Cloud Music Cookie to login',
uidTip: 'Enter User ID for quick login',
placeholder: {
phone: 'Phone Number',
password: 'Password'
password: 'Password',
cookie: 'Please enter NetEase Cloud Music Cookie (token)',
uid: 'Please enter User ID (UID)'
},
button: {
login: 'Login',
switchToQr: 'QR Code Login',
switchToPhone: 'Phone Login'
switchToPhone: 'Phone Login',
switchToToken: 'Use Cookie Login',
switchToUid: 'UID Login',
backToQr: 'Back to QR Code Login',
cookieLogin: 'Cookie Login',
autoGetCookie: 'Auto Get Cookie',
refresh: 'Click to Refresh',
refreshing: 'Refreshing...',
refreshQr: 'Refresh QR Code'
},
message: {
loginSuccess: 'Login successful',
loginFailed: 'Login failed',
tokenLoginSuccess: 'Cookie login successful',
uidLoginSuccess: 'UID login successful',
loadError: 'Error loading login information',
qrCheckError: 'Error checking QR code status'
}
qrCheckError: 'Error checking QR code status',
tokenRequired: 'Please enter Cookie',
tokenInvalid: 'Invalid Cookie, please check and try again',
uidRequired: 'Please enter User ID',
uidInvalid: 'Invalid User ID or user does not exist',
uidLoginFailed: 'UID login failed, please check if User ID is correct',
phoneRequired: 'Please enter phone number',
passwordRequired: 'Please enter password',
phoneLoginFailed: 'Phone login failed, please check if phone number and password are correct',
autoGetCookieSuccess: 'Auto get Cookie successful',
autoGetCookieFailed: 'Auto get Cookie failed',
autoGetCookieTip:
'Will open NetEase Cloud Music login page, please complete login and close the window',
qrCheckFailed: 'Failed to check QR code status, please refresh and try again',
qrLoading: 'Loading QR code...',
qrExpired: 'QR code has expired, please click to refresh',
qrExpiredShort: 'QR code expired',
qrExpiredWarning: 'QR code has expired, please click to refresh for a new one',
qrScanned: 'QR code scanned, please confirm login on your phone',
qrScannedShort: 'Scanned',
qrScannedInfo: 'QR code scanned, please confirm login on your phone',
qrConfirmed: 'Login successful, redirecting...',
qrGenerating: 'Generating QR code...'
},
qrTitle: 'NetEase Cloud Music QR Code Login',
uidWarning:
'Note: UID login is only for viewing user public information and cannot access features that require login permissions.'
};

View File

@@ -11,7 +11,12 @@ export default {
mute: 'Mute',
unmute: 'Unmute',
songNum: 'Song Number: {num}',
addCorrection: 'Add {num} seconds',
subtractCorrection: 'Subtract {num} seconds',
playFailed: 'Play Failed, Play Next Song',
parseFailedPlayNext: 'Song parsing failed, playing next',
consecutiveFailsError:
'Playback error, possibly due to network issues or invalid source. Please switch playlist or try again later',
playMode: {
sequence: 'Sequence',
loop: 'Loop',
@@ -27,7 +32,8 @@ export default {
list: 'Next'
},
lrc: {
noLrc: 'No lyrics, please enjoy'
noLrc: 'No lyrics, please enjoy',
noAutoScroll: 'This lyrics does not support auto-scroll'
},
reparse: {
title: 'Select Music Source',
@@ -36,7 +42,10 @@ export default {
failed: 'Reparse failed',
warning: 'Please select a music source',
bilibiliNotSupported: 'Bilibili videos do not support reparsing',
processing: 'Processing...'
processing: 'Processing...',
clear: 'Clear Custom Source',
customApiFailed: 'Custom API parsing failed, trying built-in sources...',
customApiError: 'Custom API request error, trying built-in sources...'
},
playBar: {
expand: 'Expand Lyrics',
@@ -47,6 +56,7 @@ export default {
eq: 'Equalizer',
playList: 'Play List',
reparse: 'Reparse',
miniPlayBar: 'Mini Play Bar',
playMode: {
sequence: 'Sequence',
loop: 'Loop',
@@ -61,6 +71,16 @@ export default {
unFavorite: 'Unfavorite {name}',
playbackSpeed: 'Playback Speed',
advancedControls: 'Advanced Controls',
intelligenceMode: {
title: 'Intelligence Mode',
needCookieLogin: 'Please login with Cookie method to use Intelligence Mode',
noFavoritePlaylist: 'Favorite playlist not found',
noLikedSongs: 'You have no liked songs yet',
loading: 'Loading Intelligence Mode',
success: 'Loaded {count} songs',
failed: 'Failed to get Intelligence Mode list',
error: 'Intelligence Mode error'
}
},
eq: {
title: 'Equalizer',
@@ -86,6 +106,11 @@ export default {
custom: 'Custom'
}
},
// Playback settings
settings: {
title: 'Playback Settings',
playbackSpeed: 'Playback Speed'
},
// Sleep timer related
sleepTimer: {
title: 'Sleep Timer',
@@ -106,7 +131,10 @@ export default {
timerEnded: 'Sleep timer ended',
playbackStopped: 'Music playback stopped',
minutesRemaining: '{minutes} min remaining',
songsRemaining: '{count} songs remaining'
songsRemaining: '{count} songs remaining',
activeTime: 'Timer Active',
activeSongs: 'Counting Songs',
activeEnd: 'End After List'
},
playList: {
clearAll: 'Clear Playlist',
@@ -114,6 +142,7 @@ export default {
cleared: 'Playlist cleared',
empty: 'Playlist is empty',
clearConfirmTitle: 'Clear Playlist',
clearConfirmContent: 'This will clear all songs in the playlist and stop the current playback. Continue?'
clearConfirmContent:
'This will clear all songs in the playlist and stop the current playback. Continue?'
}
};

View File

@@ -11,10 +11,21 @@ export default {
},
loading: {
more: 'Loading...',
failed: 'Search failed'
failed: 'Search failed',
searching: 'Searching...'
},
noMore: 'No more results',
error: {
searchFailed: 'Search failed'
}
},
search: {
single: 'Single',
album: 'Album',
playlist: 'Playlist',
mv: 'MV',
bilibili: 'Bilibili'
},
history: 'Search History',
hot: 'Hot Searches',
suggestions: 'Search Suggestions'
};

View File

@@ -10,13 +10,23 @@ export default {
network: 'Network Settings',
system: 'System Management',
donation: 'Donation',
regard: 'About'
about: 'About'
},
basic: {
themeMode: 'Theme Mode',
themeModeDesc: 'Switch between light/dark theme',
autoTheme: 'Follow System',
manualTheme: 'Manual Switch',
language: 'Language Settings',
languageDesc: 'Change display language',
tokenManagement: 'Cookie Management',
tokenManagementDesc: 'Manage NetEase Cloud Music login Cookie',
tokenStatus: 'Current Cookie Status',
tokenSet: 'Set',
tokenNotSet: 'Not Set',
setToken: 'Set Cookie',
modifyToken: 'Modify Cookie',
clearToken: 'Clear Cookie',
font: 'Font Settings',
fontDesc: 'Select fonts, prioritize fonts in order',
fontScope: {
@@ -40,7 +50,17 @@ export default {
englishText: 'The quick brown fox jumps over the lazy dog',
japaneseText: 'あいうえお かきくけこ さしすせそ',
koreanText: '가나다라마 바사아자차 카타파하'
}
},
gpuAcceleration: 'GPU Acceleration',
gpuAccelerationDesc:
'Enable or disable hardware acceleration, can improve rendering performance but may increase GPU load',
gpuAccelerationRestart:
'Changing GPU acceleration settings requires application restart to take effect',
gpuAccelerationChangeSuccess:
'GPU acceleration settings updated, restart application to take effect',
gpuAccelerationChangeError: 'Failed to update GPU acceleration settings',
tabletMode: 'Tablet Mode',
tabletModeDesc: 'Enabling tablet mode allows using PC-style interface on mobile devices'
},
playback: {
quality: 'Audio Quality',
@@ -64,11 +84,69 @@ export default {
configureMusicSources: 'Configure Sources',
selectedMusicSources: 'Selected sources:',
noMusicSources: 'No sources selected',
gdmusicInfo: 'GD Music Station intelligently resolves music from multiple platforms automatically',
gdmusicInfo:
'GD Music Station intelligently resolves music from multiple platforms automatically',
autoPlay: 'Auto Play',
autoPlayDesc: 'Auto resume playback when reopening the app',
showStatusBar: "Show Status Bar",
showStatusBarContent: "You can display the music control function in your mac status bar (effective after a restart)"
showStatusBar: 'Show Status Bar',
showStatusBarContent:
'You can display the music control function in your mac status bar (effective after a restart)',
fallbackParser: 'Fallback Parser (GD Music)',
fallbackParserDesc:
'When "GD Music" is checked and regular sources fail, this service will be used.',
parserGD: 'GD Music (Built-in)',
parserCustom: 'Custom API',
// Source labels
sourceLabels: {
migu: 'Migu',
kugou: 'Kugou',
pyncmd: 'NetEase (Built-in)',
bilibili: 'Bilibili',
gdmusic: 'GD Music',
custom: 'Custom API'
},
customApi: {
sectionTitle: 'Custom API Settings',
importConfig: 'Import JSON Config',
currentSource: 'Current Source',
notImported: 'No custom source imported yet.',
importSuccess: 'Successfully imported source: {name}',
importFailed: 'Import failed: {message}',
enableHint: 'Import a JSON config file to enable',
status: {
imported: 'Custom Source Imported',
notImported: 'Not Imported'
}
},
lxMusic: {
tabs: {
sources: 'Source Selection',
lxMusic: 'LX Music',
customApi: 'Custom API'
},
scripts: {
title: 'Imported Scripts',
importLocal: 'Import Local',
importOnline: 'Import Online',
urlPlaceholder: 'Enter LX Music Script URL',
importBtn: 'Import',
empty: 'No imported LX Music scripts',
notConfigured: 'Not configured (Configure in LX Music Tab)',
importHint: 'Import compatible custom API plugins to extend sources',
noScriptWarning: 'Please import LX Music script first',
noSelectionWarning: 'Please select an LX Music source first',
notFound: 'Source not found',
switched: 'Switched to source: {name}',
deleted: 'Deleted source: {name}',
enterUrl: 'Please enter script URL',
invalidUrl: 'Invalid URL format',
invalidScript: 'Invalid LX Music script, globalThis.lx code not found',
nameRequired: 'Name cannot be empty',
renameSuccess: 'Rename successful'
}
}
},
application: {
closeAction: 'Close Action',
@@ -168,43 +246,131 @@ export default {
},
lyricSettings: {
title: 'Lyric Settings',
tabs: {
display: 'Display',
interface: 'Interface',
typography: 'Typography',
background: 'Background',
mobile: 'Mobile'
},
pureMode: 'Pure Mode',
hideCover: 'Hide Cover',
centerDisplay: 'Center Display',
showTranslation: 'Show Translation',
hideLyrics: 'Hide Lyrics',
hidePlayBar: 'Hide Play Bar',
fontSize: 'Font Size',
letterSpacing: 'Letter Spacing',
lineHeight: 'Line Height',
hideMiniPlayBar: 'Hide Mini Play Bar',
showMiniPlayBar: 'Show Mini Play Bar',
backgroundTheme: 'Background Theme',
fontSizeMarks: {
small: 'Small',
medium: 'Medium',
large: 'Large'
},
letterSpacingMarks: {
compact: 'Compact',
default: 'Default',
loose: 'Loose'
},
lineHeightMarks: {
compact: 'Compact',
default: 'Default',
loose: 'Loose'
},
themeOptions: {
default: 'Default',
light: 'Light',
dark: 'Dark'
},
hideMiniPlayBar: 'Hide Mini Play Bar',
hideLyrics: 'Hide Lyrics',
tabs: {
interface: 'Interface',
display: 'Display',
typography: 'Typography'
fontSize: 'Font Size',
fontSizeMarks: {
small: 'Small',
medium: 'Medium',
large: 'Large'
},
fontWeight: 'Font Weight',
fontWeightMarks: {
thin: 'Thin',
normal: 'Normal',
bold: 'Bold'
},
letterSpacing: 'Letter Spacing',
letterSpacingMarks: {
compact: 'Compact',
default: 'Default',
loose: 'Loose'
},
lineHeight: 'Line Height',
lineHeightMarks: {
compact: 'Compact',
default: 'Default',
loose: 'Loose'
},
contentWidth: 'Content Width',
mobileLayout: 'Mobile Layout',
layoutOptions: {
default: 'Default',
ios: 'iOS Style',
android: 'Android Style'
},
mobileCoverStyle: 'Cover Style',
coverOptions: {
record: 'Record',
square: 'Square',
full: 'Full Screen'
},
lyricLines: 'Lyric Lines',
mobileUnavailable: 'This setting is only available on mobile devices',
// Background settings
background: {
useCustomBackground: 'Use Custom Background',
backgroundMode: 'Background Mode',
modeOptions: {
solid: 'Solid',
gradient: 'Gradient',
image: 'Image',
css: 'CSS'
},
solidColor: 'Select Color',
presetColors: 'Preset Colors',
customColor: 'Custom Color',
gradientEditor: 'Gradient Editor',
gradientColors: 'Gradient Colors',
gradientDirection: 'Gradient Direction',
directionOptions: {
toBottom: 'Top to Bottom',
toRight: 'Left to Right',
toBottomRight: 'Top Left to Bottom Right',
angle45: '45 Degrees',
toTop: 'Bottom to Top',
toLeft: 'Right to Left'
},
addColor: 'Add Color',
removeColor: 'Remove Color',
imageUpload: 'Upload Image',
imagePreview: 'Image Preview',
clearImage: 'Clear Image',
imageBlur: 'Blur',
imageBrightness: 'Brightness',
customCss: 'Custom CSS Style',
customCssPlaceholder: 'Enter CSS style, e.g.: background: linear-gradient(...)',
customCssHelp: 'Supports any CSS background property',
reset: 'Reset to Default',
fileSizeLimit: 'Image size limit: 20MB',
invalidImageFormat: 'Invalid image format',
imageTooLarge: 'Image too large, please select an image smaller than 20MB'
}
},
translationEngine: 'Lyric Translation Engine',
translationEngineOptions: {
none: 'Off',
opencc: 'OpenCC Traditionalize'
},
themeColor: {
title: 'Lyric Theme Color',
presetColors: 'Preset Colors',
customColor: 'Custom Color',
preview: 'Preview',
previewText: 'Lyric Effect',
colorNames: {
'spotify-green': 'Spotify Green',
'apple-blue': 'Apple Blue',
'youtube-red': 'YouTube Red',
orange: 'Vibrant Orange',
purple: 'Mystic Purple',
pink: 'Cherry Pink'
},
tooltips: {
openColorPicker: 'Open Color Picker',
closeColorPicker: 'Close Color Picker'
},
placeholder: '#1db954'
},
shortcutSettings: {
title: 'Shortcut Settings',
shortcut: 'Shortcut',
@@ -243,6 +409,34 @@ export default {
addIp: 'Add IP',
emptyListHint: 'Empty list means allow all IPs',
saveSuccess: 'Remote control settings saved',
accessInfo: 'Remote control access address:',
accessInfo: 'Remote control access address:'
},
cookie: {
title: 'Cookie Settings',
description: 'Please enter NetEase Cloud Music Cookie:',
placeholder: 'Please paste the complete Cookie...',
help: {
format: 'Cookie usually starts with "MUSIC_U="',
source: 'Can be obtained from browser developer tools network requests',
storage: 'Cookie will be automatically saved to local storage after setting'
},
action: {
save: 'Save Cookie',
paste: 'Paste',
clear: 'Clear'
},
validation: {
required: 'Please enter Cookie',
format: 'Cookie format may be incorrect, please check if it contains MUSIC_U'
},
message: {
saveSuccess: 'Cookie saved successfully',
saveError: 'Failed to save Cookie',
pasteSuccess: 'Pasted successfully',
pasteError: 'Paste failed, please copy manually'
},
info: {
length: 'Current length: {length} characters'
}
}
};

View File

@@ -8,7 +8,7 @@ export default {
unfavorite: 'Unlike',
removeFromPlaylist: 'Remove from Playlist',
dislike: 'Dislike',
undislike: 'Undislike',
undislike: 'Undislike'
},
message: {
downloading: 'Downloading, please wait...',
@@ -18,7 +18,7 @@ export default {
getUrlFailed: 'Failed to get music download URL, please check if logged in'
},
dialog: {
dislike:{
dislike: {
title: 'Dislike',
content: 'Are you sure you want to dislike this song?',
positiveText: 'Dislike',

View File

@@ -10,6 +10,11 @@ export default {
trackCount: '{count} tracks',
playCount: 'Played {count} times'
},
tabs: {
created: 'Created',
favorite: 'Favorite',
album: 'Album'
},
ranking: {
title: 'Listening History',
playCount: '{count} times'
@@ -20,14 +25,14 @@ export default {
noFollowings: 'No Followings',
loadMore: 'Load More',
noSignature: 'This guy is lazy, nothing left',
userFollowsTitle: '\'s Followings',
userFollowsTitle: "'s Followings",
myFollowsTitle: 'My Followings'
},
follower: {
title: 'Follower List',
noFollowers: 'No Followers',
loadMore: 'Load More',
userFollowersTitle: '\'s Followers',
userFollowersTitle: "'s Followers",
myFollowersTitle: 'My Followers'
},
detail: {
@@ -38,7 +43,7 @@ export default {
artist: 'Artist',
noSignature: 'This guy is lazy, nothing left',
invalidUserId: 'Invalid User ID',
noRecordPermission: '{name} doesn\'t let you see your listening history'
noRecordPermission: "{name} doesn't let you see your listening history"
},
message: {
loadFailed: 'Failed to load user page',

View File

@@ -0,0 +1,5 @@
export default {
hotSongs: '人気楽曲',
albums: 'アルバム',
description: 'アーティスト紹介'
};

View File

@@ -0,0 +1,51 @@
export default {
player: {
loading: 'オーディオ読み込み中...',
retry: '再試行',
playNow: '今すぐ再生',
loadingTitle: '読み込み中...',
totalDuration: '総再生時間: {duration}',
partsList: 'パートリスト ({count}話)',
playStarted: '再生を開始しました',
switchingPart: 'パートを切り替え中: {part}',
preloadingNext: '次のパートをプリロード中: {part}',
playingCurrent: '現在選択されたパートを再生中: {name}',
num: '万',
errors: {
invalidVideoId: '無効な動画ID',
loadVideoDetailFailed: '動画詳細の取得に失敗しました',
loadPartInfoFailed: '動画パート情報の読み込みができません',
loadAudioUrlFailed: 'オーディオ再生URLの取得に失敗しました',
videoDetailNotLoaded: '動画詳細が読み込まれていません',
missingParams: '必要なパラメータが不足しています',
noAvailableAudioUrl: '利用可能なオーディオURLが見つかりません',
loadPartAudioFailed: 'パートオーディオURLの読み込みに失敗しました',
audioListEmpty: 'オーディオリストが空です。再試行してください',
currentPartNotFound: '現在のパートのオーディオが見つかりません',
audioUrlFailed: 'オーディオURLの取得に失敗しました',
playFailed: '再生に失敗しました。再試行してください',
getAudioUrlFailed: 'オーディオURLの取得に失敗しました。再試行してください',
audioNotFound: '対応するオーディオが見つかりません。再試行してください',
preloadFailed: '次のパートのプリロードに失敗しました',
switchPartFailed: 'パート切り替え時のオーディオURL読み込みに失敗しました'
},
console: {
loadingDetail: 'Bilibiliビデオ詳細を読み込み中',
detailData: 'Bilibiliビデオ詳細データ',
multipleParts: 'ビデオに複数のパートがあります。合計{count}個',
noPartsData: 'ビデオにパートがないか、パートデータが空です',
loadingAudioSource: 'オーディオソースを読み込み中',
generatedAudioList: 'オーディオリストを生成しました。合計{count}個',
getDashAudioUrl: 'dashオーディオURLを取得しました',
getDurlAudioUrl: 'durlオーディオURLを取得しました',
loadingPartAudio: 'パートオーディオURLを読み込み中: {part}, cid: {cid}',
loadPartAudioFailed: 'パートオーディオURLの読み込みに失敗: {part}',
switchToPart: 'パートに切り替え中: {part}',
audioNotFoundInList: '対応するオーディオアイテムが見つかりません',
preparingToPlay: '現在選択されたパートの再生準備中: {name}',
preloadingNextPart: '次のパートをプリロード中: {part}',
playingSelectedPart: '現在選択されたパートを再生中: {name}、オーディオURL: {url}',
preloadNextFailed: '次のパートのプリロードに失敗しました'
}
}
};

View File

@@ -0,0 +1,58 @@
export default {
play: '再生',
next: '次の曲',
previous: '前の曲',
volume: '音量',
settings: '設定',
search: '検索',
loading: '読み込み中...',
loadingMore: 'さらに読み込み中...',
alipay: 'Alipay',
wechat: 'WeChat Pay',
on: 'オン',
off: 'オフ',
show: '表示',
hide: '非表示',
confirm: '確認',
cancel: 'キャンセル',
configure: '設定',
open: '開く',
modify: '変更',
success: '操作成功',
error: '操作失敗',
warning: '警告',
info: 'お知らせ',
save: '保存',
delete: '削除',
refresh: '更新',
retry: '再試行',
reset: 'リセット',
back: '戻る',
copySuccess: 'クリップボードにコピーしました',
copyFailed: 'コピーに失敗しました',
validation: {
required: 'この項目は必須です',
invalidInput: '無効な入力です',
selectRequired: 'オプションを選択してください',
numberRange: '{min}から{max}の間の数値を入力してください'
},
viewMore: 'もっと見る',
noMore: 'これ以上ありません',
selectAll: '全選択',
expand: '展開',
collapse: '折りたたみ',
songCount: '{count}曲',
language: '言語',
today: '今日',
yesterday: '昨日',
tray: {
show: '表示',
quit: '終了',
playPause: '再生/一時停止',
prev: '前の曲',
next: '次の曲',
pause: '一時停止',
play: '再生',
favorite: 'お気に入り'
}
};

222
src/i18n/lang/ja-JP/comp.ts Normal file
View File

@@ -0,0 +1,222 @@
export default {
installApp: {
description: 'アプリをインストールして、より良い体験を',
noPrompt: '今後表示しない',
install: '今すぐインストール',
cancel: '後でインストール',
download: 'ダウンロード',
downloadFailed: 'ダウンロード失敗',
downloadComplete: 'ダウンロード完了',
downloadProblem: 'ダウンロードに問題がありますか?',
downloadProblemLinkText: '最新版をダウンロード'
},
playlistDrawer: {
title: 'プレイリストに追加',
createPlaylist: '新しいプレイリストを作成',
cancelCreate: '作成をキャンセル',
create: '作成',
playlistName: 'プレイリスト名',
privatePlaylist: 'プライベートプレイリスト',
publicPlaylist: 'パブリックプレイリスト',
createSuccess: 'プレイリストの作成に成功しました',
createFailed: 'プレイリストの作成に失敗しました',
addSuccess: '楽曲の追加に成功しました',
addFailed: '楽曲の追加に失敗しました',
private: 'プライベート',
public: 'パブリック',
count: '曲',
loginFirst: 'まずログインしてください',
getPlaylistFailed: 'プレイリストの取得に失敗しました',
inputPlaylistName: 'プレイリスト名を入力してください'
},
update: {
title: '新しいバージョンが見つかりました',
currentVersion: '現在のバージョン',
cancel: '後で更新',
prepareDownload: 'ダウンロード準備中...',
downloading: 'ダウンロード中...',
nowUpdate: '今すぐ更新',
downloadFailed: 'ダウンロードに失敗しました。再試行するか手動でダウンロードしてください',
startFailed: 'ダウンロードの開始に失敗しました。再試行するか手動でダウンロードしてください',
noDownloadUrl:
'現在のシステムに適したインストールパッケージが見つかりません。手動でダウンロードしてください',
installConfirmTitle: '更新をインストール',
installConfirmContent: 'アプリを閉じて更新をインストールしますか?',
manualInstallTip:
'アプリを閉じた後にインストーラーが正常に起動しない場合は、ダウンロードフォルダでファイルを見つけて手動で開いてください。',
yesInstall: '今すぐインストール',
noThanks: '後でインストール',
fileLocation: 'ファイルの場所',
copy: 'パスをコピー',
copySuccess: 'パスをクリップボードにコピーしました',
copyFailed: 'コピーに失敗しました',
backgroundDownload: 'バックグラウンドダウンロード'
},
disclaimer: {
title: '使用上の注意',
warning:
'このアプリは開発テスト版であり、機能が不完全で、多くの問題やバグが存在する可能性があります。学習と交流のみを目的としています。',
item1:
'このアプリは個人の学習、研究、技術交流のみを目的としています。商業目的で使用しないでください。',
item2:
'ダウンロード後24時間以内に削除してください。長期使用を希望される場合は、正規の音楽サービスをサポートしてください。',
item3:
'このアプリを使用することで、関連するリスクを理解し、負担するものとします。開発者は一切の損失に対して責任を負いません。',
agree: '以上の内容を読み、同意します',
disagree: '同意せずに終了'
},
donate: {
title: '開発者を支援',
subtitle: '皆様のサポートが私の原動力です',
tip: '寄付は完全に任意です。寄付しなくてもすべての機能を通常通り使用できます。ご理解とご支援に感謝します!',
wechat: 'WeChat',
alipay: 'Alipay',
wechatQR: 'WeChat 受取コード',
alipayQR: 'Alipay 受取コード',
scanTip: 'スマートフォンのアプリで上記のQRコードをスキャンして寄付してください',
enterApp: 'アプリに入る',
noForce: '寄付は強制ではありません。クリックして入れます'
},
coffee: {
title: 'コーヒーをおごる',
alipay: 'Alipay',
wechat: 'WeChat Pay',
alipayQR: 'Alipay QRコード',
wechatQR: 'WeChat QRコード',
coffeeDesc: '一杯のコーヒー、一つのサポート',
coffeeDescLinkText: 'もっと見る',
groupText: '微信公众号AlgerMusic',
messages: {
copySuccess: 'クリップボードにコピーしました'
},
donateList: 'コーヒーをおごる'
},
playlistType: {
title: 'プレイリストカテゴリ',
showAll: 'すべて表示',
hide: '一部を非表示'
},
recommendAlbum: {
title: '最新アルバム'
},
recommendSinger: {
title: '毎日のおすすめ',
songlist: '毎日のおすすめリスト'
},
recommendSonglist: {
title: '今週の人気音楽'
},
searchBar: {
login: 'ログイン',
toLogin: 'ログインへ',
logout: 'ログアウト',
set: '設定',
theme: 'テーマ',
restart: '再起動',
refresh: '更新',
currentVersion: '現在のバージョン',
searchPlaceholder: '何かを検索してみましょう...',
zoom: 'ページズーム',
zoom100: '標準ズーム100%',
resetZoom: 'クリックしてズームをリセット',
zoomDefault: '標準ズーム'
},
titleBar: {
closeTitle: '閉じる方法を選択してください',
minimizeToTray: 'トレイに最小化',
exitApp: 'アプリを終了',
rememberChoice: '選択を記憶する',
closeApp: 'アプリを閉じる'
},
userPlayList: {
title: '{name}のよく聞く音楽'
},
musicList: {
searchSongs: '楽曲を検索',
noSearchResults: '関連する楽曲が見つかりませんでした',
switchToNormal: 'デフォルトレイアウトに切り替え',
switchToCompact: 'コンパクトレイアウトに切り替え',
playAll: 'すべて再生',
collect: 'お気に入り',
collectSuccess: 'お気に入りに追加しました',
cancelCollectSuccess: 'お気に入りから削除しました',
operationFailed: '操作に失敗しました',
cancelCollect: 'お気に入りから削除',
addToPlaylist: 'プレイリストに追加',
addToPlaylistSuccess: 'プレイリストに追加しました',
songsAlreadyInPlaylist: '楽曲は既にプレイリストに存在します',
historyRecommend: '履歴の日次推薦',
fetchDatesFailed: '日付リストの取得に失敗しました',
fetchSongsFailed: '楽曲リストの取得に失敗しました',
noSongs: '楽曲がありません'
},
playlist: {
import: {
button: 'プレイリストインポート',
title: 'プレイリストインポート',
description: 'メタデータ/テキスト/リンクの3つの方法でプレイリストをインポートできます',
linkTab: 'リンクインポート',
textTab: 'テキストインポート',
localTab: 'メタデータインポート',
linkPlaceholder: 'プレイリストのリンクを入力してください1行に1つ',
textPlaceholder: '楽曲情報を入力してください。形式:楽曲名 アーティスト名',
localPlaceholder: 'JSON形式の楽曲メタデータを入力してください',
linkTips: 'サポートされているリンクソース:',
linkTip1: 'プレイリストをWeChat/Weibo/QQでシェアした後、リンクをコピー',
linkTip2: 'プレイリスト/個人ページのリンクを直接コピー',
linkTip3: '記事のリンクを直接コピー',
textTips: '楽曲情報を入力してください1行に1曲',
textFormat: '形式:楽曲名 アーティスト名',
localTips: '楽曲メタデータを追加してください',
localFormat: '形式例:',
songNamePlaceholder: '楽曲名',
artistNamePlaceholder: 'アーティスト名',
albumNamePlaceholder: 'アルバム名',
addSongButton: '楽曲を追加',
addLinkButton: 'リンクを追加',
importToStarPlaylist: 'お気に入りの音楽にインポート',
playlistNamePlaceholder: 'プレイリスト名を入力してください',
importButton: 'インポート開始',
emptyLinkWarning: 'プレイリストのリンクを入力してください',
emptyTextWarning: '楽曲情報を入力してください',
emptyLocalWarning: '楽曲メタデータを入力してください',
invalidJsonFormat: 'JSON形式が正しくありません',
importSuccess: 'インポートタスクの作成に成功しました',
importFailed: 'インポートに失敗しました',
importStatus: 'インポート状況',
refresh: '更新',
taskId: 'タスクID',
status: 'ステータス',
successCount: '成功数',
failReason: '失敗理由',
unknownError: '不明なエラー',
statusPending: '処理待ち',
statusProcessing: '処理中',
statusSuccess: 'インポート成功',
statusFailed: 'インポート失敗',
statusUnknown: '不明なステータス',
taskList: 'タスクリスト',
taskListTitle: 'インポートタスクリスト',
action: '操作',
select: '選択',
fetchTaskListFailed: 'タスクリストの取得に失敗しました',
noTasks: 'インポートタスクがありません',
clearTasks: 'タスクをクリア',
clearTasksConfirmTitle: 'クリア確認',
clearTasksConfirmContent:
'すべてのインポートタスク記録をクリアしますか?この操作は元に戻せません。',
confirm: '確認',
cancel: 'キャンセル',
clearTasksSuccess: 'タスクリストをクリアしました',
clearTasksFailed: 'タスクリストのクリアに失敗しました'
}
},
settings: '設定',
user: 'ユーザー',
toplist: 'ランキング',
history: 'お気に入り履歴',
list: 'プレイリスト',
mv: 'MV',
home: 'ホーム',
search: '検索'
};

View File

@@ -0,0 +1,9 @@
export default {
description:
'あなたの寄付は開発・保守作業をサポートするために使用され、サーバー保守、ドメイン更新などが含まれます。',
message: 'メッセージを残す際は、メールアドレスやGitHubユーザー名を記載してください。',
refresh: 'リストを更新',
toDonateList: 'コーヒーをおごる',
noMessage: 'メッセージがありません',
title: '寄付リスト'
};

View File

@@ -0,0 +1,88 @@
export default {
title: 'ダウンロード管理',
localMusic: 'ローカル音楽',
count: '合計{count}曲',
clearAll: '記録をクリア',
settings: '設定',
tabs: {
downloading: 'ダウンロード中',
downloaded: 'ダウンロード済み'
},
empty: {
noTasks: 'ダウンロードタスクがありません',
noDownloaded: 'ダウンロード済みの楽曲がありません'
},
progress: {
total: '全体の進行状況: {progress}%'
},
status: {
downloading: 'ダウンロード中',
completed: '完了',
failed: '失敗',
unknown: '不明'
},
artist: {
unknown: '不明なアーティスト'
},
delete: {
title: '削除確認',
message: '楽曲「{filename}」を削除しますか?この操作は元に戻せません。',
confirm: '削除確認',
cancel: 'キャンセル',
success: '削除成功',
failed: '削除失敗',
fileNotFound: 'ファイルが存在しないか移動されました。記録から削除しました',
recordRemoved: 'ファイルの削除に失敗しましたが、記録から削除しました'
},
clear: {
title: 'ダウンロード記録をクリア',
message:
'すべてのダウンロード記録をクリアしますか?この操作はダウンロード済みの音楽ファイルを削除しませんが、すべての記録をクリアします。',
confirm: 'クリア確認',
cancel: 'キャンセル',
success: 'ダウンロード記録をクリアしました'
},
message: {
downloadComplete: '{filename}のダウンロードが完了しました',
downloadFailed: '{filename}のダウンロードに失敗しました: {error}'
},
loading: '読み込み中...',
playStarted: '再生開始: {name}',
playFailed: '再生失敗: {name}',
path: {
copied: 'パスをクリップボードにコピーしました',
copyFailed: 'パスのコピーに失敗しました'
},
settingsPanel: {
title: 'ダウンロード設定',
path: 'ダウンロード場所',
pathDesc: '音楽ファイルのダウンロード保存場所を設定',
pathPlaceholder: 'ダウンロードパスを選択してください',
noPathSelected: 'まずダウンロードパスを選択してください',
select: 'フォルダを選択',
open: 'フォルダを開く',
fileFormat: 'ファイル名形式',
fileFormatDesc: '音楽ダウンロード時のファイル命名形式を設定',
customFormat: 'カスタム形式',
separator: '区切り文字',
separators: {
dash: 'スペース-スペース',
underscore: 'アンダースコア',
space: 'スペース'
},
dragToArrange: 'ドラッグで並び替えまたは矢印ボタンで順序を調整:',
formatVariables: '使用可能な変数',
preview: 'プレビュー効果:',
saveSuccess: 'ダウンロード設定を保存しました',
presets: {
songArtist: '楽曲名 - アーティスト名',
artistSong: 'アーティスト名 - 楽曲名',
songOnly: '楽曲名のみ'
},
components: {
songName: '楽曲名',
artistName: 'アーティスト名',
albumName: 'アルバム名'
}
}
};

View File

@@ -0,0 +1,13 @@
export default {
title: 'お気に入り',
count: '合計{count}曲',
batchDownload: '一括ダウンロード',
download: 'ダウンロード ({count})',
emptyTip: 'まだお気に入りの楽曲がありません',
downloadSuccess: 'ダウンロード完了',
downloadFailed: 'ダウンロード失敗',
downloading: 'ダウンロード中です。しばらくお待ちください...',
selectSongsFirst: 'まずダウンロードする楽曲を選択してください',
descending: '降順',
ascending: '昇順'
};

View File

@@ -0,0 +1,44 @@
export default {
title: '再生履歴',
heatmapTitle: 'ヒートマップ',
playCount: '{count}',
getHistoryFailed: '履歴の取得に失敗しました',
tabs: {
all: 'すべての記録',
local: 'ローカル記録',
cloud: 'クラウド記録'
},
categoryTabs: {
songs: '楽曲',
playlists: 'プレイリスト',
albums: 'アルバム'
},
noDescription: '説明なし',
noData: '記録なし',
getCloudRecordFailed: 'クラウド記録の取得に失敗しました',
needLogin: 'cookieを使用してログインしてクラウド記録を表示できます',
merging: '記録を統合中...',
heatmap: {
title: '再生ヒートマップ',
loading: 'データを読み込み中...',
unit: '回再生',
footerText: 'ホバーして詳細を表示',
playCount: '{count} 回再生',
topSongs: 'その日の人気曲',
times: '回',
totalPlays: '総再生回数',
activeDays: 'アクティブ日数',
noData: '再生記録がありません',
colorTheme: 'カラーテーマ',
colors: {
green: 'グリーン',
blue: 'ブルー',
orange: 'オレンジ',
purple: 'パープル',
red: 'レッド'
},
mostPlayedSong: '最も再生された曲',
mostActiveDay: '最もアクティブな日',
latestNightSong: '深夜に再生した曲'
}
};

View File

@@ -0,0 +1,65 @@
export default {
title: {
qr: 'QRコードログイン',
phone: '電話番号ログイン',
cookie: 'Cookieログイン',
uid: 'UIDログイン'
},
qrTip: 'NetEase Cloudアプリでログイン',
phoneTip: 'NetEase Cloudアカウントでログイン',
tokenTip: '有効なNetEase Cloud MusicのCookieを入力してログイン',
uidTip: 'ユーザーIDを入力してクイックログイン',
placeholder: {
phone: '電話番号',
password: 'パスワード',
cookie: 'NetEase Cloud MusicのCookietokenを入力してください',
uid: 'ユーザーIDUIDを入力してください'
},
button: {
login: 'ログイン',
switchToQr: 'QRコードログイン',
switchToPhone: '電話番号ログイン',
switchToToken: 'Cookieログインを使用',
switchToUid: 'UIDログイン',
backToQr: 'QRコードログインに戻る',
cookieLogin: 'Cookieログイン',
autoGetCookie: 'Cookie自動取得',
refresh: 'クリックしてリフレッシュ',
refreshing: 'リフレッシュ中...',
refreshQr: 'QRコードをリフレッシュ'
},
message: {
loginSuccess: 'ログイン成功',
tokenLoginSuccess: 'Cookieログイン成功',
uidLoginSuccess: 'UIDログイン成功',
loadError: 'ログイン情報の読み込み中にエラーが発生しました',
qrCheckError: 'QRコードの状態確認中にエラーが発生しました',
tokenRequired: 'Cookieを入力してください',
tokenInvalid: 'Cookieが無効です。確認して再試行してください',
uidRequired: 'ユーザーIDを入力してください',
uidInvalid: 'ユーザーIDが無効またはユーザーが存在しません',
uidLoginFailed: 'UIDログインに失敗しました。ユーザーIDが正しいか確認してください',
autoGetCookieSuccess: 'Cookie自動取得成功',
autoGetCookieFailed: 'Cookie自動取得失敗',
autoGetCookieTip:
'NetEase Cloud Musicのログインページを開きます。ログイン完了後、ウィンドウを閉じてください',
loginFailed: 'ログイン失敗',
phoneRequired: '電話番号を入力してください',
passwordRequired: 'パスワードを入力してください',
phoneLoginFailed:
'電話番号でのログインに失敗しました。電話番号とパスワードが正しいか確認してください',
qrCheckFailed: 'QRコードの状態確認に失敗しました。リフレッシュして再試行してください',
qrLoading: 'QRコードを読み込み中...',
qrExpired: 'QRコードの期限が切れました。クリックしてリフレッシュしてください',
qrExpiredShort: 'QRコード期限切れ',
qrExpiredWarning: 'QRコードの期限が切れました。クリックして新しいQRコードを取得してください',
qrScanned: 'QRコードがスキャンされました。スマートフォンでログインを確認してください',
qrScannedShort: 'スキャン済み',
qrScannedInfo: 'QRコードがスキャンされました。スマートフォンでログインを確認してください',
qrConfirmed: 'ログイン成功、リダイレクト中...',
qrGenerating: 'QRコードを生成中...'
},
qrTitle: 'NetEase Cloud Music QRコードログイン',
uidWarning:
'注意UIDログインはユーザーの公開情報を表示するためのみ使用でき、ログイン権限が必要な機能にはアクセスできません。'
};

View File

@@ -0,0 +1,145 @@
export default {
nowPlaying: '再生中',
playlist: 'プレイリスト',
lyrics: '歌詞',
previous: '前へ',
play: '再生',
pause: '一時停止',
next: '次へ',
volumeUp: '音量を上げる',
volumeDown: '音量を下げる',
mute: 'ミュート',
unmute: 'ミュート解除',
songNum: '楽曲総数:{num}',
addCorrection: '{num}秒早める',
subtractCorrection: '{num}秒遅らせる',
playFailed: '現在の楽曲の再生に失敗しました。次の曲を再生します',
parseFailedPlayNext: '楽曲の解析に失敗しました。次の曲を再生します',
consecutiveFailsError:
'再生エラーが発生しました。ネットワークの問題または無効な音源の可能性があります。プレイリストを切り替えるか、後でもう一度お試しください',
playMode: {
sequence: '順次再生',
loop: 'リピート再生',
random: 'ランダム再生'
},
fullscreen: {
enter: 'フルスクリーン',
exit: 'フルスクリーン終了'
},
close: '閉じる',
modeHint: {
single: 'リピート再生',
list: '自動で次の曲を再生'
},
lrc: {
noLrc: '歌詞がありません。お楽しみください',
noAutoScroll: '本歌詞は自動スクロールをサポートしていません'
},
reparse: {
title: '解析音源を選択',
desc: '音源をクリックして直接解析します。次回この楽曲を再生する際は選択した音源を使用します',
success: '再解析成功',
failed: '再解析失敗',
warning: '音源を選択してください',
bilibiliNotSupported: 'Bilibili動画は再解析をサポートしていません',
processing: '解析中...',
clear: 'カスタム音源をクリア',
customApiFailed: 'カスタムAPIの解析に失敗しました。内蔵音源を試しています...',
customApiError: 'カスタムAPIのリクエストでエラーが発生しました。内蔵音源を試しています...'
},
playBar: {
expand: '歌詞を展開',
collapse: '歌詞を折りたたみ',
like: 'いいね',
lyric: '歌詞',
noSongPlaying: '再生中の楽曲がありません',
eq: 'イコライザー',
playList: 'プレイリスト',
reparse: '再解析',
playMode: {
sequence: '順次再生',
loop: 'ループ再生',
random: 'ランダム再生'
},
play: '再生開始',
pause: '再生一時停止',
prev: '前の曲',
next: '次の曲',
volume: '音量',
favorite: '{name}をお気に入りに追加しました',
unFavorite: '{name}をお気に入りから削除しました',
miniPlayBar: 'ミニ再生バー',
playbackSpeed: '再生速度',
advancedControls: 'その他の設定',
intelligenceMode: {
title: 'インテリジェンスモード',
needCookieLogin: 'Cookie方式でログインしてからインテリジェンスモードを使用してください',
noFavoritePlaylist: '「お気に入りの音楽」プレイリストが見つかりません',
noLikedSongs: 'まだ「いいね」した楽曲がありません',
loading: 'インテリジェンスモードを読み込み中',
success: '{count} 曲を読み込みました',
failed: 'インテリジェンスモードのリスト取得に失敗しました',
error: 'インテリジェンスモードの再生でエラーが発生しました'
}
},
eq: {
title: 'イコライザー',
reset: 'リセット',
on: 'オン',
off: 'オフ',
bass: '低音',
midrange: '中音',
treble: '高音',
presets: {
flat: 'フラット',
pop: 'ポップ',
rock: 'ロック',
classical: 'クラシック',
jazz: 'ジャズ',
electronic: 'エレクトロニック',
hiphop: 'ヒップホップ',
rb: 'R&B',
metal: 'メタル',
vocal: 'ボーカル',
dance: 'ダンス',
acoustic: 'アコースティック',
custom: 'カスタム'
}
},
// プレイヤー設定
settings: {
title: '再生設定',
playbackSpeed: '再生速度'
},
// タイマー機能関連
sleepTimer: {
title: 'スリープタイマー',
cancel: 'タイマーをキャンセル',
timeMode: '時間で停止',
songsMode: '楽曲数で停止',
playlistEnd: 'プレイリスト終了後に停止',
afterPlaylist: 'プレイリスト終了後に停止',
activeUntilEnd: 'リスト終了まで再生',
minutes: '分',
hours: '時間',
songs: '曲',
set: '設定',
timerSetSuccess: '{minutes}分後に停止するよう設定しました',
songsSetSuccess: '{songs}曲再生後に停止するよう設定しました',
playlistEndSetSuccess: 'プレイリスト終了後に停止するよう設定しました',
timerCancelled: 'スリープタイマーをキャンセルしました',
timerEnded: 'スリープタイマーが作動しました',
playbackStopped: '音楽再生を停止しました',
minutesRemaining: '残り{minutes}分',
songsRemaining: '残り{count}曲'
},
playList: {
clearAll: 'プレイリストをクリア',
alreadyEmpty: 'プレイリストは既に空です',
cleared: 'プレイリストをクリアしました',
empty: 'プレイリストが空です',
clearConfirmTitle: 'プレイリストをクリア',
clearConfirmContent:
'これによりプレイリスト内のすべての楽曲がクリアされ、現在の再生が停止されます。続行しますか?'
}
};

View File

@@ -0,0 +1,31 @@
export default {
title: {
hotSearch: '人気検索リスト',
searchList: '検索リスト',
searchHistory: '検索履歴'
},
button: {
clear: 'クリア',
back: '戻る',
playAll: 'リストを再生'
},
loading: {
more: '読み込み中...',
failed: '検索に失敗しました',
searching: '検索中...'
},
noMore: 'これ以上ありません',
error: {
searchFailed: '検索に失敗しました'
},
search: {
single: '楽曲',
album: 'アルバム',
playlist: 'プレイリスト',
mv: 'MV',
bilibili: 'Bilibili'
},
history: '検索履歴',
hot: '人気検索',
suggestions: '検索候補'
};

View File

@@ -0,0 +1,441 @@
export default {
theme: 'テーマ',
language: '言語',
regard: 'について',
logout: 'ログアウト',
sections: {
basic: '基本設定',
playback: '再生設定',
application: 'アプリケーション設定',
network: 'ネットワーク設定',
system: 'システム管理',
donation: '寄付サポート',
about: 'について'
},
basic: {
themeMode: 'テーマモード',
themeModeDesc: 'ライト/ダークテーマの切り替え',
autoTheme: 'システムに従う',
manualTheme: '手動切り替え',
language: '言語設定',
languageDesc: '表示言語を切り替え',
tokenManagement: 'Cookie管理',
tokenManagementDesc: 'NetEase Cloud MusicログインCookieを管理',
tokenStatus: '現在のCookieステータス',
tokenSet: '設定済み',
tokenNotSet: '未設定',
setToken: 'Cookieを設定',
modifyToken: 'Cookieを変更',
clearToken: 'Cookieをクリア',
font: 'フォント設定',
fontDesc: 'フォントを選択します。前に配置されたフォントが優先されます',
fontScope: {
global: 'グローバル',
lyric: '歌詞のみ'
},
animation: 'アニメーション速度',
animationDesc: 'アニメーションを有効にするかどうか',
animationSpeed: {
slow: '非常に遅い',
normal: '通常',
fast: '非常に速い'
},
fontPreview: {
title: 'フォントプレビュー',
chinese: '中国語',
english: 'English',
japanese: '日本語',
korean: '韓国語',
chineseText: '静夜思 床前明月光 疑是地上霜',
englishText: 'The quick brown fox jumps over the lazy dog',
japaneseText: 'あいうえお かきくけこ さしすせそ',
koreanText: '가나다라마 바사아자차 카타파하'
},
gpuAcceleration: 'GPUアクセラレーション',
gpuAccelerationDesc:
'ハードウェアアクセラレーションを有効または無効にします。レンダリングパフォーマンスを向上させますが、GPU負荷が増える可能性があります',
gpuAccelerationRestart: 'GPUアクセラレーション設定の変更はアプリの再起動後に有効になります',
gpuAccelerationChangeSuccess:
'GPUアクセラレーション設定を更新しました。アプリの再起動後に有効になります',
gpuAccelerationChangeError: 'GPUアクセラレーション設定の更新に失敗しました',
tabletMode: 'タブレットモード',
tabletModeDesc:
'タブレットモードを有効にすると、モバイルデバイスでPCスタイルのインターフェースを使用できます'
},
playback: {
quality: '音質設定',
qualityDesc: '音楽再生の音質を選択NetEase Cloud VIP',
qualityOptions: {
standard: '標準',
higher: '高音質',
exhigh: '超高音質',
lossless: 'ロスレス',
hires: 'Hi-Res',
jyeffect: 'HD サラウンド',
sky: 'イマーシブサラウンド',
dolby: 'Dolby Atmos',
jymaster: '超高解像度マスター'
},
musicSources: '音源設定',
musicSourcesDesc: '音楽解析に使用する音源プラットフォームを選択',
musicSourcesWarning: '少なくとも1つの音源プラットフォームを選択する必要があります',
musicUnblockEnable: '音楽解析を有効にする',
musicUnblockEnableDesc: '有効にすると、再生できない音楽の解析を試みます',
configureMusicSources: '音源を設定',
selectedMusicSources: '選択された音源:',
noMusicSources: '音源が選択されていません',
gdmusicInfo: 'GD音楽台は複数のプラットフォーム音源を自動解析し、最適な結果を自動選択できます',
autoPlay: '自動再生',
autoPlayDesc: 'アプリを再起動した際に自動的に再生を継続するかどうか',
showStatusBar: 'ステータスバーコントロール機能を表示するかどうか',
showStatusBarContent:
'Macのステータスバーに音楽コントロール機能を表示できます再起動後に有効',
fallbackParser: '代替解析サービス (GD音楽台)',
fallbackParserDesc:
'「GD音楽台」にチェックが入っていて、通常の音源で再生できない場合、このサービスが使用されます。',
parserGD: 'GD 音楽台 (内蔵)',
parserCustom: 'カスタム API',
sourceLabels: {
migu: 'Migu',
kugou: 'Kugou',
pyncmd: 'NetEase (内蔵)',
bilibili: 'Bilibili',
gdmusic: 'GD 音楽台',
custom: 'カスタム API'
},
customApi: {
sectionTitle: 'カスタム API 設定',
enableHint:
'カスタム API を有効にするには、まずカスタム API をインポートする必要があります。',
importConfig: 'JSON設定をインポート',
currentSource: '現在の音源',
notImported: 'カスタム音源はまだインポートされていません。',
importSuccess: '音源のインポートに成功しました: {name}',
importFailed: 'インポートに失敗しました: {message}',
status: {
imported: 'カスタム音源インポート済み',
notImported: '未インポート'
}
},
lxMusic: {
tabs: {
sources: '音源選択',
lxMusic: '落雪音源',
customApi: 'カスタムAPI'
},
scripts: {
title: 'インポート済みのスクリプト',
importLocal: 'ローカルインポート',
importOnline: 'オンラインインポート',
urlPlaceholder: '落雪音源スクリプトのURLを入力',
importBtn: 'インポート',
empty: 'インポート済みの落雪音源はありません',
notConfigured: '未設定(落雪音源タブで設定してください)',
importHint: '互換性のあるカスタムAPIプラグインをインポートして音源を拡張します',
noScriptWarning: '先に落雪音源スクリプトをインポートしてください',
noSelectionWarning: '先に落雪音源を選択してください',
notFound: '音源が存在しません',
switched: '音源を切り替えました: {name}',
deleted: '音源を削除しました: {name}',
enterUrl: 'スクリプトURLを入力してください',
invalidUrl: '無効なURL形式',
invalidScript: '無効な落雪音源スクリプトですglobalThis.lxが見つかりません',
nameRequired: '名前を空にすることはできません',
renameSuccess: '名前を変更しました'
}
}
},
application: {
closeAction: '閉じる動作',
closeActionDesc: 'ウィンドウを閉じる際の動作を選択',
closeOptions: {
ask: '毎回確認',
minimize: 'トレイに最小化',
close: '直接終了'
},
shortcut: 'ショートカット設定',
shortcutDesc: 'グローバルショートカットをカスタマイズ',
download: 'ダウンロード管理',
downloadDesc: 'ダウンロードリストボタンを常に表示するかどうか',
unlimitedDownload: '無制限ダウンロード',
unlimitedDownloadDesc:
'有効にすると音楽を無制限でダウンロードしますダウンロード失敗の可能性があります。デフォルトは300曲制限',
downloadPath: 'ダウンロードディレクトリ',
downloadPathDesc: '音楽ファイルのダウンロード場所を選択',
remoteControl: 'リモートコントロール',
remoteControlDesc: 'リモートコントロール機能を設定'
},
network: {
apiPort: '音楽APIポート',
apiPortDesc: '変更後はアプリの再起動が必要です',
proxy: 'プロキシ設定',
proxyDesc: '音楽にアクセスできない場合はプロキシを有効にできます',
proxyHost: 'プロキシアドレス',
proxyHostPlaceholder: 'プロキシアドレスを入力してください',
proxyPort: 'プロキシポート',
proxyPortPlaceholder: 'プロキシポートを入力してください',
realIP: 'realIP設定',
realIPDesc:
'制限により、このプロジェクトは海外での使用が制限されます。realIPパラメータを使用して国内IPを渡すことで解決できます',
messages: {
proxySuccess: 'プロキシ設定を保存しました。アプリ再起動後に有効になります',
proxyError: '入力が正しいかどうか確認してください',
realIPSuccess: '実IPアドレス設定を保存しました',
realIPError: '有効なIPアドレスを入力してください'
}
},
system: {
cache: 'キャッシュ管理',
cacheDesc: 'キャッシュをクリア',
cacheClearTitle: 'クリアするキャッシュタイプを選択してください:',
cacheTypes: {
history: {
label: '再生履歴',
description: '再生した楽曲の記録をクリア'
},
favorite: {
label: 'お気に入り記録',
description: 'ローカルのお気に入り楽曲記録をクリア(クラウドのお気に入りには影響しません)'
},
user: {
label: 'ユーザーデータ',
description: 'ログイン情報とユーザー関連データをクリア'
},
settings: {
label: 'アプリ設定',
description: 'アプリのすべてのカスタム設定をクリア'
},
downloads: {
label: 'ダウンロード記録',
description: 'ダウンロード履歴をクリア(ダウンロード済みファイルは削除されません)'
},
resources: {
label: '音楽リソース',
description: '読み込み済みの音楽ファイル、歌詞などのリソースキャッシュをクリア'
},
lyrics: {
label: '歌詞リソース',
description: '読み込み済みの歌詞リソースキャッシュをクリア'
}
},
restart: '再起動',
restartDesc: 'アプリを再起動',
messages: {
clearSuccess: 'クリア成功。一部の設定は再起動後に有効になります'
}
},
about: {
version: 'バージョン',
checkUpdate: '更新を確認',
checking: '確認中...',
latest: '現在最新バージョンです',
hasUpdate: '新しいバージョンが見つかりました',
gotoUpdate: '更新へ',
gotoGithub: 'Githubへ',
author: '作者',
authorDesc: 'algerkong スターを付けてください🌟',
messages: {
checkError: '更新確認に失敗しました。後でもう一度お試しください'
}
},
validation: {
selectProxyProtocol: 'プロキシプロトコルを選択してください',
proxyHost: 'プロキシアドレスを入力してください',
portNumber: '有効なポート番号を入力してください1-65535'
},
lyricSettings: {
title: '歌詞設定',
tabs: {
display: '表示',
interface: 'インターフェース',
typography: 'テキスト',
background: '背景',
mobile: 'モバイル'
},
pureMode: 'ピュアモード',
hideCover: 'カバーを非表示',
centerDisplay: '中央表示',
showTranslation: '翻訳を表示',
hideLyrics: '歌詞を非表示',
hidePlayBar: '再生バーを非表示',
hideMiniPlayBar: 'ミニ再生バーを非表示',
showMiniPlayBar: 'ミニ再生バーを表示',
backgroundTheme: '背景テーマ',
themeOptions: {
default: 'デフォルト',
light: 'ライト',
dark: 'ダーク'
},
fontSize: 'フォントサイズ',
fontSizeMarks: {
small: '小',
medium: '中',
large: '大'
},
fontWeight: 'フォントの太さ',
fontWeightMarks: {
thin: '細い',
normal: '通常',
bold: '太い'
},
letterSpacing: '文字間隔',
letterSpacingMarks: {
compact: 'コンパクト',
default: 'デフォルト',
loose: 'ゆったり'
},
lineHeight: '行の高さ',
lineHeightMarks: {
compact: 'コンパクト',
default: 'デフォルト',
loose: 'ゆったり'
},
contentWidth: 'コンテンツ幅',
mobileLayout: 'モバイルレイアウト',
layoutOptions: {
default: 'デフォルト',
ios: 'iOSスタイル',
android: 'Androidスタイル'
},
mobileCoverStyle: 'カバースタイル',
coverOptions: {
record: 'レコード',
square: '正方形',
full: 'フルスクリーン'
},
lyricLines: '歌詞行数',
mobileUnavailable: 'この設定はモバイルでのみ利用可能です',
// 背景設定
background: {
useCustomBackground: 'カスタム背景を使用',
backgroundMode: '背景モード',
modeOptions: {
solid: '単色',
gradient: 'グラデーション',
image: '画像',
css: 'CSS'
},
solidColor: '色を選択',
presetColors: 'プリセットカラー',
customColor: 'カスタムカラー',
gradientEditor: 'グラデーションエディター',
gradientColors: 'グラデーションカラー',
gradientDirection: 'グラデーション方向',
directionOptions: {
toBottom: '上から下',
toRight: '左から右',
toBottomRight: '左上から右下',
angle45: '45度',
toTop: '下から上',
toLeft: '右から左'
},
addColor: '色を追加',
removeColor: '色を削除',
imageUpload: '画像をアップロード',
imagePreview: '画像プレビュー',
clearImage: '画像をクリア',
imageBlur: 'ぼかし',
imageBrightness: '明るさ',
customCss: 'カスタム CSS スタイル',
customCssPlaceholder: 'CSSスタイルを入力、例: background: linear-gradient(...)',
customCssHelp: '任意のCSS background プロパティをサポート',
reset: 'デフォルトにリセット',
fileSizeLimit: '画像サイズ制限: 20MB',
invalidImageFormat: '無効な画像形式',
imageTooLarge: '画像が大きすぎます。20MB未満の画像を選択してください'
}
},
translationEngine: '歌詞翻訳エンジン',
translationEngineOptions: {
none: 'オフ',
opencc: 'OpenCC 繁体字化'
},
themeColor: {
title: '歌詞テーマカラー',
presetColors: 'プリセットカラー',
customColor: 'カスタムカラー',
preview: 'プレビュー効果',
previewText: '歌詞効果',
colorNames: {
'spotify-green': 'Spotify グリーン',
'apple-blue': 'Apple ブルー',
'youtube-red': 'YouTube レッド',
orange: 'バイタルオレンジ',
purple: 'ミステリアスパープル',
pink: 'サクラピンク'
},
tooltips: {
openColorPicker: 'カラーパレットを開く',
closeColorPicker: 'カラーパレットを閉じる'
},
placeholder: '#1db954'
},
shortcutSettings: {
title: 'ショートカット設定',
shortcut: 'ショートカット',
shortcutDesc: 'ショートカットをカスタマイズ',
shortcutConflict: 'ショートカットの競合',
inputPlaceholder: 'クリックしてショートカットを入力',
resetShortcuts: 'デフォルトに戻す',
disableAll: 'すべて無効',
enableAll: 'すべて有効',
togglePlay: '再生/一時停止',
prevPlay: '前の曲',
nextPlay: '次の曲',
volumeUp: '音量を上げる',
volumeDown: '音量を下げる',
toggleFavorite: 'お気に入り/お気に入り解除',
toggleWindow: 'ウィンドウ表示/非表示',
scopeGlobal: 'グローバル',
scopeApp: 'アプリ内',
enabled: '有効',
disabled: '無効',
messages: {
resetSuccess: 'デフォルトのショートカットに戻しました。保存を忘れずに',
conflict: '競合するショートカットがあります。再設定してください',
saveSuccess: 'ショートカット設定を保存しました',
saveError: 'ショートカットの保存に失敗しました。再試行してください',
cancelEdit: '変更をキャンセルしました',
disableAll: 'すべてのショートカットを無効にしました。保存を忘れずに',
enableAll: 'すべてのショートカットを有効にしました。保存を忘れずに'
}
},
remoteControl: {
title: 'リモートコントロール',
enable: 'リモートコントロールを有効にする',
port: 'サービスポート',
allowedIps: '許可されたIPアドレス',
addIp: 'IPを追加',
emptyListHint: '空のリストはすべてのIPアクセスを許可することを意味します',
saveSuccess: 'リモートコントロール設定を保存しました',
accessInfo: 'リモートコントロールアクセスアドレス:'
},
cookie: {
title: 'Cookie設定',
description: 'NetEase Cloud MusicのCookieを入力してください',
placeholder: '完全なCookieを貼り付けてください...',
help: {
format: 'Cookieは通常「MUSIC_U=」で始まります',
source: 'ブラウザの開発者ツールのネットワークリクエストから取得できます',
storage: 'Cookie設定後、自動的にローカルストレージに保存されます'
},
action: {
save: 'Cookieを保存',
paste: '貼り付け',
clear: 'クリア'
},
validation: {
required: 'Cookieを入力してください',
format: 'Cookie形式が正しくない可能性があります。MUSIC_Uが含まれているか確認してください'
},
message: {
saveSuccess: 'Cookieの保存に成功しました',
saveError: 'Cookieの保存に失敗しました',
pasteSuccess: '貼り付けに成功しました',
pasteError: '貼り付けに失敗しました。手動でコピーしてください'
},
info: {
length: '現在の長さ:{length} 文字'
}
}
};

View File

@@ -0,0 +1,28 @@
export default {
menu: {
play: '再生',
playNext: '次に再生',
download: '楽曲をダウンロード',
addToPlaylist: 'プレイリストに追加',
favorite: 'いいね',
unfavorite: 'いいね解除',
removeFromPlaylist: 'プレイリストから削除',
dislike: '嫌い',
undislike: '嫌い解除'
},
message: {
downloading: 'ダウンロード中です。しばらくお待ちください...',
downloadFailed: 'ダウンロードに失敗しました',
downloadQueued: 'ダウンロードキューに追加しました',
addedToNextPlay: '次の再生に追加しました',
getUrlFailed: '音楽ダウンロードアドレスの取得に失敗しました。ログインしているか確認してください'
},
dialog: {
dislike: {
title: 'お知らせ!',
content: 'この楽曲を嫌いにしますか?再度アクセスすると毎日のおすすめから除外されます。',
positiveText: '嫌い',
negativeText: 'キャンセル'
}
}
};

View File

@@ -0,0 +1,53 @@
export default {
profile: {
followers: 'フォロワー',
following: 'フォロー中',
level: 'レベル'
},
playlist: {
created: '作成したプレイリスト',
mine: '私が作成した',
trackCount: '{count}曲',
playCount: '{count}回再生'
},
tabs: {
created: '作成',
favorite: 'お気に入り',
album: 'アルバム'
},
ranking: {
title: '聴取ランキング',
playCount: '{count}回'
},
follow: {
title: 'フォローリスト',
viewPlaylist: 'プレイリストを見る',
noFollowings: 'フォローがありません',
loadMore: 'さらに読み込み',
noSignature: 'この人は怠け者で、何も残していません',
userFollowsTitle: 'のフォロー',
myFollowsTitle: '私のフォロー'
},
follower: {
title: 'フォロワーリスト',
noFollowers: 'フォロワーがいません',
loadMore: 'さらに読み込み',
userFollowersTitle: 'のフォロワー',
myFollowersTitle: '私のフォロワー'
},
detail: {
playlists: 'プレイリスト',
records: '聴取ランキング',
noPlaylists: 'プレイリストがありません',
noRecords: '聴取記録がありません',
artist: 'アーティスト',
noSignature: 'この人は怠け者で、何も残していません',
invalidUserId: '無効なユーザーID',
noRecordPermission: '{name}は聴取ランキングを見せてくれません'
},
message: {
loadFailed: 'ユーザーページの読み込みに失敗しました',
deleteSuccess: '削除成功',
deleteFailed: '削除失敗'
}
};

View File

@@ -0,0 +1,5 @@
export default {
hotSongs: '인기 곡',
albums: '앨범',
description: '아티스트 소개'
};

View File

@@ -0,0 +1,51 @@
export default {
player: {
loading: '오디오 로딩 중...',
retry: '다시 시도',
playNow: '지금 재생',
loadingTitle: '로딩 중...',
totalDuration: '총 재생시간: {duration}',
partsList: '파트 목록 ({count}화)',
playStarted: '재생이 시작되었습니다',
switchingPart: '파트 전환 중: {part}',
preloadingNext: '다음 파트 미리 로딩 중: {part}',
playingCurrent: '현재 선택된 파트 재생 중: {name}',
num: '만',
errors: {
invalidVideoId: '유효하지 않은 비디오 ID',
loadVideoDetailFailed: '비디오 세부정보 로드 실패',
loadPartInfoFailed: '비디오 파트 정보를 로드할 수 없습니다',
loadAudioUrlFailed: '오디오 재생 URL 가져오기 실패',
videoDetailNotLoaded: '비디오 세부정보가 로드되지 않았습니다',
missingParams: '필수 매개변수가 누락되었습니다',
noAvailableAudioUrl: '사용 가능한 오디오 URL을 찾을 수 없습니다',
loadPartAudioFailed: '파트 오디오 URL 로드 실패',
audioListEmpty: '오디오 목록이 비어있습니다. 다시 시도해주세요',
currentPartNotFound: '현재 파트의 오디오를 찾을 수 없습니다',
audioUrlFailed: '오디오 URL 가져오기 실패',
playFailed: '재생 실패. 다시 시도해주세요',
getAudioUrlFailed: '오디오 URL 가져오기 실패. 다시 시도해주세요',
audioNotFound: '해당 오디오를 찾을 수 없습니다. 다시 시도해주세요',
preloadFailed: '다음 파트 미리 로딩 실패',
switchPartFailed: '파트 전환 시 오디오 URL 로드 실패'
},
console: {
loadingDetail: 'Bilibili 비디오 세부정보 로딩 중',
detailData: 'Bilibili 비디오 세부정보 데이터',
multipleParts: '비디오에 여러 파트가 있습니다. 총 {count}개',
noPartsData: '비디오에 파트가 없거나 파트 데이터가 비어있습니다',
loadingAudioSource: '오디오 소스 로딩 중',
generatedAudioList: '오디오 목록을 생성했습니다. 총 {count}개',
getDashAudioUrl: 'dash 오디오 URL을 가져왔습니다',
getDurlAudioUrl: 'durl 오디오 URL을 가져왔습니다',
loadingPartAudio: '파트 오디오 URL 로딩 중: {part}, cid: {cid}',
loadPartAudioFailed: '파트 오디오 URL 로드 실패: {part}',
switchToPart: '파트로 전환 중: {part}',
audioNotFoundInList: '해당 오디오 항목을 찾을 수 없습니다',
preparingToPlay: '현재 선택된 파트 재생 준비 중: {name}',
preloadingNextPart: '다음 파트 미리 로딩 중: {part}',
playingSelectedPart: '현재 선택된 파트 재생 중: {name}, 오디오 URL: {url}',
preloadNextFailed: '다음 파트 미리 로딩 실패'
}
}
};

View File

@@ -0,0 +1,58 @@
export default {
play: '재생',
next: '다음 곡',
previous: '이전 곡',
volume: '볼륨',
settings: '설정',
search: '검색',
loading: '로딩 중...',
loadingMore: '더 불러오기...',
alipay: '알리페이',
wechat: '위챗 페이',
on: '켜기',
off: '끄기',
show: '표시',
hide: '숨기기',
confirm: '확인',
cancel: '취소',
configure: '구성',
open: '열기',
modify: '수정',
success: '작업 성공',
error: '작업 실패',
warning: '경고',
info: '알림',
save: '저장',
delete: '삭제',
refresh: '새로고침',
retry: '다시 시도',
reset: '재설정',
back: '뒤로',
copySuccess: '클립보드에 복사됨',
copyFailed: '복사 실패',
validation: {
required: '이 항목은 필수입니다',
invalidInput: '잘못된 입력',
selectRequired: '옵션을 선택해주세요',
numberRange: '{min}에서 {max} 사이의 숫자를 입력해주세요'
},
viewMore: '더 보기',
noMore: '더 이상 없음',
selectAll: '전체 선택',
expand: '펼치기',
collapse: '접기',
songCount: '{count}곡',
language: '언어',
today: '오늘',
yesterday: '어제',
tray: {
show: '표시',
quit: '종료',
playPause: '재생/일시정지',
prev: '이전 곡',
next: '다음 곡',
pause: '일시정지',
play: '재생',
favorite: '즐겨찾기'
}
};

221
src/i18n/lang/ko-KR/comp.ts Normal file
View File

@@ -0,0 +1,221 @@
export default {
installApp: {
description: '앱을 설치하여 더 나은 경험을 얻으세요',
noPrompt: '다시 묻지 않기',
install: '지금 설치',
cancel: '나중에 설치',
download: '다운로드',
downloadFailed: '다운로드 실패',
downloadComplete: '다운로드 완료',
downloadProblem: '다운로드에 문제가 있나요?',
downloadProblemLinkText: '최신 버전 다운로드'
},
playlistDrawer: {
title: '플레이리스트에 추가',
createPlaylist: '새 플레이리스트 만들기',
cancelCreate: '만들기 취소',
create: '만들기',
playlistName: '플레이리스트 이름',
privatePlaylist: '비공개 플레이리스트',
publicPlaylist: '공개 플레이리스트',
createSuccess: '플레이리스트 생성 성공',
createFailed: '플레이리스트 생성 실패',
addSuccess: '곡 추가 성공',
addFailed: '곡 추가 실패',
private: '비공개',
public: '공개',
count: '곡',
loginFirst: '먼저 로그인해주세요',
getPlaylistFailed: '플레이리스트 가져오기 실패',
inputPlaylistName: '플레이리스트 이름을 입력해주세요'
},
update: {
title: '새 버전 발견',
currentVersion: '현재 버전',
cancel: '나중에 업데이트',
prepareDownload: '다운로드 준비 중...',
downloading: '다운로드 중...',
nowUpdate: '지금 업데이트',
downloadFailed: '다운로드 실패, 다시 시도하거나 수동으로 다운로드해주세요',
startFailed: '다운로드 시작 실패, 다시 시도하거나 수동으로 다운로드해주세요',
noDownloadUrl: '현재 시스템에 적합한 설치 패키지를 찾을 수 없습니다. 수동으로 다운로드해주세요',
installConfirmTitle: '업데이트 설치',
installConfirmContent: '앱을 닫고 업데이트를 설치하시겠습니까?',
manualInstallTip:
'앱을 닫은 후 설치 프로그램이 정상적으로 나타나지 않으면 다운로드 폴더에서 파일을 찾아 수동으로 열어주세요.',
yesInstall: '지금 설치',
noThanks: '나중에 설치',
fileLocation: '파일 위치',
copy: '경로 복사',
copySuccess: '경로가 클립보드에 복사됨',
copyFailed: '복사 실패',
backgroundDownload: '백그라운드 다운로드'
},
disclaimer: {
title: '이용 안내',
warning:
'본 앱은 개발 테스트 버전으로 기능이 아직 미흡하며, 다수의 문제와 버그가 존재할 수 있습니다. 학습 및 교류 목적으로만 사용하십시오.',
item1:
'본 앱은 개인의 학습, 연구 및 기술 교류 목적으로만 사용되며, 상업적 용도로 사용하지 마십시오.',
item2:
'다운로드 후 24시간 이내에 삭제해 주십시오. 장기 사용을 원하시면 정품 음악 서비스를 이용해 주십시오.',
item3:
'본 앱을 사용함으로써 관련 위험을 이해하고 감수하는 것으로 간주합니다. 개발자는 어떠한 손실에 대해서도 책임을 지지 않습니다.',
agree: '숙지하였으며 이에 동의합니다',
disagree: '동의하지 않음 및 정지'
},
donate: {
title: '개발자 지원',
subtitle: '여러분의 지원이 저의 원동력입니다',
tip: '후원은 완전히 자율적입니다. 후원하지 않더라도 모든 기능을 정상적으로 사용할 수 있습니다. 이해와 지원에 감사드립니다!',
wechat: 'WeChat',
alipay: 'Alipay',
wechatQR: 'WeChat 결제 코드',
alipayQR: 'Alipay 결제 코드',
scanTip: '휴대전화로 위 QR 코드를 스캔하여 후원해 주세요',
enterApp: '앱 시작하기',
noForce: '후원은 강제가 아닙니다. 클릭하여 시작할 수 있습니다'
},
coffee: {
title: '커피 한 잔 사주세요',
alipay: '알리페이',
wechat: '위챗 페이',
alipayQR: '알리페이 결제 QR코드',
wechatQR: '위챗 결제 QR코드',
coffeeDesc: '커피 한 잔, 하나의 지원',
coffeeDescLinkText: '더 보기',
groupText: '微信公众号AlgerMusic',
messages: {
copySuccess: '클립보드에 복사됨'
},
donateList: '커피 한 잔 사주세요'
},
playlistType: {
title: '플레이리스트 분류',
showAll: '모두 표시',
hide: '일부 숨기기'
},
recommendAlbum: {
title: '최신 앨범'
},
recommendSinger: {
title: '일일 추천',
songlist: '일일 추천 목록'
},
recommendSonglist: {
title: '이번 주 인기 음악'
},
searchBar: {
login: '로그인',
toLogin: '로그인하기',
logout: '로그아웃',
set: '설정',
theme: '테마',
restart: '재시작',
refresh: '새로고침',
currentVersion: '현재 버전',
searchPlaceholder: '검색해보세요...',
zoom: '페이지 확대/축소',
zoom100: '표준 확대/축소 100%',
resetZoom: '클릭하여 확대/축소 재설정',
zoomDefault: '표준 확대/축소'
},
titleBar: {
closeTitle: '닫기 방법을 선택해주세요',
minimizeToTray: '트레이로 최소화',
exitApp: '앱 종료',
rememberChoice: '선택 기억하기',
closeApp: '앱 닫기'
},
userPlayList: {
title: '{name}의 자주 듣는 음악'
},
musicList: {
searchSongs: '곡 검색',
noSearchResults: '관련 곡을 찾을 수 없습니다',
switchToNormal: '기본 레이아웃으로 전환',
switchToCompact: '컴팩트 레이아웃으로 전환',
playAll: '모두 재생',
collect: '수집',
collectSuccess: '수집 성공',
cancelCollectSuccess: '수집 취소 성공',
operationFailed: '작업 실패',
cancelCollect: '수집 취소',
addToPlaylist: '재생 목록에 추가',
addToPlaylistSuccess: '재생 목록에 추가 성공',
songsAlreadyInPlaylist: '곡이 이미 재생 목록에 있습니다',
historyRecommend: '일일 기록 권장',
fetchDatesFailed: '날짜를 가져오지 못했습니다',
fetchSongsFailed: '곡을 가져오지 못했습니다',
noSongs: '노래 없음'
},
playlist: {
import: {
button: '플레이리스트 가져오기',
title: '플레이리스트 가져오기',
description: '메타데이터/텍스트/링크 세 가지 방법으로 플레이리스트 가져오기 지원',
linkTab: '링크 가져오기',
textTab: '텍스트 가져오기',
localTab: '메타데이터 가져오기',
linkPlaceholder: '플레이리스트 링크를 입력하세요. 한 줄에 하나씩',
textPlaceholder: '곡 정보를 입력하세요. 형식: 곡명 가수명',
localPlaceholder: 'JSON 형식의 곡 메타데이터를 입력하세요',
linkTips: '지원되는 링크 소스:',
linkTip1: '플레이리스트를 위챗/웨이보/QQ로 공유한 후 링크 복사',
linkTip2: '플레이리스트/개인 홈페이지 링크 직접 복사',
linkTip3: '기사 링크 직접 복사',
textTips: '곡 정보를 입력하세요. 한 줄에 한 곡씩',
textFormat: '형식: 곡명 가수명',
localTips: '곡 메타데이터를 추가해주세요',
localFormat: '형식 예시:',
songNamePlaceholder: '곡명',
artistNamePlaceholder: '아티스트명',
albumNamePlaceholder: '앨범명',
addSongButton: '곡 추가',
addLinkButton: '링크 추가',
importToStarPlaylist: '내가 좋아하는 음악으로 가져오기',
playlistNamePlaceholder: '플레이리스트 이름을 입력하세요',
importButton: '가져오기 시작',
emptyLinkWarning: '플레이리스트 링크를 입력해주세요',
emptyTextWarning: '곡 정보를 입력해주세요',
emptyLocalWarning: '곡 메타데이터를 입력해주세요',
invalidJsonFormat: 'JSON 형식이 올바르지 않습니다',
importSuccess: '가져오기 작업 생성 성공',
importFailed: '가져오기 실패',
importStatus: '가져오기 상태',
refresh: '새로고침',
taskId: '작업 ID',
status: '상태',
successCount: '성공 수',
failReason: '실패 이유',
unknownError: '알 수 없는 오류',
statusPending: '처리 대기 중',
statusProcessing: '처리 중',
statusSuccess: '가져오기 성공',
statusFailed: '가져오기 실패',
statusUnknown: '알 수 없는 상태',
taskList: '작업 목록',
taskListTitle: '가져오기 작업 목록',
action: '작업',
select: '선택',
fetchTaskListFailed: '작업 목록 가져오기 실패',
noTasks: '가져오기 작업이 없습니다',
clearTasks: '작업 지우기',
clearTasksConfirmTitle: '지우기 확인',
clearTasksConfirmContent:
'모든 가져오기 작업 기록을 지우시겠습니까? 이 작업은 되돌릴 수 없습니다.',
confirm: '확인',
cancel: '취소',
clearTasksSuccess: '작업 목록이 지워졌습니다',
clearTasksFailed: '작업 목록 지우기 실패'
}
},
settings: '설정',
user: '사용자',
toplist: '순위',
history: '수집 기록',
list: '플레이리스트',
mv: 'MV',
home: '홈',
search: '검색'
};

View File

@@ -0,0 +1,9 @@
export default {
description:
'귀하의 기부는 서버 유지보수, 도메인 갱신 등을 포함한 개발 및 유지보수 작업을 지원하는 데 사용됩니다.',
message: '메시지를 남길 때 이메일이나 GitHub 이름을 남겨주세요.',
refresh: '목록 새로고침',
toDonateList: '커피 한 잔 사주세요',
noMessage: '메시지가 없습니다',
title: '기부 목록'
};

View File

@@ -0,0 +1,88 @@
export default {
title: '다운로드 관리',
localMusic: '로컬 음악',
count: '총 {count}곡',
clearAll: '기록 지우기',
settings: '설정',
tabs: {
downloading: '다운로드 중',
downloaded: '다운로드 완료'
},
empty: {
noTasks: '다운로드 작업이 없습니다',
noDownloaded: '다운로드된 곡이 없습니다'
},
progress: {
total: '전체 진행률: {progress}%'
},
status: {
downloading: '다운로드 중',
completed: '완료',
failed: '실패',
unknown: '알 수 없음'
},
artist: {
unknown: '알 수 없는 가수'
},
delete: {
title: '삭제 확인',
message: '곡 "{filename}"을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
confirm: '삭제 확인',
cancel: '취소',
success: '삭제 성공',
failed: '삭제 실패',
fileNotFound: '파일이 존재하지 않거나 이동되었습니다. 기록에서 제거되었습니다',
recordRemoved: '파일 삭제 실패, 하지만 기록에서 제거되었습니다'
},
clear: {
title: '다운로드 기록 지우기',
message:
'모든 다운로드 기록을 지우시겠습니까? 이 작업은 다운로드된 음악 파일을 삭제하지 않지만 모든 기록을 지웁니다.',
confirm: '지우기 확인',
cancel: '취소',
success: '다운로드 기록이 지워졌습니다'
},
message: {
downloadComplete: '{filename} 다운로드 완료',
downloadFailed: '{filename} 다운로드 실패: {error}'
},
loading: '로딩 중...',
playStarted: '재생 시작: {name}',
playFailed: '재생 실패: {name}',
path: {
copied: '경로가 클립보드에 복사됨',
copyFailed: '경로 복사 실패'
},
settingsPanel: {
title: '다운로드 설정',
path: '다운로드 위치',
pathDesc: '음악 파일 다운로드 저장 위치 설정',
pathPlaceholder: '다운로드 경로를 선택해주세요',
noPathSelected: '먼저 다운로드 경로를 선택해주세요',
select: '폴더 선택',
open: '폴더 열기',
fileFormat: '파일명 형식',
fileFormatDesc: '음악 다운로드 시 파일 이름 형식 설정',
customFormat: '사용자 정의 형식',
separator: '구분자',
separators: {
dash: '공백-공백',
underscore: '밑줄',
space: '공백'
},
dragToArrange: '드래그하여 정렬하거나 화살표 버튼을 사용하여 순서 조정:',
formatVariables: '사용 가능한 변수',
preview: '미리보기 효과:',
saveSuccess: '다운로드 설정이 저장됨',
presets: {
songArtist: '곡명 - 가수명',
artistSong: '가수명 - 곡명',
songOnly: '곡명만'
},
components: {
songName: '곡명',
artistName: '가수명',
albumName: '앨범명'
}
}
};

View File

@@ -0,0 +1,13 @@
export default {
title: '내 수집',
count: '총 {count}곡',
batchDownload: '일괄 다운로드',
download: '다운로드 ({count})',
emptyTip: '아직 수집한 곡이 없습니다',
downloadSuccess: '다운로드 완료',
downloadFailed: '다운로드 실패',
downloading: '다운로드 중입니다. 잠시만 기다려주세요...',
selectSongsFirst: '먼저 다운로드할 곡을 선택해주세요',
descending: '내림차순',
ascending: '오름차순'
};

View File

@@ -0,0 +1,44 @@
export default {
title: '재생 기록',
heatmapTitle: '히트맵',
playCount: '{count}',
getHistoryFailed: '기록 가져오기 실패',
tabs: {
all: '전체 기록',
local: '로컬 기록',
cloud: '클라우드 기록'
},
categoryTabs: {
songs: '곡',
playlists: '플레이리스트',
albums: '앨범'
},
noDescription: '설명 없음',
noData: '기록 없음',
getCloudRecordFailed: '클라우드 기록 가져오기 실패',
needLogin: 'cookie를 사용하여 로그인하여 클라우드 기록을 볼 수 있습니다',
merging: '기록 병합 중...',
heatmap: {
title: '재생 히트맵',
loading: '데이터 로딩 중...',
unit: '회 재생',
footerText: '마우스를 올려서 자세히 보기',
playCount: '{count}회 재생',
topSongs: '오늘의 인기곡',
times: '회',
totalPlays: '총 재생 횟수',
activeDays: '활동 일수',
noData: '재생 기록이 없습니다',
colorTheme: '색상 테마',
colors: {
green: '그린',
blue: '블루',
orange: '오렌지',
purple: '퍼플',
red: '레드'
},
mostPlayedSong: '가장 많이 재생한 노래',
mostActiveDay: '가장 활발한 날',
latestNightSong: '가장 늘게 재생한 노래'
}
};

View File

@@ -0,0 +1,64 @@
export default {
title: {
qr: 'QR코드 로그인',
phone: '휴대폰 번호 로그인',
cookie: 'Cookie 로그인',
uid: 'UID 로그인'
},
qrTip: '넷이즈 클라우드 뮤직 앱으로 QR코드를 스캔하여 로그인',
phoneTip: '넷이즈 클라우드 계정으로 로그인',
tokenTip: '유효한 넷이즈 클라우드 뮤직 Cookie을 입력하여 로그인',
uidTip: '사용자 ID를 입력하여 빠른 로그인',
placeholder: {
phone: '휴대폰 번호',
password: '비밀번호',
cookie: '넷이즈 클라우드 뮤직 Cookie(token)을 입력하세요',
uid: '사용자 ID(UID)를 입력하세요'
},
button: {
login: '로그인',
switchToQr: 'QR코드 로그인',
switchToPhone: '휴대폰 번호 로그인',
switchToToken: 'Cookie 로그인 사용',
switchToUid: 'UID 로그인',
backToQr: 'QR코드 로그인으로 돌아가기',
cookieLogin: 'Cookie 로그인',
autoGetCookie: 'Cookie 자동 가져오기',
refresh: '새로고침',
refreshing: '새로고침 중...',
refreshQr: 'QR코드 새로고침'
},
message: {
loginSuccess: '로그인 성공',
tokenLoginSuccess: 'Cookie 로그인 성공',
uidLoginSuccess: 'UID 로그인 성공',
loadError: '로그인 정보 로드 중 오류 발생',
qrCheckError: 'QR코드 상태 확인 중 오류 발생',
tokenRequired: 'Cookie을 입력하세요',
tokenInvalid: 'Cookie이 유효하지 않습니다. 확인 후 다시 시도하세요',
uidRequired: '사용자 ID를 입력하세요',
uidInvalid: '사용자 ID가 유효하지 않거나 사용자가 존재하지 않습니다',
uidLoginFailed: 'UID 로그인에 실패했습니다. 사용자 ID가 올바른지 확인하세요',
autoGetCookieSuccess: 'Cookie 자동 가져오기 성공',
autoGetCookieFailed: 'Cookie 자동 가져오기 실패',
autoGetCookieTip:
'넷이즈 클라우드 뮤직 로그인 페이지를 열겠습니다. 로그인 완료 후 창을 닫아주세요',
loginFailed: '로그인 실패',
phoneRequired: '휴대폰 번호를 입력하세요',
passwordRequired: '비밀번호를 입력하세요',
phoneLoginFailed: '휴대폰 번호 로그인 실패, 휴대폰 번호와 비밀번호가 올바른지 확인하세요',
qrCheckFailed: 'QR코드 상태 확인 실패, 새로고침하여 다시 시도하세요',
qrLoading: 'QR코드 로딩 중...',
qrExpired: 'QR코드가 만료되었습니다. 클릭하여 새로고침하세요',
qrExpiredShort: 'QR코드 만료됨',
qrExpiredWarning: 'QR코드가 만료되었습니다. 클릭하여 새로운 QR코드를 받으세요',
qrScanned: 'QR코드가 스캔되었습니다. 휴대폰에서 로그인을 확인하세요',
qrScannedShort: '스캔됨',
qrScannedInfo: 'QR코드가 스캔되었습니다. 휴대폰에서 로그인을 확인하세요',
qrConfirmed: '로그인 성공, 리다이렉트 중...',
qrGenerating: 'QR코드를 생성 중...'
},
qrTitle: '넷이즈 클라우드 뮤직 QR코드 로그인',
uidWarning:
'주의: UID 로그인은 사용자 공개 정보를 확인하는 데만 사용할 수 있으며, 로그인 권한이 필요한 기능에 액세스할 수 없습니다.'
};

View File

@@ -0,0 +1,143 @@
export default {
nowPlaying: '현재 재생 중',
playlist: '재생 목록',
lyrics: '가사',
previous: '이전',
play: '재생',
pause: '일시정지',
next: '다음',
volumeUp: '볼륨 증가',
volumeDown: '볼륨 감소',
mute: '음소거',
unmute: '음소거 해제',
songNum: '총 곡 수: {num}',
addCorrection: '{num}초 앞당기기',
subtractCorrection: '{num}초 지연',
playFailed: '현재 곡 재생 실패, 다음 곡 재생',
parseFailedPlayNext: '곡 분석 실패, 다음 곡 재생',
consecutiveFailsError:
'재생 오류가 발생했습니다. 네트워크 문제 또는 유효하지 않은 음원일 수 있습니다. 재생 목록을 변경하거나 나중에 다시 시도하세요',
playMode: {
sequence: '순차 재생',
loop: '한 곡 반복',
random: '랜덤 재생'
},
fullscreen: {
enter: '전체화면',
exit: '전체화면 종료'
},
close: '닫기',
modeHint: {
single: '한 곡 반복',
list: '자동으로 다음 곡 재생'
},
lrc: {
noLrc: '가사가 없습니다. 음악을 감상해주세요',
noAutoScroll: '본 가사는 자동 스크롤을 지원하지 않습니다'
},
reparse: {
title: '음원 선택',
desc: '음원을 클릭하여 직접 분석하세요. 다음에 이 곡을 재생할 때 선택한 음원을 사용합니다',
success: '재분석 성공',
failed: '재분석 실패',
warning: '음원을 선택해주세요',
bilibiliNotSupported: 'B站 비디오는 재분석을 지원하지 않습니다',
processing: '분석 중...',
clear: '사용자 정의 음원 지우기',
customApiFailed: '사용자 정의 API 분석 실패, 기본 음원을 시도합니다...',
customApiError: '사용자 정의 API 요청 오류, 기본 음원을 시도합니다...'
},
playBar: {
expand: '가사 펼치기',
collapse: '가사 접기',
like: '좋아요',
lyric: '가사',
noSongPlaying: '재생 중인 곡이 없습니다',
eq: '이퀄라이저',
playList: '재생 목록',
reparse: '재분석',
playMode: {
sequence: '순차 재생',
loop: '반복 재생',
random: '랜덤 재생'
},
play: '재생 시작',
pause: '재생 일시정지',
prev: '이전 곡',
next: '다음 곡',
volume: '볼륨',
favorite: '{name} 즐겨찾기 추가됨',
unFavorite: '{name} 즐겨찾기 해제됨',
miniPlayBar: '미니 재생바',
playbackSpeed: '재생 속도',
advancedControls: '고급 설정',
intelligenceMode: {
title: '인텔리전스 모드',
needCookieLogin: '쿠키 방식으로 로그인한 후 인텔리전스 모드를 사용할 수 있습니다',
noFavoritePlaylist: '내가 좋아하는 음악 재생목록을 찾을 수 없습니다',
noLikedSongs: '아직 좋아한 노래가 없습니다',
loading: '인텔리전스 모드를 불러오는 중',
success: '총 {count}곡을 불러왔습니다',
failed: '인텔리전스 모드 목록을 가져오는 데 실패했습니다',
error: '인텔리전스 모드 재생 오류'
}
},
eq: {
title: '이퀄라이저',
reset: '재설정',
on: '켜기',
off: '끄기',
bass: '저음',
midrange: '중음',
treble: '고음',
presets: {
flat: '플랫',
pop: '팝',
rock: '록',
classical: '클래식',
jazz: '재즈',
electronic: '일렉트로닉',
hiphop: '힙합',
rb: 'R&B',
metal: '메탈',
vocal: '보컬',
dance: '댄스',
acoustic: '어쿠스틱',
custom: '사용자 정의'
}
},
// 플레이어 설정
settings: {
title: '재생 설정',
playbackSpeed: '재생 속도'
},
sleepTimer: {
title: '타이머 종료',
cancel: '타이머 취소',
timeMode: '시간으로 종료',
songsMode: '곡 수로 종료',
playlistEnd: '재생 목록 완료 후 종료',
afterPlaylist: '재생 목록 완료 후 종료',
activeUntilEnd: '목록 끝까지 재생',
minutes: '분',
hours: '시간',
songs: '곡',
set: '설정',
timerSetSuccess: '{minutes}분 후 종료로 설정됨',
songsSetSuccess: '{songs}곡 재생 후 종료로 설정됨',
playlistEndSetSuccess: '재생 목록 완료 후 종료로 설정됨',
timerCancelled: '타이머 종료 취소됨',
timerEnded: '타이머 종료 실행됨',
playbackStopped: '음악 재생이 중지됨',
minutesRemaining: '남은 시간 {minutes}분',
songsRemaining: '남은 곡 수 {count}곡'
},
playList: {
clearAll: '재생 목록 비우기',
alreadyEmpty: '재생 목록이 이미 비어있습니다',
cleared: '재생 목록이 비워졌습니다',
empty: '재생 목록이 비어있습니다',
clearConfirmTitle: '재생 목록 비우기',
clearConfirmContent: '재생 목록의 모든 곡을 삭제하고 현재 재생을 중지합니다. 계속하시겠습니까?'
}
};

View File

@@ -0,0 +1,31 @@
export default {
title: {
hotSearch: '인기 검색',
searchList: '검색 목록',
searchHistory: '검색 기록'
},
button: {
clear: '지우기',
back: '뒤로',
playAll: '재생 목록'
},
loading: {
more: '로딩 중...',
failed: '검색 실패',
searching: '검색 중...'
},
noMore: '더 이상 없음',
error: {
searchFailed: '검색 실패'
},
search: {
single: '단일곡',
album: '앨범',
playlist: '플레이리스트',
mv: 'MV',
bilibili: 'B站'
},
history: '검색 기록',
hot: '인기 검색',
suggestions: '검색 제안'
};

View File

@@ -0,0 +1,442 @@
export default {
theme: '테마',
language: '언어',
regard: '정보',
logout: '로그아웃',
sections: {
basic: '기본 설정',
playback: '재생 설정',
application: '애플리케이션 설정',
network: '네트워크 설정',
system: '시스템 관리',
donation: '후원 지원',
about: '정보'
},
basic: {
themeMode: '테마 모드',
themeModeDesc: '낮/밤 테마 전환',
autoTheme: '시스템 따라가기',
manualTheme: '수동 전환',
language: '언어 설정',
languageDesc: '표시 언어 전환',
tokenManagement: 'Cookie 관리',
tokenManagementDesc: '넷이즈 클라우드 뮤직 로그인 Cookie 관리',
tokenStatus: '현재 Cookie 상태',
tokenSet: '설정됨',
tokenNotSet: '설정되지 않음',
setToken: 'Cookie 설정',
modifyToken: 'Cookie 수정',
clearToken: 'Cookie 지우기',
font: '폰트 설정',
fontDesc: '폰트 선택, 앞에 있는 폰트를 우선 사용',
fontScope: {
global: '전역',
lyric: '가사만'
},
animation: '애니메이션 속도',
animationDesc: '애니메이션 활성화 여부',
animationSpeed: {
slow: '매우 느림',
normal: '보통',
fast: '매우 빠름'
},
fontPreview: {
title: '폰트 미리보기',
chinese: '中文',
english: 'English',
japanese: '日本語',
korean: '한국어',
chineseText: '静夜思 床前明月光 疑是地上霜',
englishText: 'The quick brown fox jumps over the lazy dog',
japaneseText: 'あいうえお かきくけこ さしすせそ',
koreanText: '가나다라마 바사아자차 카타파하'
},
gpuAcceleration: 'GPU 가속',
gpuAccelerationDesc:
'GPU 가속을 사용하면 애니메이션이 빠르게 재생되고 애니메이션이 느리게 재생되는 것보다 느릴 수 있습니다.',
gpuAccelerationRestart: 'GPU 가속 설정을 변경하면 애플리케이션을 다시 시작해야 합니다',
gpuAccelerationChangeSuccess:
'GPU 가속 설정이 업데이트되었습니다. 애플리케이션을 다시 시작하여 적용하십시오',
gpuAccelerationChangeError: 'GPU 가속 설정 업데이트에 실패했습니다',
tabletMode: '태블릿 모드',
tabletModeDesc:
'태블릿 모드를 사용하면 모바일 기기에서 PC 스타일의 인터페이스를 사용할 수 있습니다'
},
playback: {
quality: '음질 설정',
qualityDesc: '음악 재생 음질 선택 (넷이즈 클라우드 VIP)',
qualityOptions: {
standard: '표준',
higher: '높음',
exhigh: '매우 높음',
lossless: '무손실',
hires: 'Hi-Res',
jyeffect: 'HD 서라운드',
sky: '몰입형 서라운드',
dolby: '돌비 애트모스',
jymaster: '초고화질 마스터'
},
musicSources: '음원 설정',
musicSourcesDesc: '음악 해석에 사용할 음원 플랫폼 선택',
musicSourcesWarning: '최소 하나의 음원 플랫폼을 선택해야 합니다',
musicUnblockEnable: '음악 해석 활성화',
musicUnblockEnableDesc: '활성화하면 재생할 수 없는 음악을 해석하려고 시도합니다',
configureMusicSources: '음원 구성',
selectedMusicSources: '선택된 음원:',
noMusicSources: '음원이 선택되지 않음',
gdmusicInfo: 'GD 뮤직은 여러 플랫폼 음원을 자동으로 해석하고 최적의 결과를 자동 선택합니다',
autoPlay: '자동 재생',
autoPlayDesc: '앱을 다시 열 때 자동으로 재생을 계속할지 여부',
showStatusBar: '상태바 제어 기능 표시 여부',
showStatusBarContent: 'Mac 상태바에 음악 제어 기능을 표시할 수 있습니다 (재시작 후 적용)',
fallbackParser: '대체 분석 서비스 (GD Music)',
fallbackParserDesc:
'"GD Music"을 선택하고 일반 음원을 사용할 수 없을 때 이 서비스를 사용합니다.',
parserGD: 'GD Music (내장)',
parserCustom: '사용자 지정 API',
// 음원 라벨
sourceLabels: {
migu: 'Migu',
kugou: 'Kugou',
pyncmd: 'NetEase (내장)',
bilibili: 'Bilibili',
gdmusic: 'GD Music',
custom: '사용자 지정 API'
},
customApi: {
sectionTitle: '사용자 지정 API 설정',
importConfig: 'JSON 설정 가져오기',
currentSource: '현재 음원',
notImported: '아직 사용자 지정 음원을 가져오지 않았습니다.',
importSuccess: '음원 가져오기 성공: {name}',
importFailed: '가져오기 실패: {message}',
enableHint: '사용하려면 먼저 JSON 구성 파일을 가져오세요',
status: {
imported: '사용자 지정 음원 가져옴',
notImported: '가져오지 않음'
}
},
lxMusic: {
tabs: {
sources: '음원 선택',
lxMusic: '낙설 음원',
customApi: '사용자 정의 API'
},
scripts: {
title: '가져온 스크립트',
importLocal: '로컬 가져오기',
importOnline: '온라인 가져오기',
urlPlaceholder: '낙설 음원 스크립트 URL 입력',
importBtn: '가져오기',
empty: '가져온 낙설 음원이 없습니다',
notConfigured: '설정되지 않음 (낙설 음원 탭에서 설정하세요)',
importHint: '소스 확장을 위해 호환되는 사용자 정의 API 플러그인을 가져옵니다',
noScriptWarning: '먼저 낙설 음원 스크립트를 가져오세요',
noSelectionWarning: '먼저 낙설 음원 소스를 선택하세요',
notFound: '음원이 존재하지 않습니다',
switched: '음원으로 전환되었습니다: {name}',
deleted: '음원이 삭제되었습니다: {name}',
enterUrl: '스크립트 URL을 입력하세요',
invalidUrl: '유효하지 않은 URL 형식',
invalidScript: '유효하지 않은 낙설 음원 스크립트입니다 (globalThis.lx 코드를 찾을 수 없음)',
nameRequired: '이름은 비워둘 수 없습니다',
renameSuccess: '이름이 변경되었습니다'
}
}
},
application: {
closeAction: '닫기 동작',
closeActionDesc: '창을 닫을 때의 동작 선택',
closeOptions: {
ask: '매번 묻기',
minimize: '트레이로 최소화',
close: '직접 종료'
},
shortcut: '단축키 설정',
shortcutDesc: '전역 단축키 사용자 정의',
download: '다운로드 관리',
downloadDesc: '다운로드 목록 버튼을 항상 표시할지 여부',
unlimitedDownload: '무제한 다운로드',
unlimitedDownloadDesc:
'활성화하면 음악을 무제한으로 다운로드합니다 (다운로드 실패가 발생할 수 있음), 기본 제한 300곡',
downloadPath: '다운로드 디렉토리',
downloadPathDesc: '음악 파일의 다운로드 위치 선택',
remoteControl: '원격 제어',
remoteControlDesc: '원격 제어 기능 설정'
},
network: {
apiPort: '음악 API 포트',
apiPortDesc: '수정 후 앱을 재시작해야 합니다',
proxy: '프록시 설정',
proxyDesc: '음악에 액세스할 수 없을 때 프록시를 활성화할 수 있습니다',
proxyHost: '프록시 주소',
proxyHostPlaceholder: '프록시 주소를 입력하세요',
proxyPort: '프록시 포트',
proxyPortPlaceholder: '프록시 포트를 입력하세요',
realIP: 'realIP 설정',
realIPDesc:
'제한으로 인해 이 프로젝트는 해외에서 사용할 때 제한을 받을 수 있으며, realIP 매개변수를 사용하여 국내 IP를 전달하여 해결할 수 있습니다',
messages: {
proxySuccess: '프록시 설정이 저장되었습니다. 앱을 재시작한 후 적용됩니다',
proxyError: '입력이 올바른지 확인하세요',
realIPSuccess: '실제 IP 설정이 저장되었습니다',
realIPError: '유효한 IP 주소를 입력하세요'
}
},
system: {
cache: '캐시 관리',
cacheDesc: '캐시 지우기',
cacheClearTitle: '지울 캐시 유형을 선택하세요:',
cacheTypes: {
history: {
label: '재생 기록',
description: '재생한 곡 기록 지우기'
},
favorite: {
label: '즐겨찾기 기록',
description: '로컬 즐겨찾기 곡 기록 지우기 (클라우드 즐겨찾기에는 영향 없음)'
},
user: {
label: '사용자 데이터',
description: '로그인 정보 및 사용자 관련 데이터 지우기'
},
settings: {
label: '앱 설정',
description: '앱의 모든 사용자 정의 설정 지우기'
},
downloads: {
label: '다운로드 기록',
description: '다운로드 기록 지우기 (다운로드된 파일은 삭제되지 않음)'
},
resources: {
label: '음악 리소스',
description: '로드된 음악 파일, 가사 등 리소스 캐시 지우기'
},
lyrics: {
label: '가사 리소스',
description: '로드된 가사 리소스 캐시 지우기'
}
},
restart: '재시작',
restartDesc: '앱 재시작',
messages: {
clearSuccess: '지우기 성공, 일부 설정은 재시작 후 적용됩니다'
}
},
about: {
version: '버전',
checkUpdate: '업데이트 확인',
checking: '확인 중...',
latest: '현재 최신 버전입니다',
hasUpdate: '새 버전 발견',
gotoUpdate: '업데이트하러 가기',
gotoGithub: 'Github로 이동',
author: '작성자',
authorDesc: 'algerkong 별점🌟 부탁드려요',
messages: {
checkError: '업데이트 확인 실패, 나중에 다시 시도하세요'
}
},
validation: {
selectProxyProtocol: '프록시 프로토콜을 선택하세요',
proxyHost: '프록시 주소를 입력하세요',
portNumber: '유효한 포트 번호를 입력하세요 (1-65535)'
},
lyricSettings: {
title: '가사 설정',
tabs: {
display: '표시',
interface: '인터페이스',
typography: '텍스트',
background: '배경',
mobile: '모바일'
},
pureMode: '순수 모드',
hideCover: '커버 숨기기',
centerDisplay: '중앙 표시',
showTranslation: '번역 표시',
hideLyrics: '가사 숨기기',
hidePlayBar: '재생바 숨기기',
hideMiniPlayBar: '미니 재생바 숨기기',
showMiniPlayBar: '미니 재생바 표시',
backgroundTheme: '배경 테마',
themeOptions: {
default: '기본',
light: '밝음',
dark: '어둠'
},
fontSize: '폰트 크기',
fontSizeMarks: {
small: '작음',
medium: '중간',
large: '큼'
},
fontWeight: '글꼴 두께',
fontWeightMarks: {
thin: '가늘게',
normal: '보통',
bold: '굵게'
},
letterSpacing: '글자 간격',
letterSpacingMarks: {
compact: '좁음',
default: '기본',
loose: '넓음'
},
lineHeight: '줄 높이',
lineHeightMarks: {
compact: '좁음',
default: '기본',
loose: '넓음'
},
contentWidth: '콘텐츠 너비',
mobileLayout: '모바일 레이아웃',
layoutOptions: {
default: '기본',
ios: 'iOS 스타일',
android: '안드로이드 스타일'
},
mobileCoverStyle: '커버 스타일',
coverOptions: {
record: '레코드',
square: '정사각형',
full: '전체화면'
},
lyricLines: '가사 줄 수',
mobileUnavailable: '이 설정은 모바일에서만 사용 가능합니다',
// 배경 설정
background: {
useCustomBackground: '사용자 정의 배경 사용',
backgroundMode: '배경 모드',
modeOptions: {
solid: '단색',
gradient: '그라데이션',
image: '이미지',
css: 'CSS'
},
solidColor: '색상 선택',
presetColors: '프리셋 색상',
customColor: '사용자 정의 색상',
gradientEditor: '그라데이션 편집기',
gradientColors: '그라데이션 색상',
gradientDirection: '그라데이션 방향',
directionOptions: {
toBottom: '위에서 아래로',
toRight: '왼쪽에서 오른쪽으로',
toBottomRight: '왼쪽 위에서 오른쪽 아래로',
angle45: '45도',
toTop: '아래에서 위로',
toLeft: '오른쪽에서 왼쪽으로'
},
addColor: '색상 추가',
removeColor: '색상 제거',
imageUpload: '이미지 업로드',
imagePreview: '이미지 미리보기',
clearImage: '이미지 지우기',
imageBlur: '흐림',
imageBrightness: '밝기',
customCss: '사용자 정의 CSS 스타일',
customCssPlaceholder: 'CSS 스타일 입력, 예: background: linear-gradient(...)',
customCssHelp: '모든 CSS background 속성 지원',
reset: '기본값으로 재설정',
fileSizeLimit: '이미지 크기 제한: 20MB',
invalidImageFormat: '잘못된 이미지 형식',
imageTooLarge: '이미지가 너무 큽니다. 20MB 미만의 이미지를 선택하세요'
}
},
translationEngine: '가사 번역 엔진',
translationEngineOptions: {
none: '닫기',
opencc: 'OpenCC 중국어 번체'
},
themeColor: {
title: '가사 테마 색상',
presetColors: '미리 설정된 색상',
customColor: '사용자 정의 색상',
preview: '미리보기 효과',
previewText: '가사 효과',
colorNames: {
'spotify-green': 'Spotify 그린',
'apple-blue': '애플 블루',
'youtube-red': 'YouTube 레드',
orange: '활력 오렌지',
purple: '신비 퍼플',
pink: '벚꽃 핑크'
},
tooltips: {
openColorPicker: '색상 선택기 열기',
closeColorPicker: '색상 선택기 닫기'
},
placeholder: '#1db954'
},
shortcutSettings: {
title: '단축키 설정',
shortcut: '단축키',
shortcutDesc: '단축키 사용자 정의',
shortcutConflict: '단축키 충돌',
inputPlaceholder: '클릭하여 단축키 입력',
resetShortcuts: '기본값 복원',
disableAll: '모두 비활성화',
enableAll: '모두 활성화',
togglePlay: '재생/일시정지',
prevPlay: '이전 곡',
nextPlay: '다음 곡',
volumeUp: '볼륨 증가',
volumeDown: '볼륨 감소',
toggleFavorite: '즐겨찾기/즐겨찾기 취소',
toggleWindow: '창 표시/숨기기',
scopeGlobal: '전역',
scopeApp: '앱 내',
enabled: '활성화',
disabled: '비활성화',
messages: {
resetSuccess: '기본 단축키로 복원되었습니다. 저장을 잊지 마세요',
conflict: '충돌하는 단축키가 있습니다. 다시 설정하세요',
saveSuccess: '단축키 설정이 저장되었습니다',
saveError: '단축키 저장 실패, 다시 시도하세요',
cancelEdit: '수정이 취소되었습니다',
disableAll: '모든 단축키가 비활성화되었습니다. 저장을 잊지 마세요',
enableAll: '모든 단축키가 활성화되었습니다. 저장을 잊지 마세요'
}
},
remoteControl: {
title: '원격 제어',
enable: '원격 제어 활성화',
port: '서비스 포트',
allowedIps: '허용된 IP 주소',
addIp: 'IP 추가',
emptyListHint: '빈 목록은 모든 IP 액세스를 허용함을 의미합니다',
saveSuccess: '원격 제어 설정이 저장되었습니다',
accessInfo: '원격 제어 액세스 주소:'
},
cookie: {
title: 'Cookie 설정',
description: '넷이즈 클라우드 뮤직의 Cookie를 입력하세요:',
placeholder: '완전한 Cookie를 붙여넣으세요...',
help: {
format: 'Cookie는 일반적으로 "MUSIC_U="로 시작합니다',
source: '브라우저 개발자 도구의 네트워크 요청에서 얻을 수 있습니다',
storage: 'Cookie 설정 후 자동으로 로컬 저장소에 저장됩니다'
},
action: {
save: 'Cookie 저장',
paste: '붙여넣기',
clear: '지우기'
},
validation: {
required: 'Cookie를 입력하세요',
format: 'Cookie 형식이 올바르지 않을 수 있습니다. MUSIC_U가 포함되어 있는지 확인하세요'
},
message: {
saveSuccess: 'Cookie 저장 성공',
saveError: 'Cookie 저장 실패',
pasteSuccess: '붙여넣기 성공',
pasteError: '붙여넣기 실패, 수동으로 복사하세요'
},
info: {
length: '현재 길이: {length} 문자'
}
}
};

View File

@@ -0,0 +1,28 @@
export default {
menu: {
play: '재생',
playNext: '다음에 재생',
download: '곡 다운로드',
addToPlaylist: '플레이리스트에 추가',
favorite: '좋아요',
unfavorite: '좋아요 취소',
removeFromPlaylist: '플레이리스트에서 삭제',
dislike: '싫어요',
undislike: '싫어요 취소'
},
message: {
downloading: '다운로드 중입니다. 잠시 기다려주세요...',
downloadFailed: '다운로드 실패',
downloadQueued: '다운로드 대기열에 추가됨',
addedToNextPlay: '다음 재생에 추가됨',
getUrlFailed: '음악 다운로드 주소 가져오기 실패, 로그인 상태를 확인하세요'
},
dialog: {
dislike: {
title: '알림!',
content: '이 곡을 싫어한다고 확인하시겠습니까? 다시 들어가면 일일 추천에서 제외됩니다.',
positiveText: '싫어요',
negativeText: '취소'
}
}
};

View File

@@ -0,0 +1,53 @@
export default {
profile: {
followers: '팔로워',
following: '팔로잉',
level: '레벨'
},
playlist: {
created: '생성한 플레이리스트',
mine: '내가 만든',
trackCount: '{count}곡',
playCount: '{count}회 재생'
},
tabs: {
created: '생성',
favorite: '즐겨찾기',
album: '앨범'
},
ranking: {
title: '음악 청취 순위',
playCount: '{count}회'
},
follow: {
title: '팔로잉 목록',
viewPlaylist: '플레이리스트 보기',
noFollowings: '팔로잉이 없습니다',
loadMore: '더 보기',
noSignature: '이 사람은 게을러서 아무것도 남기지 않았습니다',
userFollowsTitle: '의 팔로잉',
myFollowsTitle: '내 팔로잉'
},
follower: {
title: '팔로워 목록',
noFollowers: '팔로워가 없습니다',
loadMore: '더 보기',
userFollowersTitle: '의 팔로워',
myFollowersTitle: '내 팔로워'
},
detail: {
playlists: '플레이리스트',
records: '음악 청취 순위',
noPlaylists: '플레이리스트가 없습니다',
noRecords: '음악 청취 기록이 없습니다',
artist: '아티스트',
noSignature: '이 사람은 게을러서 아무것도 남기지 않았습니다',
invalidUserId: '사용자 ID가 유효하지 않습니다',
noRecordPermission: '{name}님이 음악 청취 순위를 보지 못하게 했습니다'
},
message: {
loadFailed: '사용자 페이지 로드 실패',
deleteSuccess: '삭제 성공',
deleteFailed: '삭제 실패'
}
};

View File

@@ -0,0 +1,51 @@
export default {
player: {
loading: '听书加载中...',
retry: '重试',
playNow: '立即播放',
loadingTitle: '加载中...',
totalDuration: '总时长: {duration}',
partsList: '分P列表 (共{count}集)',
playStarted: '已开始播放',
switchingPart: '切换到分P: {part}',
preloadingNext: '预加载下一个分P: {part}',
playingCurrent: '播放当前选中的分P: {name}',
num: '万',
errors: {
invalidVideoId: '视频ID无效',
loadVideoDetailFailed: '获取视频详情失败',
loadPartInfoFailed: '无法加载视频分P信息',
loadAudioUrlFailed: '获取音频播放地址失败',
videoDetailNotLoaded: '视频详情未加载',
missingParams: '缺少必要参数',
noAvailableAudioUrl: '未找到可用的音频地址',
loadPartAudioFailed: '加载分P音频URL失败',
audioListEmpty: '音频列表为空,请重试',
currentPartNotFound: '未找到当前分P的音频',
audioUrlFailed: '获取音频URL失败',
playFailed: '播放失败,请重试',
getAudioUrlFailed: '获取音频地址失败,请重试',
audioNotFound: '未找到对应的音频,请重试',
preloadFailed: '预加载下一个分P失败',
switchPartFailed: '切换分P时加载音频URL失败'
},
console: {
loadingDetail: '加载B站视频详情',
detailData: 'B站视频详情数据',
multipleParts: '视频有多个分P共{count}个',
noPartsData: '视频无分P或分P数据为空',
loadingAudioSource: '加载音频源',
generatedAudioList: '已生成音频列表,共{count}首',
getDashAudioUrl: '获取到dash音频URL',
getDurlAudioUrl: '获取到durl音频URL',
loadingPartAudio: '加载分P音频URL: {part}, cid: {cid}',
loadPartAudioFailed: '加载分P音频URL失败: {part}',
switchToPart: '切换到分P: {part}',
audioNotFoundInList: '未找到对应的音频项',
preparingToPlay: '准备播放当前选中的分P: {name}',
preloadingNextPart: '预加载下一个分P: {part}',
playingSelectedPart: '播放当前选中的分P: {name}音频URL: {url}',
preloadNextFailed: '预加载下一个分P失败'
}
}
};

View File

@@ -27,6 +27,7 @@ export default {
refresh: '刷新',
retry: '重试',
reset: '重置',
back: '返回',
copySuccess: '已复制到剪贴板',
copyFailed: '复制失败',
validation: {
@@ -42,6 +43,8 @@ export default {
collapse: '收起',
songCount: '{count}首',
language: '语言',
today: '今天',
yesterday: '昨天',
tray: {
show: '显示',
quit: '退出',

View File

@@ -50,6 +50,27 @@ export default {
copyFailed: '复制失败',
backgroundDownload: '后台下载'
},
disclaimer: {
title: '使用须知',
warning: '本应用为开发测试版本,功能尚不完善,可能存在较多问题和 Bug仅供学习交流使用。',
item1: '本应用仅供个人学习、研究和技术交流使用,请勿用于任何商业用途。',
item2: '请在下载后 24 小时内删除,如需长期使用请支持正版音乐服务。',
item3: '使用本应用即表示您理解并承担相关风险,开发者不对任何损失负责。',
agree: '我已阅读并同意',
disagree: '不同意并退出'
},
donate: {
title: '支持开发者',
subtitle: '您的支持是我前进的动力',
tip: '捐赠完全自愿,不捐赠也可以正常使用所有功能,感谢您的理解与支持!',
wechat: '微信',
alipay: '支付宝',
wechatQR: '微信收款码',
alipayQR: '支付宝收款码',
scanTip: '请使用手机扫描上方二维码进行捐赠',
enterApp: '进入应用',
noForce: '不强制捐赠,点击即可进入'
},
coffee: {
title: '请我喝咖啡',
alipay: '支付宝',
@@ -58,7 +79,7 @@ export default {
wechatQR: '微信收款码',
coffeeDesc: '一杯咖啡,一份支持',
coffeeDescLinkText: '查看更多',
qqGroup: 'QQ频道algermusic',
groupText: '微信公众号AlgerMusic',
messages: {
copySuccess: '已复制到剪贴板'
},
@@ -88,7 +109,11 @@ export default {
restart: '重启',
refresh: '刷新',
currentVersion: '当前版本',
searchPlaceholder: '搜索点什么吧...'
searchPlaceholder: '搜索点什么吧...',
zoom: '页面缩放',
zoom100: '标准缩放100%',
resetZoom: '点击重置缩放',
zoomDefault: '标准缩放'
},
titleBar: {
closeTitle: '请选择关闭方式',
@@ -113,6 +138,78 @@ export default {
cancelCollect: '取消收藏',
addToPlaylist: '添加到播放列表',
addToPlaylistSuccess: '添加到播放列表成功',
songsAlreadyInPlaylist: '歌曲已存在于播放列表中'
}
songsAlreadyInPlaylist: '歌曲已存在于播放列表中',
historyRecommend: '历史日推',
fetchDatesFailed: '获取日期列表失败',
fetchSongsFailed: '获取歌曲列表失败',
noSongs: '暂无歌曲'
},
playlist: {
import: {
button: '歌单导入',
title: '歌单导入',
description: '支持通过元数据/文字/链接三种方式导入歌单',
linkTab: '链接导入',
textTab: '文字导入',
localTab: '元数据导入',
linkPlaceholder: '请输入歌单链接,每行一个',
textPlaceholder: '请输入歌曲信息,格式为:歌曲名 歌手名',
localPlaceholder: '请输入JSON格式的歌曲元数据',
linkTips: '支持的链接来源:',
linkTip1: '将歌单分享到微信/微博/QQ后复制链接',
linkTip2: '直接复制歌单/个人主页链接',
linkTip3: '直接复制文章链接',
textTips: '请输入歌曲信息,每行一首歌',
textFormat: '格式:歌曲名 歌手名',
localTips: '请添加歌曲元数据',
localFormat: '格式示例:',
songNamePlaceholder: '歌曲名称',
artistNamePlaceholder: '艺术家名称',
albumNamePlaceholder: '专辑名称',
addSongButton: '添加歌曲',
addLinkButton: '添加链接',
importToStarPlaylist: '导入到我喜欢的音乐',
playlistNamePlaceholder: '请输入歌单名称',
importButton: '开始导入',
emptyLinkWarning: '请输入歌单链接',
emptyTextWarning: '请输入歌曲信息',
emptyLocalWarning: '请输入歌曲元数据',
invalidJsonFormat: 'JSON格式不正确',
importSuccess: '导入任务创建成功',
importFailed: '导入失败',
importStatus: '导入状态',
refresh: '刷新',
taskId: '任务ID',
status: '状态',
successCount: '成功数量',
failReason: '失败原因',
unknownError: '未知错误',
statusPending: '等待处理',
statusProcessing: '处理中',
statusSuccess: '导入成功',
statusFailed: '导入失败',
statusUnknown: '未知状态',
taskList: '任务列表',
taskListTitle: '导入任务列表',
action: '操作',
select: '选择',
fetchTaskListFailed: '获取任务列表失败',
noTasks: '暂无导入任务',
clearTasks: '清除任务',
clearTasksConfirmTitle: '确认清除',
clearTasksConfirmContent: '确定要清除所有导入任务记录吗?此操作不可恢复。',
confirm: '确认',
cancel: '取消',
clearTasksSuccess: '任务列表已清除',
clearTasksFailed: '清除任务列表失败'
}
},
settings: '设置',
user: '用户',
toplist: '排行榜',
history: '收藏历史',
list: '歌单',
mv: 'MV',
home: '首页',
search: '搜索'
};

View File

@@ -3,6 +3,7 @@ export default {
localMusic: '本地音乐',
count: '共 {count} 首歌曲',
clearAll: '清空记录',
settings: '设置',
tabs: {
downloading: '下载中',
downloaded: '已下载'
@@ -44,5 +45,43 @@ export default {
downloadComplete: '{filename} 下载完成',
downloadFailed: '{filename} 下载失败: {error}'
},
loading: '加载中...'
loading: '加载中...',
playStarted: '开始播放: {name}',
playFailed: '播放失败: {name}',
path: {
copied: '路径已复制到剪贴板',
copyFailed: '复制路径失败'
},
settingsPanel: {
title: '下载设置',
path: '下载位置',
pathDesc: '设置音乐文件下载保存的位置',
pathPlaceholder: '请选择下载路径',
noPathSelected: '请先选择下载路径',
select: '选择文件夹',
open: '打开文件夹',
fileFormat: '文件名格式',
fileFormatDesc: '设置下载音乐时的文件命名格式',
customFormat: '自定义格式',
separator: '分隔符',
separators: {
dash: '空格-空格',
underscore: '下划线',
space: '空格'
},
dragToArrange: '拖动排序或使用箭头按钮调整顺序:',
formatVariables: '可用变量',
preview: '预览效果:',
saveSuccess: '下载设置已保存',
presets: {
songArtist: '歌曲名 - 歌手名',
artistSong: '歌手名 - 歌曲名',
songOnly: '仅歌曲名'
},
components: {
songName: '歌曲名',
artistName: '歌手名',
albumName: '专辑名'
}
}
};

View File

@@ -1,5 +1,44 @@
export default {
title: '播放历史',
heatmapTitle: '热力图',
playCount: '{count}',
getHistoryFailed: '获取历史记录失败'
getHistoryFailed: '获取历史记录失败',
categoryTabs: {
songs: '歌曲',
playlists: '歌单',
albums: '专辑'
},
tabs: {
all: '全部记录',
local: '本地记录',
cloud: '云端记录'
},
getCloudRecordFailed: '获取云端记录失败',
needLogin: '请使用cookie登录以查看云端记录',
merging: '正在合并记录...',
noDescription: '暂无描述',
noData: '暂无记录',
heatmap: {
title: '播放热力图',
loading: '正在加载数据...',
unit: '次播放',
footerText: '鼠标悬停查看详细信息',
playCount: '播放 {count} 次',
topSongs: '当天热门歌曲',
times: '次',
totalPlays: '总播放次数',
activeDays: '活跃天数',
noData: '暂无播放记录',
colorTheme: '配色方案',
colors: {
green: '绿色',
blue: '蓝色',
orange: '橙色',
purple: '紫色',
red: '红色'
},
mostPlayedSong: '播放最多的歌曲',
mostActiveDay: '最活跃的一天',
latestNightSong: '最晚播放的歌曲'
}
};

View File

@@ -1,29 +0,0 @@
import artist from './artist';
import common from './common';
import comp from './comp';
import donation from './donation';
import download from './download';
import favorite from './favorite';
import history from './history';
import login from './login';
import player from './player';
import search from './search';
import settings from './settings';
import songItem from './songItem';
import user from './user';
export default {
common,
donation,
favorite,
history,
login,
player,
search,
settings,
songItem,
user,
download,
comp,
artist
};

View File

@@ -1,22 +1,62 @@
export default {
title: {
qr: '扫码登录',
phone: '手机号登录'
phone: '手机号登录',
cookie: 'Cookie登录',
uid: 'UID登录'
},
qrTip: '使用网易云APP扫码登录',
phoneTip: '使用网易云账号登录',
tokenTip: '输入有效的网易云音乐Cookie即可登录',
uidTip: '输入用户ID快速登录',
placeholder: {
phone: '手机号',
password: '密码'
password: '密码',
cookie: '请输入网易云音乐Cookietoken',
uid: '请输入用户IDUID'
},
button: {
login: '登录',
switchToQr: '扫码登录',
switchToPhone: '手机号登录'
switchToPhone: '手机号登录',
switchToToken: '使用Cookie登录',
switchToUid: 'UID登录',
backToQr: '返回二维码登录',
cookieLogin: 'Cookie登录',
autoGetCookie: '自动获取Cookie',
refresh: '点击刷新',
refreshing: '刷新中...',
refreshQr: '刷新二维码'
},
message: {
loginSuccess: '登录成功',
loginFailed: '登录失败',
tokenLoginSuccess: 'Cookie登录成功',
uidLoginSuccess: 'UID登录成功',
loadError: '加载登录信息时出错',
qrCheckError: '检查二维码状态时出错'
}
qrCheckError: '检查二维码状态时出错',
tokenRequired: '请输入Cookie',
tokenInvalid: 'Cookie无效请检查后重试',
uidRequired: '请输入用户ID',
uidInvalid: '用户ID无效或用户不存在',
uidLoginFailed: 'UID登录失败请检查用户ID是否正确',
phoneRequired: '请输入手机号',
passwordRequired: '请输入密码',
phoneLoginFailed: '手机号登录失败,请检查手机号和密码是否正确',
autoGetCookieSuccess: '自动获取Cookie成功',
autoGetCookieFailed: '自动获取Cookie失败',
autoGetCookieTip: '将打开网易云音乐登录页面,请完成登录后关闭窗口',
qrCheckFailed: '检查二维码状态失败,请刷新重试',
qrLoading: '正在加载二维码...',
qrExpired: '二维码已过期,请点击刷新',
qrExpiredShort: '二维码已过期',
qrExpiredWarning: '二维码已过期,请点击刷新获取新的二维码',
qrScanned: '已扫码,请在手机上确认登录',
qrScannedShort: '已扫码',
qrScannedInfo: '已扫码,请在手机上确认登录',
qrConfirmed: '登录成功,正在跳转...',
qrGenerating: '正在生成二维码...'
},
qrTitle: '扫码登录网易云音乐',
uidWarning: '注意UID登录仅用于查看用户公开信息无法访问需要登录权限的功能'
};

View File

@@ -11,10 +11,14 @@ export default {
mute: '静音',
unmute: '取消静音',
songNum: '歌曲总数:{num}',
addCorrection: '提前 {num} 秒',
subtractCorrection: '延迟 {num} 秒',
playFailed: '当前歌曲播放失败,播放下一首',
parseFailedPlayNext: '歌曲解析失败,播放下一首',
consecutiveFailsError: '播放遇到错误,可能是网络波动或解析源失效,请切换播放列表或稍后重试',
playMode: {
sequence: '顺序播放',
loop: '循环播放',
loop: '单曲循环',
random: '随机播放'
},
fullscreen: {
@@ -27,7 +31,8 @@ export default {
list: '自动播放下一个'
},
lrc: {
noLrc: '暂无歌词, 请欣赏'
noLrc: '暂无歌词, 请欣赏',
noAutoScroll: '本歌词不支持自动滚动'
},
reparse: {
title: '选择解析音源',
@@ -36,7 +41,10 @@ export default {
failed: '重新解析失败',
warning: '请选择一个音源',
bilibiliNotSupported: 'B站视频不支持重新解析',
processing: '解析中...'
processing: '解析中...',
clear: '清除自定义音源',
customApiFailed: '自定义API解析失败正在尝试使用内置音源...',
customApiError: '自定义API请求出错正在尝试使用内置音源...'
},
playBar: {
expand: '展开歌词',
@@ -61,7 +69,17 @@ export default {
unFavorite: '已取消收藏{name}',
miniPlayBar: '迷你播放栏',
playbackSpeed: '播放速度',
advancedControls: '更多设置s',
advancedControls: '更多设置',
intelligenceMode: {
title: '心动模式',
needCookieLogin: '请使用 Cookie 方式登录后使用心动模式',
noFavoritePlaylist: '未找到我喜欢的音乐歌单',
noLikedSongs: '您还没有喜欢的歌曲',
loading: '正在加载心动模式',
success: '已加载 {count} 首歌曲',
failed: '获取心动模式列表失败',
error: '心动模式播放出错'
}
},
eq: {
title: '均衡器',
@@ -87,6 +105,11 @@ export default {
custom: '自定义'
}
},
// 播放器设置
settings: {
title: '播放设置',
playbackSpeed: '播放速度'
},
// 定时关闭功能相关
sleepTimer: {
title: '定时关闭',

View File

@@ -11,10 +11,21 @@ export default {
},
loading: {
more: '加载中...',
failed: '搜索失败'
failed: '搜索失败',
searching: '搜索中...'
},
noMore: '没有更多了',
error: {
searchFailed: '搜索失败'
}
},
search: {
single: '单曲',
album: '专辑',
playlist: '歌单',
mv: 'MV',
bilibili: 'B站'
},
history: '搜索历史',
hot: '热门搜索',
suggestions: '搜索建议'
};

View File

@@ -10,13 +10,23 @@ export default {
network: '网络设置',
system: '系统管理',
donation: '捐赠支持',
regard: '关于'
about: '关于'
},
basic: {
themeMode: '主题模式',
themeModeDesc: '切换日间/夜间主题',
autoTheme: '跟随系统',
manualTheme: '手动切换',
language: '语言设置',
languageDesc: '切换显示语言',
tokenManagement: 'Cookie管理',
tokenManagementDesc: '管理网易云音乐登录Cookie',
tokenStatus: '当前Cookie状态',
tokenSet: '已设置',
tokenNotSet: '未设置',
setToken: '设置Cookie',
modifyToken: '修改Cookie',
clearToken: '清除Cookie',
font: '字体设置',
fontDesc: '选择字体,优先使用排在前面的字体',
fontScope: {
@@ -40,7 +50,14 @@ export default {
englishText: 'The quick brown fox jumps over the lazy dog',
japaneseText: 'あいうえお かきくけこ さしすせそ',
koreanText: '가나다라마 바사아자차 카타파하'
}
},
gpuAcceleration: 'GPU加速',
gpuAccelerationDesc: '启用或禁用硬件加速可以提高渲染性能但可能会增加GPU负载',
gpuAccelerationRestart: '更改GPU加速设置需要重启应用后生效',
gpuAccelerationChangeSuccess: 'GPU加速设置已更新重启应用后生效',
gpuAccelerationChangeError: 'GPU加速设置更新失败',
tabletMode: '平板模式',
tabletModeDesc: '启用后将在移动设备上使用PC样式界面适合平板等大屏设备'
},
playback: {
quality: '音质设置',
@@ -69,6 +86,64 @@ export default {
autoPlayDesc: '重新打开应用时是否自动继续播放',
showStatusBar: '是否显示状态栏控制功能',
showStatusBarContent: '可以在您的mac状态栏显示音乐控制功能(重启后生效)',
fallbackParser: 'GD音乐台(music.gdstudio.xyz)设置',
fallbackParserDesc:
'GD音乐台将自动尝试多个音乐平台进行解析无需额外配置。优先级高于其他解析方式但是请求可能较慢。感谢music.gdstudio.xyz\n',
parserGD: 'GD 音乐台 (内置)',
parserCustom: '自定义 API',
// 音源标签
sourceLabels: {
migu: '咪咕音乐',
kugou: '酷狗音乐',
pyncmd: '网易云(内置)',
bilibili: 'Bilibili',
gdmusic: 'GD音乐台',
custom: '自定义 API'
},
// 自定义API相关的提示
customApi: {
sectionTitle: '自定义 API 设置',
importConfig: '导入 JSON 配置',
currentSource: '当前音源',
notImported: '尚未导入自定义音源。',
importSuccess: '成功导入音源: {name}',
importFailed: '导入失败: {message}',
enableHint: '请先导入 JSON 配置文件才能启用',
status: {
imported: '已导入自定义音源',
notImported: '未导入'
}
},
lxMusic: {
tabs: {
sources: '音源选择',
lxMusic: '落雪音源',
customApi: '自定义API'
},
scripts: {
title: '已导入的音源脚本',
importLocal: '本地导入',
importOnline: '在线导入',
urlPlaceholder: '输入落雪音源脚本 URL',
importBtn: '导入',
empty: '暂无已导入的落雪音源',
notConfigured: '未配置 (请去落雪音源Tab配置)',
importHint: '导入兼容的自定义 API 插件以扩展音源',
noScriptWarning: '请先导入落雪音源脚本',
noSelectionWarning: '请先选择一个落雪音源',
notFound: '音源不存在',
switched: '已切换到音源: {name}',
deleted: '已删除音源: {name}',
enterUrl: '请输入脚本 URL',
invalidUrl: '无效的 URL 格式',
invalidScript: '无效的落雪音源脚本,未找到 globalThis.lx 相关代码',
nameRequired: '名称不能为空',
renameSuccess: '重命名成功'
}
}
},
application: {
closeAction: '关闭行为',
@@ -167,19 +242,41 @@ export default {
portNumber: '请输入有效的端口号(1-65535)'
},
lyricSettings: {
title: '页面设置',
title: '歌词设置',
tabs: {
display: '显示',
interface: '界面',
typography: '文字',
background: '背景',
mobile: '移动端'
},
pureMode: '纯净模式',
hideCover: '隐藏封面',
centerDisplay: '居中显示',
showTranslation: '显示翻译',
hideLyrics: '隐藏歌词',
hidePlayBar: '隐藏播放栏',
hideMiniPlayBar: '隐藏迷你播放栏',
showMiniPlayBar: '显示迷你播放栏',
backgroundTheme: '背景主题',
themeOptions: {
default: '默认',
light: '亮色',
dark: '暗色'
},
fontSize: '字体大小',
fontSizeMarks: {
small: '小',
medium: '中',
large: '大'
},
letterSpacing: '文字间距',
fontWeight: '字体粗细',
fontWeightMarks: {
thin: '细',
normal: '常规',
bold: '粗'
},
letterSpacing: '字间距',
letterSpacingMarks: {
compact: '紧凑',
default: '默认',
@@ -191,20 +288,86 @@ export default {
default: '默认',
loose: '宽松'
},
backgroundTheme: '背景主题',
themeOptions: {
contentWidth: '内容区宽度',
mobileLayout: '移动端布局',
layoutOptions: {
default: '默认',
light: '亮色',
dark: '暗色'
ios: 'iOS风格',
android: '安卓风格'
},
hideMiniPlayBar: '隐藏迷你播放栏',
hideLyrics: '隐藏歌词',
tabs: {
interface: '界面',
typography: '文字',
display: '显示'
mobileCoverStyle: '封面样式',
coverOptions: {
record: '唱片',
square: '方形',
full: '全屏'
},
lyricLines: '歌词行数',
mobileUnavailable: '此设置仅在移动端可用',
// 背景设置
background: {
useCustomBackground: '使用自定义背景',
backgroundMode: '背景模式',
modeOptions: {
solid: '纯色',
gradient: '渐变',
image: '图片',
css: 'CSS'
},
solidColor: '选择颜色',
presetColors: '预设颜色',
customColor: '自定义颜色',
gradientEditor: '渐变编辑器',
gradientColors: '渐变颜色',
gradientDirection: '渐变方向',
directionOptions: {
toBottom: '上到下',
toRight: '左到右',
toBottomRight: '左上到右下',
angle45: '45度',
toTop: '下到上',
toLeft: '右到左'
},
addColor: '添加颜色',
removeColor: '移除颜色',
imageUpload: '上传图片',
imagePreview: '图片预览',
clearImage: '清除图片',
imageBlur: '模糊度',
imageBrightness: '明暗度',
customCss: '自定义 CSS 样式',
customCssPlaceholder: '输入 CSS 样式,如: background: linear-gradient(...)',
customCssHelp: '支持任意 CSS background 属性',
reset: '重置为默认',
fileSizeLimit: '图片大小限制: 20MB',
invalidImageFormat: '无效的图片格式',
imageTooLarge: '图片过大,请选择小于 20MB 的图片'
}
},
translationEngine: '歌詞翻譯引擎',
translationEngineOptions: {
none: '关闭',
opencc: 'OpenCC 繁化'
},
themeColor: {
title: '歌词主题色',
presetColors: '预设颜色',
customColor: '自定义颜色',
preview: '预览效果',
previewText: '歌词效果',
colorNames: {
'spotify-green': 'Spotify 绿',
'apple-blue': '苹果蓝',
'youtube-red': 'YouTube 红',
orange: '活力橙',
purple: '神秘紫',
pink: '樱花粉'
},
tooltips: {
openColorPicker: '打开色板',
closeColorPicker: '关闭色板'
},
placeholder: '#1db954'
},
shortcutSettings: {
title: '快捷键设置',
shortcut: '快捷键',
@@ -243,6 +406,34 @@ export default {
addIp: '添加IP',
emptyListHint: '空列表表示允许所有IP访问',
saveSuccess: '远程控制设置已保存',
accessInfo: '远程控制访问地址:',
accessInfo: '远程控制访问地址:'
},
cookie: {
title: 'Cookie设置',
description: '请输入网易云音乐的Cookie',
placeholder: '请粘贴完整的Cookie...',
help: {
format: 'Cookie通常以 "MUSIC_U=" 开头',
source: '可以从浏览器开发者工具的网络请求中获取',
storage: 'Cookie设置后将自动保存到本地存储'
},
action: {
save: '保存Cookie',
paste: '粘贴',
clear: '清空'
},
validation: {
required: '请输入Cookie',
format: 'Cookie格式可能不正确请检查是否包含MUSIC_U'
},
message: {
saveSuccess: 'Cookie保存成功',
saveError: 'Cookie保存失败',
pasteSuccess: '粘贴成功',
pasteError: '粘贴失败,请手动复制'
},
info: {
length: '当前长度:{length} 字符'
}
}
};

View File

@@ -8,7 +8,7 @@ export default {
unfavorite: '取消喜欢',
removeFromPlaylist: '从歌单中删除',
dislike: '不喜欢',
undislike: '取消不喜欢',
undislike: '取消不喜欢'
},
message: {
downloading: '正在下载中,请稍候...',

View File

@@ -10,6 +10,11 @@ export default {
trackCount: '{count}首',
playCount: '播放{count}次'
},
tabs: {
created: '创建',
favorite: '收藏',
album: '专辑'
},
ranking: {
title: '听歌排行',
playCount: '{count}次'

View File

@@ -0,0 +1,5 @@
export default {
hotSongs: '熱門歌曲',
albums: '專輯',
description: '藝人介紹'
};

View File

@@ -0,0 +1,51 @@
export default {
player: {
loading: '聽書載入中...',
retry: '重試',
playNow: '立即播放',
loadingTitle: '載入中...',
totalDuration: '總時長: {duration}',
partsList: '分P列表 (共{count}集)',
playStarted: '已開始播放',
switchingPart: '切換到分P: {part}',
preloadingNext: '預載入下一個分P: {part}',
playingCurrent: '播放當前選中的分P: {name}',
num: '萬',
errors: {
invalidVideoId: '影片ID無效',
loadVideoDetailFailed: '獲取影片詳情失敗',
loadPartInfoFailed: '無法載入影片分P資訊',
loadAudioUrlFailed: '獲取音訊播放地址失敗',
videoDetailNotLoaded: '影片詳情未載入',
missingParams: '缺少必要參數',
noAvailableAudioUrl: '未找到可用的音訊地址',
loadPartAudioFailed: '載入分P音訊URL失敗',
audioListEmpty: '音訊列表為空,請重試',
currentPartNotFound: '未找到當前分P的音訊',
audioUrlFailed: '獲取音訊URL失敗',
playFailed: '播放失敗,請重試',
getAudioUrlFailed: '獲取音訊地址失敗,請重試',
audioNotFound: '未找到對應的音訊,請重試',
preloadFailed: '預載入下一個分P失敗',
switchPartFailed: '切換分P時載入音訊URL失敗'
},
console: {
loadingDetail: '載入B站影片詳情',
detailData: 'B站影片詳情資料',
multipleParts: '影片有多個分P共{count}個',
noPartsData: '影片無分P或分P資料為空',
loadingAudioSource: '載入音訊來源',
generatedAudioList: '已生成音訊列表,共{count}首',
getDashAudioUrl: '獲取到dash音訊URL',
getDurlAudioUrl: '獲取到durl音訊URL',
loadingPartAudio: '載入分P音訊URL: {part}, cid: {cid}',
loadPartAudioFailed: '載入分P音訊URL失敗: {part}',
switchToPart: '切換到分P: {part}',
audioNotFoundInList: '未找到對應的音訊項目',
preparingToPlay: '準備播放當前選中的分P: {name}',
preloadingNextPart: '預載入下一個分P: {part}',
playingSelectedPart: '播放當前選中的分P: {name}音訊URL: {url}',
preloadNextFailed: '預載入下一個分P失敗'
}
}
};

View File

@@ -0,0 +1,58 @@
export default {
play: '播放',
next: '下一首',
previous: '上一首',
volume: '音量',
settings: '設定',
search: '搜尋',
loading: '載入中...',
loadingMore: '載入更多...',
alipay: '支付寶',
wechat: '微信支付',
on: '開啟',
off: '關閉',
show: '顯示',
hide: '隱藏',
confirm: '確認',
cancel: '取消',
configure: '設定',
open: '開啟',
modify: '修改',
success: '操作成功',
error: '操作失敗',
warning: '警告',
info: '提示',
save: '儲存',
delete: '刪除',
refresh: '重新整理',
retry: '重試',
reset: '重設',
back: '返回',
copySuccess: '已複製到剪貼簿',
copyFailed: '複製失敗',
validation: {
required: '此項為必填',
invalidInput: '輸入無效',
selectRequired: '請選擇一個選項',
numberRange: '請輸入 {min} 到 {max} 之間的數字'
},
viewMore: '查看更多',
noMore: '沒有更多了',
selectAll: '全選',
expand: '展開',
collapse: '收合',
songCount: '{count}首',
language: '語言',
today: '今天',
yesterday: '昨天',
tray: {
show: '顯示',
quit: '退出',
playPause: '播放/暫停',
prev: '上一首',
next: '下一首',
pause: '暫停',
play: '播放',
favorite: '收藏'
}
};

View File

@@ -0,0 +1,215 @@
export default {
installApp: {
description: '安裝應用程式,獲得更好的體驗',
noPrompt: '不再提示',
install: '立即安裝',
cancel: '暫不安裝',
download: '下載',
downloadFailed: '下載失敗',
downloadComplete: '下載完成',
downloadProblem: '下載遇到問題?去',
downloadProblemLinkText: '下載最新版本'
},
playlistDrawer: {
title: '新增至播放清單',
createPlaylist: '建立新播放清單',
cancelCreate: '取消建立',
create: '建立',
playlistName: '播放清單名稱',
privatePlaylist: '私人播放清單',
publicPlaylist: '公開播放清單',
createSuccess: '播放清單建立成功',
createFailed: '播放清單建立失敗',
addSuccess: '歌曲新增成功',
addFailed: '歌曲新增失敗',
private: '私人',
public: '公開',
count: '首歌曲',
loginFirst: '請先登入',
getPlaylistFailed: '取得播放清單失敗',
inputPlaylistName: '請輸入播放清單名稱'
},
update: {
title: '發現新版本',
currentVersion: '目前版本',
cancel: '暫不更新',
prepareDownload: '準備下載...',
downloading: '下載中...',
nowUpdate: '立即更新',
downloadFailed: '下載失敗,請重試或手動下載',
startFailed: '啟動下載失敗,請重試或手動下載',
noDownloadUrl: '未找到適合目前系統的安裝包,請手動下載',
installConfirmTitle: '安裝更新',
installConfirmContent: '是否關閉應用程式並安裝更新?',
manualInstallTip: '如果關閉應用程式後沒有正常彈出安裝程式,請至下載資料夾尋找檔案並手動開啟。',
yesInstall: '立即安裝',
noThanks: '稍後安裝',
fileLocation: '檔案位置',
copy: '複製路徑',
copySuccess: '路徑已複製到剪貼簿',
copyFailed: '複製失敗',
backgroundDownload: '背景下載'
},
disclaimer: {
title: '使用說明',
warning: '本程式為開發測試版本,功能尚未完善,可能存在諸多問題及臭蟲,僅供學習交流使用。',
item1: '本程式僅供個人學習、研究及技術交流之目的,不得用於任何商業用途。',
item2: '請在下載後 24 小時內刪除,若對您有所幫助,請支持正版音樂。',
item3: '使用本程式即代表您已了解並同意相關風險,開發者對任何損失概不負責。',
agree: '我已了解並同意',
disagree: '不同意並退出'
},
donate: {
title: '支援開發者',
subtitle: '您的支援是我持續更新的動力',
tip: '捐贈完全採自願原則。即使不捐贈,您依然可以正常使用所有功能。感謝您的理解與支援!',
wechat: '微信支付',
alipay: '支付寶',
wechatQR: '微信收款碼',
alipayQR: '支付寶收款碼',
scanTip: '請使用手機 App 掃描 QR Code 進行捐贈',
enterApp: '進入程式',
noForce: '捐贈並非強制,您可以點擊按鈕直接進入'
},
coffee: {
title: '請我喝杯咖啡',
alipay: '支付寶',
wechat: '微信支付',
alipayQR: '支付寶收款碼',
wechatQR: '微信收款碼',
coffeeDesc: '一杯咖啡,一份支持',
coffeeDescLinkText: '查看更多',
groupText: '微信公众号AlgerMusic',
messages: {
copySuccess: '已複製到剪貼簿'
},
donateList: '請我喝杯咖啡'
},
playlistType: {
title: '播放清單分類',
showAll: '顯示全部',
hide: '隱藏部分'
},
recommendAlbum: {
title: '最新專輯'
},
recommendSinger: {
title: '每日推薦',
songlist: '每日推薦清單'
},
recommendSonglist: {
title: '本週最熱音樂'
},
searchBar: {
login: '登入',
toLogin: '去登入',
logout: '登出',
set: '設定',
theme: '主題',
restart: '重新啟動',
refresh: '重新整理',
currentVersion: '目前版本',
searchPlaceholder: '搜尋點什麼吧...',
zoom: '頁面縮放',
zoom100: '標準縮放100%',
resetZoom: '點擊重設縮放',
zoomDefault: '標準縮放'
},
titleBar: {
closeTitle: '請選擇關閉方式',
minimizeToTray: '最小化到系統匣',
exitApp: '退出應用程式',
rememberChoice: '記住我的選擇',
closeApp: '關閉應用程式'
},
userPlayList: {
title: '{name}的常聽'
},
musicList: {
searchSongs: '搜尋歌曲',
noSearchResults: '沒有找到相關歌曲',
switchToNormal: '切換到預設版面',
switchToCompact: '切換到緊湊版面',
playAll: '播放全部',
collect: '收藏',
collectSuccess: '收藏成功',
cancelCollectSuccess: '取消收藏成功',
operationFailed: '操作失敗',
cancelCollect: '取消收藏',
addToPlaylist: '新增至播放清單',
addToPlaylistSuccess: '新增至播放清單成功',
songsAlreadyInPlaylist: '歌曲已存在於播放清單中',
historyRecommend: '歷史日推',
fetchDatesFailed: '獲取日期列表失敗',
fetchSongsFailed: '獲取歌曲列表失敗',
noSongs: '暫無歌曲'
},
playlist: {
import: {
button: '播放清單匯入',
title: '播放清單匯入',
description: '支援透過元資料/文字/連結三種方式匯入播放清單',
linkTab: '連結匯入',
textTab: '文字匯入',
localTab: '元資料匯入',
linkPlaceholder: '請輸入播放清單連結,每行一個',
textPlaceholder: '請輸入歌曲資訊,格式為:歌曲名 歌手名',
localPlaceholder: '請輸入JSON格式的歌曲元資料',
linkTips: '支援的連結來源:',
linkTip1: '將播放清單分享到微信/微博/QQ後複製連結',
linkTip2: '直接複製播放清單/個人主頁連結',
linkTip3: '直接複製文章連結',
textTips: '請輸入歌曲資訊,每行一首歌',
textFormat: '格式:歌曲名 歌手名',
localTips: '請新增歌曲元資料',
localFormat: '格式範例:',
songNamePlaceholder: '歌曲名稱',
artistNamePlaceholder: '藝人名稱',
albumNamePlaceholder: '專輯名稱',
addSongButton: '新增歌曲',
addLinkButton: '新增連結',
importToStarPlaylist: '匯入到我喜歡的音樂',
playlistNamePlaceholder: '請輸入播放清單名稱',
importButton: '開始匯入',
emptyLinkWarning: '請輸入播放清單連結',
emptyTextWarning: '請輸入歌曲資訊',
emptyLocalWarning: '請輸入歌曲元資料',
invalidJsonFormat: 'JSON格式不正確',
importSuccess: '匯入任務建立成功',
importFailed: '匯入失敗',
importStatus: '匯入狀態',
refresh: '重新整理',
taskId: '任務ID',
status: '狀態',
successCount: '成功數量',
failReason: '失敗原因',
unknownError: '未知錯誤',
statusPending: '等待處理',
statusProcessing: '處理中',
statusSuccess: '匯入成功',
statusFailed: '匯入失敗',
statusUnknown: '未知狀態',
taskList: '任務清單',
taskListTitle: '匯入任務清單',
action: '操作',
select: '選擇',
fetchTaskListFailed: '取得任務清單失敗',
noTasks: '暫無匯入任務',
clearTasks: '清除任務',
clearTasksConfirmTitle: '確認清除',
clearTasksConfirmContent: '確定要清除所有匯入任務記錄嗎?此操作不可恢復。',
confirm: '確認',
cancel: '取消',
clearTasksSuccess: '任務清單已清除',
clearTasksFailed: '清除任務清單失敗'
}
},
settings: '設定',
user: '使用者',
toplist: '排行榜',
history: '收藏歷史',
list: '播放清單',
mv: 'MV',
home: '首頁',
search: '搜尋'
};

View File

@@ -0,0 +1,8 @@
export default {
description: '您的捐贈將用於支持開發和維護工作,包括但不限於伺服器維護、域名續費等。',
message: '留言時可留下您的電子郵件或 github 名稱。',
refresh: '重新整理列表',
toDonateList: '請我喝杯咖啡',
noMessage: '暫無留言',
title: '捐贈列表'
};

View File

@@ -0,0 +1,87 @@
export default {
title: '下載管理',
localMusic: '本機音樂',
count: '共 {count} 首歌曲',
clearAll: '清空記錄',
settings: '設定',
tabs: {
downloading: '下載中',
downloaded: '已下載'
},
empty: {
noTasks: '暫無下載任務',
noDownloaded: '暫無已下載歌曲'
},
progress: {
total: '總進度: {progress}%'
},
status: {
downloading: '下載中',
completed: '已完成',
failed: '失敗',
unknown: '未知'
},
artist: {
unknown: '未知歌手'
},
delete: {
title: '刪除確認',
message: '確定要刪除歌曲 "{filename}" 嗎?此操作不可恢復。',
confirm: '確定刪除',
cancel: '取消',
success: '刪除成功',
failed: '刪除失敗',
fileNotFound: '檔案不存在或已被移動,已從記錄中移除',
recordRemoved: '檔案刪除失敗,但已從記錄中移除'
},
clear: {
title: '清空下載記錄',
message: '確定要清空所有下載記錄嗎?此操作不會刪除已下載的音樂檔案,但將清空所有記錄。',
confirm: '確定清空',
cancel: '取消',
success: '下載記錄已清空'
},
message: {
downloadComplete: '{filename} 下載完成',
downloadFailed: '{filename} 下載失敗: {error}'
},
loading: '載入中...',
playStarted: '開始播放: {name}',
playFailed: '播放失敗: {name}',
path: {
copied: '路徑已複製到剪貼簿',
copyFailed: '複製路徑失敗'
},
settingsPanel: {
title: '下載設定',
path: '下載位置',
pathDesc: '設定音樂檔案下載儲存的位置',
pathPlaceholder: '請選擇下載路徑',
noPathSelected: '請先選擇下載路徑',
select: '選擇資料夾',
open: '開啟資料夾',
fileFormat: '檔名格式',
fileFormatDesc: '設定下載音樂時的檔案命名格式',
customFormat: '自訂格式',
separator: '分隔符號',
separators: {
dash: '空格-空格',
underscore: '底線',
space: '空格'
},
dragToArrange: '拖曳排序或使用箭頭按鈕調整順序:',
formatVariables: '可用變數',
preview: '預覽效果:',
saveSuccess: '下載設定已儲存',
presets: {
songArtist: '歌曲名 - 歌手名',
artistSong: '歌手名 - 歌曲名',
songOnly: '僅歌曲名'
},
components: {
songName: '歌曲名',
artistName: '歌手名',
albumName: '專輯名'
}
}
};

View File

@@ -0,0 +1,13 @@
export default {
title: '我的收藏',
count: '共 {count} 首',
batchDownload: '批次下載',
download: '下載 ({count})',
emptyTip: '還沒有收藏歌曲',
downloadSuccess: '下載完成',
downloadFailed: '下載失敗',
downloading: '正在下載中,請稍候...',
selectSongsFirst: '請先選擇要下載的歌曲',
descending: '降',
ascending: '升'
};

View File

@@ -0,0 +1,44 @@
export default {
title: '播放歷史',
heatmapTitle: '熱力圖',
playCount: '{count}',
getHistoryFailed: '取得歷史記錄失敗',
categoryTabs: {
songs: '歌曲',
playlists: '歌單',
albums: '專輯'
},
tabs: {
all: '全部記錄',
local: '本地記錄',
cloud: '雲端記錄'
},
getCloudRecordFailed: '取得雲端記錄失敗',
needLogin: '請使用cookie登入以查看雲端記錄',
merging: '正在合併記錄...',
noDescription: '暫無描述',
noData: '暫無記錄',
heatmap: {
title: '播放熱力圖',
loading: '正在載入數據...',
unit: '次播放',
footerText: '滑鼠懸停查看詳細信息',
playCount: '播放 {count} 次',
topSongs: '當天熱門歌曲',
times: '次',
totalPlays: '總播放次數',
activeDays: '活躍天數',
noData: '暫無播放記錄',
colorTheme: '配色方案',
colors: {
green: '綠色',
blue: '藍色',
orange: '橙色',
purple: '紫色',
red: '紅色'
},
mostPlayedSong: '播放最多的歌曲',
mostActiveDay: '最活躍的一天',
latestNightSong: '最晚播放的歌曲'
}
};

View File

@@ -0,0 +1,62 @@
export default {
title: {
qr: '掃碼登入',
phone: '手機號登入',
cookie: 'Cookie登入',
uid: 'UID登入'
},
qrTip: '使用網易雲APP掃碼登入',
phoneTip: '使用網易雲帳號登入',
tokenTip: '輸入有效的網易雲音樂Cookie即可登入',
uidTip: '輸入使用者ID快速登入',
placeholder: {
phone: '手機號',
password: '密碼',
cookie: '請輸入網易雲音樂Cookietoken',
uid: '請輸入使用者IDUID'
},
button: {
login: '登入',
switchToQr: '掃碼登入',
switchToPhone: '手機號登入',
switchToToken: '使用Cookie登入',
switchToUid: 'UID登入',
backToQr: '返回二維碼登入',
cookieLogin: 'Cookie登入',
autoGetCookie: '自動取得Cookie',
refresh: '點擊刷新',
refreshing: '刷新中...',
refreshQr: '刷新二維碼'
},
message: {
loginSuccess: '登入成功',
tokenLoginSuccess: 'Cookie登入成功',
uidLoginSuccess: 'UID登入成功',
loadError: '載入登入資訊時出錯',
qrCheckError: '檢查二維碼狀態時出錯',
tokenRequired: '請輸入Cookie',
tokenInvalid: 'Cookie無效請檢查後重試',
uidRequired: '請輸入使用者ID',
uidInvalid: '使用者ID無效或使用者不存在',
uidLoginFailed: 'UID登入失敗請檢查使用者ID是否正確',
autoGetCookieSuccess: '自動取得Cookie成功',
autoGetCookieFailed: '自動取得Cookie失敗',
autoGetCookieTip: '將開啟網易雲音樂登入頁面,請完成登入後關閉視窗',
loginFailed: '登入失敗',
phoneRequired: '請輸入手機號',
passwordRequired: '請輸入密碼',
phoneLoginFailed: '手機號登入失敗,請檢查手機號和密碼是否正確',
qrCheckFailed: '檢查二維碼狀態失敗,請刷新重試',
qrLoading: '正在載入二維碼...',
qrExpired: '二維碼已過期,請點擊刷新',
qrExpiredShort: '二維碼已過期',
qrExpiredWarning: '二維碼已過期,請點擊刷新獲取新的二維碼',
qrScanned: '已掃碼,請在手機上確認登入',
qrScannedShort: '已掃碼',
qrScannedInfo: '已扫码,请在手机上确认登录',
qrConfirmed: '登入成功,正在跳轉...',
qrGenerating: '正在生成二維碼...'
},
qrTitle: '掃碼登入網易雲音樂',
uidWarning: '注意UID登入僅用於查看使用者公開資訊無法訪問需要登入權限的功能'
};

View File

@@ -0,0 +1,143 @@
export default {
nowPlaying: '正在播放',
playlist: '播放清單',
lyrics: '歌詞',
previous: '上一個',
play: '播放',
pause: '暫停',
next: '下一個',
volumeUp: '音量增加',
volumeDown: '音量減少',
mute: '靜音',
unmute: '取消靜音',
songNum: '歌曲總數:{num}',
addCorrection: '提前 {num} 秒',
subtractCorrection: '延遲 {num} 秒',
playFailed: '目前歌曲播放失敗,播放下一首',
parseFailedPlayNext: '歌曲解析失敗,播放下一首',
consecutiveFailsError: '播放遇到錯誤,可能是網路波動或解析源失效,請切換播放清單或稍後重試',
playMode: {
sequence: '順序播放',
loop: '單曲循環',
random: '隨機播放'
},
fullscreen: {
enter: '全螢幕',
exit: '退出全螢幕'
},
close: '關閉',
modeHint: {
single: '單曲循環',
list: '自動播放下一個'
},
lrc: {
noLrc: '暫無歌詞, 請欣賞',
noAutoScroll: '本歌詞不支持自動滾動'
},
reparse: {
title: '選擇解析音源',
desc: '點擊音源直接進行解析,下次播放此歌曲時將使用所選音源',
success: '重新解析成功',
failed: '重新解析失敗',
warning: '請選擇一個音源',
bilibiliNotSupported: 'B站影片不支援重新解析',
processing: '解析中...',
clear: '清除自訂音源',
customApiFailed: '自定義API解析失敗正在嘗試使用內置音源...',
customApiError: '自定義API請求出錯正在嘗試使用內置音源...'
},
playBar: {
expand: '展開歌詞',
collapse: '收合歌詞',
like: '喜歡',
lyric: '歌詞',
noSongPlaying: '沒有正在播放的歌曲',
eq: '等化器',
playList: '播放清單',
reparse: '重新解析',
playMode: {
sequence: '順序播放',
loop: '循環播放',
random: '隨機播放'
},
play: '開始播放',
pause: '暫停播放',
prev: '上一首',
next: '下一首',
volume: '音量',
favorite: '已收藏{name}',
unFavorite: '已取消收藏{name}',
miniPlayBar: '迷你播放列',
playbackSpeed: '播放速度',
advancedControls: '更多設定',
intelligenceMode: {
title: '心動模式',
needCookieLogin: '請使用 Cookie 方式登入後使用心動模式',
noFavoritePlaylist: '未找到我喜歡的音樂歌單',
noLikedSongs: '您還沒有喜歡的歌曲',
loading: '正在載入心動模式',
success: '已載入 {count} 首歌曲',
failed: '取得心動模式清單失敗',
error: '心動模式播放出錯'
}
},
eq: {
title: '等化器',
reset: '重設',
on: '開啟',
off: '關閉',
bass: '低音',
midrange: '中音',
treble: '高音',
presets: {
flat: '平坦',
pop: '流行',
rock: '搖滾',
classical: '古典',
jazz: '爵士',
electronic: '電子',
hiphop: '嘻哈',
rb: 'R&B',
metal: '金屬',
vocal: '人聲',
dance: '舞曲',
acoustic: '原聲',
custom: '自訂'
}
},
// 播放器設定
settings: {
title: '播放設定',
playbackSpeed: '播放速度'
},
// 定時關閉功能相關
sleepTimer: {
title: '定時關閉',
cancel: '取消定時',
timeMode: '按時間關閉',
songsMode: '按歌曲數關閉',
playlistEnd: '播放完清單後關閉',
afterPlaylist: '播放完清單後關閉',
activeUntilEnd: '播放至清單結束',
minutes: '分鐘',
hours: '小時',
songs: '首歌',
set: '設定',
timerSetSuccess: '已設定{minutes}分鐘後關閉',
songsSetSuccess: '已設定播放{songs}首歌後關閉',
playlistEndSetSuccess: '已設定播放完清單後關閉',
timerCancelled: '已取消定時關閉',
timerEnded: '定時關閉已觸發',
playbackStopped: '音樂播放已停止',
minutesRemaining: '剩餘{minutes}分鐘',
songsRemaining: '剩餘{count}首歌'
},
playList: {
clearAll: '清空播放清單',
alreadyEmpty: '播放清單已經為空',
cleared: '已清空播放清單',
empty: '播放清單為空',
clearConfirmTitle: '清空播放清單',
clearConfirmContent: '這將清空所有播放清單中的歌曲並停止目前播放。是否繼續?'
}
};

View File

@@ -0,0 +1,31 @@
export default {
title: {
hotSearch: '熱搜列表',
searchList: '搜尋列表',
searchHistory: '搜尋歷史'
},
button: {
clear: '清空',
back: '返回',
playAll: '播放列表'
},
loading: {
more: '載入中...',
failed: '搜尋失敗',
searching: '搜尋中...'
},
noMore: '沒有更多了',
error: {
searchFailed: '搜尋失敗'
},
search: {
single: '單曲',
album: '專輯',
playlist: '歌單',
mv: 'MV',
bilibili: 'B站'
},
history: '搜尋歷史',
hot: '熱門搜尋',
suggestions: '搜尋建議'
};

View File

@@ -0,0 +1,437 @@
export default {
theme: '主題',
language: '語言',
regard: '關於',
logout: '登出',
sections: {
basic: '基礎設定',
playback: '播放設定',
application: '應用程式設定',
network: '網路設定',
system: '系統管理',
donation: '捐贈支持',
about: '關於'
},
basic: {
themeMode: '主題模式',
themeModeDesc: '切換日間/夜間主題',
autoTheme: '跟隨系統',
manualTheme: '手動切換',
language: '語言設定',
languageDesc: '切換顯示語言',
tokenManagement: 'Cookie管理',
tokenManagementDesc: '管理網易雲音樂登入Cookie',
tokenStatus: '目前Cookie狀態',
tokenSet: '已設定',
tokenNotSet: '未設定',
setToken: '設定Cookie',
setCookie: '設定Cookie',
modifyToken: '修改Cookie',
clearToken: '清除Cookie',
font: '字體設定',
fontDesc: '選擇字體,優先使用排在前面的字體',
fontScope: {
global: '全域',
lyric: '僅歌詞'
},
animation: '動畫速度',
animationDesc: '是否開起動畫',
animationSpeed: {
slow: '極慢',
normal: '正常',
fast: '極快'
},
fontPreview: {
title: '字體預覽',
chinese: '中文',
english: 'English',
japanese: '日本語',
korean: '한국어',
chineseText: '靜夜思 床前明月光 疑是地上霜',
englishText: 'The quick brown fox jumps over the lazy dog',
japaneseText: 'あいうえお かきくけこ さしすせそ',
koreanText: '가나다라마 바사아자차 카타파하'
},
gpuAcceleration: 'GPU加速',
gpuAccelerationDesc: '啟用或禁用硬體加速可以提高渲染性能但可能會增加GPU負載',
gpuAccelerationRestart: '更改GPU加速設定需要重啟應用後生效',
gpuAccelerationChangeSuccess: 'GPU加速設定已更新重啟應用後生效',
gpuAccelerationChangeError: 'GPU加速設定更新失敗',
tabletMode: '平板模式',
tabletModeDesc: '啟用後將在移動設備上使用PC樣式界面適合平板等大屏設備'
},
playback: {
quality: '音質設定',
qualityDesc: '選擇音樂播放音質網易云VIP',
qualityOptions: {
standard: '標準',
higher: '較高',
exhigh: '極高',
lossless: '無損',
hires: 'Hi-Res',
jyeffect: '高清環繞聲',
sky: '沉浸環繞聲',
dolby: '杜比全景聲',
jymaster: '超清母帶'
},
musicSources: '音源設定',
musicSourcesDesc: '選擇音樂解析使用的音源平台',
musicSourcesWarning: '至少需要選擇一個音源平台',
musicUnblockEnable: '啟用音樂解析',
musicUnblockEnableDesc: '開啟後將嘗試解析無法播放的音樂',
configureMusicSources: '設定音源',
selectedMusicSources: '已選音源:',
noMusicSources: '未選擇音源',
gdmusicInfo: 'GD音樂台可自動解析多個平台音源自動選擇最佳結果',
autoPlay: '自動播放',
autoPlayDesc: '重新開啟應用程式時是否自動繼續播放',
showStatusBar: '是否顯示狀態列控制功能',
showStatusBarContent: '可以在您的mac狀態列顯示音樂控制功能(重啟後生效)',
fallbackParser: '備用解析服務 (GD音樂台)',
fallbackParserDesc: '當勾選「GD音樂台」且常規音源無法播放時將使用此服務嘗試解析。',
parserGD: 'GD 音樂台 (內建)',
parserCustom: '自訂 API',
// 音源標籤
sourceLabels: {
migu: '咪咕音樂',
kugou: '酷狗音樂',
pyncmd: '網易雲(內建)',
bilibili: 'Bilibili',
gdmusic: 'GD音樂台',
custom: '自訂 API'
},
customApi: {
sectionTitle: '自訂 API 設定',
importConfig: '匯入 JSON 設定',
currentSource: '目前音源',
notImported: '尚未匯入自訂音源。',
importSuccess: '成功匯入音源:{name}',
importFailed: '匯入失敗:{message}',
enableHint: '請先匯入 JSON 設定檔才能啟用',
status: {
imported: '已匯入自訂音源',
notImported: '未匯入'
}
},
lxMusic: {
tabs: {
sources: '音源選擇',
lxMusic: '落雪音源',
customApi: '自訂API'
},
scripts: {
title: '已匯入的音源腳本',
importLocal: '本機匯入',
importOnline: '線上匯入',
urlPlaceholder: '輸入落雪音源腳本 URL',
importBtn: '匯入',
empty: '暫無已匯入的落雪音源',
notConfigured: '未設定 (請至落雪音源分頁設定)',
importHint: '匯入相容的自訂 API 外掛以擴充音源',
noScriptWarning: '請先匯入落雪音源腳本',
noSelectionWarning: '請先選擇一個落雪音源',
notFound: '音源不存在',
switched: '已切換到音源: {name}',
deleted: '已刪除音源: {name}',
enterUrl: '請輸入腳本 URL',
invalidUrl: '無效的 URL 格式',
invalidScript: '無效的落雪音源腳本,未找到 globalThis.lx 相關程式碼',
nameRequired: '名稱不能為空',
renameSuccess: '重新命名成功'
}
}
},
application: {
closeAction: '關閉行為',
closeActionDesc: '選擇關閉視窗時的行為',
closeOptions: {
ask: '每次詢問',
minimize: '最小化到系統匣',
close: '直接退出'
},
shortcut: '快捷鍵設定',
shortcutDesc: '自訂全域快捷鍵',
download: '下載管理',
downloadDesc: '是否始終顯示下載清單按鈕',
unlimitedDownload: '無限制下載',
unlimitedDownloadDesc: '開啟後將無限制下載音樂(可能出現下載失敗的情況), 預設限制 300 首',
downloadPath: '下載目錄',
downloadPathDesc: '選擇音樂檔案的下載位置',
remoteControl: '遠端控制',
remoteControlDesc: '設定遠端控制功能'
},
network: {
apiPort: '音樂API連接埠',
apiPortDesc: '修改後需要重啟應用程式',
proxy: '代理設定',
proxyDesc: '無法存取音樂時可以開啟代理',
proxyHost: '代理位址',
proxyHostPlaceholder: '請輸入代理位址',
proxyPort: '代理連接埠',
proxyPortPlaceholder: '請輸入代理連接埠',
realIP: 'realIP設定',
realIPDesc: '由於限制,此項目在國外使用會受到限制可使用realIP參數,傳進國內IP解決',
messages: {
proxySuccess: '代理設定已儲存,重啟應用程式後生效',
proxyError: '請檢查輸入是否正確',
realIPSuccess: '真實IP設定已儲存',
realIPError: '請輸入有效的IP位址'
}
},
system: {
cache: '快取管理',
cacheDesc: '清除快取',
cacheClearTitle: '請選擇要清除的快取類型:',
cacheTypes: {
history: {
label: '播放歷史',
description: '清除播放過的歌曲記錄'
},
favorite: {
label: '收藏記錄',
description: '清除本機收藏的歌曲記錄(不會影響雲端收藏)'
},
user: {
label: '使用者資料',
description: '清除登入資訊和使用者相關資料'
},
settings: {
label: '應用程式設定',
description: '清除應用程式的所有自訂設定'
},
downloads: {
label: '下載記錄',
description: '清除下載歷史記錄(不會刪除已下載的檔案)'
},
resources: {
label: '音樂資源',
description: '清除已載入的音樂檔案、歌詞等資源快取'
},
lyrics: {
label: '歌詞資源',
description: '清除已載入的歌詞資源快取'
}
},
restart: '重新啟動',
restartDesc: '重新啟動應用程式',
messages: {
clearSuccess: '清除成功,部分設定在重啟後生效'
}
},
about: {
version: '版本',
checkUpdate: '檢查更新',
checking: '檢查中...',
latest: '目前已是最新版本',
hasUpdate: '發現新版本',
gotoUpdate: '前往更新',
gotoGithub: '前往 Github',
author: '作者',
authorDesc: 'algerkong 點個star🌟呗',
messages: {
checkError: '檢查更新失敗,請稍後重試'
}
},
validation: {
selectProxyProtocol: '請選擇代理協議',
proxyHost: '請輸入代理位址',
portNumber: '請輸入有效的連接埠號(1-65535)'
},
lyricSettings: {
title: '歌詞設定',
tabs: {
display: '顯示',
interface: '介面',
typography: '文字',
background: '背景',
mobile: '行動端'
},
pureMode: '純淨模式',
hideCover: '隱藏封面',
centerDisplay: '置中顯示',
showTranslation: '顯示翻譯',
hideLyrics: '隱藏歌詞',
hidePlayBar: '隱藏播放列',
hideMiniPlayBar: '隱藏迷你播放列',
showMiniPlayBar: '顯示迷你播放列',
backgroundTheme: '背景主題',
themeOptions: {
default: '預設',
light: '亮色',
dark: '暗色'
},
fontSize: '字體大小',
fontSizeMarks: {
small: '小',
medium: '中',
large: '大'
},
fontWeight: '字體粗細',
fontWeightMarks: {
thin: '細',
normal: '常規',
bold: '粗'
},
letterSpacing: '字間距',
letterSpacingMarks: {
compact: '緊湊',
default: '預設',
loose: '寬鬆'
},
lineHeight: '行高',
lineHeightMarks: {
compact: '緊湊',
default: '預設',
loose: '寬鬆'
},
contentWidth: '內容區寬度',
mobileLayout: '行動端佈局',
layoutOptions: {
default: '預設',
ios: 'iOS 風格',
android: 'Android 風格'
},
mobileCoverStyle: '封面風格',
coverOptions: {
record: '唱片',
square: '方形',
full: '全螢幕'
},
lyricLines: '歌詞行數',
mobileUnavailable: '此設定僅在行動端可用',
// 背景設定
background: {
useCustomBackground: '使用自訂背景',
backgroundMode: '背景模式',
modeOptions: {
solid: '純色',
gradient: '漸層',
image: '圖片',
css: 'CSS'
},
solidColor: '選擇顏色',
presetColors: '預設顏色',
customColor: '自訂顏色',
gradientEditor: '漸層編輯器',
gradientColors: '漸層顏色',
gradientDirection: '漸層方向',
directionOptions: {
toBottom: '上到下',
toRight: '左到右',
toBottomRight: '左上到右下',
angle45: '45度',
toTop: '下到上',
toLeft: '右到左'
},
addColor: '新增顏色',
removeColor: '移除顏色',
imageUpload: '上傳圖片',
imagePreview: '圖片預覽',
clearImage: '清除圖片',
imageBlur: '模糊度',
imageBrightness: '明暗度',
customCss: '自訂 CSS 樣式',
customCssPlaceholder: '輸入 CSS 樣式,如: background: linear-gradient(...)',
customCssHelp: '支援任意 CSS background 屬性',
reset: '重設為預設',
fileSizeLimit: '圖片大小限制: 20MB',
invalidImageFormat: '無效的圖片格式',
imageTooLarge: '圖片過大,請選擇小於 20MB 的圖片'
}
},
themeColor: {
title: '歌詞主題色',
presetColors: '預設顏色',
customColor: '自訂顏色',
preview: '預覽效果',
previewText: '歌詞效果',
colorNames: {
'spotify-green': 'Spotify 綠',
'apple-blue': '蘋果藍',
'youtube-red': 'YouTube 紅',
orange: '活力橙',
purple: '神秘紫',
pink: '櫻花粉'
},
tooltips: {
openColorPicker: '開啟色板',
closeColorPicker: '關閉色板'
},
placeholder: '#1db954'
},
translationEngine: '歌詞翻譯引擎',
translationEngineOptions: {
none: '關閉',
opencc: 'OpenCC 繁化'
},
shortcutSettings: {
title: '快捷鍵設定',
shortcut: '快捷鍵',
shortcutDesc: '自訂快捷鍵',
shortcutConflict: '快捷鍵衝突',
inputPlaceholder: '點擊輸入快捷鍵',
resetShortcuts: '恢復預設',
disableAll: '全部停用',
enableAll: '全部啟用',
togglePlay: '播放/暫停',
prevPlay: '上一首',
nextPlay: '下一首',
volumeUp: '增加音量',
volumeDown: '減少音量',
toggleFavorite: '收藏/取消收藏',
toggleWindow: '顯示/隱藏視窗',
scopeGlobal: '全域',
scopeApp: '應用程式內',
enabled: '已啟用',
disabled: '已停用',
messages: {
resetSuccess: '已恢復預設快捷鍵,請記得儲存',
conflict: '存在快捷鍵衝突,請重新設定',
saveSuccess: '快捷鍵設定已儲存',
saveError: '快捷鍵儲存失敗,請重試',
cancelEdit: '已取消修改',
disableAll: '已停用所有快捷鍵,請記得儲存',
enableAll: '已啟用所有快捷鍵,請記得儲存'
}
},
remoteControl: {
title: '遠端控制',
enable: '啟用遠端控制',
port: '服務連接埠',
allowedIps: '允許的 IP 位址',
addIp: '新增 IP',
emptyListHint: '空白清單表示允許所有 IP 存取',
saveSuccess: '遠端控制設定已儲存',
accessInfo: '遠端控制存取位址:'
},
cookie: {
title: 'Cookie設定',
description: '請輸入網易雲音樂的Cookie',
placeholder: '請貼上完整的Cookie...',
help: {
format: 'Cookie通常以 "MUSIC_U=" 開頭',
source: '可以從瀏覽器開發者工具的網路請求中取得',
storage: 'Cookie設定後將自動儲存到本機儲存'
},
action: {
save: '儲存Cookie',
paste: '貼上',
clear: '清空'
},
validation: {
required: '請輸入Cookie',
format: 'Cookie格式可能不正確請檢查是否包含MUSIC_U'
},
message: {
saveSuccess: 'Cookie儲存成功',
saveError: 'Cookie儲存失敗',
pasteSuccess: '貼上成功',
pasteError: '貼上失敗,請手動複製'
},
info: {
length: '目前長度:{length} 字元'
}
}
};

View File

@@ -0,0 +1,28 @@
export default {
menu: {
play: '播放',
playNext: '下一首播放',
download: '下載歌曲',
addToPlaylist: '新增至播放清單',
favorite: '喜歡',
unfavorite: '取消喜歡',
removeFromPlaylist: '從播放清單中刪除',
dislike: '不喜歡',
undislike: '取消不喜歡'
},
message: {
downloading: '正在下載中,請稍候...',
downloadFailed: '下載失敗',
downloadQueued: '已加入下載佇列',
addedToNextPlay: '已新增至下一首播放',
getUrlFailed: '取得音樂下載位址失敗,請檢查是否登入'
},
dialog: {
dislike: {
title: '提示!',
content: '確認不喜歡這首歌嗎?再次進入將從每日推薦中排除。',
positiveText: '不喜歡',
negativeText: '取消'
}
}
};

View File

@@ -0,0 +1,53 @@
export default {
profile: {
followers: '粉絲',
following: '關注',
level: '等級'
},
playlist: {
created: '建立的歌單',
mine: '我建立的',
trackCount: '{count}首',
playCount: '播放{count}次'
},
tabs: {
created: '建立',
favorite: '收藏',
album: '專輯'
},
ranking: {
title: '聽歌排行',
playCount: '{count}次'
},
follow: {
title: '關注列表',
viewPlaylist: '查看歌單',
noFollowings: '暫無關注',
loadMore: '載入更多',
noSignature: '這個傢伙很懶,什麼都沒留下',
userFollowsTitle: '的關注',
myFollowsTitle: '我的關注'
},
follower: {
title: '粉絲列表',
noFollowers: '暫無粉絲',
loadMore: '載入更多',
userFollowersTitle: '的粉絲',
myFollowersTitle: '我的粉絲'
},
detail: {
playlists: '歌單',
records: '聽歌排行',
noPlaylists: '暫無歌單',
noRecords: '暫無聽歌記錄',
artist: '歌手',
noSignature: '這個人很懶,什麼都沒留下',
invalidUserId: '使用者ID無效',
noRecordPermission: '{name}不讓你聽歌排行'
},
message: {
loadFailed: '載入使用者頁面失敗',
deleteSuccess: '刪除成功',
deleteFailed: '刪除失敗'
}
};

25
src/i18n/languages.ts Normal file
View File

@@ -0,0 +1,25 @@
// 语言配置文件 - 集中管理语言相关的配置
// 语言显示名称映射
export const LANGUAGE_DISPLAY_NAMES: Record<string, string> = {
'zh-CN': '简体中文',
'zh-Hant': '繁體中文',
'en-US': 'English',
'ja-JP': '日本語',
'ko-KR': '한국어'
};
// 默认语言
export const DEFAULT_LANGUAGE = 'zh-CN';
// 回退语言
export const FALLBACK_LANGUAGE = 'en-US';
// 语言排序优先级用于在UI中的显示顺序
export const LANGUAGE_PRIORITY: Record<string, number> = {
'zh-CN': 1,
'zh-Hant': 2,
'en-US': 3,
'ja-JP': 4,
'ko-KR': 5
};

View File

@@ -1,17 +1,15 @@
import enUS from './lang/en-US';
import zhCN from './lang/zh-CN';
import { DEFAULT_LANGUAGE } from './languages';
import { buildLanguageMessages } from './utils';
const messages = {
'zh-CN': zhCN,
'en-US': enUS
} as const;
// 使用工具函数构建语言消息对象
const messages = buildLanguageMessages();
type Language = keyof typeof messages;
// 为主进程提供一个简单的 i18n 实现
const mainI18n = {
global: {
currentLocale: 'zh-CN' as Language,
currentLocale: DEFAULT_LANGUAGE as Language,
get locale() {
return this.currentLocale;
},

View File

@@ -1,17 +1,15 @@
import { createI18n } from 'vue-i18n';
import enUS from './lang/en-US';
import zhCN from './lang/zh-CN';
import { DEFAULT_LANGUAGE, FALLBACK_LANGUAGE } from './languages';
import { buildLanguageMessages } from './utils';
const messages = {
'zh-CN': zhCN,
'en-US': enUS
};
// 使用工具函数构建语言消息对象
const messages = buildLanguageMessages();
const i18n = createI18n({
legacy: false,
locale: 'zh-CN',
fallbackLocale: 'en-US',
locale: DEFAULT_LANGUAGE,
fallbackLocale: FALLBACK_LANGUAGE,
messages,
globalInjection: true,
silentTranslationWarn: true,

60
src/i18n/utils.ts Normal file
View File

@@ -0,0 +1,60 @@
// 自动导入所有语言的所有翻译文件
const allLangModules = import.meta.glob('./lang/**/*.ts', { eager: true });
// 构建语言消息对象
export const buildLanguageMessages = () => {
const messages: Record<string, Record<string, any>> = {};
Object.entries(allLangModules).forEach(([path, module]) => {
// 解析路径,例如 './lang/zh-CN/common.ts' -> { lang: 'zh-CN', module: 'common' }
const match = path.match(/\.\/lang\/([^/]+)\/([^/]+)\.ts$/);
if (match) {
const [, langCode, moduleName] = match;
// 跳过 index 文件
if (moduleName !== 'index') {
if (!messages[langCode]) {
messages[langCode] = {};
}
messages[langCode][moduleName] = (module as any).default;
}
}
});
return messages;
};
// 获取所有支持的语言
export const getSupportedLanguages = (): string[] => {
const messages = buildLanguageMessages();
return Object.keys(messages);
};
export const isLanguageSupported = (lang: string): boolean => {
return getSupportedLanguages().includes(lang);
};
import { LANGUAGE_DISPLAY_NAMES, LANGUAGE_PRIORITY } from './languages';
// 获取语言显示名称的映射
export const getLanguageDisplayNames = (): Record<string, string> => {
return LANGUAGE_DISPLAY_NAMES;
};
// 生成语言选项数组,用于下拉选择等组件
export const getLanguageOptions = () => {
const supportedLanguages = getSupportedLanguages();
const displayNames = getLanguageDisplayNames();
// 按优先级排序
const sortedLanguages = supportedLanguages.sort((a, b) => {
const priorityA = LANGUAGE_PRIORITY[a] || 999;
const priorityB = LANGUAGE_PRIORITY[b] || 999;
return priorityA - priorityB;
});
return sortedLanguages.map((lang) => ({
label: displayNames[lang] || lang,
value: lang
}));
};

View File

@@ -8,28 +8,29 @@ import { loadLyricWindow } from './lyric';
import { initializeConfig } from './modules/config';
import { initializeFileManager } from './modules/fileManager';
import { initializeFonts } from './modules/fonts';
import { initializeLoginWindow } from './modules/loginWindow';
import { initializeOtherApi } from './modules/otherApi';
import { initializeRemoteControl } from './modules/remoteControl';
import { initializeShortcuts, registerShortcuts } from './modules/shortcuts';
import { initializeStats, setupStatsHandlers } from './modules/statsService';
import { initializeTray, updateCurrentSong, updatePlayState, updateTrayMenu } from './modules/tray';
import { setupUpdateHandlers } from './modules/update';
import { createMainWindow, initializeWindowManager } from './modules/window';
import { createMainWindow, initializeWindowManager, setAppQuitting } from './modules/window';
import { initWindowSizeManager } from './modules/window-size';
import { startMusicApi } from './server';
import { initLxMusicHttp } from './modules/lxMusicHttp';
// 导入所有图标
const iconPath = join(__dirname, '../../resources');
const icon = nativeImage.createFromPath(
process.platform === 'darwin'
? join(iconPath, 'icon.icns')
: join(iconPath, 'icon.png')
process.platform === 'darwin' ? join(iconPath, 'icon.icns') : join(iconPath, 'icon.png')
);
let mainWindow: Electron.BrowserWindow;
// 初始化应用
function initialize() {
// 初始化配置管理
const store = initializeConfig();
function initialize(configStore: any) {
// 使用已初始化配置存储
const store = configStore;
// 设置初始语言
const savedLanguage = store.get('set.language') as Language;
@@ -39,10 +40,14 @@ function initialize() {
// 初始化文件管理
initializeFileManager();
// 初始化其他 API (搜索建议等)
initializeOtherApi();
// 初始化窗口管理
initializeWindowManager();
// 初始化字体管理
initializeFonts();
// 初始化登录窗口
initializeLoginWindow();
// 创建主窗口
mainWindow = createMainWindow(icon);
@@ -50,15 +55,12 @@ function initialize() {
// 初始化托盘
initializeTray(iconPath, mainWindow);
// 初始化统计服务
initializeStats();
// 设置统计相关的IPC处理程序
setupStatsHandlers(ipcMain);
// 启动音乐API
startMusicApi();
// 初始化落雪音乐 HTTP 请求处理
initLxMusicHttp();
// 加载歌词窗口
loadLyricWindow(ipcMain, mainWindow);
@@ -78,6 +80,23 @@ const isSingleInstance = app.requestSingleInstanceLock();
if (!isSingleInstance) {
app.quit();
} else {
// 在应用准备就绪前初始化GPU加速设置
// 必须在 app.ready 之前调用 disableHardwareAcceleration
try {
// 初始化配置管理以获取GPU加速设置
const store = initializeConfig();
const enableGpuAcceleration = store.get('set.enableGpuAcceleration', true) as boolean;
if (!enableGpuAcceleration) {
console.log('GPU加速已禁用');
app.disableHardwareAcceleration();
} else {
console.log('GPU加速已启用');
}
} catch (error) {
console.error('GPU加速设置初始化失败:', error);
// 如果配置读取失败默认启用GPU加速
}
// 当第二个实例启动时,将焦点转移到第一个实例的窗口
app.on('second-instance', () => {
if (mainWindow) {
@@ -99,12 +118,18 @@ if (!isSingleInstance) {
optimizer.watchWindowShortcuts(window);
});
// 初始化窗口大小管理器
initWindowSizeManager();
// 重新初始化配置管理以获取完整的配置存储
const store = initializeConfig();
// 初始化应用
initialize();
initialize(store);
// macOS 激活应用时的处理
app.on('activate', () => {
if (mainWindow === null) initialize();
if (mainWindow === null) initialize(store);
});
});
@@ -140,6 +165,12 @@ if (!isSingleInstance) {
}
});
// 应用即将退出时的处理
app.on('before-quit', () => {
// 设置退出标志
setAppQuitting(true);
});
// 重启应用
ipcMain.on('restart', () => {
app.relaunch();

Some files were not shown because too many files have changed in this diff Show More