myMusic / 功能与交互重设计 / 2026-10-21

五个入口,
一张自己的节目单。

榜单用来发现,歌单用来编排,搜索用来抵达,我的用来留下,设置负责把播放规则调到顺手。自建歌单可以同步到 GitHub Gist、Gitee,应用内更新则先校验、再交给系统安装。

核心区分浏览来源与播放来源分开
音乐库本地优先,自建歌单可云端同步
应用更新校验 SHA-256 与签名后安装
设备范围手机、平板、电视共用焦点规则

首页不再承担所有事情。

现在的首页同时放推荐歌单、排行榜、歌单分类和热门歌曲,导致“发现”这件事没有单一入口。新结构把首页拆成两个明确任务:榜单回答“现在什么在流行”,歌单回答“我想听一组什么歌”。音乐库升级为“我的”,成为收藏与自建歌单的家。

现在的入口四栏
首页推荐歌单 / 排行榜 / 歌单分类 / 热门歌曲
搜索聚合搜索与链接解析
音乐库收藏 / 最近播放 / 下载 / 我的歌单
设置外观、聚合、账号与缓存
→
新的入口五栏,任务各自独立
榜单平台排行榜 + 热歌,保留“整榜播放、单曲换源”
歌单推荐歌单 + 分类浏览,按平台查看,不伪造跨平台榜单
搜索搜索历史、聚合结果、音源选择与人工纠错
我的喜欢、自建歌单、最近播放、下载;歌单可同步到 Gist / Gitee
设置设置索引 + 独立子页;新增“关于与更新”

“首页”不是改名,而是被拆掉了。平台排行榜归入榜单,推荐歌单与分类归入歌单,热门歌曲放在榜单下部。这样每个入口只有一个主动作,平台切换也不再同时代表“浏览哪个平台”和“用什么播放”。

四条会贯穿全套界面的规则

浏览来源不是播放来源

榜单和歌单顶部的平台选择只决定内容从哪里读;播放仍按设置里的聚合策略自动选源。页面上用“榜单来源”“歌单来源”说清楚,播放器里再显示“当前播放源”。

本地先行,远程只是副本

新建、改名、加歌、删歌先落本机 Room,界面立刻反馈;同步在后台完成。断网时仍是完整可用的音乐库,而不是一个空壳。

内容页只做一套

平台歌单、排行榜、专辑和自建歌单共用同一套歌曲列表与批量操作。换源、收藏、下载、加入歌单的位置一致,不为每种来源复制一遍页面。

失败必须给出下一步

榜单单平台失败时提示换来源;同步冲突时给出保留哪一版;更新签名不一致时说明无法覆盖安装。所有错误都避免只说“失败”。

哪些是旧能力重组,哪些是新增能力

入口直接复用的现有能力本次新增或重做
榜单topLists、topListSongs、hotSongs、聚合换源独立榜单页、统一榜单详情、全榜播放、来源与播放分离的固定文案
歌单recommendedPlaylists、categories、categoryPlaylists独立推荐与分类视图、平台持久化、分类分页状态保留
搜索AggregateSearchEngine、人工合并/拆分、试听与 VIP 状态搜索落地页、历史记录、链接自动识别、音源选择底部面板、结果状态保留
我的收藏、最近播放、下载、自建歌单统一音乐库结构、自建歌单编辑、Gist / Gitee 同步、冲突处理
设置主题、聚合、账号、缓存索引式设置、独立子页、更新通道、关于页
均衡器现有 Media3 播放会话五段实时均衡、内置与自定义预设、按设备音效能力降级
应用更新GitHub Actions Release 产物更新清单、下载校验、签名校验、系统安装器、更新状态 UI

先把入口点一遍。

下面的手机可以直接操作。底栏切换五个页面;榜单卡、歌单、搜索历史、同步图标、冲突提示、设置中的“关于与更新”都能继续往下走。原型里的数据和版本号是示意,不指向真实发布。

9:41

发现

榜单

榜单来源

更多榜单

平台热歌

网易云音乐

浏览

歌单

今天适合听

换一批

华语流行

查看分类

跨平台

搜索

5 个平台已启用
聚合搜索:网易云、QQ、酷狗、酷我、咪咕

最近搜索

只保留关键词,不上传。

按类型搜索

结果会保留
粘贴网易云、QQ 音乐等平台的分享链接,搜索框会自动识别并打开对应内容。试听、VIP、无版权状态仍会逐条标出。

本地优先

我的

126喜欢
8自建歌单
24已下载

偏好

设置

外观

播放

数据

其他

月
若月亮没来王宇宙Leto / 网易云音乐
可交互原型,数据与版本号仅为示意方向键 / 触摸均可

每一个页面,
都先画出来再实现。

下面是完整界面图库。五栏主页面、所有内容详情、搜索与音源、音乐库四个分段、自建歌单编辑、同步连接与冲突、全部设置子页、播放器、歌词、队列、均衡器,以及平板和电视布局,都按同一套视觉规则单独绘制。

发现与歌单

从榜单和编排进入音乐

5 个界面
9:41

发现

榜单

网易云音乐 榜单来源
飙升榜每日更新

现在上升最快的歌

100 首 / 网易云音乐

01
月
若月亮没来王宇宙Leto / 乔浚丞
02
晴
晴天周杰伦

更多榜单

全部
热
QQ 音乐热歌榜每日更新 / QQ 音乐
新
酷狗 TOP500每日更新 / 酷狗音乐
界面 01榜单主导航默认页。来源只决定榜单内容,播放仍按聚合策略自动换源。
9:41
飙升榜网易云音乐 / 每日更新
升

飙升榜

按播放涨幅计算,每日更新

100 首自动换源
播放全部换源设置
排名与歌曲显示可用音源
01
若月亮没来王宇宙Leto / 乔浚丞
可播
02
晴天周杰伦 / 叶惠美
可播
03
春庭雪等什么君
试听
04
跳楼机LBI利比
可播
05
如果呢郑润泽
可播
界面 02榜单详情封面、播放全部、换源入口和排名列表。点击任意歌曲进入音源与版本面板。
9:41

浏览

歌单

网易云音乐QQ 音乐酷狗酷我
推荐分类
夜

夜行车载:把城市调成静音

编辑推荐 / 38 首 / 网易云音乐

今天适合听

换一批
雨
下雨天的旧唱片28 首
慢
慢下来,做完手上这件事42 首
醒
清晨六点的第一首歌31 首
界面 03歌单 · 推荐平台来源、推荐/分类切换、主推歌单与横向推荐行。
9:41

浏览

歌单

网易云音乐QQ 音乐酷狗酷我
推荐分类
全部华语流行摇滚民谣电子
夜
深夜电台42 首
路
公路与风35 首
书
适合读书的安静曲子27 首
旧
旧日留声机60 首
界面 04歌单 · 分类分类筛选、两列歌单网格;切换分类不离开本页,翻页保留当前位置。
9:41
夜行车载网易云音乐歌单 / 38 首
夜

夜行车载:把城市调成静音

编辑推荐 / 38 首 / 更新于今天

播放全部收藏歌单
歌曲按聚合策略播放
01
若月亮没来王宇宙Leto / 乔浚丞
可播
02
晴天周杰伦 / 叶惠美
可播
03
春庭雪等什么君
可播
04
跳楼机LBI利比
可播
界面 05平台歌单详情和榜单共用同一套媒体列表;收藏、播放、单曲换源的位置保持一致。
搜索

