简体中文 | English
针对 iPod nano 第 5 代与第 6 代的 iTunes Genius Mix 研究。仓库给出设备 .itdb 数据库的字节级布局、Genius 约束链求值语义、簇邻接图、Mix 状态机门槛与歌单门控,以及一套仅依赖 Python 标准库的修复、对齐、聚类与模拟工具。文末的发现路径给出结论从容器枚举到字节码消融的收敛过程。
Genius 由四个独立数据面构成:Kind-32 容器保存候选种子,genius_similarities 提供候选边,genius_metadata 存储约束键,genius_config.data 是逐条约束的字节码。Mix 的可用阈值为 count >= 2(目标 10 首);按曲目生成歌单的默认目标为 25 首、下限 10 首。
第 5 代与第 6 代使用同一份 151,212 字节的原厂 genius_config.data,数据库结构只差 Dynamic.itdb.item_stats 的一列。逐项对照见跨代验证。
- 6G 的
Dynamic.itdb.item_stats.genius_id必须与Library.itdb.item.genius_id逐首一致,否则 Mix 会出现但为空/不可播;生成与部署工具已自动同步/校验。 - 回放增益有两条独立链:
item.relative_volume(逐曲)与avformat_info.volume_normalization_energy(音量平衡/Sound Check,X=1000*10^(-G/10));设置只作用于后者。 - 歌曲排序由
item.title_order决定;tools/fix_sort_orders.py按 A-Z(忽略冠词)→ 汉字拼音 → 数字重建,并同步 artist/album/genre 依赖表。 - 详见 关键结论。
按曲目生成 Genius 歌单 Genius Mix
当前曲目有效且 genius_id 非零 Kind-32 容器遍历器
| item_to_container 按 physical_order
| 排除 item.genius_id == 0
| |
| LCG 随机种子抽样器 (Primary 门控)
| n=0 失败;n=1 直接取唯一种子
| n>1 无放回抽样,至多 min(n,100)
| 仅 j=0 成功时设置 primary
| 后续成功进入 extras,不补 primary
+----------------------+---------------+
|
Mix 曲目生成入口 (NextMixTrack 执行器)
|
Genius 图遍历与歌单构建共用核心
|
genius_metadata 查询种子:无行或空 data 即失败
32B 基线 = 4×小端 u64 约束键,供 op=1/2 按 field 取键
|
genius_similarities:读取候选 genius_id -> 扩展、去重、解析 metadata
|
Config 约束字节码求值器 (Constraint Evaluator)
op=2 簇邻接白名单 / op=1、3 同键间隔 / op=4 跳过统计
op=5 随机抖动;返回 0 接受、1 暂拒、2 拒绝并标记已见
|
接受曲目 -> 更新约束状态 -> 继续扩展
|
Mix:target=10 / minimum=2;单曲歌单:默认 25 / 10
达到目标停止;count >= minimum 且对象有效即可用
修复工具按同容器步长 1/5/9/13 写入四个合法 genius_id,得到每行 32B 的约束键。该构造早期称为“同容器稠密连通图”;第三轮解码确认槽位语义为约束键,候选可达性由 genius_similarities 提供。每节点最多四个引用,小容器允许重复键。
| 变体 | 保留条目 | 大小 | 最终结果 |
|---|---|---|---|
cfg_empty |
无 | 48 B | 可用 |
cfg_jitter |
#6 random_jitter |
52 B | 可用 |
cfg_limits |
#2/#3 distance、#4 skip_count |
108 B | 可用 |
cfg_notable |
#1..#6,无大表 |
120 B | 可用 |
cfg_tableonly |
#0 591 项大表 |
151,140 B | 失败 |
cfg_tableonly(只含 591 项大表)在离线模型上失败。设备基线(第 11–16 轮)把准入定在 op=2 的命中与否:命中通过,未命中返回 2,该条目缺席时约束不实例化;metadata 长度与 field=20 的取值都不改变可播性,见跨代验证 §2。108B cfg_limits 是保留两条 distance 与一条 skip_count 的紧凑方案,详见格式文档。
原始 151,212B 配置在两代设备上逐字节不改即可运行,载体是 genius_metadata.data 的 168B(21 个 u64)布局:第 7 条的 field=20 因此按曲目读到真实键,间隔约束对每首曲目生效。32B 布局下该条目取键 0,可播性由 op=2 的命中与否决定,与长度无关(跨代验证 §2)。
再把 metadata[0] 填成簇表内的 id,op=2 的簇邻接白名单就会按流派收敛候选。簇表有 33 个连通分量,其中若干是完全图;把同一家族的流派放进同一分量的不同簇,族内互兼容、族间被过滤。候选仍来自 genius_similarities,使用库级池——收窄到容器级会让小容器候选不足。
完整方案、参数与校验见对齐文档;边界实测见边界记录,逐轮真机验证见真机轮次记录,回放增益见增益说明,Mix 名称与本地化见命名说明,设备级差异见跨代验证。
环境为 Python 3.9+,仅依赖标准库。操作前退出 iTunes 等同步软件。工具在已有 Kind-32 容器与已有非空 similarities 上就地改写约束键和配置。
$dbDir = Read-Host '请输入 iTunes Library.itlp 目录'
$backupDir = Read-Host '请输入仓库外的私人备份目录'
python tools/apply_genius_mix_fix.py "$dbDir" --backup-dir "$backupDir"工具先校验输入,用 SQLite 备份接口保存全部 .itdb 快照,然后在单一事务内改写 Genius.itdb 的 metadata 与 id=1 配置。默认构造 108B cfg_limits;--config empty 选择 48B 空约束变体。全程无外部二进制依赖。
输入基线:
- 容器为 Kind-32,每个 Mix 至少包含两个不同且非零的
genius_id - 成员具备 metadata 与非空 similarities,各 Mix 成员互不重叠
Dynamic.itdb.item_stats.genius_id与Library.itdb.item.genius_id一致;生成与部署工具会自动同步并校验该列,genius_sim.py --strict-stats可把不一致当作失败- 工具沿既有 similarities 图求值;新增可达性通过实际播放确认
完成后安全弹出并重启 iPod,检查实际播放。同步软件会覆盖离线改动。恢复时退出同步软件,把备份目录中的数据库文件放回原库目录。
# 1) 只扫描并生成专辑缓存(不改设备)
python tools/apply_album_replaygain.py --dev I: --dry-run --resume --jobs 4
# 2) 写 SoundCheck 并清零旧的 relative_volume
python tools/apply_soundcheck_from_replaygain.py --dev I: --apply| 文件 | 用途 |
|---|---|
tools/apply_genius_mix_fix.py |
兼容方案:保留容器,写入 32B 约束键与 48B / 108B 配置,并同步 item_stats.genius_id |
tools/cluster_align.py |
原始配置方案:簇对齐 + 168B metadata + 库级 similarities,并同步 item_stats.genius_id |
tools/cluster_graph.py |
解码 op=2 簇邻接表,输出连通分量与完全分量 |
tools/custom_graph.py |
自定义聚类:按 spec 写出 metadata 首槽与 similarities,同步 item_stats.genius_id,校验容器内标签相邻 |
tools/genius_sim.py |
离线模拟器:按固件语义复现生成流程;--strict-stats 在 item_stats 不一致时失败 |
tools/deploy_aligned.py |
部署:快照备份 + 输入校验(含 item_stats 一致性)+ 写入 + 刷盘 |
tools/boundary_matrix.py |
边界测试夹具:按规格合成 Kind-32 容器 |
tools/genius_stats.py |
6G item_stats.genius_id 的同步、校验与刷盘辅助;5G 自动降级为无操作 |
tools/fix_sort_orders.py |
重建歌曲/艺术家/专辑/流派排序键:A-Z(忽略冠词)→ 汉字拼音 → 数字,含依赖表与快照 |
tools/apply_album_replaygain.py |
专辑级 ffmpeg ReplayGain 扫描与缓存;--dry-run 只生成缓存,--apply 写 relative_volume |
tools/apply_soundcheck_from_replaygain.py |
复用专辑缓存写 SoundCheck volume_normalization_energy,并清零 relative_volume |
全部工具只依赖 Python 标准库;genius_sim.py 与 cluster_align.py 可完全离线运行。
生成器、部署器与模拟器共用 tools/genius_stats.py:6G 上逐首同步
Dynamic.itdb.item_stats.genius_id,5G 上自动跳过。
- 定位容器:在
Library.itdb中按container.distinguished_kind=32枚举 Genius Mix 容器,由item_to_container取出成员与physical_order。 - 收敛调用点:沿
genius_metadata查询与genius_config.data读取点,把生成逻辑收敛到 Mix 遍历器与NextMixTrack执行器。 - 解码字节码:按 opcode 决定长度解析
data,得到 op=1/3 distance、op=2 簇邻接、op=4 统计过滤、op=5 随机抖动,并还原 151,212B 原配置的七条条目与控制尾。 - 二分消融:固定容器与 similarities,仅替换
data,得到 48B / 52B / 108B / 120B 可用与 151,140B 失败。 - 隔离冲突:离线模型把失败点收敛到
op=1 field=20在 32B metadata 下的键 0 停滞。 - 落地修复:按同容器步长 1/5/9/13 写入 32B 约束键,配套 SQLite 快照备份与单事务写入。
- 解码簇表:
op=2的邻接表为无向图,591 个节点全部带自环,含多个完全图分量;把流派映射到同一分量的不同簇即可获得出厂语义。 - 修正失败点:离线模型把失败点收敛到第 7 条
op=1 field=20对 32B metadata 的越界读取;第 11–16 轮的真机单变量序列把准入判据定在op=2的命中与未命中,原七条在 32B 与 168B 两种 metadata 下均可播。 - 边界实测:合成 1 … 189 个成员、1 … 7 个流派的容器,确认容器数量、成员数与流派跨度均无上限;空容器可见但不可播;重复成员行无副作用。
- 跨代复核:在 nano 5G 上重跑单变量序列,确认两代共用同一份原厂
genius_config.data,结构差异只在Dynamic.itdb.item_stats的一列。 - 自定义聚类:以
op=2的完全分量为标签池,把自定义聚类映射到簇 id,由tools/custom_graph.py写出并校验。
本项目给出 iPod nano 的 Genius 数据库结构与整数布局,以及修复、对齐、聚类与模拟工具和规范文本。模拟结果来自离线分析,真机结果取自测量记录。贡献方式见 CONTRIBUTING.md,安全问题见 SECURITY.md。