Archived
为什么:原先三处都在手写轮子——ffmpeg CLI 拼参数写标签、aiohttp 单连接手搓 下载、自己比对魔数判格式。手写部分既难测又易错;改走成熟库后测试从 144 涨到 175,并且彻底去掉了 ffmpeg 这个外部二进制依赖。 下载 → aria2c 常驻 JSON-RPC(aria2p 客户端),新增 _aria2.py - 单例后端:首次调用时拉起 aria2c,只监听 127.0.0.1 且强制随机 secret (无鉴权的 aria2 RPC 允许本机任意进程操纵队列、读写任意文件) - split=5 / max-connection-per-server=5 多连接 + 原生断点续传 - 异常语义与内置通道逐一对齐:取消/超限清残片抛 DownloadCanceled / DownloadException,任务失败/超时保留残片抛 RequestException 供续传 - 取不到 aria2c 时 get_backend() 返回 None,自动降级到内置 aiohttp 通道 (本机无 aria2c 的降级路径已实测) 标签 → mutagen 纯 Python 写入,新增 tagging.py - 取代 _write_metadata_with_ffmpeg + _build_format_args(226 行 shell 参数拼接) - MP3(ID3v2.3)/FLAC/M4A/OGG/Opus 分容器实现,无子进程、不重编码 - 就地改帧:TXXX 等未触及的标签原样保留(ffmpeg 整帧重写会丢) - 临时文件 + os.replace 原子替换,写坏不会留下半个文件 - 为什么不是 ffmpeg-python(原方案):实测它用 **kwargs 建模选项,无法表达 重复键(-metadata ×N),list 值还会被字符串化成 "['0', '1:v']";-map 尚有 内置的 stream 位置参数入口,但 -metadata 无解,且 overwrite_output=True 生成的 -y 被排到输出文件之后、可能失效 格式探测 → filetype,改 _http.py - 删除手写的 _AUDIO_MAGIC 魔数表,改用 filetype.guess() 判 MIME (audio/* 放行,video/mp4 作为容器显式放行) 配套 - Dockerfile:镜像不再装 ffmpeg,改装 aria2 - pyproject:新增 filetype / aria2p / mutagen;dev 加 httpx2(消除测试里的 StarletteDeprecationWarning,现 0 warning) - __main__.py / __init__.py / models.py:清理 ffmpeg 相关导出与文案 测试:新增 31 个用例(test_aria2.py 13、test_tagging.py 21,含最小合法 FLAC 样本构造);全套 175 passed / 0 warning
28 lines
1.5 KiB
Docker
28 lines
1.5 KiB
Docker
# 基础镜像 Python 3.12(3.9 已于 2025-10 EOL)
|
||
FROM python:3.12-alpine3.21
|
||
WORKDIR /app
|
||
# 使用阿里云 apk 镜像源加速安装
|
||
# tzdata:alpine 无 zoneinfo,ENV TZ=Asia/Shanghai 不装它不生效
|
||
# (容器内日志/展示本地时间差 8 小时;计费/会话全部 epoch 秒不受影响)
|
||
# aria2:下载加速通道(常驻 RPC,仅监听 127.0.0.1 的随机端口 + 随机 secret)
|
||
# ——标签写入已改为 mutagen 纯 Python 实现,镜像不再需要 ffmpeg
|
||
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories && \
|
||
apk add --no-cache tzdata aria2
|
||
# 依赖由 uv 从 uv.lock 精确安装(可复现构建);uv 二进制仅存在于构建阶段
|
||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||
ENV UV_PROJECT_ENVIRONMENT=/usr/local UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
|
||
COPY pyproject.toml uv.lock ./
|
||
RUN uv sync --frozen --no-dev
|
||
COPY . .
|
||
RUN chmod +x /app/entrypoint.sh
|
||
# 非 root 运行(容器安全基线)。注:挂载卷 ./downloads ./data 的宿主机目录
|
||
# 需对 UID 10001 可写(见 docker-compose.yml 注释),否则下载与数据库写入会失败
|
||
RUN adduser -D -u 10001 appuser && chown -R appuser:appuser /app
|
||
USER appuser
|
||
ENV TZ=Asia/Shanghai
|
||
EXPOSE 5000
|
||
# 容器健康检查(/health 为轻量本地端点,不触发上游请求)
|
||
HEALTHCHECK --interval=60s --timeout=5s --start-period=20s --retries=3 \
|
||
CMD wget -qO- http://127.0.0.1:5000/health || exit 1
|
||
CMD ["/app/entrypoint.sh"]
|