先接住问题,再把平台差异摊开

4 个界面
9:41

跨平台

搜索

5 个平台已启用
歌曲、歌单、专辑,或粘贴链接搜索

聚合搜索:网易云、QQ、酷狗、酷我、咪咕

最近搜索

只保留关键词,不上传。

晴天若月亮没来夜行车载周杰伦 叶惠美

按类型搜索

结果会保留
单曲歌单专辑
粘贴网易云、QQ 音乐等平台的分享链接,搜索框会自动识别。试听、VIP、无版权状态会逐条标出。
界面 06搜索首页搜索历史、聚合范围和类型提示。没有输入时不请求任何平台。
9:41

跨平台

搜索

晴天搜索
网易云 2QQ 3酷狗 2酷我 超时咪咕 1
“晴天”的聚合结果部分平台异常
晴
晴天周杰伦 / 叶惠美
完整4 个平台04:29
月
若月亮没来王宇宙Leto / 乔浚丞
完整3 个平台QQ 仅 VIP

其他版本

不会自动合并
L
晴天 (Live)周杰伦 / 世界巡回演唱会
现场版2 个平台05:12
界面 07搜索结果平台状态、作品级合并结果和其他版本。点结果卡进入音源面板。
9:41

跨平台

搜索

晴天搜索
网易云 2QQ 3酷我 超时
晴
晴天周杰伦 / 叶惠美
月
若月亮没来王宇宙Leto / 乔浚丞

晴天

周杰伦 / 叶惠美 / 04:29

网易网易云音乐完整音源 / 320 kbps完整
QQQQ 音乐完整音源 / 无损完整
酷狗酷狗音乐仅返回试听片段试听
酷我酷我音乐暂未检测到可用地址待检测
从所选音源播放

换源是在目标平台重新检索同一录音,不会转移会员权益。找不到音源时,可以检查“其他版本”或调整匹配严格度。

界面 08音源选择完整、试听、VIP、待检测分开表达;可记住本曲的平台选择。
9:41

跨平台

搜索

雨夜没有这首歌搜索
网易云 0QQ 0酷狗 超时酷我 错误咪咕 0
全部返回后仍没有结果部分平台失败
没有找到这首歌

试试歌曲名加歌手,或换一个关键词。酷狗和酷我这次没有返回结果,可以单独重试。

歌手 + 歌名只搜当前平台重试异常平台
部分平台失败时,空结果不能等同于“全网没有”。界面会保留失败平台和重试入口。
界面 09搜索无结果区分“确实没有”和“部分平台失败”,给出可执行的下一步。
我的与同步

本地音乐库、歌单编辑与云端副本

9 个界面
9:41

本地优先

我的

126喜欢
8自建歌单
24已下载
喜欢歌单最近下载

最近喜欢

126 首
晴
晴天周杰伦 / 叶惠美
可播
月
若月亮没来王宇宙Leto / 乔浚丞
可播
跳
跳楼机LBI利比
VIP
海
海底一支榴莲
可播
查看全部 126 首
界面 10我的 · 喜欢收藏页保留播放入口,并可在曲目更多菜单里加入自建歌单。
9:41

本地优先

我的

126喜欢
8自建歌单
24已下载
喜欢歌单最近下载
已同步到 GitHub Gist2 分钟前同步 / 8 个歌单
夜
夜间驾驶32 首 / 更新于昨天
已同步
日
周日打扫18 首 / 更新于 3 天前
待同步
旧
旧唱片26 首 / 两个设备都改过
有冲突
晨
清晨六点21 首 / 更新于一周前
已同步
新建歌单
界面 11我的 · 歌单默认分段。同步状态直接出现在歌单行:已同步、待同步、有冲突。
9:41

本地记录

我的

126喜欢
8自建歌单
24已下载
喜欢歌单最近下载

今天

雪
春庭雪等什么君 / 22:18
换源
旧
旧梦一场阿悠悠 / 21:52
换源
海
海底一支榴莲 / 21:40
换源

昨天

跳
跳楼机LBI利比 / 23:08
换源
晴
晴天周杰伦 / 20:11
换源
界面 12我的 · 最近播放按日期分组,保留“换源”和加入歌单入口;记录只留在本机。
9:41

本地文件

我的

126喜欢
8自建歌单
24已下载
喜欢歌单最近下载
186 MB24 首已完成 / 1 首下载中
下载缓存其他
晴
晴天周杰伦 / 8.6 MB / 已完成
播放
月
若月亮没来王宇宙Leto / 7.9 MB / 已完成
播放
跳
跳楼机LBI利比 / 下载中 62%
暂停
雪
春庭雪等什么君 / 7.4 MB / 已完成
播放
界面 13我的 · 下载下载占用、进度、暂停与本地播放。已下载文件播放时优先于网络音源。
9:41
夜间驾驶自建歌单 / 32 首
夜

夜间驾驶

32 首 / 49 分钟前编辑

已同步到 GitHub Gist上次同步 2 分钟前
播放全部添加歌曲编辑
歌曲按本机顺序
01
夜空中最亮的星逃跑计划 / 世界
已下载
02
平凡之路朴树 / 猎户星座
可播
03
一路向北周杰伦 / 头文字D
可播
04
若月亮没来王宇宙Leto / 乔浚丞
可播
05
晴天周杰伦 / 叶惠美
可播
界面 14自建歌单详情同步状态、播放全部、添加歌曲、编辑排序,以及逐曲移除。
9:41
编辑歌单夜间驾驶 / 32 首完成
拖动右侧把手调整顺序,点击减号移除歌曲。电视端选中歌曲后用方向键移动。
≡
星
夜空中最亮的星逃跑计划 / 世界
−
≡
平
平凡之路朴树 / 猎户星座
−
≡
北
一路向北周杰伦 / 头文字D
−
≡
月
若月亮没来王宇宙Leto / 乔浚丞
−
≡
晴
晴天周杰伦 / 叶惠美
−
已修改 2 项 / 自动保存完成
界面 15歌单编辑模式显式进入编辑,拖拽排序,减号移除;不使用难发现的滑动删除。
9:41

本地优先

我的

已同步到 GitHub Gist2 分钟前同步 / 8 个歌单
夜
夜间驾驶32 首
已同步

音乐库同步

只同步你自建的歌单和歌曲信息

GitHub Gist已连接

mymusic-library.json / 2 分钟前同步 / 自动同步已开启

8歌单126首歌1个冲突
立即同步处理冲突
本机和云端都改过「旧唱片」。同步不会自动覆盖,先处理冲突后才会继续上传。

同步到

GitHub Gist已连接 / 私人 Gist Gitee 代码片段私人令牌连接 GitLab Snippets可选后端 WebDAV自建网盘

Cookie、收藏、最近播放、下载文件和播放地址都不会进入同步文件。可在设置中关闭自动同步或限制 Wi-Fi。

界面 16同步中心连接状态、同步结果、冲突入口和后端选择。作为面板从“我的”进入。
9:41
连接同步源第 1 步 / 选择存储位置
1选择后端2验证3首次合并

把歌单放在哪里?

同步文件只包含自建歌单和歌曲元数据,不包含令牌、Cookie 或下载文件。

GitHub Gist私人 Gist / 推荐 Gitee 代码片段国内访问更稳定 GitLab Snippets私有 snippet WebDAV自己的网盘

