Sign inSign up

liuloktar/musix

By liuloktar

•Updated 5 days ago

NAS-first self-hosted music hub for Apple Music, Netease, QQ, Kugou, YouTube

Image
1

10K+

liuloktar/musix repository overview

⁠Musix Hub

NAS 优先、自托管的跨平台音乐聚合与播放中心。统一管理 Navidrome、Apple Music、网易云、QQ 音乐、酷狗与 YouTube,提供搜索、榜单、推荐、歌单、收藏、播放历史、换源和 Web 播放。

⁠0.7.8 更新

  • 播放器接入真实逐字歌词:酷狗 KRC、网易 YRC 与 QQ QRC 均保留字词级时间轴;Web 和 iOS/macOS 端以逐字高亮与换行动画呈现。
  • 默认 Compose 的 ncm-api 与内置 qqmusic-api 已可直接提供网易 YRC 和 QQ QRC;QQ QRC 会从公开歌词端点下载并在 sidecar 内解码,不再需要额外配置逐字歌词增强服务。
  • 保留普通 LRC 降级路径,旧版或自定义网易/QQ API 可继续按需配置增强服务作为兼容回退。

⁠0.7.6 更新

  • 每日私享基于有效播放事件、最近收听衰减和探索配额生成;服务端可补充外部艺人发现,Web 与 iOS/macOS 首页同步展示。
  • 播放失败的本地文件会被隔离并尝试恢复可用音源,减少坏文件阻断队列;iPhone 本地文件浏览恢复目录、专辑和歌手信息。
  • Spotlight 搜索在 iOS/macOS 直接提交 YouTube 等分享链接时改走分享解析接口,可继续播放并下载入库;Web 修复客户端标识回退与远程歌单分页游标。

⁠0.7.4 更新

  • Web 本地文件浏览补全内嵌封面、专辑、歌手和入库时间,并保持目录层级浏览体验。
  • Web 远程歌单的更多菜单新增“同步最新数据”,可强制从上游刷新歌单内容。

⁠0.7.2 更新

  • 修复 QQ 音乐搜索专辑映射:singer/singers 为字符串或单对象时不再因 .map is not a function 导致搜索失败(如搜索「周杰伦」)。

⁠0.7.1 更新

  • QQ 音乐与酷狗“猜你喜欢”接入推荐服务,Web 与 iOS/macOS 首页可直接展示平台推荐歌单。
  • 入库改进:本地歌单文件直接使用本地音频,不再回到平台搜索下载;新下载资源按 平台/专辑/歌曲 或 平台/歌手-歌手ID/歌曲 保存,并保留可用于数据库重建的音频、封面与歌词关联信息。
  • 会员/试听限制会生成严格匹配的替代音源建议;确认替换后只会尝试用户选择的音源及其可用音质,不会回退下载原 QQ/其它平台曲目。
  • 首页精选增加歌单内容、收紧最近播放的展示占比;修复播放会话、换源入库与恢复流程的边界问题。

⁠0.7.0 更新

  • Web 与 iOS/macOS 新增 Spotlight 搜索:输入联想、平台、分享链接与本地搜索,结果页支持主动刷新(Web 刷新按钮、iOS 下拉刷新)。
  • FLAC/.flc 播放兼容:保留原始无损文件,播放时按需生成 AAC/M4A 缓存,沉浸式多声道输出降为双声道。
  • 播放会话固定内容版本,Range 请求不再拼接不同文件;流地址签名支持 IP 直连播放。
  • 源替换与音源管理增强:候选探测、预热、源管理面板与操作历史。
  • 入库识别修复:ID3 标签不再误判音频格式;QQ 移动端搜索接口修复错误处理与未知总数分页。
  • 镜像内置 ffmpeg,yt-dlp 改从 Alpine 仓库安装,迁移失败可自动恢复。

⁠0.6.7 更新

  • 修复 QQ 音乐搜索后 qqmusic-api 容器崩溃重启。
  • 搜索改走可用的 QQ musicu.fcg 接口;独立音源目录不再先打会崩溃的 sidecar /search。

⁠0.6.6 更新

  • 统一播放会话、音源整理与跨平台完整音源入库。
  • Web 专辑音源检查、播放恢复与管理员数据清理。
  • iOS/macOS 对接统一播放与整理 API,更新首页、播放器和键盘控制。
  • 升级前备份 PostgreSQL 与应用数据;容器启动自动执行 Prisma 迁移。

