Skip to content
twinkling.top服务AudiobookshelfEN
板型any Pi 4 or 5; the library scan is metadata parsing and is not expensive
内核6.6.51+rpt-rpi-v8
空闲温度48 °C
内核架构arm64
参考机:Pi 4B 8GB / Bookworm 64-bit

服务卡片 · 媒体

Audiobookshelf:让进度在车里和厨房之间跟着你

有声书服务器真正提供的东西不是文件,是位置。用文件管理器在手机上放 MP3,这个位置每次都会丢;Audiobookshelf 把位置、倍速和书签都存在服务端,于是同一本书能在车载音响、厨房音箱和笔记本上接着听,而不需要任何人去翻文件夹。

ghcr.io/advplyr/audiobookshelf:2.19.4 · 2026-10-19 ·

Audiobookshelf rack plate: board stack and host ports
服务参数
容器镜像ghcr.io/advplyr/audiobookshelf:2.19.4
宿主端口:13378/tcp
数据目录/srv/homelab/audiobookshelf/config
内存预留180 MB
CPU 上限0.40 vCPU (cpus: "0.40") — transcoding for mobile clients is the peak
更新节奏quarterly. The mobile app updates more often than the server, and the server usually needs to be within a few versions of it
ARM 兼容arm64 native including the ffmpeg build used for streaming and chapter embedding
端口映射与暴露面
宿主容器proto暴露用途
:1337880tcp仅局域网web player and the mobile app API

部署步骤

  1. 建好配置和元数据目录,并把属主交给容器

    两个目录都必须对容器的 uid 可写。其中任何一个只读挂载,都会得到一个能提供媒体库、但保存进度时静默失败的服务端。

    run
    sudo mkdir -p /srv/homelab/audiobookshelf/{config,metadata}
    sudo chown -R 1000:1000 /srv/homelab/audiobookshelf
  2. 媒体库只读挂载,并让扫描器指向它

    只读是刻意的:扫描器把标签读进自己的数据库,从不写回文件。要改一个标签,就在 NAS 上改文件然后重新扫描。

    run
    cd /srv/homelab/audiobookshelf && docker compose up -d
    # 界面里:设置 -> 添加媒体库 -> 有声书 -> /audiobooks
    docker logs --tail 30 audiobookshelf | grep -i scan
  3. 加一个播客源,并限制保留多少集

    没有保留设置的话,播客目录会在固态盘上无限增长。在添加源的时候就设好每档节目的集数上限,而不是等盘满了再补。

    run
    # 媒体库 -> 添加播客 -> 粘贴 RSS 地址
    du -sh /srv/homelab/audiobookshelf/metadata/feeds
    # 然后在节目设置里限定保留集数

文件从哪来,以及唯一必须做对的一件事

有声书是唯一一种「目录结构比标签更重要」的媒体类型,因为一本书就是一个装着章节文件的文件夹,扫描器以文件夹为单位。一本书一个文件夹,上面是作者文件夹,配一张 cover.jpg 或在第一条轨道里嵌入封面。

在首次扫描之前把这件事做对,值十分钟;做完之后再改,意味着媒体库里会把一百本书显示成一本有一百章的书,或者更糟——一百本各自独立的书。

shell
# /mnt/nas/audiobooks/
#   作者名/
#     书名/
#       01 - Chapter.mp3
#       02 - Chapter.mp3
#       cover.jpg
#       metadata.json(可选)

直连与转码

在局域网内,App 播原始文件,派完全不干活。走移动网络时,App 可以请求一个低码率的转码流,这时派的 CPU 才有意义:Pi 4 上一次转码很轻松,两次就不行了。

要限制的是转码并发数。有声书很长——一次要四分钟才能追上听众的转码是糟糕的体验,所以不设上限时,第二个听众会让两个人一起缓冲。

场景发生什么派的开销
局域网,原始文件直接播放无
移动网络,64k opus实时转码约单核的 12%
两个移动端听众第二个排队不设上限时一个核、双方都在缓冲

