multi-scrobbler 0.13.3 配置参数详解

multi-scrobbler 0.13.3 三种配置方式与全部核心参数语义、密钥插值机制、生产配置模板,逐项实测。

multi-scrobblermulti-scrobbler音乐DockerDocker Compose2026/10/30

multi-scrobbler 0.13.3 配置参数详解

目标:系统性讲清 multi-scrobbler 0.13.3 的三种配置方式(ENV / 分文件 JSON / AIO 全量 JSON)、全部核心参数的语义与默认值、密钥不落盘的插值机制,并给出可直接套用的生产配置模板。已在 Ubuntu 22.04 / Docker Engine 29.9.2 环境以「VLC 轮询源 → Maloja 目标」最小闭环逐项实测,端到端 scrobble 与阈值行为均以真实回显为准。

一、环境信息

  • 服务器系统:Ubuntu 22.04(x86_64),Docker Engine 29.9.2 / Compose v5.6.1
  • multi-scrobbler:0.13.3(官方镜像 foxxmd/multi-scrobbler:0.13.3;镜像内运行时为 Node.js,package.json 声明 engines.node >= 24.14.0、许可证 MIT,镜像内实查)
  • 验证用目标:Maloja 3.2.4(krateng/maloja:3.2.4,本地统计目标,API 密钥 q1w2e3r4)
  • 验证用源:VLC 3.0.16 Vetinari(HTTP 接口轮询源,接口口令 q1w2e3r4)
  • 配置目录:/opt/multi-scrobbler/config/(服务内 /config)
  • 仪表盘端口:宿主 8147 → 服务内 9078
  • 查询日期:2026-10-29(官方参数语义按当日官方文档站核定)

💡 说明:本文的 VLC/Maloja 是验证参数行为的「源/目标」载体;生产中换成 Jellyfin、Navidrome、last.fm 等,参数体系完全一致。部署过程见《multi-scrobbler Docker Compose 部署指南》,此处直接在既有栈上操作。

二、前置条件

  1. 已完成《multi-scrobbler Docker Compose 部署指南》第四章部署,服务处于运行状态,健康接口返回正常:
curl -s http://127.0.0.1:8147/api/health
# 实测输出:
# {"messages":[]}
  1. 配置目录中已有 AIO 配置文件(无配置时服务也能启动,仅仪表盘无源/目标数据):
ls -la /opt/multi-scrobbler/config/
# 实测输出:
# -rw-r--r-- 1 911 911  610 Oct 29 22:24 config.json
# -rw-r--r-- 1 911 911  159 Oct 29 22:53 ms-scrobble.cache
  1. 验证用播放源已就绪(VLC HTTP 接口 8080 在栈内可达,部署指南 4.6 步骤)。

三、参数查看与修改方式

multi-scrobbler 同一套源/目标配置有三种写法,服务启动时三种同时解析、可混用(官方配置总览 Configuration Types,2026-10-29 查询),但建议统一用一种:

方式载体适用场景(官方建议)
ENV 环境变量compose environment: 或系统环境单用户、一个源对一个目标的极简场景;不习惯编辑 JSON
分文件 JSONCONFIG_DIR 下按类型命名的文件(如 jellyfin.json、maloja.json),文件内是数组同类型多实例(如 2 个 last.fm 账号、3 台 Jellyfin)、需要源→目标定向转发
AIO 全量 JSONCONFIG_DIR/config.json完整配置能力:监控通知、源/目标默认值、变换器、全局选项;AIO 是「最完整」的方式(官方原话)

两种 JSON 形态的差异只在一点:AIO 中每个源/目标项必须带 type 字段(分文件的 type 由文件名隐含)。本文以 AIO 为主线讲解,其余两种在对应小节给出换算方式。

修改参数的标准流程(每步实测):

# 1. 编辑配置
vi /opt/multi-scrobbler/config/config.json

# 2. 重启服务使配置生效
docker compose -f /opt/multi-scrobbler/docker-compose.yml restart multi-scrobbler
# 实测输出:
#  Container multi-scrobbler-0-13-3-app Restarting
#  Container multi-scrobbler-0-13-3-app Started