GitHub 私人令牌

ghp_••••••••••••••••

需要 gist 权限。若使用已有 Gist,下一步可以粘贴链接;没有 Gist 时会为你新建一个私人 Gist。

验证并继续

或者不使用账号,导入 / 导出本地 JSON

创建令牌后请只粘贴一次;应用不会记录或展示完整令牌。
界面 17连接同步源三步向导:选择后端、验证令牌、首次合并预览。也支持不走账号的文件导入导出。
9:41
GitHub Gist已连接

mymusic-library.json / 8 个歌单

处理同步冲突

旧唱片 / 两个设备都改过这个歌单

旧唱片

上次同步后,两边都改动了曲目。

本机版本26 首 / 今天 08:12新增 3 首,调换 2 首
云端版本24 首 / 昨天 23:40新增 1 首,删除 1 首
合并两版保留本机使用云端

“合并两版”保留本机歌曲顺序,并把云端新增的歌曲补在后面,按来源与 ID 去重;删除项不会在合并时自动恢复。

冲突解决前不会上传任何修改,避免一台设备覆盖另一台。
界面 18同步冲突显示本机与云端两版差异,默认推荐合并,绝不为图省事静默覆盖。
设置

每个子页只回答一个问题

11 个界面
9:41

偏好

设置

外观

主题跟随系统 / 动态配色开

播放与浏览

播放与换源自动换源 / 优先平台 / 严格匹配
均衡器流行 / 已开启
搜索与浏览5 个聚合平台 / 默认浏览来源
平台账号网易云、QQ 音乐已登录

数据

音乐库同步GitHub Gist / 2 分钟前
存储缓存 214 MB / 下载 186 MB

其他

关于与更新myMusic 1.0.0.128
界面 19设置首页各子页入口,改动即保存;关于与更新用圆点提示有可用版本。
9:41
外观主题、配色与动效
正在播放深松绿预览

夜行车载

王宇宙Leto / 乔浚丞

主题

跟随系统 浅色 深色
动态配色
减少动画
手机上显示底部导航

Android 12 以上跟随系统取色;Android 6–11 使用内置的深松绿 / 青瓷绿配色。电视端不使用触摸预览。

界面 20外观主题三选一、系统动态配色、动效开关。预览直接展示播放界面。
9:41
播放与换源播放策略、音源优先级与匹配

换源模式

自动按优先平台固定平台

自动:完整音源优先,其次按下面的平台顺序与码率选择。

优先平台

1网易云音乐≡
2QQ 音乐≡
3酷狗音乐≡
4酷我音乐≡
允许试听片段
严格匹配

严格匹配会降低 Live、伴奏和重制版被误合并的概率。自动换源与手动换源都使用这里的规则。

恢复自动匹配
界面 21播放与换源换源模式、优先顺序、试听与严格匹配集中在一页;均衡器是设置索引中的独立入口。
9:41
搜索与浏览聚合平台与默认内容来源

参与聚合搜索的平台

网易网易云音乐
QQQQ 音乐
酷狗酷狗音乐
酷我酷我音乐
咪咕咪咕音乐
汽水汽水音乐

默认浏览来源

网易云音乐

只影响榜单、歌单等浏览页的初始来源,不会改变播放时的自动换源策略。

当前启用 5 个聚合平台。平台越多,结果越完整,但搜索与匹配耗时也可能更长。
界面 22搜索与浏览选择聚合平台与默认内容来源。明确区别于播放源的优先级设置。
9:41
平台账号Cookie、扫码登录与退出
平台账号相互独立。应用不提供统一账号,也不会把 Cookie 写入同步文件。
部分平台的二维码登录依赖其官方接口,能力以 ProviderInfo.QRLogin 为准。
界面 23平台账号逐平台展示登录状态、扫码与 Cookie 操作,不和其他设置混在一起。
9:41
存储缓存、下载与占用
612 MB应用共占用
214 MB 播放缓存186 MB 下载其他
播放缓存214 MB清除
匹配缓存18 MB清除
下载文件24 首 / 186 MB管理

清理建议

播放缓存可随时重新生成。匹配缓存清除后,下一次换源会重新匹配,不影响歌单和收藏。
下载文件是唯一的离线音源。清除前会再次确认,本地歌单不会因此丢失。
清除全部播放缓存
界面 24存储用分段条展示缓存 / 下载占用;清除动作有明确范围和二次确认。
9:41
音乐库同步账户、自动同步与冲突
GitHub Gist已连接

mymusic-library.json / 上次同步 2 分钟前

8歌单126首歌1个冲突
自动同步
仅在 Wi-Fi 下同步
检查频率回到前台超过 15 分钟
待处理冲突1 个
管理令牌已加密
立即备份到本机JSON
同步只写入自建歌单和歌曲元数据。收藏、最近播放、下载、Cookie、播放地址不进入云端。
断开同步并删除本机令牌

断开后本机歌单和非同步数据保留;远端文件不会被删除。

界面 25音乐库同步设置账户、自动同步、Wi-Fi 限制、冲突与令牌管理。断开不会删除本机歌单。
9:41
关于与更新版本、许可和项目信息
m

myMusic

版本 1.0.0.128 / versionCode 128

AGPL-3.0
检查更新有新版本 1.0.0.129
开源许可AGPL-3.0
项目主页GitHub
隐私说明本地优先
复制诊断信息不含 Cookie
Cookie、播放记录和下载文件只保存在本机。同步仅使用你选择的 Gist / Gitee 账号,写入自建歌单数据;应用没有集中式服务器。
平台层 music-lib / 7cc4467b
学习项目,请遵守各音乐平台服务条款。
界面 26关于与更新版本、更新入口、许可、隐私和诊断集中在一页,是设置里唯一的版本入口。
9:41
m

myMusic

版本 1.0.0.128

检查更新有新版本

新版本可用

1.0.0.129 / 18.4 MB / 2026-10-20

这次更新
  • 自建歌单可以同步到 Gitee 代码片段。
  • 修复换源播放中断后进度没有恢复的问题。
  • 电视端榜单焦点顺序调整。
下载后校验 SHA-256、包名和签名,再打开 Android 系统安装器。
正在下载62%
取消下载

Android 不允许静默安装。完成后会打开系统安装器,由你确认覆盖安装。

界面 27检查更新版本说明、大小、下载进度与校验提示。下载中断可取消或重试。
9:41
开源许可应用、上游库与第三方依赖
GNU Affero General Public License v3.0

myMusic 的应用代码与移植的平台层均以 AGPL-3.0 发布。

查看完整文本

上游与第三方

music-lib

平台能力来源。当前纳入 commit 7cc4467,保留 Go 源码用于移植参考与许可证说明。

music-lib / Kotlin 移植

使用 OkHttp、原生加密工具与 Kotlin 实现,不引入 GoMobile、AAR 或额外后端。

AndroidX、Media3、Coil、Room

均按其 Apache-2.0 或对应开源许可使用;完整列表随应用和仓库提供。

如果二次分发,请保留许可证、版权声明与修改说明,并遵守 AGPL-3.0 的源码提供义务。

界面 28开源许可应用许可、上游 commit 与第三方依赖分别说明,便于合规检查。
9:41
隐私说明哪些数据留在本机,哪些会离开
留在本机

Cookie、令牌、收藏、最近播放、下载文件、播放进度和匹配缓存都只保存在设备上。Cookie 与同步令牌使用 Android Keystore 加密。