⁠0.6.0 更新

  • Server/Web/iOS/macOS 统一发布版本
  • 曲风目录、跨平台曲风推荐与每日 08:00 缓存预热
  • 搜索聚合、换源和曲风详情页体验优化

⁠0.5.4 更新

  • 新建歌单支持在弹框内选择本地/NAS目录
  • 创建本地歌单后自动启动首次扫描、音频解析、平台匹配、封面刮削与入库
  • 本地导入进度实时展示,修复重复文件路径导致的入库冲突
  • 单曲封面优先使用平台刮削结果,避免整张专辑共用文件内嵌封面

⁠0.5.3 更新

  • 本地目录导入:目录选择器展示当前目录下的文件列表,并高亮音频文件、显示数量与占用
  • 本地歌单编辑视图与路由优化,资料库本地文件页支持按时间排序的入库记录
  • 启用本地目录监听与导入曲目的自动同步归属

⁠0.5.2 更新

  • 修复 iOS 端播放历史删除后重启重现的问题(后端路由冲突修复)
  • Web 端最近播放支持右键菜单删除单条记录
  • Web 主题自定义图库补全保存/清除按钮

⁠镜像标签

标签内容
0.7.8推荐的固定版本
0.7.6历史固定版本
0.7.4历史固定版本
0.7当前 0.7 系列最新版本
0.7.2历史固定版本
0.7.1历史固定版本
0.7.0历史固定版本
0.6.7历史固定版本(不含 FLAC/.flc 播放修复)
0.6.6历史固定版本(不含 FLAC/.flc 播放修复)
0.60.6 系列最新版本
latest最新正式版本
qqmusic-apiQQ Music API 最新发行依赖
qqmusic-api-0.7.8与 0.7.8 配套的 QQ 固定版本
qqmusic-api-0.7.6历史固定版本
kugou-api酷狗 API 最新发行依赖
kugou-api-0.7.8与 0.7.8 配套的酷狗固定版本
kugou-api-0.7.6历史固定版本

⁠快速部署

创建一个空目录,保存下面的 .env 和 compose.yaml:

mkdir -p musix-stack
cd musix-stack
mkdir -p ~/musix-media      # 入库音乐存储位置(容器内 /media)
# 保存下方 compose.yaml 与 .env 后再执行:
docker compose config -q
docker compose pull
docker compose up -d
⁠.env
TZ=Asia/Shanghai
PUID=1000
PGID=1000

MUSIX_IMAGE=liuloktar/musix:0.7.8
QQMUSIC_IMAGE=liuloktar/musix:qqmusic-api-0.7.8
KUGOU_IMAGE=liuloktar/musix:kugou-api-0.7.8
NETEASE_IMAGE=moefurina/ncm-api:latest

POSTGRES_PASSWORD=请替换为数据库强密码
MUSIX_SECRET=请替换为至少32位且部署后保持不变的随机字符串
# FLAC/.flc 播放兼容需要使用内置 ffmpeg 的新镜像;原始文件不会被覆盖。
MUSIX_PLAYBACK_TRANSCODE_FLAC=1
MUSIX_PLAYBACK_AAC_BITRATE=192k
MUSIX_PLAYBACK_CACHE_MAX_AGE_MS=604800000
MUSIX_PLAYBACK_CACHE_MAX_BYTES=2147483648
MUSIX_FFMPEG_TIMEOUT_MS=120000

# 新版 QQ / 微信扫码使用;两个容器共用,不写入镜像
QQMUSIC_LOGIN_SECRET=请替换为至少32位随机字符串
MUSIX_AUTH=请填写有效的Musix授权Token
MUSIX_AUTH_RPC=
MUSIX_AUTH_PROXY=

MUSIX_PLUGINS=navidrome,apple,netease,qqmusic,kugou,youtube
NAVIDROME_USERNAME=demo
NAVIDROME_PASSWORD=demo
COOKIECLOUD_PORT=8088

POSTGRES_PASSWORD、MUSIX_SECRET 和 MUSIX_AUTH 必须修改。MUSIX_SECRET 用于保护会话和平台凭据,部署后不要随意更换。

生产环境建议固定使用 0.7.8 这类明确 tag;latest 只适合希望自动跟随新版本的测试环境。升级前备份数据库,且保留现有 POSTGRES_PASSWORD、MUSIX_SECRET 和媒体挂载路径。

