mirror of
https://github.com/hectorqin/reader.git
synced 2026-11-11 05:20:54 +08:00
朗读(Closes #13 的朗读部分) 新增服务端 HTTP TTS 代理与客户端第二、第三个朗读引擎,三者在同一个 SpeechEngine 接口下可切换: - 服务端 GET /api/v1/tts 代理 TTS_URL 指向的合成服务(edge-tts / Piper 等兼容形态),只代理不内置合成模型;GET /api/v1/tts/voices 回答 「这个实例能用什么」,未配置时返回 http:false 而不是 404。 按句合成、磁盘缓存、上游返回非 audio/* 时明确报错(一个指到网页的 TTS_URL 会以 200 返回 HTML,塞进 audio 里既没声音也没事件)。 /tts 是精确的查询串令牌白名单项之一:<audio src> 无法带 Authorization。 - 客户端 HttpTtsEngine 用 <audio> 而不是 Web Audio,事件驱动推进队列。 - 客户端 NativeTtsEngine 走 Android 外壳新增的 speech 接口(shell v3): WebView 自带的合成器与系统的是两个引擎,手机系统装好的中文语音经常 不在 getVoices() 里,这是「朗读没有中文声音」最常见的原因。 - speechAvailability 决定 auto 用哪个引擎:native → system → http。 - 原 TtsEngine 抽出 loadQueue/onChunk/onState 为公开字段以结构化满足接口。 书架 - 排序:最近更新 / 最近入库 / 书名 / 作者,中文按数字大小排。 排序规则抽到 shelf-order.ts,离线路径与服务端用同一条规则。 - 密度、作者显隐、封面进度条;搜索一键清空 + 回车即搜;下拉刷新。 - 服务端 BookDto 增加 addedAt,否则客户端离线排序无法复现服务端结果。 自定义设置 - 朗读引擎可选(引擎多于一个时才显示该行);音调行只对有声调的引擎出现。 - 书架设置独立成 sheet,与阅读面板分开。 测试与文档 - server: tts.test.ts(10 例)。web: tts-http / speech / shelf-order 新增 39 例,合计 245 passing。 - android/scripts/check-shell.sh 修正为同时校验嵌套的 speech 接口, 之前它只能看到一个顶层接口。 - README / docs/api.md / docs/architecture.md 补齐三个引擎的取舍、 环境变量与错误码。 Ref: #13
64 lines
2.8 KiB
YAML
64 lines
2.8 KiB
YAML
# One command to get running:
|
|
#
|
|
# docker compose up -d
|
|
#
|
|
# Then open http://<your-host>:8080 and register the first account, which
|
|
# automatically becomes the instance admin.
|
|
services:
|
|
reader:
|
|
image: cnb.cool/hectorqin/reader:latest
|
|
# To build from source instead of pulling the published image. The context is
|
|
# the repository root because the image bakes in the H5 client built from
|
|
# ./web as well as the server.
|
|
# build:
|
|
# context: .
|
|
# dockerfile: server/Dockerfile
|
|
container_name: reader
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8080:8080"
|
|
environment:
|
|
# Polling intervals in seconds. Set to 0 to disable (a manual scan is
|
|
# still available from the admin API).
|
|
SCAN_INTERVAL: "1800"
|
|
WATCH_INTERVAL: "60"
|
|
LOG_LEVEL: "info"
|
|
# Set this to the address you actually reach the server on, so download
|
|
# links work behind a reverse proxy.
|
|
# PUBLIC_URL: "https://reader.example.com"
|
|
# Uncomment to allow family members to self-register instead of the admin
|
|
# creating their accounts:
|
|
# ALLOW_REGISTRATION: "true"
|
|
# Origins allowed to call the API from a browser, comma separated.
|
|
# Empty (the default) reflects whatever origin asks. Fine for a LAN: the
|
|
# client does not know the address it will be reached on, and there are no
|
|
# cookies in the design. Set it if the instance is on the public internet:
|
|
# CORS_ORIGINS: "https://reader.example.com"
|
|
# Directory holding the built H5 client, served at `/`. Already set in the
|
|
# image; only override if you build the client separately.
|
|
# WEB_DIR: "/app/web"
|
|
|
|
# --- HTTP speech, for clients that have no engine of their own ---
|
|
# The server only *proxies*; it does not bundle a synthesizer, because
|
|
# that would multiply the image size and a NAS's CPU budget. Point this at
|
|
# any service that accepts the classic `?text=...&speed=...` shape
|
|
# (edge-tts, a local Piper wrapper, a commercial API with a shim).
|
|
#
|
|
# TTS_URL: "http://host.docker.internal:5002/tts"
|
|
# TTS_TOKEN: "" # bearer token, if the upstream wants one
|
|
# TTS_VOICES_URL: "" # defaults to <TTS_URL>/voices
|
|
# TTS_CACHE_BYTES: "268435456" # audio cache cap in /data; 0 disables
|
|
volumes:
|
|
# --- your books, mounted READ-ONLY ---
|
|
# The server NEVER writes to this directory. Replace the left-hand side
|
|
# with the path to your own library.
|
|
- /path/to/your/books:/books:ro
|
|
# --- everything the server writes lives here ---
|
|
# SQLite database, cover cache, scan journal.
|
|
- ./data:/data
|
|
healthcheck:
|
|
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8080/api/v1/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|