写入你选择的云端

启用同步后,只把自建歌单和歌曲元数据写入你的 GitHub Gist 或 Gitee 代码片段。同步文件不包含 Cookie、令牌、播放地址和下载文件。

网络请求

应用直接请求音乐平台上游接口、更新清单和同步服务,没有 myMusic 自建中转服务器。第三方仍会看到其服务所需的常规请求信息。

诊断信息

复制诊断只包含版本、设备型号、Android 版本、启用平台和最近错误;不包含 Cookie、令牌或完整播放 URL。

退出平台账号或断开同步会清除对应的本机凭据;卸载应用会删除应用目录内的所有本地数据。

界面 29隐私说明按“本机、云端、网络、诊断”四类说明数据边界,不用笼统承诺代替细节。
播放、音效与自适应

播放器、歌词、队列、均衡器与大屏布局

5 个界面
9:41
正在播放来自“飙升榜”
月

若月亮没来

王宇宙Leto / 乔浚丞

播放源:网易云音乐 / 320 kbps换源
01:5404:29
界面 30全屏播放器封面、曲目、当前播放源、换源入口和传输控制。播放源永远可见。
9:41
若月亮没来王宇宙Leto / 乔浚丞
若月亮没来王宇宙Leto / 乔浚丞
风吹过山岗 月亮停在窗台 若月亮没来 01:54.2 我该怎么把心事说出来 夜色慢慢落下来 把没说出口的话藏进海
界面 31歌词逐行高亮与自动滚动,当前句保持视觉中心;底部保留进度与播放源。
9:41
月

若月亮没来

王宇宙Leto / 乔浚丞

播放源:网易云音乐

播放队列

32 首 / 当前第 4 首 / 来自“夜间驾驶”

月
若月亮没来王宇宙Leto / 乔浚丞
正在播放
晴
晴天周杰伦 / 叶惠美
可播
雪
春庭雪等什么君
可播
跳
跳楼机LBI利比
可播
旧
旧梦一场阿悠悠
可播
随机播放列表循环清空

队列沿用当前播放策略。某一首换源失败时保留原进度,并提示当前实际播放平台。

界面 32播放队列当前项、后续曲目与播放模式。队列不属于任何页签,切换页面不会丢失。
9:41
均衡器本机播放音效 / 不影响下载文件
均衡器已开启当前输出:扬声器 / 实时生效

预设

平直流行摇滚爵士人声自定义
频段调节-10 dB 至 +10 dB
+6
60 Hz
+3
230 Hz
0
910 Hz
-2
3.6 kHz
+4
14 kHz
恢复平直保存为自定义
音效只作用于这台设备的播放输出,不会修改音频文件,也不会写入同步数据。切换歌曲或音源后保持当前设置。
部分蓝牙耳机、USB 声卡或系统省电模式可能不支持第三方音效。此时会保留设置,但提示“当前输出未生效”。
正在播放:若月亮没来 / 网易云音乐 / 320 kbps
界面 33均衡器五段实时调节、内置预设与自定义曲线。作用于本机播放,不改文件、不进同步。
榜单 歌单 搜索 我的 设置
发现

榜单

网易云音乐
飙升榜 / 每日更新

现在上升最快的歌

100 首 / 网易云音乐

月
若月亮没来王宇宙Leto / 乔浚丞
可播
晴
晴天周杰伦 / 叶惠美
可播
雪
春庭雪等什么君
试听
热
QQ 音乐热歌榜每日更新 / QQ 音乐
新
酷狗 TOP500每日更新 / 酷狗音乐
原
原创音乐榜每周更新 / 网易云音乐

正在播放

月
若月亮没来王宇宙Leto / 网易云音乐
01:5404:29
同步已开启刚刚
自动换源已开启
网易云账号已登录
v1.0.0.128可更新
界面 34平板 / 电视布局左侧导航轨、主内容网格与常驻播放侧栏;遥控器焦点按阅读顺序移动。

榜单只负责发现,
播放交给聚合层。

榜单是这次改版的新一级入口。平台排行榜本身不做跨平台合并,因为各平台的榜单口径不同,强行合成会产生一个没有意义的数字。跨平台只发生在“播放一首歌时重新找源”。

页面结构

榜单
├─ 顶部来源选择        网易云 / QQ / 酷狗…
├─ 主推榜单            趋势信息 + 前 3 首
├─ 更多榜单            该平台可用的榜单列表
├─ 平台热歌            当前来源的热门单曲
└─ 迷你播放器 + 五栏底导

进入榜单
├─ 封面、名称、更新频率、曲目数
├─ 播放全部 / 换源设置
└─ 排名列表
   ├─ 点击歌曲:播放并打开播放器
   └─ 更多:换源、其他版本、合并/拆分、收藏、下载

为什么这样分

原首页的“排行榜”只是推荐位;榜单作为主入口后,需要承载来源切换、榜单列表、热歌和详情页。与其把四种模块塞进首页,不如让榜单成为可反复浏览的空间。

不新增“综合热榜”。上游没有统一的加权公式,平台数据也不具备可比性。页面只展示真实的平台榜单;如果未来有可靠的数据源,再单独设计。

来源持久化

记住上次浏览的榜单来源,但默认仍使用设置中的默认平台;首次进入时与设置一致。切换来源只刷新本页,不改变播放设置。

交互与状态

场景界面行为实现注意
切换榜单来源顶部胶囊立即更新;主推榜单和列表显示骨架屏,失败时保留来源选择取消旧请求;用 generation 防止旧来源回包覆盖新来源
加载榜单详情显示封面和标题骨架;首批歌曲到达前不显示“暂无歌曲”缓存 `provider + chartId`;与通用歌单详情共用路由
播放全部建立 canonical 队列,按现有聚合策略逐首解析;不预先解析整张榜单避免 N 次封面/音频解析卡住界面;播放失败时继续到下一首并显示提示
平台没有榜单隐藏主推区,显示“这个平台没有提供排行榜”与“换来源”根据 `ProviderInfo.topLists` 能力判断,不发空请求
部分歌曲不可播歌曲行展示完整 / 试听 / VIP / 待检测标签,播放时按策略回退沿用 `availabilityOf` 与 `SourceResolver`,不在 UI 层自行判断

实现映射

数据来源

MusicRepository.topLists topListSongs hotSongs

页面状态

sourceProvider topLists featuredChartId chartSongs loading / error

复用组件

MediaList TrackRow SourcePickerSheet MiniPlayer

推荐与分类,
在同一个浏览上下文里。

歌单页把原首页的“推荐歌单”和“歌单分类”合并。推荐负责低决策成本的进入,分类负责有目的的寻找;两者共用同一个平台来源和详情页,不产生两套卡片样式。

结构

歌单
├─ 来源:网易云 / QQ / 酷狗 / 酷我…
├─ 推荐 | 分类
│
├─ 推荐
│  ├─ 主推歌单:大封面 + 标题 + 曲目数
│  ├─ 横向推荐行
│  └─ 分类快捷入口
│
└─ 分类
   ├─ 分类 chip 组(可折叠)
   ├─ 两列封面网格
   └─ 上一页 / 下一页

详情
├─ 封面、标题、来源、曲目数
├─ 播放全部 / 收藏整张歌单
└─ 与榜单详情相同的歌曲列表

刻意不做的事