⁠compose.yaml
name: musix

services:
  postgres:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: musix
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: musix
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U musix -d musix"]
      interval: 10s
      timeout: 5s
      start_period: 20s
      retries: 10

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - ./data/redis:/data

  navidrome:
    image: deluan/navidrome:latest
    restart: unless-stopped
    user: "${PUID:-1000}:${PGID:-1000}"
    ports:
      - "4533:4533"
    environment:
      ND_SCANSCHEDULE: 1h
      ND_LOGLEVEL: info
      ND_SESSIONTIMEOUT: 24h
    volumes:
      - ./data/navidrome:/data
      - ./music:/music:ro

  netease-api:
    image: ${NETEASE_IMAGE:-moefurina/ncm-api:latest}
    restart: unless-stopped
    environment:
      PORT: 3000
      CORS_ALLOW_ORIGIN: "*"
      ENABLE_PROXY: "false"
      ENABLE_GENERAL_UNBLOCK: "false"
      ENABLE_FLAC: "false"

  qqmusic-api:
    image: ${QQMUSIC_IMAGE:-liuloktar/musix:qqmusic-api-0.7.8}
    restart: unless-stopped
    environment:
      PORT: 3300
      NODE_ENV: production
      QQMUSIC_LOGIN_SECRET: ${QQMUSIC_LOGIN_SECRET:-}

  kugou-api:
    image: ${KUGOU_IMAGE:-liuloktar/musix:kugou-api-0.7.8}
    restart: unless-stopped
    environment:
      PORT: 3400
      NODE_ENV: production

  cookiecloud:
    image: easychen/cookiecloud:latest
    restart: unless-stopped
    ports:
      - "${COOKIECLOUD_PORT:-8088}:8088"
    volumes:
      - ./data/cookiecloud:/data/api/data

  musix:
    image: ${MUSIX_IMAGE:-liuloktar/musix:0.7.8}
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      TZ: ${TZ:-Asia/Shanghai}
      PORT: 8080
      NODE_ENV: production
      DATABASE_URL: postgresql://musix:${POSTGRES_PASSWORD}@postgres:5432/musix?schema=public
      REDIS_URL: redis://redis:6379
      MUSIX_SECRET: ${MUSIX_SECRET}
      MUSIX_AUTH: ${MUSIX_AUTH}
      MUSIX_AUTH_RPC: ${MUSIX_AUTH_RPC:-}
      MUSIX_AUTH_PROXY: ${MUSIX_AUTH_PROXY:-}
      MUSIX_PLUGINS: ${MUSIX_PLUGINS:-navidrome,apple,netease,qqmusic,kugou,youtube}
      MUSIX_LOG_LEVEL: info
      MUSIX_PLAYBACK_TRANSCODE_FLAC: ${MUSIX_PLAYBACK_TRANSCODE_FLAC:-1}
      MUSIX_PLAYBACK_AAC_BITRATE: ${MUSIX_PLAYBACK_AAC_BITRATE:-192k}
      MUSIX_PLAYBACK_CACHE_MAX_AGE_MS: ${MUSIX_PLAYBACK_CACHE_MAX_AGE_MS:-604800000}
      MUSIX_PLAYBACK_CACHE_MAX_BYTES: ${MUSIX_PLAYBACK_CACHE_MAX_BYTES:-2147483648}
      MUSIX_FFMPEG_TIMEOUT_MS: ${MUSIX_FFMPEG_TIMEOUT_MS:-120000}
      MUSIX_FFMPEG_PATH: ${MUSIX_FFMPEG_PATH:-/usr/bin/ffmpeg}
      MUSIX_DATA_DIR: /app/data
      NAVIDROME_URL: http://navidrome:4533
      NAVIDROME_USERNAME: ${NAVIDROME_USERNAME:-demo}
      NAVIDROME_PASSWORD: ${NAVIDROME_PASSWORD:-demo}
      NETEASE_API_URL: http://netease-api:3000
      NETEASE_CHART_ID: 19723756
      QQMUSIC_API_URL: http://qqmusic-api:3300
      QQMUSIC_CHART_ID: 4
      QQMUSIC_LOGIN_SECRET: ${QQMUSIC_LOGIN_SECRET:-}
      KUGOU_API_URL: http://kugou-api:3400
      KUGOU_CHART_ID: 8888
      YTDLP_API_URL: http://127.0.0.1:3500
      YTDLP_EMBEDDED: 1
      YTDLP_JS_RUNTIME: node
      YTDLP_COOKIES_FILE: /app/data/youtube-cookies.txt
      COOKIECLOUD_URL: http://cookiecloud:8088
      APPLE_CONFIG_DIR: /app/data/apple
      P8_PATH: /app/p8
      MUSIX_LIBRARY_DIR: /media
    volumes:
      - ./data/musix:/app/data
      - ./data/musix/apple:/app/p8
      - ~/musix-media:/media
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
      navidrome:
        condition: service_started
      netease-api:
        condition: service_started
      qqmusic-api:
        condition: service_started
      kugou-api:
        condition: service_started
      cookiecloud:
        condition: service_started

