Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

开发日志

边写代码边留痕。每篇自包含、可检索、可复用。

功能索引

日期 功能 里程碑 说明
2026-08-03 调研与总体方案 M0 立项调研、技术选型、差异化定位
2026-08-03 Bilibili 客户端 M1 Wbi 签名、搜索、view、playurl DASH 音频流
2026-08-03 下载与转码 M2 DASH 下载、m4a直拷/mp3-flac转码、命名、SQLite 去重
2026-08-03 元数据反查与打标签 M3 咪咕/网易云多源反查、mutagen 打标签、webp封面转换
2026-08-03 扫码登录与 API 加固 M3补 B站扫码登录降风控、搜索双端点、网易云 weapi 兜底
2026-08-03 歌词获取与校准 M4 LRCLIB/网易云/B站字幕多源降级、快速校准、lyric-align 强制对齐
2026-08-04 pipeline 闭环 + 搜索 + TUI M5 get 一键闭环、网易云歌词正文反查、Textual TUI
2026-08-04 Web 界面 M6 FastAPI + WebSocket 进度、原生单页、[web] extra
2026-08-04 日志 + 统一状态通道 M7 日志文件滚动、status.emit 双写、provider 级解析状态、config/等待输入三端显示
2026-08-04 便携模式 M8 .portable 标记/env 触发、data/ 目录、portable on/off 命令、配置迁移
2026-08-04 统一入口 + 部署测试 M9 bilimuse-start 安装/配置/使用一条龙、setup 全量档、从零部署实测
2026-08-05 E2E 测试集 + 便携默认 M10 真实网络 34 用例 + gold 校准基准;安装默认便携模式
2026-08-06 v1 Review 决策层 v1 auto/ai/confirm 三模式、LLM 免费预设、去重改文件存在校验、TUI 综合管理面板;v1.1 补充:Web 批量队列/预览/设置/模型管理/评审弹窗(三端闭环)、MV+字幕(复用校准结果)、搜索三层改进、DeepSeek 预设、官方原曲终审推荐、歌词双栏对比
2026-08-08 校准信任优先策略 v1.1 治「whisper 越校越差」:平台歌词健康度判定 + 轻度失配线性缩放 + 官方原曲跳过 whisper + 对齐结果可信度校验(score/锚点 MAD/时间轴合理性)
2026-08-08 Web v2 + whisper 真百分比 + MCP v2 前端零构建重做(ESM + Web Components + pub/sub store + OKLCH 令牌)、whisper 校准直连 faster-whisper 真百分比、web -c 配置、MCP stdio server + AI skill;v2.1 增量:封面防盗链(no-referrer)、70% 弹窗预览、评审歌词正文、换歌词(后悔药)三端点、队列完成即消失、using 徽章按 kind 匹配、whisper 下拉对齐

技术沉淀速查表