不在歌单页做“聚合歌单内容”。同名歌单只是名字相同,曲目、顺序和版本都可能不同。搜索页可以把多个平台的同名歌单并列展示;歌单页本身只读取一个平台。

分类是可选能力

上游没有实现分类的平台直接隐藏“分类”段控件,保留推荐。不要用“暂无分类”占一屏。

分页留在本页

分类翻页后在列表底部展示“上一页 / 第 N 页 / 下一页”,不跳出当前歌单页。返回时恢复平台、分类和页码。

交互与状态

用户动作结果边界处理
切换歌单来源来源芯片变化;推荐和分类一起刷新只发该平台支持的请求;旧结果全部丢弃
切换推荐 / 分类保持页面滚动位置独立记忆没有分类能力时隐藏该入口
展开分类分类 chip 行变多,按钮“收起”页面不跳转,未选中的分类不变
翻页显示加载状态,底部追加或替换当前页返回第一页或空页时禁用按钮;失败保留原页
点歌单进入统一详情页,展示歌曲列表详情加载失败仍保留标题和来源,可重试

统一详情页的好处:平台歌单、排行榜、专辑和自建歌单都使用同一套歌曲行动作。以后新增“按顺序播放”“批量下载”或“添加到我的歌单”,只需要改一处。

先把音乐库做成
可以带走的东西。

“我的”承接喜欢、自建歌单、最近播放和下载。重点不是换一个名字,而是把自建歌单升级成真正属于用户的数据:可以编辑、可以导出、可以同步到 GitHub Gist 或 Gitee,并且在本机永远先可用。

页面结构

我的
├─ 顶部:云同步入口(状态点)
├─ 统计条:喜欢 / 自建歌单 / 已下载
├─ 段控件:喜欢 | 歌单 | 最近 | 下载
│
├─ 歌单
│  ├─ 同步状态横幅
│  ├─ 歌单列表(已同步 / 待同步 / 冲突)
│  └─ 新建歌单
│
├─ 喜欢 / 最近
│  └─ 歌曲行,支持播放与加入歌单
│
└─ 下载
   └─ 完成 / 下载中的本地文件

自建歌单详情
├─ 播放全部 / 添加歌曲
├─ 同步状态
├─ 排序与移除
└─ 更多:改名、删除、导出

为什么默认停在“歌单”

“喜欢”是一组自动形成的歌,“自建歌单”是用户主动维护、最需要同步和编辑能力的部分。作为本次改版的重点,进入“我的”默认展示歌单,其余段按用户上次选择记忆。

没有账号系统

这里的“我的”不是登录后的个人主页。应用没有自己的账号,只展示本机音乐库和第三方同步连接状态。

下载与收藏不强行同步

下载文件体积大且受版权限制;收藏与最近播放属于个人行为数据。V1 只同步自建歌单,避免把隐私和文件写入云端。

自建歌单的编辑交互

动作触摸 / 鼠标电视遥控器
新建歌单底部“新建歌单”,弹出名称输入框同样入口,输入使用系统键盘
添加歌曲曲目行更多菜单 →“添加到歌单”;或歌单详情“添加歌曲”进入多选菜单项获得焦点,确认后进入多选
调整顺序“编辑排序”后拖拽;也可用上下移动按钮不使用拖拽,选中歌曲后按上下键移动
移除歌曲曲目行更多菜单 →“从歌单移除”相同菜单,不使用滑动删除
改名 / 删除歌单详情右上角更多菜单相同菜单,删除二次确认
同步状态歌单行右侧显示已同步 / 待同步 / 有冲突状态同时有文字,不只靠颜色和圆点

立即反馈:所有编辑先写本机数据库,列表和歌单详情立即更新。同步失败只在同步入口显示状态,不用弹窗打断编辑;手动点“立即同步”时才展示详细错误。

设置是索引,
不是一个无限长的表单。

现有设置把所有内容堆在一个 LazyColumn 里,平台账号、聚合、缓存和 Cookie 混在一起。新设置按领域拆成独立子页,每个子页只回答一个问题;均衡器是设置索引里的独立入口。关于与更新也在这里有了稳定的入口。

设置索引

设置
├─ 外观
│  └─ 主题 / 动态配色 / 减少动画
├─ 播放与换源
│  └─ 换源模式 / 优先平台 / 试听 / 匹配严格度
├─ 均衡器
│  └─ 开关 / 预设 / 频段 / 自定义曲线
├─ 搜索与浏览
│  └─ 聚合平台 / 搜索范围 / 默认浏览来源
├─ 平台账号
│  └─ Cookie / 扫码登录 / 退出
├─ 音乐库同步
│  └─ 同步账户 / 自动同步 / Wi-Fi / 冲突
├─ 存储
│  └─ 播放缓存 / 匹配缓存 / 下载
└─ 关于与更新
   ├─ 版本、构建号、更新检查
   ├─ 开源许可、项目主页
   └─ 隐私说明、诊断信息

交互约定

设置项即改即存,没有底部“保存”按钮。令牌、Cookie 等敏感输入离开页面即清空明文,只保留加密存储。危险操作(清空缓存、断开同步、退出账号)都需要二次确认,并说明会影响什么。

平板与电视

宽度足够时变成左侧索引、右侧子页;电视仍使用导航栏 + 子页,不依赖触摸。所有开关和按钮获得明确焦点框。

关于不是设置垃圾桶

只放版本、更新、许可、隐私和诊断。播放参数留在各自的设置子页。

子页边界

子页包含不包含
播放与换源自动 / 优先 / 固定平台,优先顺序,是否允许试听,严格匹配,恢复自动匹配登录、缓存、主题、均衡器
均衡器开关、预设、设备实际频段、自定义曲线、重置换源策略、登录、缓存
搜索与浏览聚合平台多选,默认浏览来源,搜索范围播放源排序(放播放与换源)
平台账号当前平台选择、Cookie、扫码登录、退出自建歌单同步令牌
音乐库同步同步后端、账号、文件、自动同步、Wi-Fi、冲突平台 Cookie、下载管理
存储播放缓存、匹配缓存、下载文件、占用统计同步设置
关于与更新版本、更新、许可、隐私、项目链接、诊断账号和播放参数

音效在本机完成,
设置跟着设备走。

均衡器作为“设置 → 均衡器”的独立页面。它直接作用于当前播放会话,不修改音频文件,也不参与歌单同步;关闭页面后效果继续,重启应用后恢复上次设置。

界面与交互

设置
├─ 播放与换源
│  ├─ 换源模式
│  ├─ 优先平台
│  └─ 试听 / 严格匹配
└─ 均衡器
   ├─ 开关与当前输出
   ├─ 预设
   └─ 频段 / 自定义

均衡器
├─ 开关 + 当前输出状态
├─ 预设:平直 / 流行 / 摇滚 / 爵士 / 人声 / 自定义
├─ 频段滑杆(按设备实际频段绘制)
│  ├─ 拖动立即生效
│  ├─ 数值以 dB 显示
│  └─ 手动改动后自动切到“自定义”
├─ 恢复平直 / 保存为自定义
└─ 兼容性说明与当前播放源

为什么不做成浮层

均衡器是多参数、需要反复试听的页面。把它塞进播放器浮层会遮挡封面,也不方便精细拖动。独立页面能容纳完整频段、预设和兼容性说明,并能在播放器继续播放的同时操作。