发行配置中的 QQ 与酷狗服务只有 image,没有 build,部署机只从 Docker Hub 拉取依赖。

⁠YouTube 与 CookieCloud

Musix 主镜像已内置 yt-dlp,不需要单独部署 yt-dlp 容器。YouTube 登录 Cookie 建议通过 CookieCloud 同步:

  1. 浏览器安装 CookieCloud 扩展并选择「上传 Cookie」。
  2. 扩展服务器填写 http://NAS局域网IP:8088;同机可使用 http://localhost:8088。
  3. 域名填写 youtube.com,保存后执行一次手动上传。
  4. 打开 Musix「设置 → 服务地址 → YouTube CookieCloud」。
  5. 服务地址填写 http://cookiecloud:8088,UUID 与密码必须和扩展一致。
  6. 点击「测试并同步」,成功后再测试 YouTube 插件。

扩展地址不要追加 /get、/update 或 /api。Cookie 文件位于 ./data/musix/youtube-cookies.txt,不要提交或公开。

⁠数据与升级

路径内容
./musicNavidrome 音乐库,只读挂载
~/musix-media入库音乐文件(容器内 /media,MUSIX_LIBRARY_DIR)
./data/postgres数据库
./data/redisRedis 持久化
./data/navidromeNavidrome 配置与索引
./data/cookiecloudCookieCloud 加密同步数据
./data/musixMusix 数据、Apple 私钥和 YouTube Cookie

升级时先备份 ./data,然后把 .env 中 Musix、QQ 和酷狗三个配套标签同时更新到同一版本,再滚动更新:

# .env:把三个 tag 一起改成 0.7.8(或其它固定版本)
docker compose config -q
docker compose pull
docker compose up -d --no-deps musix qqmusic-api kugou-api
docker compose ps
docker compose logs --tail=200 musix

主容器启动时会自动执行 Prisma 数据库迁移,无需手工执行 SQL。三个 tag 必须保持配套:只升级 Musix 而继续使用旧 QQ/酷狗 API,容易出现接口契约不一致。

需要回滚时,把三个 tag 一起改回上一个固定版本,并从升级前备份恢复数据库;不要依赖 latest 或 docker compose down -v(后者会删除数据卷)。

⁠常见问题

YouTube 提示需要登录或确认不是机器人:确认 CookieCloud 已从登录 YouTube 的浏览器上传,并在 Musix 中重新测试同步。

YouTube 提示 No video formats found:0.5.4 起镜像已内置 Node.js 和 EJS 挑战求解;确认实际运行的是 0.7.8(或更新的固定 tag)并重新拉取容器。

QQ / 酷狗出现构建步骤:发行 Compose 只应使用镜像,例如 liuloktar/musix:qqmusic-api-0.7.8 和 liuloktar/musix:kugou-api-0.7.8;不要复制源码开发版的 build 配置。

⁠免责声明

本项目仅用于个人学习、研究和自托管。网易云、QQ、酷狗和 YouTube 等接口及内容归各平台或上游项目所有,可能随平台策略变化而失效。只能使用本人合法拥有的账号、Cookie、Token 和订阅权益;不得绕过 DRM、破解会员、批量下载、二次分发或对外提供未授权流媒体服务。

生产环境必须使用强密码,妥善保存 MUSIX_SECRET、数据库、Cookie 和 Apple 私钥,并通过防火墙或反向代理限制管理端与 CookieCloud 端口。

Tag summary

Content type

Image

Digest

sha256:d6d5cf9f0…

Size

289.5 MB

Last updated

5 days ago

docker pull liuloktar/musix