# 3. 看日志确认加载结果
docker compose -f /opt/multi-scrobbler/docker-compose.yml logs --since 1m multi-scrobbler 2>&1 | grep -E 'Added|Initialized|Error'
# 实测输出(节选):
# multi-scrobbler-0-13-3-app  | [2026-10-29 23:54:53.496 +0800] INFO   : [App] [Scrobblers] [Maloja - labMaloja] Client Added from config.json
# multi-scrobbler-0-13-3-app  | [2026-10-29 23:54:53.593 +0800] INFO   : [App] [Sources] [Vlc - Lab VLC] Source Added from config.json
# multi-scrobbler-0-13-3-app  | [2026-10-29 23:54:55.621 +0800] INFO   : [App] [Sources] [Vlc - Lab VLC] Connected successfully, found VLC 3.0.16 Vetinari

Client/Source Added from config.json 即 AIO 配置加载生效的标志;若 JSON 语法有误,启动日志会直接抛出解析错误并指明行号,修正后重启即可。官方还提供 Config Playground(https://foxxmd.github.io/multi-scrobbler/playground/,官方文档站)可在网页上交互式探索完整配置模式。

四、参数总览

AIO 配置(config.json)顶层键一览(语义按官方文档核定,默认值来自官方 AIO 示例与镜像内源码实查):

顶层键类型默认值作用
debugMode布尔false全局调试模式,输出更详细日志
disableWeb布尔false关闭 Web 仪表盘与 API(仅纯后台搬运时使用)
baseUrl字符串http://localhost:9078对外地址,用于生成 OAuth 回调 URL(ENV BASE_URL 同义)
sourceDefaults对象见 5.2所有源的默认行为与阈值
clientDefaults对象见 5.2所有目标的默认重试行为
sources数组[]源实例列表
clients数组[]目标实例列表
webhooks数组[]通知推送(Gotify/ntfy)
cache对象内置默认缓存存储位置(auth/valkey)

环境变量侧的常设变量(Docker 形态):

变量默认值作用
TZEtc/GMT时区
PORT9078仪表盘/API 端口
BASE_URLhttp://localhost:9078同 baseUrl
PUID / PGID911 / 911运行用户/组
CONFIG_DIR / DATA_DIR / LOGS_DIRDocker 内自动设定配置/数据/日志目录
CACHE_VALKEY未启用Valkey 二级缓存连接串
CACHE_AUTHfile认证缓存存储(file 或 valkey)
SOURCE_SCROBBLE_DURATION / SOURCE_SCROBBLE_PERCENT无以 ENV 覆盖全局 scrobble 阈值(镜像内源码实查:ScrobbleSources.ts 读取这两个变量并输出 Set default scrobble threshold ... based on env 日志)

💡 技术拓展:配置里的「源(Source)」与「目标(Client)」是 multi-scrobbler 的两个对偶概念——源是播放记录的生产者(轮询 API 或接收 Webhook),目标是消费者(提交 scrobble 的统计服务)。一个源可经 clients 字段定向转发给一个或多个目标;不指定时转发给全部目标。这与 last.fm 系统计服务里被动接收记录的「scrobbler 插件」不是同一层东西,选型辨析见《multi-scrobbler 介绍与选型指南》。

五、核心参数分类详解

5.1 全局开关(debugMode / disableWeb / baseUrl / PORT)

  • debugMode: false:排障时可临时改 true,日志会输出每个播放的完整载荷与判定过程;生产保持 false;
  • disableWeb: false:仪表盘与 API 是状态查看的主要入口(官方 API 见《multi-scrobbler 0.13.3 API 使用详解》),一般不关;关闭后只能靠日志与目标侧核对;
  • baseUrl / BASE_URL:影响的是回调地址的生成而非监听端口——Spotify、last.fm 等 OAuth 类配置若未显式写 redirectUri,回调将拼成 BASE_URL:PORT/<client|source>/callback(官方 Base URL 章节的拼装规则表)。反代子路径部署时必须以 ENV 形式设置(官方要求);
  • PORT:仪表盘/API 监听端口(官方文档:The web UI and API is served on port 9078. This can be modified using the PORT environmental variable.)。本文实测保持 9078、宿主映射 8147。

5.2 源/目标默认值(sourceDefaults / clientDefaults)

官方 AIO 示例的完整默认集(默认值即官方示例值):

{
  "sourceDefaults": {
    "logPayload": false,
    "logFilterFailure": "warn",
    "logPlayerState": false,
    "scrobbleThresholds": {
      "duration": 30,
      "percent": 50
    },
    "maxPollRetries": 1,
    "maxRequestRetries": 1,
    "retryMultiplier": 1.5
  },
  "clientDefaults": {
    "maxRequestRetries": 1,
    "retryMultiplier": 1.5
  }
}

逐项说明:

  • logPayload:把源返回的原始载荷写进日志(排障元数据错乱时开);
  • logFilterFailure:播放未达阈值/被过滤时的日志级别(warn 时可在日志看到每次被过滤的原因);
  • logPlayerState:轮询源每次查询的播放器状态落日志(调试轮询链路用);
  • scrobbleThresholds.duration / .percent:记账双阈值——播放时长满 duration 秒且进度满 percent% 才产生 scrobble(本文实测:150 秒曲目在约 75 秒处触发,恰为 50% 进度点,见 5.8 回显);两者都调大可有效过滤「切歌试听」;
  • maxPollRetries / maxRequestRetries:轮询失败与请求失败的即时重试次数;
  • retryMultiplier:重试间隔倍率(指数退避系数)。

ENV 覆盖方式(镜像内源码实查,/app/src/backend/sources/ScrobbleSources.ts):

# compose environment 中加入后,日志会输出:
# Set default scrobble threshold duration to '60' based on env SOURCE_SCROBBLE_DURATION
SOURCE_SCROBBLE_DURATION=60
SOURCE_SCROBBLE_PERCENT=60

5.3 源配置(sources[])

每个源实例的骨架(本文实测使用的 VLC 源):

{
  "type": "vlc",
  "enable": true,
  "name": "Lab VLC",
  "id": "vlc-lab",
  "clients": ["labMaloja"],
  "data": {
    "url": "vlc:8080",
    "password": "q1w2e3r4"
  }
}

逐项说明:

  • type:源类型标识(AIO 必填;分文件 JSON 用作文件名,如 vlc.json)。常用取值:jellyfin、subsonic(Navidrome/Airsonic 兼容)、plex/tautulli、mopidy、mpris、vlc、spotify、deezer、ytmusic、lastfm、listenbrainz、webscrobbler 等(官方 Sources 总览);
  • enable:临时停用某源改 false 即可,不必删配置;
  • name:实例显示名(日志与仪表盘用它标识,如 [Vlc - Lab VLC]);
  • id:强烈建议显式设置——数据库按 id 关联播放记录,配置改名后数据不丢账(官方 Database 章节要求);
  • clients:定向转发,值是目标的 name 数组;实测该源 scrobble 只进了 labMaloja(Maloja API 查询回显见 5.8);省略则转发给所有目标;
  • data:类型专属参数。VLC 源为 url(主机:端口,栈内可用服务名)+ password(VLC HTTP 接口口令);Jellyfin 源为 url/user/apiKey(服务器后台生成 API Key);Subsonic 系为 url/user/password(或 API Token)。

💡 技术拓展:Jellyfin/Subsonic 系源支持「轮询」与「Webhook 推送」两种接入方式——轮询由 multi-scrobbler 定期拉会话/最近播放(配置简单,秒级延迟);Webhook 由媒体服务器主动回调(实时性最好,但需媒体服务器可达本服务)。按官方各源配置页在 data 中选择 endpoint 类型即可,本文验证用的 VLC 属纯轮询源。

5.4 目标配置(clients[])

每个目标实例的骨架(本文实测使用的 Maloja 目标):

{
  "type": "maloja",
  "enable": true,
  "name": "labMaloja",
  "id": "maloja-lab",
  "data": {
    "url": "http://maloja:42010",
    "apiKey": "q1w2e3r4"
  }
}
  • type 常用取值:lastfm、listenbrainz、maloja、koito(官方 Clients 总览);
  • data 按类型而异:Maloja 为 url + apiKey;ListenBrainz 为 url(默认官方地址)+ 用户 Token;Koito 为 url + API Key(在其仪表盘 Settings → API Keys 创建,官方 Quickstart 说明);last.fm 需要 API Key + Secret + OAuth 授权回调;
  • 连通性验证不靠手工 curl:服务启动时自动做「通信测试 + 认证测试」,实测回显:
[2026-10-29 22:47:06.671 +0800] INFO   : [App] [Scrobblers] [Maloja - labMaloja] [API] [API - Maloja - labMaloja] Communication test succeeded.
[2026-10-29 22:47:06.677 +0800] INFO   : [App] [Scrobblers] [Maloja - labMaloja] [API] [API - Maloja - labMaloja] Maloja Server Version: 3.2.4
[2026-10-29 22:47:06.677 +0800] INFO   : [App] [Scrobblers] [Maloja - labMaloja] [API] [API - Maloja - labMaloja] Auth test passed!
[2026-10-29 22:47:06.677 +0800] INFO   : [App] [Scrobblers] [Maloja - labMaloja] Fully Initialized!

⚠️ 注意:last.fm / ListenBrainz 的凭据需要在其官方平台注册申请(last.fm:创建 API 账户页申请 api key/shared secret;ListenBrainz:用户设置页生成 User Token),本文无法代读者注册,下文生产模板中以 ${LASTFM_API_KEY}、${LISTENBRAINZ_TOKEN} 占位并给出注入方式。Maloja/Koito 这类自托管目标的密钥由读者自己掌控(本文演示值 q1w2e3r4)。

5.5 密钥插值([[ENV]],密钥不落盘)

JSON 配置支持把环境变量插进任意字符串值:写作 [[ENV_NAME]],服务启动时替换为同名环境变量的值(官方配置总览 Secrets Interpolation 章节,本节机制说明以官方文档为准)。要点:

  • 插值键不区分大小写;只对字符串值生效;
  • 环境变量缺失不报错:原样保留字符串并输出 WARN(官方示例日志格式:WARN : [App] [Sources] [spotify Secrets] Matched: None | Unmatched: SPOTIFY_SECRET);
  • 典型用法(官方示例结构)——lastfm.json 中写 "apiKey": "[[MY_APIKEY]]",compose 的 environment 中注入 MY_APIKEY=<真实值>,配置文件即可安全入库 git;
  • 注入方式:compose environment: - MY_APIKEY=${MY_APIKEY},在宿主 .env 文件(compose 同目录,git 忽略)中落真实值,执行 docker compose up -d 时自动带入。

5.6 通知 Webhook(webhooks[])

scrobble 结果可推送到 Gotify / ntfy(官方 AIO 示例结构):

{
  "webhooks": [
    {
      "name": "FirstGotifyServer",
      "type": "gotify",
      "url": "http://localhost:8070",
      "token": "MyGotifyToken",
      "priorities": { "info": 5, "warn": 7, "error": 10 }
    },
    {
      "type": "ntfy",
      "name": "MyNtfyFriendlyNameForLogs",
      "url": "http://localhost:9991",
      "topic": "MyMultiScrobblerTopic",
      "username": "Optional",
      "password": "Optional",
      "priorities": { "info": 3, "warn": 4, "error": 5 }
    }
  ]
}
  • priorities 按 info/warn/error 三级映射到 Gotify/ntfy 的优先级数值;
  • url 指向自建通知服务地址;token(Gotify)/topic(ntfy)为必填,账号口令可选。本文验证栈未部署通知服务,参数语义按官方 AIO 示例核定。

5.7 缓存与二级缓存(cache / CACHE_VALKEY)

  • 认证缓存默认落 DATA_DIR 下的 ms-auth.cache 文件(本文实测配置目录中的 ms-scrobble.cache 即缓存文件,159 字节,首次 scrobble 后自动生成),重启不丢凭据;
  • 二级缓存:配置 CACHE_VALKEY=redis://valkey:6379 后启用,官方说明收益为「跨重启持久化、更大容量、更长 TTL」,配合 MusicBrainz 变换器时强烈建议开启;官方给出的配套 Valkey 服务片段:
services:
  valkey:
    image: valkey/valkey
    volumes:
      - valkeydata:/data
volumes:
  valkeydata:
    driver: local
  • 认证缓存如需也走 Valkey,显式设置 CACHE_AUTH=valkey(官方:因 Valkey 可能无卷易失,默认不把认证放进二级缓存)。

5.8 阈值行为实测(scrobbleThresholds 验证)

用 150 秒测试曲目验证默认阈值(30 秒 + 50%)的判定行为。multi-scrobbler 侧日志(实测):

[2026-10-29 22:48:22.745 +0800] INFO   : [App] [Scrobblers] [Maloja - labMaloja] Scrobbled (Backlog)     => (vlc) Lab Ensemble - Neon Skyline @ 2026-10-29T22:47:08+08:00 (S)

播放开始于 22:47:08,scrobble 触发于 22:48:22(约 74 秒后),恰为 50% 进度点——时长阈值(≥30 秒)早已满足,进度阈值(≥50%)成为触发条件,证明两阈值需同时满足。目标侧 Maloja 入库回显(实测):

curl -s -H 'Authorization: TOKEN q1w2e3r4' 'http://127.0.0.1:8148/apis/mlj_1/scrobbles?max=5'
# {"status": "ok", "list": [{"time": 1793285228, "track": {"artists": ["Lab Ensemble"], "title": "Neon Skyline", "album": {"artists": ["Lab Ensemble"], "albumtitle": "Test Sessions"}, "length": 150}, "duration": 75, "origin": "client:default"}], "pagination": {"page": 0, "perpage": 5, "next_page": null, "prev_page": null}}

length: 150 与曲目时长一致、duration: 75 与触发点一致,元数据(曲名/艺人/专辑)来自 ID3 标签透传。同时 /api/status 中该源播放对象记录了完整的监听区间(实测节选):listenedFor: 141、listenRanges 起止时间戳、mediaPlayerVersion: 3.0.16 Vetinari——排障时可据此核对每个播放的判定过程。

5.9 数据库与 ID 稳定性(ms.db / id)

  • SQLite 数据库 ms.db 首次产生数据后生成于配置目录,存储全部播放、元数据与调试信息;每个播放按「源/目标配置 + id」关联入库(官方 Database 章节);
  • 官方明确要求:必须为每个源/目标设置 id,否则配置项改名后数据库无法续接同一实例的记录;
  • 保留量级:每条播放的体积随源暴露的字段、目标数量(每多一个目标多一份记录)而变,个人规模年数据量通常在几十 MB 量级(官方 Retention 说明;本文验证栈实测 ms-scrobble.cache 159 字节、Maloja 侧数据库 60KB 量级,均为小库);版本升级涉及库结构变更时官方自动备份迁移(官方 Updating 文档)。

六、生产配置模板

适用场景:家庭 NAS / 小型媒体服务器(8~16GB 内存、SSD,Jellyfin 或 Navidrome 为主要音源),目标为 last.fm + ListenBrainz 双记账并保留本地 Maloja 备份。内存占用预期:multi-scrobbler 为 Node 常驻服务,数百 MB 量级即可承载家庭规模轮询负载。

/opt/multi-scrobbler/config/config.json(密钥占位规则:第三方平台密钥一律走 [[ENV]] 插值,真实值放 compose 同目录 .env 文件;自托管目标演示值可直接替换):

{
  "debugMode": false,
  "disableWeb": false,
  "sourceDefaults": {
    "logFilterFailure": "warn",
    "scrobbleThresholds": {
      "duration": 30,
      "percent": 50
    },
    "maxRequestRetries": 2,
    "retryMultiplier": 2
  },
  "clientDefaults": {
    "maxRequestRetries": 2,
    "retryMultiplier": 2
  },
  "sources": [
    {
      "type": "jellyfin",
      "enable": true,
      "name": "Home Jellyfin",
      "id": "jf-home",
      "clients": ["lfm", "lbrnz", "malHome"],
      "data": {
        "url": "http://192.168.1.10:8096",
        "user": "musicfan",
        "apiKey": "[[JELLYFIN_APIKEY]]"
      }
    },
    {
      "type": "subsonic",
      "enable": true,
      "name": "Home Navidrome",
      "id": "nd-home",
      "clients": ["lfm", "lbrnz", "malHome"],
      "data": {
        "url": "http://192.168.1.10:4533",
        "user": "musicfan",
        "password": "[[NAVIDROME_PASSWORD]]"
      }
    }
  ],
  "clients": [
    {
      "type": "lastfm",
      "enable": true,
      "name": "lfm",
      "id": "lfm-home",
      "data": {
        "apiKey": "[[LASTFM_API_KEY]]",
        "secret": "[[LASTFM_SHARED_SECRET]]"
      }
    },
    {
      "type": "listenbrainz",
      "enable": true,
      "name": "lbrnz",
      "id": "lbrnz-home",
      "data": {
        "url": "https://api.listenbrainz.org",
        "token": "[[LISTENBRAINZ_TOKEN]]"
      }
    },
    {
      "type": "maloja",
      "enable": true,
      "name": "malHome",
      "id": "mal-home",
      "data": {
        "url": "http://maloja:42010",
        "apiKey": "q1w2e3r4"
      }
    }
  ],
  "webhooks": [
    {
      "type": "ntfy",
      "name": "ScrobbleNotify",
      "url": "http://192.168.1.10:9991",
      "topic": "scrobble-alerts",
      "priorities": { "info": 3, "warn": 4, "error": 5 }
    }
  ]
}

配套 .env(与 docker-compose.yml 同目录,权限 600,不提交 git):

JELLYFIN_APIKEY=在 Jellyfin 控制台「API 密钥」页生成
NAVIDROME_PASSWORD=该用户在 Navidrome 的密码
LASTFM_API_KEY=在 last.fm 创建 API 账户页申请
LASTFM_SHARED_SECRET=同上页一并签发
LISTENBRAINZ_TOKEN=在 ListenBrainz 用户设置页生成

配套 compose 环境变量(把 .env 值透传进服务,供 [[ENV]] 插值):

    environment:
      - TZ=Asia/Shanghai
      - JELLYFIN_APIKEY=${JELLYFIN_APIKEY}
      - NAVIDROME_PASSWORD=${NAVIDROME_PASSWORD}
      - LASTFM_API_KEY=${LASTFM_API_KEY}
      - LASTFM_SHARED_SECRET=${LASTFM_SHARED_SECRET}
      - LISTENBRAINZ_TOKEN=${LISTENBRAINZ_TOKEN}

模板要点:三个目标共用两个源(clients 数组定向);maxRequestRetries/retryMultiplier 较默认值放宽以容忍外网抖动;last.fm OAuth 首次授权需在仪表盘点击登录并回调(回调地址 = BASE_URL/lastfm/callback,BASE_URL 设为访问仪表盘的地址);自托管 Maloja 密钥 q1w2e3r4 为演示值,生产替换为强随机串。

七、常见问题

Q1:改了 config.json 不生效?

配置在启动时解析,修改后需 docker compose -f /opt/multi-scrobbler/docker-compose.yml restart multi-scrobbler;再用 docker compose logs --since 1m multi-scrobbler 确认出现对应的 Added from config.json。若日志报 JSON 解析错误,多为多写/漏写逗号,按指明行号修正。

Q2:日志出现 WARN ... Secrets Matched: None | Unmatched: XXX?

[[XXX]] 引用的环境变量没有注入到服务进程。检查 compose environment 是否透传、.env 文件是否在 compose 同目录、变量名拼写是否与插值键一致(大小写不敏感)。未修复前该字段保留 [[XXX]] 原文,认证测试会失败。

Q3:同一首歌重复入库?

确认源的 id 是否设置且稳定——同一逻辑源改名/重建后又没有固定 id,数据库会当成新实例重新记账;另 0.13.x 已内置重复 scrobble 检测(官方版本说明),若仍复现多为两个源实例覆盖了同一播放场景,梳理 clients 定向关系即可。

Q4:Maloja 目标报认证失败?

核对 data.apiKey 与 Maloja 密钥文件 maloja-data/config/apikeys.yml 中的值一致(层级易错,见部署指南 Q5);multi-scrobbler 启动日志的 Auth test passed!/Auth test failed 是最直接的判据。

Q5:想按天/按播放时长过滤(只记整曲)?

调大 scrobbleThresholds:如 duration: 60、percent: 80; ENV 也可用 SOURCE_SCROBBLE_DURATION/SOURCE_SCROBBLE_PERCENT 全局覆盖(见 5.2 源码实查依据)。

八、参考链接