实时生效:没有“应用”按钮。预设和频段变化直接写入音频效果,页面只显示当前值;退出页面不会撤销。

按设备绘制:原型画的是常见五段(60 Hz / 230 Hz / 910 Hz / 3.6 kHz / 14 kHz)。实际界面按 Equalizer.getNumberOfBands() 与中心频率生成,不伪造固定频段。

交互状态

场景界面行为实现注意
打开页面显示开关、当前预设、真实频段与增益;无播放会话时开关可用但标注“播放后生效”音效对象随播放会话创建;无会话时不盲目创建 Equalizer
切换预设所有滑杆在约 150 ms 内过渡到目标曲线,保留开关状态预设由应用定义,按对数频率插值到设备实际频段;不依赖系统预设名称
拖动频段数值与滑杆实时变化,预设自动变成“自定义”;防抖写 DataStore以 0.5 dB 或 1 dB 为步进写 setBandLevel;滑杆视觉轨道可细,触摸热区至少 44–48dp
电视 / 键盘左右切换频段,上下按 1 dB 调节;焦点框清晰可见,不使用拖动为自定义滑杆补 DPAD / 方向键处理;实时读屏描述“60 Hz,+6 dB”
切换歌曲 / 换源效果不中断,页面数值不重置如果 Media3 重建了 audio session,释放旧效果、用新 session 重建并重放设置
切换输出设备显示“当前输出:蓝牙耳机 / 扬声器”;若效果未生效明确说明部分蓝牙 / USB 路由不应用第三方音效,不能假装成功
设备不支持开关禁用并显示原因:系统或输出设备不支持均衡器捕获 UnsupportedOperationException / IllegalStateException,保留本机设置但不影响播放
下载播放同样使用本地文件播放会话,效果可用音效不写回下载文件;关闭后恢复原始声音

实现方式

播放会话

Media3 getAudioSessionId() 提供当前 audio session。

→
音频效果

用 session 创建 android.media.audiofx.Equalizer。

→
曲线映射

应用预设 dB 曲线到设备实际频段,写 band level。

→
状态回写

DataStore 保存开关、预设和自定义曲线。

控制器职责

EqualizerControllerapp 进程 / 跟随 PlaybackService
class EqualizerController(
    private val store: EqualizerSettingsStore,
) {
    fun attach(sessionId: Int)     // 创建或重建 Equalizer
    fun detach()                   // 播放器销毁 / session 失效
    fun setEnabled(enabled: Boolean)
    fun applyPreset(preset: EqPreset)
    fun setBandLevel(band: Short, millibels: Short)
    fun resetFlat()
    fun saveAsCustom()
}

// Media3:Player.Listener.onAudioSessionIdChanged
// 与 Player.getAudioSessionId() 获取会话。
// ExoPlayer 的相关 API 标注为 UnstableApi,
// 需要在 PlaybackService 中显式 OptIn。

保存与生效

DataStore 只保存 enabled、presetId 和自定义频段增益(dB)。应用启动或 PlaybackService 重建时读取并重新应用,不把设置写进歌曲或歌单。

预设曲线由应用定义:平直全 0 dB;流行强调低频与高频;摇滚提升低频和 3 kHz 附近;爵士轻微提升低频与高频;人声压低 60–230 Hz 并抬高中频。设备支持的频段数不同,就按中心频率做对数插值,而不是硬套五段。

不承诺所有耳机都生效。效果使用 Android 系统音频效果框架,受输出路由、OEM 音频实现和省电策略影响。界面要明确显示“当前输出是否生效”,不能把设置成功当成实际听到。

数据与生命周期

项目处理
音效对象不持久化;每次有可用 audio session 时创建,session 变化或播放器销毁时 release()
持久化开关、预设、自定义频段写入 DataStore;不跨设备同步,因为不同设备的频段和音频能力不同
权限不申请运行时权限;使用应用自己的播放会话。若某些 OEM 需要额外权限或能力,降级为不可用,不阻塞播放
后台播放控制器随 PlaybackService 存活;切到后台、锁屏或通知栏播放时效果保持
失败恢复创建结果用显式状态表达:Available / Unsupported / NoSession;失败时开关灰显,播放本身不受影响
不做不引入 NDK / 自研 DSP,不改变音频文件,不做响度战争式自动增益,不把音效设置写入同步 JSON

测试重点:在扬声器、有线耳机和至少一款蓝牙耳机上验证开关与频段;覆盖切歌、换源、切后台、播放结束、音源失败与蓝牙重连。设备不支持时必须显示“未生效”,而不是静默把滑块移来移去。

云端是副本,
本机才是主版本。

新增同步的目标只有一个:让用户自建的歌单可以在多台 Android 设备之间带走。实现上采用“本地数据库 + 单一版本化 JSON 快照 + 三方合并”,先支持 GitHub Gist 和 Gitee 代码片段,再扩展到其他后端。

V1 同步范围:仅自建歌单及其曲目元数据。不同步收藏、最近播放、下载文件、Cookie、播放地址、播放进度。这个边界既降低隐私风险,也避免把大文件和易失效 URL 写进 Gist。

后端适配

后端接入方式鉴权 / 存储版本识别优先级
GitHub GistGET/POST/PATCH /gists,建议私人 Gist,文件名固定Fine-grained PAT 或 classic token 的 gist 权限history[0].version + 内容 SHA-256V1
Gitee 代码片段/api/v5/gists,创建时设 public=falseGitee 私人令牌,勾选代码片段权限;API 接受 access_tokenupdated_at + 内容 SHA-256V1
GitLab Snippets/api/v4/snippets,私有 snippetPersonal Access Token,api 权限updated_at + 内容 SHA-256P2
WebDAVGET / PUT 固定 JSON 路径服务地址、用户名、应用密码ETag + If-MatchP2
文件导入导出系统文件选择器 SAF,读写 JSON无账号不适用V1

Gitee 与 GitHub 的 Gist 更新接口不提供强等价的 If-Match 语义。客户端采用“写前重读、版本未变才写、写后回读”的优化并发策略,并把无法确认的并发保留为下一次同步的冲突,而不是静默覆盖。

同步文件格式

mymusic-library.jsonschema v1
{
  "schema": "mymusic.library",
  "version": 1,
  "deviceId": "a7c2e6f1",
  "updatedAt": "2026-10-21T02:19:41Z",
  "playlists": [
    {
      "id": "b5e1d0e8-3a2f-4ff8-84b8-2f7da0f4c139",
      "name": "夜间驾驶",
      "createdAt": "2026-09-03T12:10:00Z",
      "updatedAt": "2026-10-20T22:40:10Z",
      "deletedAt": null,
      "tracks": [
        {
          "key": "netease:186016",
          "provider": "netease",
          "id": "186016",
          "title": "晴天",
          "artist": "周杰伦",
          "album": "叶惠美",
          "durationSec": 269,
          "cover": "https://example.invalid/cover.jpg"
        }
      ]
    }
  ]
}
稳定 ID

歌单使用 UUID,设备间不依赖自增主键。曲目使用 provider:id 作为稳定键。

删除用墓碑

删除歌单写入 deletedAt,同步一轮后再清理,避免另一台设备把删除项重新创建。

体积控制

只存元数据。单一文件超过 900 KB 时停止自动上传并提示导出,不在 Gist 中无界增长。

同步流程

本地修改

Room 立即提交,标记 dirty;界面先完成。

