project-infoREQ-BILI-DYNAMIC-COLLECTOR-20260804-001DEV-PROJECT-INFO-BILI-AUTHENTICATED-SESSION-DOWNLOAD-20260805-001HANDOFF-INFOADMIN-INFODEV-BILI-PLUGIN-FULL-VIDEO-NARROW-SCOPE-ASSIGN-20260805-001dev.developer.project / infodevdev.reviewer.project / inforev青枫浦上Q / BV1HA3o6oEJJ / https://www.bilibili.com/video/BV1HA3o6oEJJ3133.95 s;已隔离错误预览:600.133313 s本 V001 仅设计“完整文件入口”增量。已经独立审核 PASS/0 的dev/project-dev/bili_video_download_bridge.py accept-browser-file 后半程保持原字节、原 CLI 和原测试合同,不在本设计中重写或放宽。当前已安装 1.0.5 TXT 扩展、其 localhost 服务、SQLite、固定 Cookie 临时文件和 token 查询接口也保持不变且不被完整视频模式调用。
设计审核阶段外部动作固定为:真实 Cookie 读取 0、真实下载 0、Chrome/扩展安装或修改 0、Native Host 注册 0、F:\video 写入 0、正式 ana-data 写入 0、600 秒隔离预览读取 0。
在项目自有、用户可见的相邻 side-panel 模式中复用“添加任务 → 进行中/失败重试 → 已完成”的交互,完成以下单条闭环:
bestvideo+bestaudio/best,由 FFmpeg 仅做流复制合并,生成一个完整 MKV。accept-browser-file 后半程,执行稳定性、partial、音视频流、远端/本地时长、SHA-256、CreateNew 媒体和映射门禁。.m4s 直链。受保护数据包括 Cookie 名称和值、会话 token、密码、验证码、内部解析得到的签名清单/媒体 URL,以及包含这些值的异常、请求、调试对象和下载器 info_dict。真实值只允许短暂存在于:
这些值不得进入 Codex、任务文本、argv、环境变量、配置、项目文件、浏览器 storage、Native Host manifest、日志、stdout/stderr、映射、栈追踪、测试、证据或 handoff。
allowed_origins 必须是安装后实际扩展 ID 对应的唯一精确 chrome-extension://<id>/,禁止占位符遗留、通配符或第二来源。输入 schema、来源、页面证明、Cookie 边界、认证元数据、DRM、格式、下载、合并、候选唯一性、后半程或清理任一环节不能满足合同,任务均不得显示 COMPLETE、不得创建正式媒体/映射、不得把 600 秒预览交给转写。未知异常只映射为固定安全错误码,原异常文本与对象不出进程。
用户可见 side panel
└─ 用户点击校验/添加
└─ background service worker
├─ 注入只读页面证明(无秘密持久化)
├─ chrome.cookies.getAll(精确 Bilibili URL)
└─ chrome.runtime.connectNative(精确 host)
└─ 专用 Native Host
├─ 严格协议校验
├─ Cookie 数组 → io.StringIO CookieJar
├─ yt-dlp API → 内部暂存 → FFmpeg stream-copy MKV
├─ 清空并关闭内存 CookieJar
└─ 冻结 accept-browser-file 子进程
└─ F:\video\青枫浦上Q\BV1HA3o6oEJJ.mkv
+ BV1HA3o6oEJJ.download.json
实现使用相邻的项目自有 side-panel 构建和专用 Native Host,不向当前 TXT 扩展二进制注入代码。界面状态和按钮语义复用现有可见工作流;安全边界与 localhost TXT 后端完全分离。background 持有一个长连接,Native Host 同一时刻仅允许一个任务;side panel 关闭再打开时只从 Native Host 查询非秘密的阶段、百分比、错误码和最终文件名,不使用 chrome.storage 保存任务或秘密。
扩展 manifest 只申请:
sidePanel:用户可见控制面;activeTab 与 scripting:仅在用户点击时读取当前页的非秘密播放证明;cookies 加 https://www.bilibili.com/* host permission:仅在用户点击添加/重试时读取该 URL 可发送的 Cookie;nativeMessaging:连接唯一专用 Native Host。不申请 downloads、storage、debugger、webRequest、declarativeNetRequest、tabs 通配访问或 127.0.0.1 权限;不注册 content script、外部消息入口或快捷键自动触发。
用户点击“校验当前页面”后,background 通过 chrome.scripting.executeScript 取得并立刻验证:
www.bilibili.com 且 path 精确为 /video/BV1HA3o6oEJJ;query/hash 不作为下游输入,host 只接收冻结 canonical URL;readyState >= 1、videoWidth > 0、videoHeight > 0;duration 与 3133.95 s 差值不超过 max(3.0 s, 3133.95*0.1%);mediaKeys === null;出现 EME/DRM、登录/验证码/付费阻断或无法获得完整时长均 fail-closed;52:14 时继续。该人工可见确认不是唯一门禁,后续认证元数据与最终时长仍必须独立通过。页面校验结果只包含 BVID、规范 URL、时长、尺寸、readyState、DRM 布尔值和时间戳,不包含 DOM 文本、HTML、媒体 URL 或播放器内部对象;校验结果过期 60 秒即失效。
只有在有效页面证明尚未过期且用户点击“添加完整视频任务”或“重试”时,background 才调用 chrome.cookies.getAll({url: "https://www.bilibili.com/"})。扩展不序列化到 storage,不显示值,不计算证据哈希,不在错误对象中附带请求。发送完成后立即清空数组引用。
Native Host 只接受 domain 为 bilibili.com 或以 .bilibili.com 结尾、path 以 / 开头的 Cookie;单个字段、Cookie 数、总 UTF-8 字节均有上限。外域、控制字符、重复关键字段、未知字段、空值、超限消息一律拒绝,且固定返回 E_SECRET_INPUT,不回显原值。
扩展到主机只允许:
{"type":"status","schema":1}:无秘密状态查询;{"type":"start","schema":1,"target":"BV1HA3o6oEJJ","page_proof":{...},"cookies":[...]}:一次任务;{"type":"cancel","schema":1,"target":"BV1HA3o6oEJJ"}:用户显式取消。主机到扩展只返回固定字段:schema/type/target/phase/progress/error_code/formal_filename/mapping_filename。禁止返回 URL、命令、Cookie、下载器对象、stderr、异常文本或内部绝对暂存路径。正式文件仅返回 basename;项目用法另行记录固定授权目标目录。
消息采用 Chrome Native Messaging 长度前缀;主机在分配大对象前拒绝超长帧。JSON 必须是 UTF-8、对象、无重复键、精确字段集合和正确类型。target 不允许由请求选择其他 BVID。主机全局单任务;第二个 start 返回 E_BUSY,不产生网络或文件动作。
主机 stdout 仅写协议帧;stderr 默认空。yt-dlp 使用自定义 logger 和 progress hook:logger 将所有第三方字符串丢弃,仅在内存更新固定错误码;progress hook只抽取 status、已下载字节、总字节和数值百分比,不保存或转发 filename/info_dict/url/fragment/headers。顶层捕获 BaseException,执行清理后发送静态码,不打印 traceback。测试模式也只使用合成哨兵,真实秘密永不进入证据。
实现阶段拟新增一个项目目录和一个测试目录;不会改动冻结 bridge:
dev/project-dev/bili_authenticated_extension/:manifest、side panel、background、Native Host、构建/当前用户安装脚本和非秘密配置范本;dev/project-dev/test/bili_authenticated_extension/:协议、秘密不落盘、失败清理和 UI 桩测试;dev-doc/project-doc/B站已登录会话完整视频扩展入口.md:安装、按钮顺序、卸载和真实验收说明。Native Host 用 Python 实现并构建为 Windows 当前用户可执行程序;构建产物不包含真实配置或秘密。安装脚本只在后续实现审核 PASS 且由获授权操作者显式执行时:
开发/复审不执行安装脚本,不写注册表,不启动 Chrome。打包采用固定依赖版本的 one-directory 可执行构建;不把 Cookie、会话、路径样本或运行日志打入产物。
主机把通过 schema 的 Chrome Cookie 转换为 Netscape 格式文本并写入 io.StringIO,将这个 text stream 直接传给 yt-dlp cookiefile 参数。已核对本机 yt-dlp 2026.07.04 的 YoutubeDLCookieJar 支持文件名或 text stream;设计不使用 Cookie 临时文件、固定路径、浏览器 profile 或 --cookies-from-browser。
所有 yt-dlp 操作在同一 with YoutubeDL(opts) 生命周期完成;结束或失败时依次 seek(0)、truncate(0)、close() 并释放 Cookie/请求引用。Python 不承诺物理内存安全擦除,但不跨进程生命周期、不持久化,符合“仅可信扩展/服务内存短暂存在”的授权边界。
下载前先在同一个认证上下文中 extract_info(download=False),只在内存检查:
id == BV1HA3o6oEJJ,无 entries、playlist、live 或 multi-P 展开;max(3.0 s, remote*0.1%) 门禁;has_drm,选中格式及其组成格式均没有 DRM 标志;info_dict、format URL、HTTP headers 和下载器异常只存在内存,不写 JSON/description/thumbnail/subtitle/日志/cache。禁止 verbose、dump、print、write-info、write-comments、write-playlist-metafiles、浏览器 Cookie 导出和插件加载。
yt-dlp 固定选项:
format="bestvideo+bestaudio/best";merge_output_format="mkv";noplaylist=True、continuedl=False、overwrites=False、cachedir=False;主机从固定 %LOCALAPPDATA%\project-info\bili-auth-ingress\BV1HA3o6oEJJ\ 下独占创建随机运行目录,固定输出模板,不接受消息路径。创建、遍历和清理前确认所有路径位于固定根且不是重解析点。下载中间件只能留在该目录;任务结束只允许存在一个受支持的非 partial 媒体候选,出现多个候选、未知 sidecar、.crdownload/.part/.tmp 残留或文本型 URL 状态文件即 fail-closed 并清理。启动时只清理固定根内未提交的陈旧运行目录,不触碰正式目录或其他用户文件。
完整 MKV 形成后,主机先关闭 CookieJar 并释放认证元数据,再以固定非秘密 argv 启动冻结 bridge:
<bridge-python> <bridge-script>
--input <exact-batch-json>
--yt-dlp <credential-free-yt-dlp>
accept-browser-file
--bvid BV1HA3o6oEJJ
--media-file <fixed-internal-stage-candidate>
--destination <authorized-destination>
--ffprobe <ffprobe>
argv 不含 Cookie、token、signed URL 或网页对象。bridge 继续负责:输入文件稳定且无 companion partial、公共无凭据远端元数据、目标卷只读复制、FFprobe 同时有音视频、3133.95 s 时长一致性、源/正式双 SHA-256、CreateNew 媒体与 mapping、BaseException 回滚和暂存清理。600.133313 秒预览必须在正式发布前失败。
主机只解析 bridge 的固定 JSON 成功字段;失败 stdout/stderr 不原样进入扩展或日志。只有 exit 0、映射 BVID/bytes/hash/duration/acquisition_mode 全部匹配,且正式媒体和 mapping 均存在时返回 COMPLETE。成功后可清理主机自有的内部候选;若成功后清理失败,正式交付仍保留并返回静态 W_STAGING_RETAINED,下次启动仅在确认正式 mapping 已存在且哈希匹配时删除本主机运行目录。主机绝不删除或覆盖正式文件。
E_BACKHALF。KeyboardInterrupt、SystemExit、Native Host 断连、Chrome 关闭和未知 BaseException:先结束本任务后代、关闭内存 CookieJar、清理内部暂存,再传播为固定失败状态;不打印原对象。E_EXISTS,无覆盖、无重复下载。设计 PASS 后仅允许新增/修改下列范围:
dev/project-dev/bili_authenticated_extension/ 内最小静态扩展、Native Host、构建和当前用户安装脚本;dev/project-dev/test/bili_authenticated_extension/;禁止修改:
dev/project-dev/bili_video_download_bridge.pydev/project-dev/test/test_bili_video_download_bridge.pyF:\video\青枫浦上Q、正式 ana-data、600 秒隔离预览实现审核前全部测试使用合成 Cookie/URL 哨兵、fixture、mock Chrome API、fake yt-dlp/FFmpeg/FFprobe/bridge 和 TemporaryDirectory;网络、Chrome、扩展安装、注册表、真实 Cookie、真实媒体及正式路径动作均为 0。
cookies.getAll 和 native connect 前失败。使用唯一 synthetic sentinel 作为 Cookie、token、signed URL、header 和第三方异常文本;覆盖成功、metadata 失败、下载失败、FFmpeg 失败、bridge 失败、取消、BaseException 和断连。逐字节扫描 stdout/stderr、协议响应、配置、项目临时树、argv/env、日志、mapping fixture、异常和证据,sentinel 出现次数必须为 0。
把文件 API、NamedTemporaryFile、mkstemp、yt-dlp CookieJar 和 subprocess 设为观测桩,证明 Cookie 只进入 io.StringIO,不存在 Netscape Cookie 文件、固定 Cookie 路径、token 文件、URL sidecar 或浏览器 profile 访问。关闭后 stream 长度为 0 且已关闭。
bestvideo+bestaudio/best、MKV、noplaylist、无 cache/metadata/thumbnail/subtitle/plugin、内部 HTTP 下载器和本地 FFmpeg 输入;签名 URL 不进入 argv。chrome.cookies 返回 synthetic 值,断言只在有效用户点击后调用一次;side panel 关闭/重开只查询安全状态;重试重新取 Cookie。dev.reviewer.project 合并安全设计审核;HOLD 则只修设计,禁止实现。case_analysis.video_downloader 按其真实动作授权安装项目自有扩展/Native Host,在目标页可见地点击一次完整任务。开发线程不代替下载员读取真实会话或写正式目录。3133.95 s、同时含音视频、无 partial、SHA-256 与 exact canonical mapping 的完整原件;再交媒体处理员顺序转写。独立审核需要逐项确认:
设计 PASS 仅授权离线最小实现,不授权真实 Cookie、Chrome 安装、真实下载、F:\video、正式 ana-data 或转写。