技巧/坑 一句话 位置
URL 拼接 f"{API}/{path.lstrip('/')}",API 常量忘加尾斜杠会拼成 api.bilibili.comx bilimuse/providers/bilibili.py:94
Wbi 签名 播放接口需 wbi 签名 + buvid3 cookie 防 -412 bilimuse/providers/bilibili.py:76
wbi 搜索被风控 wbi 搜索端点未登录返回 v_voucher 无结果,用旧版 search/type bilibili.py:112
httpx 系统代理 httpx 0.28 在 Windows 读注册表 WinINET 代理,需 trust_env=False bilibili.py:34
控制台乱码 $env:PYTHONIOENCODING='utf-8',数据本身 UTF-8 正确 仅显示层
typer 0.27 Exit Exit 只有 code 参数,错误信息先 echoExit(code=1) bilimuse/cli.py:79
下载前查 ffmpeg 需转码时先 shutil.which 再下载,避免半途失败 bilimuse/services/download.py:87
SQLite 去重 UNIQUE(bvid,cid) + INSERT OR REPLACE 幂等 bilimuse/db.py:38
ffmpeg 内嵌 imageio-ffmpeg 可选 extra,PyPI 拉取不经 GitHub;find_ffmpeg config→PATH→内置 bilimuse/services/download.py:32
ffmpeg 路径三级回退 config.ffmpeg_pathshutil.whichimageio_ffmpeg.get_ffmpeg_exe()(懒 import) download.py:32
mock 未装包 setitem(sys.modules,'pkg',None)import 抛 ImportError,模拟未安装 tests/test_download.py:44
网易云无周杰伦版权 2018 授权到期,搜索只剩翻唱/remix → 咪咕 MIGUM2.0 为第一源 bilimuse/providers/meta.py
咪咕封面 用搜索结果 imgItems URL(勿按 id 再搜),webp 用 ffmpeg 管道转 jpeg meta.py:96
标题清洗/匹配 clean_title+split_query 拆歌手/歌名,歌手命中±分 bilimuse/services/tagger.py:30
B站扫码登录 passport qrcode generate/poll;外层 code=0 恒真,看 data.code;成功从 Set-Cookie 取 SESSDATA bilimuse/services/auth.py
B站搜索双端点 登录态优先 wbi,result 空(v_voucher)自动回退旧版 bilimuse/providers/bilibili.py:119
网易云 weapi 端点用 weapi/search/get/web(cloudsearch 已 50000005);v3 详情用 al/ar bilimuse/providers/meta.py:119
登录降风控 匿名流量是 B 站风控重点,SESSDATA 后走 wbi 主链路 风险表
fMP4 时长 mutagen 读分片 MP4 时长为 0,用 ffmpeg -i -f null - 解析 Duration bilimuse/services/aligner.py:38
whisper 模型国内下载 hf-mirror 极慢,ModelScope 镜像官方 faster-whisper 快;whisper_model 支持本地路径 aligner.py:107
lyric-align 编码 Windows GBK 读崩 UTF-8 歌词 → 子进程 PYTHONUTF8=1 aligner.py:111
LRC 清理 网易云剥作曲/编曲头;LRCLIB 剥空行/live标题行;翻译合并 bilimuse/services/lyric.py
align 置信度回退 直连对齐产出 AlignedLine.to_dict(matched 标记);匹配率<50% 回退原歌词,不盲目缩放 aligner.py:_align_in_process
语言自动检测 假名→ja 决定性;咪咕 tags 网络信号;whisper_language 兜底。勿硬编码 zh aligner.py / providers/meta.py
锚点线性拟合 matched<50% 但锚点≥3 时最小二乘 aligned=a·source+b 整体变换(治前留白) aligner.py:_apply_alignment
稳健拟合 锚点偏移 MAD≤3s 判纯平移(中位数),否则 LSQ;防离群点带偏 aligner.py:_robust_fit
外文歌译文 主源非netease,detect非zh → 网易云双语对替换(_from_netease_bilingual lyric.py
译文配对 校准前按时间戳 pair_translation(英文/拟声行→None),校准后 reattach 按行序贴回;勿行序1:1 lyric.py:pair_translation/reattach_translation
歌词正文搜索 网易云 weapi s 参数即按歌词搜(返回歌名对、歌手是翻唱者);LRCLIB 不搜歌词正文 services/search.py
pipeline 事件化 编排抽 services/pipeline.py,on_event 推 info/progress/meta/lyric,CLI/TUI/Web 复用 pipeline.py
Textual 8 Input.action_submit() 是协程需 await;headless 用 run_test+pilot.pause() tui.py
「」/《》歌名提取 split_query 优先括号内歌名(日式引号),再 - 分隔 bilimuse/services/tagger.py
cmd 中文不乱码 .cmd 存 UTF-8 无 BOM + 首行 @echo offchcp 65001;PowerShell 5.1 则必须 UTF-8 带 BOM,机制相反 bilimuse-start.cmd / setup.ps1
首次配置探测 python -c "from bilimuse.config import default_config_dir; sys.exit(...)" + errorlevel,无 venv 无 python 判断直接进安装 bilimuse-start.cmd:17
统一入口 启动器管安装/配置/菜单,命令转发 bilimuse.cmd 保持纯净;参数直达 config/tui/web 分流 bilimuse-start.cmd
决策桥 UI 提供 request(point)->Decision;CLI 内联 input(EOF 兜底),TUI ModalScreen+Future(callback set_result,Esc 兜底) bilimuse/tui.py:239
App.query_one 不查模态屏 App.query_one 只查基础屏 DOM,弹窗内 widget 用 app.screen.query_one tests/test_tui.py:test_manage_modal_save
LLM JSON 鲁棒提取 response_format=json_object + 平衡括号扫描(容忍 markdown 包裹)+ 失败重试一次 services/llm.py:66
免费预设回落 resolve_llm_cfg 空字段回落默认预设(GLM-4-Flash),配置存空即可,模型名变动只改代码 services/llm.py:58
候选化不动 auto confirm/ai 才走 fetch_lyrics_candidates(gather 并行+保序+去重+双语),auto 保留早退 services/lyric.py:173
Textual 无分隔符 OptionList 无 Separator(8.2.8),详情内联进 label,索引 1:1 bilimuse/tui.py:32
去重以文件为准 already_downloaded = DB 记录 + file_path 真实存在(文件丢失允许重下);--force 穿透 bilimuse/db.py:48
E2E 缓存复用 key=bvid:fmt:align 持久 JSON;每用例独立下载目录防同名覆盖;每轮重置 db 抗去重 tests/e2e/run_testset.py
标准答案双轨 expect 机器校验 + review 人工评审(A/B/C);bvid 实地固化 + 成员集断言抗 B站 排序漂移 tests/e2e/cases.yaml
pytest 隔离 e2e @pytest.mark.e2e + addopts="-m 'not e2e'"(引号防拆分);conftest 显式 fixture 不污染单元 pyproject.toml
搜索分区字段 B 站搜索返回的是 typeid(子分区 id,193 MV/31 翻唱/130 综合…)非 tid,音乐区判断用 MUSIC_SUB_TIDS 集合 + is_music_tid() bilibili.py:_parse_search / search.py
Web 静态资源缓存 改前端必须 bump index.html?v=,否则旧 JS + 新 HTML 列错位 web/static/index.html
WS 评审回传 review_result 处理必须 resolve() 返回 Decision 而非 str('str' object has no attribute 'choice' web.py:WSReviewBridge
Bing 纠错时机 编辑距离 ≤1 对中文同样生效(「晴雨」→「晴天」)→ 仅零结果时才替换重搜,建议条始终展示 services/suggest.py / search.py
MV 字幕零额外 ASR MV 音频轨与音频版同流 → 歌词校准(whisper)结果直接 lrc_to_srt 转 .srt pipeline.py / db.py:kind
官方原曲终审 author/title 含「官方/Official」→ 终审默认推荐原始歌词(MV 前留白/器乐尾会拉偏校准);v1.1 起 auto 模式也跳过 whisper 强制对齐 services/aligner.py:is_official_upload
WS 发送就绪保护 ws.send 未 OPEN 静默丢消息 → 入队 pendingSends,onopen flush web/static/app.js
队列竞态 create_task 与事件推送顺序不定 → 先发 queued 事件再建任务 web.py:DownloadTaskManager
whisper 真百分比 faster-whisper 无 progress_callback → 惰性生成器 seg.end/info.duration 推 pct;线程内跑(释放 GIL)+ loop.call_soon_threadsafe 桥回事件循环 services/aligner.py:104
MCP 帧格式 stdio = 换行分隔 JSON(非 Content-Length 头);tools/call 业务失败用 result isError 而非协议 error;unknown -32601 / 坏 JSON -32700 bilimuse/mcp_server.py:366
自定义元素建壳 connectedCallback 里 innerHTML=外壳 会摧毁 light-DOM 子节点(弹窗内容丢失)→ 程序化 createElement + 移动子节点 web/static/js/components/bm-modal.js:3
web -c 保存同路径 读用 _load_cfg() 时,写也要 cfg.save(_CONFIG_PATH),否则读自定义写回默认目录 bilimuse/web.py:49
重试 force 判定 去重错误真实文案「已下载过且文件存在,跳过」(「去重」只在测试假消息里) web/static/js/views/queue-view.js
视图模块装配 import 视图模块必须调 init*(store, …),否则模块级 store undefined,store.set 抛 TypeError 静默失败(表单空/引导不开) web/static/js/main.js
封面防盗链 hdslb 对非 bilibili Referer 返 403 → 图片级 referrerpolicy="no-referrer"(空 pic 先 trim 判空防坏 URL) web/static/js/views/search-view.js:renderResults
弹窗 Esc 后被 store 重开 modal.hide() 不清 state → 监听 bm-close 事件里清 store.preview,否则任意 store.set 又 show() js/views/search-view.js:initSearch
换歌词防陈旧 apply 端点重拉 fetch_lyrics_candidates 再按 index 取(弹窗打开期间候选可能变化) bilimuse/web.py:api_lyric_apply
歌词预览复用 评审 detail 与换歌词 preview 共用 lyric_preview(迁自 pipeline _lyric_preview services/lyric.py
换歌词写盘 pair_translation 校准前 / reattach_translation 校准后贴回,占位符不重打标签 services/pipeline.py:replace_lyric
前端循环 import 需要互相调用的视图模块,一个方向改由 main.js 注入(initDownloads(store,{openLyricReplace})),import 单向往 js/main.js
队列完成即消失 用户裁定:result/cancelled 分支 tasks.delete(id) 立即移除,error 卡保留(重试必需) js/main.js:applyEvent
whisper 下拉对齐 HF 缓存条目 value=size(剥 faster-whisper- 前缀),与 cfg 存储一致;已检测模型去重「按需下载」项 js/views/settings-view.js:loadWhisperSelect
using 徽章按 kind resolve.kind local/cached 限定种类再匹配(本地 value=路径、缓存 value=大小名,互斥防双徽章) js/views/models-view.js:refreshModels
测试 mock 要 async 端点 await 候选函数,monkeypatch 需 async def 包列表,lambda 直接 'list' object can't be awaited tests/test_web.py