→
调度

WorkManager 延迟合并,网络可用时启动。

→
三方合并

上次同步基线 / 本机 / 云端逐歌单比较。

→
写回

无冲突则上传;有冲突则停止并显示冲突入口。

连接流程

一
选择后端并输入凭据

选择 GitHub Gist 或 Gitee,填写令牌。界面提供最小权限说明和创建令牌的入口文案,但不把令牌写到日志。

必须
二
验证身份与权限

读取当前用户信息,验证令牌至少能访问 Gist。失败区分“未授权”“权限不足”“网络不可达”。

必须
三
创建或选择远端文件

默认新建私人 Gist / 代码片段,文件名为 mymusic-library.json;也可以粘贴已有 Gist ID 或链接。

必须
四
首次合并预览

分别显示本机与云端的歌单数、曲目数。两端都有内容时,让用户选择合并、保留本机或使用云端;先自动导出一份本机备份。

必须
五
上传基线并开启自动同步

保存远端版本号与内容哈希作为下次三方合并的基线。默认开启自动同步,允许只走 Wi-Fi。

必须

冲突策略

本机 / 云端相对上次基线处理用户看到什么
只有本机改变直接上传本机版本同步横幅显示“正在同步”,完成后显示时间
只有云端改变直接拉取云端版本更新本机歌单行短暂显示“正在更新”,不用弹窗
两边都未变不写远端,刷新同步时间只更新“刚刚检查”状态
两边都变,已有一方删除冲突,绝不自动删除“本机删除了这个歌单,云端修改了它。选择保留或删除。”
两边都变,内容不同冲突,默认“合并两版”显示歌单名、两侧曲目数与修改时间;可选本机、云端或合并
远端 JSON 损坏或 schema 不支持停止上传,保护本机“云端文件无法读取,本机数据没有改动。”提供重新选择文件或导出本机数据

数据与安全

本机模型

Room v4新增 / 迁移
playlists
  id TEXT PK (UUID)
  name TEXT
  createdAt / updatedAt
  dirty INTEGER
  deletedAt TEXT?

playlist_entries
  playlistId TEXT FK
  position INTEGER
  songKey TEXT
  payload TEXT

sync_accounts
  provider TEXT PK
  remoteId TEXT
  fileName TEXT
  lastSyncedAt INTEGER
  remoteRevision TEXT
  autoSync INTEGER
  wifiOnly INTEGER

sync_base
  accountId TEXT PK
  snapshot TEXT
  remoteRevision TEXT

sync_conflicts
  playlistId TEXT PK
  localSnapshot TEXT
  remoteSnapshot TEXT
  detectedAt INTEGER

凭据与迁移

令牌使用 Android Keystore 的 AES-GCM 密钥加密,存入独立的 SecretStore,不进入 Room,也不进入同步 JSON。应用备份规则排除 SecretStore;断开同步时删除令牌和基线,但保留本机歌单。

现有 LocalPlaylist(id: Long, songs: JSON) 迁移到 UUID 歌单和逐条曲目表:开新表、解析旧 JSON、复制曲目和顺序、最后切换读取路径。迁移必须在事务中完成,旧表保留一个版本周期再删除。

私人 Gist 不是加密存储。它只是不出现在公开列表里。不要同步 Cookie、令牌或任何下载地址;同步文件只放歌单元数据。

自动同步的触发与克制

触发行为
歌单编辑标记 dirty,30 秒防抖后调度一次后台同步;5 分钟内不重复跑同一账户
App 回到前台若距上次同步超过 15 分钟且网络满足条件,静默拉取一次
手动“立即同步”忽略节流,显示显式进度和结果;失败弹 Snackbar,并给出重试
无网络 / 仅移动网络且开启 Wi-Fi 限制保持待同步,不弹错误;网络恢复后由 WorkManager 重试
令牌失效暂停自动同步,显示“需要重新登录”;本机编辑继续可用

更新是一个校验流程,
不是一条下载链接。

应用内更新放在“关于与更新”:显示当前版本与构建号,自动检查静默进行,手动检查才展示结果。下载完成后必须校验哈希、包名、版本号和签名,再交给 Android 系统安装器,绝不静默安装。

发布清单

CI 在 Release 中同时发布 APK、update.json 和 APK 的 SHA-256。客户端读取稳定版的更新清单;清单不可用时退回浏览器打开 Release 页面。

update.json随 Release 发布
{
  "schema": "mymusic.update",
  "channel": "stable",
  "versionCode": 129,
  "versionName": "1.0.0.129",
  "tag": "v1.0.0.129",
  "publishedAt": "2026-10-20T08:00:00Z",
  "minSdk": 23,
  "apk": {
    "url": "https://github.com/mytv-android/myMusic/releases/download/v1.0.0.129/myMusic-1.0.0.129.apk",
    "size": 19293798,
    "sha256": "8b0f...9c4e"
  },
  "notes": [
    "自建歌单可以同步到 Gitee 代码片段。",
    "修复换源播放中断后进度没有恢复的问题。",
    "电视端榜单焦点顺序调整。"
  ]
}

当前 CI 已经把 VERSION_CODE 写入构建,Release 的版本号形如 1.0.0.{run_number}。发布清单直接复用构建产物里的 versionName / versionCode,避免手工维护不一致。

检查与安装流程

检查

启动后最多每 24 小时一次,缓存 ETag;手动检查立即请求。

→
比较

只比较 versionCode,版本名仅用于展示。

→
下载

后台下载 APK,显示进度,可取消;只接受清单中的大小。

→
校验

SHA-256、包名、versionCode、签名证书逐项比对。

→
安装

FileProvider 打开系统安装器,用户确认覆盖安装。

自动检查不打扰

启动时如果发现稳定版更新,只在设置索引的“关于与更新”旁显示一个圆点,不弹窗。用户进入关于页才看到版本差异与更新说明。同一版本被“稍后”后,24 小时内不再提示。手动检查则无论是否有更新都给出明确结果。

只提供稳定通道。当前 main 发布稳定版,dev 为预发布;V1 不跟随预发布,避免用户被开发版打断。将来要加测试通道时,在清单里增加 channel 并由用户显式选择。

必须处理的失败

网络失败显示“检查更新失败”,提供重试和浏览器打开;不缓存错误结果
APK 哈希不符删除文件,提示“更新包校验失败”,不安装
包名不符视为错误清单,拒绝安装并记录诊断信息
版本号不高于当前视为服务端清单异常,提示已是最新版本
签名与当前安装不一致明确说明无法覆盖安装,建议从当前渠道重新下载;不能引导用户直接卸载而丢数据
未知来源权限未开启跳转到本应用的“安装未知应用”设置页;返回后保留已下载文件
存储空间不足在下载前检查清单大小,显示所需空间,不产生半截文件

关于页内容

区块内容动作
应用图标、名称、版本名与 versionCode、AGPL-3.0 标识无
更新检查更新、可用版本、发布说明、下载大小打开更新面板
许可与来源AGPL-3.0 完整许可、music-lib 上游 commit、第三方依赖清单查看文本或项目主页
隐私Cookie 和播放记录仅存本机;同步只写歌单元数据;没有集中式服务器查看详细说明
诊断版本、设备型号、Android 版本、启用的平台、最近一次同步/更新错误复制,明确不含 Cookie 和令牌
链接项目主页、问题反馈浏览器打开

Android 集成点

权限

