feat: 经文数据外置 sutras/*.json,加减经不改代码

- 7部经文迁移至 sutras/ 目录,/api/sutras 实时扫描返回清单
- 前端改为按需懒加载经文 JSON(selectToken 防快速切换乱序)
- add_sutra.sh:校验+上传/删除 一键管理,免重启
- 修正生僻异体字(𫗪→喂、𫄨→絺、𦈎→繟、鬪→斗)
- run.md 同步新架构与经文管理文档

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-10-04 18:41:24 +08:00
co-authored by Devin
parent bc0bfd9263
commit 0b0da2d002
14 changed files with 984 additions and 296 deletions
Executable
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# 管理服务器上的经文:加经 / 减经。
# 目录是实时扫描的,无需重启服务,操作完即生效。
#
# 用法:
# ./add_sutra.sh <经文.json> # 加经(校验 → 上传 → 验证)
# ./add_sutra.sh --remove <id> # 减经(如 ./add_sutra.sh -d qingjing)
# FJ_PASS=xxx ./add_sutra.sh ... # 密码登录(需 sshpass);已配 SSH key 则不需要
#
# JSON 格式见 sutras/ 下现有文件:id/order/name/cat/title/seal/translator/source/sourceUrl/pageSize/segments[{h?,g?,t}]
set -euo pipefail
cd "$(dirname "$0")"
HOST=154.8.162.18
USER=root
DEST=/opt/fj/sutras
SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=15"
SSH_CMD="ssh $SSH_OPTS"
if [ -n "${FJ_PASS:-}" ]; then
command -v sshpass >/dev/null || { echo "缺少 sshpass:brew install sshpass 或改用 SSH key"; exit 1; }
SSH_CMD="sshpass -p $FJ_PASS ssh $SSH_OPTS"
fi
list_remote() {
curl -s --max-time 15 https://fj.all8ai.top/api/sutras | python3 -c "
import json, sys
items = {s['id']: s['name'] for s in json.load(sys.stdin)['sutras']}
print(' 当前目录:' + ('、'.join(items.values()) or '(空)'))
"
}
# ---- 减经 ----
if [ "${1:-}" = "--remove" ] || [ "${1:-}" = "-d" ]; then
ID="${2:-}"
if [ -z "$ID" ]; then
echo "用法:$0 --remove <id>(如 $0 -d qingjing)"; exit 1
fi
echo "==> 删除 $USER@$HOST:$DEST/ 中 id=$ID 的经文"
# 按文件名或 JSON 内 id 字段匹配,命中即删
$SSH_CMD "$USER@$HOST" "python3 -c 'import json,sys,pathlib
d=pathlib.Path(\"$DEST\")
i=\"$ID\"
for f in sorted(d.glob(\"*.json\")):
try: meta=json.loads(f.read_text(encoding=\"utf-8\"))
except Exception: continue
if f.stem==i or meta.get(\"id\")==i:
f.unlink(); print(\"已删除\", f.name); break
else:
print(\"不存在:\", i); sys.exit(1)'"
echo "==> 验证目录接口"
sleep 1
list_remote
echo "完成。该经的 TTS 缓存文件仍在 cache/(无害,复用文本时仍可命中)。"
exit 0
fi
# ---- 加经 ----
FILE="${1:-}"
if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
echo "用法:$0 <经文.json> 或 $0 --remove <id>"; exit 1
fi
# 基本校验:合法 JSON + 必填字段齐全 + segments 非空且每段有 t
echo "==> 校验 $FILE"
python3 - "$FILE" <<'PY'
import json, sys
d = json.load(open(sys.argv[1], encoding="utf-8"))
req = ["id", "name", "cat", "title", "seal", "translator", "source", "sourceUrl", "pageSize", "segments"]
missing = [k for k in req if k not in d]
assert not missing, f"缺少字段: {missing}"
segs = d["segments"]
assert isinstance(segs, list) and segs, "segments 必须是非空数组"
assert all(s.get("t") for s in segs), "存在缺 t 字段的段"
long_seg = [i for i, s in enumerate(segs) if len(s["t"]) > 800]
assert not long_seg, f"第 {long_seg} 段超过 800 字上限,请拆分"
print(f" 《{d['name']}》 {len(segs)} 段, 分类 {d['cat']}, order {d.get('order', 99)} —— 校验通过")
PY
NAME=$(basename "$FILE")
echo "==> 上传到 $USER@$HOST:$DEST/$NAME"
rsync -az --timeout=30 -e "$SSH_CMD" "$FILE" "$USER@$HOST:$DEST/$NAME"
echo "==> 验证目录接口"
sleep 1
list_remote
echo "完成。刷新 https://fj.all8ai.top 即可在下拉框看到。"