播客是被低估的那一半

播客功能会按计划从 RSS 源下载剧集、保留可配置数量的最新剧集,并用和有声书一样的进度跟踪来提供服务。对一个听四五个节目的家庭来说,这替代掉了播客 App 的云账号。

下载内容进的是元数据目录而不是 NAS,这是对的位置——它们本来就是一次性的,放在 NAS 上以外的地方能让备份集保持干净。

shell
# 添加源:媒体库 -> 添加播客 -> 粘贴 RSS 地址
# 设置每个节目保留的剧集数与检查间隔
# 存在 /srv/homelab/audiobookshelf/metadata/feeds 下

compose 文件

整份文件放在 /srv/homelab/audiobookshelf/compose.yaml。标签固定版本号,不用 latest——树莓派上回滚比升级麻烦得多。

compose.yaml
services:
  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:2.19.4
    container_name: audiobookshelf
    restart: unless-stopped
    ports:
      - "13378:80/tcp"
    environment:
      TZ: Asia/Shanghai
      AUDIOBOOKSHELF_UID: "1000"
      AUDIOBOOKSHELF_GID: "1000"
    volumes:
      - /srv/homelab/audiobookshelf/config:/config
      - /srv/homelab/audiobookshelf/metadata:/metadata
      - /mnt/nas/audiobooks:/audiobooks:ro
      - /mnt/nas/podcasts:/podcasts:ro
    networks: [rack]

networks:
  rack:
    external: true

加固清单

  • 账号按人创建,首次运行的管理员账号从默认名改掉
  • 媒体目录以只读挂载,扫描器无法就地修改标签
  • 反向代理路由经认证门户要求家庭成员组
  • 手机 App 指向 VPN 地址而不是转发端口,收听进度因此保持私密

备份方案

音频文件本身在 NAS 上,这里不复制;配置目录里有媒体库索引、收听进度和用户账号,要备份的是它。进度是人们真正在意的部分——丢了它意味着每本书都要从头开始听。

上线后验证

  • 在手机 App 里开始的一本书,在浏览器播放器里从同一位置继续
  • 媒体库扫描显示每本书只有一条记录、包含全部章节,而不是拆成多个条目
  • 走移动网络的转码流播放没有断续,同时派上显示一个核被部分占用
  • 在某一台设备上听完的播客剧集,在另一台上显示为已播放

踩过的坑

  • 把书文件直接放在作者目录下的文件夹,会产出一本巨大的书。目录结构就是元数据模型,不是建议。
  • 元数据目录必须从任何同时监视 NAS 的同步工具里排除,否则 .metadata 里的 JSON 文件会和正在写它们的服务互相打架。
  • 配置和元数据目录必须对容器的 uid 可写。其中任何一个只读挂载,都会造成「服务能启动、能提供媒体库、但保存进度时静默失败」——对这个服务来说这是最糟糕的失败方式。
  • 手机 App 缓存很激进,常常需要手动刷新才能看到新书。这是 App 的行为而不是服务端的问题,重装服务端也修不了。

硬件与选型问答

有了 Navidrome 还需要这个吗?
它们的重叠比人们以为的少。Navidrome 是给音乐的——专辑、歌单、随机播放、大量短曲目。Audiobookshelf 是给长音频的,那里位置和章节结构就是全部意义。既有音乐收藏又有有声书的家庭两个都跑,加起来占 320MB。
手机 App 够不够好用,能天天用吗?
它是开源选项里最好的一个,车载使用也说得过去,包括 Android Auto。弱点和所有自建 App 一样:缓存行为偶尔需要手动同步,以及要求服务端可达——而 VPN 就是为此存在的。
有声书库要占多少空间?
按常见码率,每本书大约 200 到 400MB,所以一百本大约 30GB,再加上由保留设置管理的播客下载。这个体量小到可以放在 NAS 上而不用多想。