REQUEST_INSTALL_PACKAGES 用于发起安装;Android 8+ 仍需用户在系统设置中允许“安装未知应用”。

文件共享

使用已有的 androidx.core 提供的 FileProvider,在 Manifest 中声明 cache/updates 路径。

包校验

用 PackageManager.getPackageArchiveInfo 读取 APK 的包名、versionCode、签名证书,与已安装应用比较;Android 6–8 使用旧签名 API 分支。

CI

在 Release job 中根据 output-metadata.json 生成 update.json 和 SHA-256,上传为 Release assets;只在成功完成测试后发布。

先拆页面,
再拆状态。

现有 AppUi.kt 约一千行、MusicViewModel.kt 约一千四百行,首页、搜索、音乐库和设置都写在一起。建议分两步,而不是一次性重写:先把 UI 按新入口拆开,复用现有数据与播放逻辑;再把同步和更新做成独立的数据层与状态持有者。

目标结构

导航

根导航五个入口;详情页使用 NavHost 路由。播放器保持全局浮层,不属于任何一个页签,切换页面不会中断。

UI 页面

ChartsScreen PlaylistsScreen SearchScreen LibraryScreen SettingsScreen ChartDetail / PlaylistDetail / LocalPlaylistDetail SyncCenter AboutScreen UpdateSheet

共享组件

MediaList TrackRow SourcePickerSheet PlayerBar EmptyState ErrorState FocusableCard

状态

保留全局播放与平台状态;拆出 SearchUiState、LibraryUiState、SyncUiState、UpdateUiState。不要继续把所有字段塞进一个 MusicUiState。

数据

MusicRepository SettingsStore Room v4 EqualizerController SyncCoordinator PlaylistSyncProvider SecretStore UpdateRepository ApkVerifier

涉及的文件

路径动作内容
ui/AppNavigation.kt新增五栏根导航、详情路由、播放器浮层、返回栈
ui/AppScaffold.kt新增手机底栏 / 平板电视导航栏,迷你播放器,Snackbar 宿主
ui/AppUi.kt拆分保留共享 UI;主页、音乐库、设置拆到各自目录
ui/charts/新增榜单列表、榜单详情、来源切换
ui/playlists/新增推荐 / 分类浏览、平台歌单详情
ui/search/新增搜索落地、结果列表、搜索历史
ui/library/新增我的、自建歌单编辑、同步中心、冲突处理
ui/settings/新增设置索引、播放与换源、均衡器、账号、存储、关于页、更新面板
playback/EqualizerController.kt新增绑定 Media3 audio session,创建 / 重建 Equalizer,应用预设与频段并处理不支持状态
playback/PlaybackService.kt修改在创建 / 重建播放器时把 audio session 交给 EqualizerController;服务销毁时释放效果
data/sync/新增PlaylistSyncProvider、Gist / Gitee 适配、合并引擎、WorkManager worker、SecretStore
data/update/新增更新清单解析、下载、哈希/签名校验、安装 Intent
data/AppStore.kt修改Room v4、歌单条目、同步账户与基线;DataStore 增加均衡器开关、预设和自定义频段;保留收藏 / 历史 / 下载表
ui/MusicViewModel.kt提取播放与聚合逻辑剥离为稳定内核;搜索、音乐库、同步各自状态
.github/workflows/build.yml修改发布 APK 时生成 update.json 与 SHA-256
app/src/main/AndroidManifest.xml修改安装包权限、FileProvider、密钥备份排除规则
gradle/libs.versions.toml修改加入 WorkManager;同步网络任务与重试

状态边界

保留为全局

播放队列与播放器 当前播放源 平台能力表 Cookie / 账号 聚合设置 均衡器开关与预设 下载记录

这些状态会跨页签存在,且播放不能被搜索或音乐库页面的生命周期打断。播放器与 MediaController 仍由全局持有者管理。

下沉为页面状态

榜单来源与缓存 歌单来源与分页 搜索查询与历史 我的分段与编辑模式 同步状态与冲突 设置子页输入

每个页面只持有自己需要的状态。切换页签时保留,离开应用后不要求恢复草稿;搜索历史、歌单来源等需要持久化的内容写入 DataStore。

分阶段实施

一
导航与页面拆分

五个根入口、三类详情、全局播放器浮层;把现有首页模块移到榜单与歌单。先保持数据逻辑不变,确保没有功能倒退。

无数据迁移
二
搜索与统一详情

搜索落地页、历史、链接识别、音源底部面板;榜单、歌单、专辑接入同一套媒体列表与操作。

复用引擎
三
音乐库编辑与 Room v4

自建歌单改为 UUID + 曲目条目;加入排序、移除、添加到歌单;完成旧数据迁移与回归测试。

需迁移
四
同步内核

PlaylistSyncProvider 抽象、GitHub Gist、文件导入导出、三方合并、冲突 UI 和 WorkManager。先在本地文件后端上跑通合并测试。

重点
五
Gitee 与更多后端

接入 Gitee 代码片段,验证令牌权限、私人片段和更新语义;GitLab / WebDAV 作为适配器扩展,不阻塞首发。

P2
六
更新与关于

Release 更新清单、下载校验、签名比对、系统安装器、关于页、许可与诊断;补齐 TV 焦点与失败状态。

独立
七
均衡器与音频效果

接通播放器 audio session,加入五段 / 设备实际频段均衡、预设、自定义保存、输出设备状态和能力降级。先用真机验证系统是否应用效果,再发布。

独立

测试重点

同步合并单元测试

覆盖本机新增、远端新增、删除墓碑、双改冲突、远端损坏、同曲目不同顺序等场景。合并函数不依赖 Android,先用纯 JVM 测试。

更新校验测试

伪造哈希不一致、错误包名、低版本号、签名不一致,确保都在打开系统安装器前被拒绝。

播放回归

切换五个页签、打开详情、播放中断换源、下载优先本地文件,播放状态不能被页面销毁或搜索取消影响。

均衡器真机矩阵

至少覆盖扬声器、有线耳机、一款蓝牙耳机与一台不支持音效的设备;测试重建 audio session 后设置是否恢复,以及切换输出时是否如实显示生效状态。

TV 与无障碍

遥控器能完成搜索、换源、打开同步、处理冲突、调均衡器和检查更新;状态不只靠颜色表达,焦点框在全套组件中一致。

做到这些,
这次重设计才算完成。

验收清单

这次明确不做

综合热榜

没有可信的统一排名口径,不编造跨平台名次。只展示各平台真实榜单。

同步收藏和播放历史

V1 只同步自建歌单,避免把行为数据和个人偏好写进第三方 Gist。

把歌单写入第三方音乐平台

不调用各平台的写接口,不产生账号间数据不一致。自建歌单只存在于本机与用户选择的同步后端。

静默安装更新

Android 需要用户确认安装。应用负责下载和校验,系统安装器负责最后一步。

自动迁移不同平台的同名歌单

同名不代表同内容。只做并列展示,不做隐式合并。

云端中转服务

不自建账号、不代理播放地址、不收集 Cookie。同步直接发生在设备和用户自己的 Gist / Gitee 之间。

下一步建议:先按阶段一完成五个入口和共享详情页,拿着这版 HTML 对照真机确认导航与焦点;然后单独评审同步协议和冲突文案,再接入 Gist。这样不会让“同步”这个新能力把整次改版拖成一次大爆炸式重构。