资讯动态

VutronMusic 数据库 Schema 全解析:SQLite 多插件音乐库的存储设计

发布时间:2026/10/14 20:20:16 来源:尧图企业网站定制
桌面应用音视频前端【免费下载链接】VutronMusic高颜值的第三方网易云播放器通过自写插件可支持其他线上音乐服务支持流媒体音乐如navidrome、jellyfin、emby支持本地音乐播放、离线歌单、逐字歌词、桌面歌词、Touch Bar歌词、Mac状态栏歌词显示、Linux-gnome与Linux-kde桌面状态栏歌词显示支持降调降速支持自定义主题等。支持 Windows / macOS / Linux :electron:项目地址https://gitcode.com/gh_mirrors/vu/VutronMusic点击查看免费下载导读VutronMusic 作为一款高颜值第三方网易云播放器同时支持本地音乐、在线音乐库网易云、酷狗与流媒体服务Navidrome、Jellyfin、Emby等多源播放。要让同一首歌在多个平台各有一个身份这一复杂关系被可靠持久化项目选择SQLite better-sqlite3作为本地存储引擎并设计了一套以Track/TrackSource/Audio三表分离为核心的数据库 Schema。本文将基于官方架构文档 数据库 Schema 参考 与仓库真实建表脚本 plugin.sql逐表拆解 20 张表的字段含义、表间关联、设计决策与迁移机制帮助你理解用户拥有的歌曲在 VutronMusic 中如何被建模与访问。一、Schema 的定位与数据架构背景在深入逐表结构之前先明确这张 Schema 在整体架构中的位置。数据架构总览文档 数据架构总览 给出了几个关键结论项目内容引擎better-sqlite3同步 API主进程直接调用文件路径{userData}/api_cache/vutron_music.sqlite建表脚本src/public/migrations/plugin.sql→ 20 张表初始化入口src/main/db.ts建表 → 开启 WAL → 执行迁移查询辅助层src/main/dbHelpers.ts去重 / 匹配 / CRUD / 跨表组装插件数据访问插件通过api.db.get / set读写PluginData表渲染进程访问❌ 不允许必须通过 IPC 间接访问最核心的一条设计原则是Track/Album/Artist表只存储用户拥有的歌曲本地文件、加入歌单的歌曲而搜索、浏览的结果只存在于渲染进程 Pinia store 的内存中不落库。这保证了数据库体积可控、数据语义清晰。从架构决策记录 ADR-0004SQLite Schema 可以看到项目曾对比过 JSON 文件存储与 IndexedDB最终因复杂多对多 JOIN 查询、离线可用、零配置、跨平台、同步 API 不阻塞 UI等优势选择了 SQLite better-sqlite3。二、表一览20 张表的职责地图Schema 参考文档首先以表格形式给出了全部表的业务用途与核心关联完整继承如下#表名业务用途核心关联1Track歌曲元数据用户拥有的→ Album, → Audio, → TrackSource2Album专辑元数据→ Track, → ArtistAlbum3Artist艺术家元数据→ TrackArtist, → ArtistAlbum4Audio本地音频文件信息→ Track5TrackSource歌曲在各插件的映射↔ Track, ↔ Plugins6AlbumSource专辑在各插件的映射↔ Album, ↔ Plugins7ArtistSource艺术家在各插件的映射↔ Artist, ↔ Plugins8TrackArtistTrack-Artist 多对多关联↔ Track, ↔ Artist9ArtistAlbumArtist-Album 多对多关联↔ Artist, ↔ Album10Lyrics歌词内容每插件一份↔ Track, ↔ Plugins11LyricOffsets歌词行偏移微调↔ Track, ↔ Plugins12Playlist歌单→ Plugins13PlaylistEntry歌单项引用 sourceContext→ Playlist14Plugins已注册插件清单—15PluginData插件自由键值存储→ Plugins16AppData应用级配置—17Unblock解锁/替代源—18LocalAlbumCover本地专辑封面缓存—19AppleMusicAlbum(遗留) Apple Music 专辑—20AppleMusicArtist(遗留) Apple Music 艺术家—表格来源src/public/migrations/plugin.sql。需要注意两点TrackSource/AlbumSource/ArtistSource三类*Source表是整套设计的枢纽——它们把抽象元数据实体与各插件中的具体坐标解耦Unblock、LocalAlbumCover、AppleMusicAlbum、AppleMusicArtist在 Tables 枚举 中仍被保留但属于历史遗留表业务上已基本不再使用。三、核心表结构详解Schema 参考文档给出了 5 张核心表的精简 SQL下面结合 plugin.sql 中的完整定义逐表展开并补充字段说明。3.1Track— 歌曲元数据CREATE TABLE IF NOT EXISTS Track ( id TEXT PRIMARY KEY, name TEXT NOT NULL, duration INTEGER NOT NULL, albumId TEXT, no INTEGER NOT NULL DEFAULT 0, alias TEXT NOT NULL DEFAULT , picUrl TEXT NOT NULL DEFAULT , playCount INTEGER NOT NULL DEFAULT 0, liked INTEGER NOT NULL DEFAULT 0, deleted INTEGER NOT NULL DEFAULT 0, musicBrainzTrackId TEXT, createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY(albumId) REFERENCES Album(id) );字段说明字段含义id字符串主键格式为${pluginId}:${type}:${key}见下文主键格式name歌曲名duration时长毫秒albumId所属专辑外键指向Album(id)no在专辑中的曲目序号alias别名如翻译名、其他语种名picUrl封面图 URLplayCount播放次数支持通过$inc原子自增liked是否喜欢0/1deleted软删除标记0/1所有业务查询默认WHERE deleted 0musicBrainzTrackIdMusicBrainz 全球曲目 ID用于强去重归并musicBrainzTrackId是去重策略中强匹配的关键依据详见 Track 数据模型设计。3.2Audio— 本地物理音频文件CREATE TABLE IF NOT EXISTS Audio ( id TEXT PRIMARY KEY, trackId TEXT NOT NULL, filePath TEXT NOT NULL, md5 TEXT NOT NULL, bitrate INTEGER NOT NULL DEFAULT 0, gain REAL NOT NULL DEFAULT 0, peak REAL NOT NULL DEFAULT 1, size INTEGER NOT NULL DEFAULT 0, deleted INTEGER NOT NULL DEFAULT 0, cueOffset INTEGER NOT NULL DEFAULT 0, cueDuration INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(trackId) REFERENCES Track(id) );字段说明字段含义id本地文件唯一 IDtrackId外键指向Track(id)一个 Track 可对应多个 Audio如多版本filePath本地物理文件路径文件移动时只需更新此字段md5文件哈希用于内容级去重bitrate比特率gain/peakReplayGain 响度归一化数据由缓存流程写入对应songUrl返回的replayGain、peaksize文件大小字节cueOffset/cueDurationCUE 分轨的起始偏移与时长用于 CUE 整轨文件拆出的分轨歌曲3.3TrackSource— 歌曲跨插件映射CREATE TABLE IF NOT EXISTS TrackSource ( trackId TEXT NOT NULL, pluginId TEXT NOT NULL, sourceContext TEXT NOT NULL, matched INTEGER NOT NULL DEFAULT 1, createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(trackId, pluginId) );这是整套多源架构的枢纽表。它的设计决策可追溯到 ADR-0002TrackSource 表设计项目放弃了在 Track 表为每个平台加列和预留 JSON 字段两种方案最终选择每行记录一个(trackId, pluginId)映射。其优势在于Schema 稳定新增平台 插入新行无需修改表结构支持多实例同一平台多个实例如两个 Navidrome 服务器可通过不同插件 ID 共存插件私有上下文sourceContext是插件自行生成与维护的 JSON 文本框架层不解析、只透传人工确认标记matched字段0/1记录当前音源与歌曲元数据是否已经过人工匹配确认注释见 plugin.sql 第 103 行。sourceContext的具体形态因插件而异例如// 网易云 { id: 536099, albumId: 12345, artists: [{ id: 678, name: 买辣椒也用券 }] } // 本地 { filePath: /music/起风了.flac, md5: abc123 } // Navidrome { id: song-001, streamUrl: /api/song/001/stream }这些示例与框架不解析的约定在 Track 数据模型设计 中有完整说明。3.4Plugins— 插件注册表CREATE TABLE IF NOT EXISTS Plugins ( id TEXT PRIMARY KEY, name TEXT NOT NULL DEFAULT , type TEXT NOT NULL DEFAULT , path TEXT NOT NULL DEFAULT , builtIn INTEGER NOT NULL DEFAULT 0, enabled INTEGER NOT NULL DEFAULT 1, createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP );字段说明字段含义id插件 ID也是 TrackSource 等表中pluginId的取值name插件显示名type插件类型local本地音乐/library在线音乐库/stream流媒体服务器path插件文件路径builtIn是否内置插件1 为内置enabled是否启用1 为启用默认启用建表脚本同时预置了 6 个内置插件INSERT OR IGNORE INTO Plugins (id, name, type, builtIn) VALUES (local, 本地音乐, local, 1), (kugou, 酷狗音乐, library, 1), (netease, 网易云音乐, library, 1), (emby, Emby, stream, 1), (jellyfin, Jellyfin, stream, 1), (navidrome, Navidrome, stream, 1);type字段同时被大量 SQL 联表查询使用例如在deleteCacheFromDB中通过JOIN Plugins p ON ts.pluginId p.id判断某 Track 是否还有local/stream来源以此决定是否清理孤立 Track见 dbHelpers.ts。3.5PluginData— 插件自由键值存储CREATE TABLE IF NOT EXISTS PluginData ( id TEXT NOT NULL, pluginId TEXT NOT NULL, type TEXT NOT NULL, json TEXT NOT NULL, updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) );PluginData为插件提供通用的 KV 扩展能力插件可通过api.db.get / set访问见 插件开发入门。从实现上看setPluginData 以id pluginId -1的固定形式写入登录态、token、cookie 等数据而 getPluginData 在无记录时返回{ userId: 0, userName: , pwd: , isVip: false, cookie: , token: }作为默认登录态。四、其余表结构补全Schema 参考文档指出其余表的具体定义见plugin.sql这里将完整定义补全方便整体把握。4.1Album/Artist— 专辑与艺术家元数据CREATE TABLE IF NOT EXISTS Artist ( id TEXT PRIMARY KEY, name TEXT NOT NULL, picUrl TEXT NOT NULL DEFAULT , description TEXT NOT NULL DEFAULT , followed INTEGER NOT NULL DEFAULT 0, createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS Album ( id TEXT PRIMARY KEY, name TEXT NOT NULL, picUrl TEXT NOT NULL DEFAULT , type TEXT NOT NULL DEFAULT , company TEXT NOT NULL DEFAULT , description TEXT NOT NULL DEFAULT , subscribed INTEGER NOT NULL DEFAULT 0, isExplicit INTEGER NOT NULL DEFAULT 0, publishTime INTEGER NOT NULL DEFAULT 0, createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP );Album.type在类型层面对应为专辑 | EP | 单曲 | liveCD | 精选集 | 合集 | 其他见 schemas.ts 的 AlbumSchema。4.2 多对多关联表TrackArtist/ArtistAlbumCREATE TABLE IF NOT EXISTS TrackArtist ( trackId TEXT NOT NULL, artistId TEXT NOT NULL, PRIMARY KEY(trackId, artistId) ); CREATE TABLE IF NOT EXISTS ArtistAlbum ( artistId TEXT NOT NULL, albumId TEXT NOT NULL, PRIMARY KEY(artistId, albumId) );由于一首歌可能有多位歌手含演唱者与专辑歌手两种身份、一张专辑可能由多位艺术家合作所以用复合主键关联表表达多对多关系而非在Track表塞入冗余列。查询辅助层在组装歌曲时会分别按TrackArtist与ArtistAlbum建立映射产出artists与albumArtists两个列表见 dbHelpers.ts。4.3 插件映射AlbumSource/ArtistSourceCREATE TABLE IF NOT EXISTS AlbumSource ( albumId TEXT NOT NULL, pluginId TEXT NOT NULL, sourceContext TEXT NOT NULL, PRIMARY KEY(albumId, pluginId) ); CREATE TABLE IF NOT EXISTS ArtistSource ( artistId TEXT NOT NULL, pluginId TEXT NOT NULL, sourceContext TEXT NOT NULL, PRIMARY KEY(artistId, pluginId) );二者与TrackSource遵循同一设计模式分别是专辑、艺术家在各插件中的坐标由插件自行维护sourceContext。4.4 歌词Lyrics/LyricOffsetsCREATE TABLE IF NOT EXISTS Lyrics ( trackId TEXT NOT NULL, pluginId TEXT NOT NULL, content TEXT NOT NULL, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(trackId, pluginId) ); CREATE TABLE IF NOT EXISTS LyricOffsets ( pluginId TEXT NOT NULL, trackId TEXT NOT NULL, offset REAL NOT NULL DEFAULT 0, updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (pluginId, trackId) );设计要点Lyrics以(trackId, pluginId)为复合主键保证每个插件对同一首歌只保留一份歌词内容互不覆盖LyricOffsets.offset为实数记录用户对某插件某首歌的歌词行整体偏移微调值秒用于解决不同平台歌词时间轴不一致的问题二者都通过cleanupOrphanRefs()在 Track 删除时级联清理DELETE FROM Lyrics WHERE trackId NOT IN (SELECT id FROM Track)见 数据清理策略。4.5 歌单Playlist/PlaylistEntryCREATE TABLE IF NOT EXISTS Playlist ( id TEXT NOT NULL, pluginId TEXT NOT NULL, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT , picUrl TEXT NOT NULL DEFAULT , createTime INTEGER NOT NULL, updateTime INTEGER NOT NULL, PRIMARY KEY (id, pluginId) ); CREATE TABLE IF NOT EXISTS PlaylistEntry ( id INTEGER PRIMARY KEY AUTOINCREMENT, playlistId TEXT NOT NULL, pluginId TEXT NOT NULL, sourceContext TEXT NOT NULL, position INTEGER NOT NULL DEFAULT 0, createTime INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_playlist_entry_playlist_id ON PlaylistEntry (playlistId); CREATE UNIQUE INDEX IF NOT EXISTS idx_playlist_entry_unique ON PlaylistEntry (playlistId, pluginId, sourceContext);要点Playlist以(id, pluginId)复合主键歌单归属具体插件PlaylistEntry不直接存 Track ID而是存sourceContext文本体现歌单项引用插件坐标的设计两个索引分别用于快速按歌单查条目以及防止同一歌单内重复添加同一首歌position用于排序读取时按ORDER BY position DESC新增条目时取MAX(position) 1见 addPlaylistEntry。4.6 应用配置AppDataCREATE TABLE IF NOT EXISTS AppData ( id TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY (id) );极简的 KV 表最典型的使用是记录appVersion——迁移逻辑正是读取它来决定执行哪些增量迁移 SQL见下节。4.7 遗留表Unblock/LocalAlbumCover/AppleMusicAlbum/AppleMusicArtist这四张表在Tables枚举中仍保留名称见 db.ts但没有任何 CREATE TABLE 语句出现在当前迁移脚本中从源码结构看属于历史遗留的占位/废弃表Unblock曾是解锁/替代源LocalAlbumCover曾是本地专辑封面缓存AppleMusicAlbum/AppleMusicArtist曾是 Apple Music 扩展时代的产物。对当前 Schema 而言它们没有实际列定义可视为已退役。五、核心数据关系Schema 参考文档给出了下面的关系图它完整表达了整套多源关联体系Plugins ──┬── TrackSource ──── Track ──┬── Audio ├── AlbumSource ──── Album ├── Lyrics ├── ArtistSource ─── Artist └── TrackArtist ── Artist ├── Lyrics ArtistAlbum ── Album └── PluginData把这张图展开成用户视角就是 Track 数据模型设计 中的三表分离模型Track 表一首歌的抽象描述 ├─ id, name, duration, albumId, musicBrainzTrackId TrackSource 表各插件中这首歌的「坐标」 ├─ (trackId, pluginId) → sourceContext (插件私有 JSON) ├─ 网易云: { id: 12345 } ├─ 酷狗: { hash: ... } └─ 本地: { filePath: ... } Audio 表本地物理音频文件 └─ filePath, md5, bitrate, gain, cueOffset由此衍生出清晰的业务能力矩阵场景支持方式用户从网易云播放TrackSource查询 → 调用插件songUrl用户从本地播放Audio表获取filePath→ 直接读文件用户切换音源同一 Track 的不同TrackSource条目 → 换插件本地文件移动只需更新Audio.filePath去重MusicBrainz ID 相同的 Audio 归并为同一 Track去重策略分三档MusicBrainz Track ID 完全一致强归并为同一 Track、归一化标题专辑艺术家相同且时长差 ≤ 2s中归并、仅部分匹配弱暂不归并并标记待确认。其中归一化规则为 trim 空格、全角/半角统一、忽略大小写且刻意不去除(Live)、(Remix)等括注因为这些括注反映歌曲版本差异。六、Schema 设计决策主键、软删除与 PRAGMA6.1 主键格式所有核心表的 ID 使用字符串格式${pluginId}:${type}:${key}例如netease:track:536099、local:audio:abc123。这种自解释格式的好处是全局唯一、无需额外 type 字段、不同插件之间天然不会冲突。6.2 软删除Track与Audio都带deleted0/1字段采用逻辑删除而非物理删除优点用户误删后可恢复删除只是 UPDATE 而非 DELETE不阻塞代价查询时必须记得WHERE deleted 0数据持续增长需定期清理。本地音乐扫描流程正是围绕软删除设计的一整套状态机扫描前调用 markAllLocalMusicDeleted 把本地独占的 Track/Audio 标记为deleted1命中文件通过 restoreLocalMusicDeleted 恢复为deleted0异常时用 restoreAllLocalMusic 回滚。注意 SQLiteIN子句参数上限为 999因此restoreLocalMusicDeleted按每批 900 个路径分批执行。6.3 WAL 与 auto_vacuum数据库初始化时执行两条关键 PRAGMA见 db.ts 构造函数this.sqlite.pragma(auto_vacuum FULL) this.sqlite.pragma(journal_modeWAL)journal_modeWAL读写并发友好读操作不阻塞写操作写入性能更好故障恢复能力更强auto_vacuum FULL删除数据后自动回收磁盘空间代价是每次写入略慢但影响很小。七、数据库迁移机制db.ts 的 migrate() 实现了内置的增量迁移它从AppData表读取appVersion扫描migrations目录下所有N.N.N.sql命名的脚本凡是版本号大于当前记录版本的都会按序执行const sqlFiles fs.readdirSync(migrationsDir).sort() sqlFiles.forEach((sqlFile: string) { const versionMatch sqlFile.match(/^(\d(\.\d)*)(?\.)/) const version versionMatch ? versionMatch[0] : if (!validate(version)) return if (compare(version, appVersion, )) { const file readSqlFile(sqlFile) this.sqlite.exec(file) this.sqlite.pragma(journal_modeWAL) } }) updateAppVersionInDB()一个现成的迁移示例是 3.3.1.sql它通过ALTER TABLE ADD COLUMN为Plugins表增加sortOrder排序字段并给内置插件赋初始值BEGIN TRANSACTION; ALTER TABLE Plugins ADD COLUMN sortOrder INTEGER NOT NULL DEFAULT 9999; UPDATE Plugins SET sortOrder 1 WHERE id netease AND sortOrder 9999; UPDATE Plugins SET sortOrder 2 WHERE id kugou AND sortOrder 9999; COMMIT;这种以版本号命名的 SQL 文件 AppData 记录当前版本的方案避免了引入重型迁移框架同时保证升级过程可追溯。如 ADR-0004 所述迁移逻辑内置于db.ts构造函数中不建议手动调用或修改。八、数据访问层从 CRUD 到场景函数8.1 通用 CRUDdb.tsdb.ts 中的DB类提供了一批基于Tables枚举的通用方法所有方法都先通过assertTable校验表名合法性防止 SQL 注入查询findByIdPlatform/findManyByIds/findAll写入insert默认INSERT OR IGNORE/insertMany事务批量更新updateByIdPlatform/replace/replaceMany/upsertON CONFLICT ... DO UPDATE冲突键可指定/upsertMany删除deleteManyByIds/truncate/vacuumAppDatafindAppData/upsertAppData批量方法均通过better-sqlite3的transaction()包装保证原子性。8.2 场景化查询层dbHelpers.ts与通用的 cache 路由不同dbHelpers.ts 为每个业务场景提供职责单一的具名函数覆盖两类核心场景① 本地音乐管理loadScanDedupData预载去重快照、writeBatchData扫描结果事务批量入库、markAllLocalMusicDeleted/restoreLocalMusicDeleted/restoreAllLocalMusic软删除状态机、deleteAllLocalMusicData清空本地音乐、deleteCacheFromDB清理缓存。② TrackSource 路由查询跨插件查找音源findTrackSourcesByTrackId— 查某 trackId 的所有音源按matched降序人工确认过的排前面findTrackSourcesBySourceContext— 根据sourceContext反查该歌的全部音源findTrackIdBySourceContext— 通过json_extract(sourceContext, $.id)反查 canonical trackIdinsertTrackSourceOnce/upsertTrackSource/checkTrackSourceExists— TrackSource 的写入与存在性检查reassignTrackId— 匹配流程发现同一歌曲存在多个 trackId 时把TrackSource/TrackArtist/Lyrics/LyricOffsets迁移到目标 trackId不迁移 Audio、不删除旧 Track以避免外键约束冲突。8.3 插件 Worker 数据路由pluginDbGet/pluginDbSet是插件与数据库的统一出入口插件通过api.db.get(Track, { ids })之类调用主进程按 key 路由到具体逻辑。其中Track查询会跨表组装出完整的歌曲对象Track Album 名 演唱者 专辑歌手 本地音频信息并特别处理了WHERE IN不保证顺序的问题——按传入 ids 重建顺序见 dbHelpers.ts。updateTrackField还支持$inc原子自增语法例如{ $inc: { playCount: 1 } }会生成playCount playCount 1用于播放计数这类高频写操作。8.4 缓存回写链路当用户开启自动缓存歌曲后缓存 Worker cacheTrack.ts 下载音频、用 taglib-wasm 补全元数据与封面主进程在 IPCs.ts 收到task-done消息后调用db.saveCacheResult(data, meta)在一个事务内完成Track/Album/Artist/TrackSource/Audio的多表写入——这正是各表协同工作的典型调用链。九、数据清理策略与注意事项数据清理策略 给出了完整的数据生命周期约定数据类型清理时机策略软删除的 Track软件启动时 / 手动触发删除 30 天且用户未恢复的deleted1记录失效的 Audio 路径每次扫描时文件不存在的标记为deleted1孤立歌词Track 删除时一并处理级联删除插件缓存数据卸载插件时清理关联的 PluginData TrackSourceCUE 分离数据源文件变更时重新解析 CUE 文件目前已实现的能力包括本地扫描自动标记失效文件、UI 侧过滤软删除数据、cleanupOrphanRefs()清理孤立 Album/Artist/Lyrics/LyricOffsets、deleteCacheFromDB()、deleteAllLocalMusicData()等而自动定期清理超期软删除记录孤立数据检测工具 UI仍属待完善项。对于 CUE 分轨数据一致性约定为扫描时检测 CUE 文件是否存在且 MD5 是否变化CUE 内容变更即全量重解析所有分轨源文件丢失则仅标记deleted1而非直接清除。总结VutronMusic 的数据库 Schema 用一个简洁的抽象实体表 插件坐标表 本地文件表三件套优雅地解决了多源音乐库的核心矛盾——同一首歌在网易云、酷狗、Navidrome 和本地磁盘上各自拥有不同的身份。TrackSource及其兄弟表把插件系统的扩展性提升到了加行不加列的程度sourceContext的框架不解析原则让插件可以自由定义自己的数据形态而软删除、WAL、版本化迁移脚本与场景化查询层则保证了数据在长期使用中的可靠与可维护。如果你想深入实践建议按以下顺序阅读仓库源码建表全量脚本src/public/migrations/plugin.sql初始化与迁移src/main/db.ts场景化查询辅助层src/main/dbHelpers.ts插件 API 约定插件开发入门 与 插件 API 参考相关决策记录ADR-0002TrackSource 设计、ADR-0004SQLite Schema赞分享桌面应用音视频前端【免费下载链接】VutronMusic高颜值的第三方网易云播放器通过自写插件可支持其他线上音乐服务支持流媒体音乐如navidrome、jellyfin、emby支持本地音乐播放、离线歌单、逐字歌词、桌面歌词、Touch Bar歌词、Mac状态栏歌词显示、Linux-gnome与Linux-kde桌面状态栏歌词显示支持降调降速支持自定义主题等。支持 Windows / macOS / Linux :electron:项目地址https://gitcode.com/gh_mirrors/vu/VutronMusic点击查看免费下载相关推荐开源音乐播放器Moosync深度评测为什么它能替代你的Spotify客户端开源音乐播放器Moosync深度评测为什么它能替代你的Spotify客户端 Moosync是一款功能强大的开源音乐播放器支持播放本地音频文件以及来自YouEVCC 数据库设计SQLite数据存储方案EVCC 数据库设计SQLite数据存储方案 概述 EVCCElectric Vehicle Charge Controller是一个开源电动汽车充电控制后端前端智能硬件物联网能源管理Duix-Avatar 本地部署教程一条命令离线生成数字人10秒视频克隆自己的数字分身Duix Avatar 本地部署教程一条命令离线生成数字人10秒视频克隆自己的数字分身 做云端数字人平台素材要先上传到别人服务器生成一条视频收一次费还人工智能AI 应用数字人媒体生成桌面应用上一篇Fugu开发指南贡献开源iOS越狱项目的入门教程下一篇终极dokploy环境配置指南多环境部署与高效配置管理方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