- 音视频
【免费下载链接】VideoDownloadHelper
Chrome Extension to Help Download Video for Some Video Sites.
本指南以仓库根目录的 CONTRIBUTING.md 为骨架,完整梳理 Simple Video Download Helper(Chrome Manifest V3 视频下载扩展)的贡献流程:从项目布局、开发环境搭建、构建打包,到编码规范、新增站点解析器、翻译维护与 PR 提交流程。读完本文,你将能够在本仓库中独立完成"新增一个视频站点解析器"和"新增一种界面语言"两大典型贡献任务,并理解解析引擎ParseVideo的真实调用链与测试、覆盖率、打包等工具链的底层实现依据。
项目概览:仓库与扩展的边界
Simple Video Download Helper 是一个帮助用户在受支持的视频站点上发现并下载视频的浏览器扩展。整个扩展及其全部工具链都位于仓库的video-url-parser/子目录中,而仓库根目录暴露了与子目录同名的 npm 脚本并**委派(delegate)**到该目录执行,因此开发者既可以在仓库根目录工作,也可以直接进入video-url-parser/工作。这一设计在根 package.json 中体现为:"test": "npm --prefix video-url-parser test"、"build": "npm --prefix video-url-parser run build"等脚本统一使用npm --prefix委派,并通过postinstall(npm --prefix video-url-parser install)在根目录安装依赖时自动联动安装子目录依赖。
项目布局:理解代码放哪里
CONTRIBUTING.md 给出了清晰的目录结构,结合仓库实际内容可进一步细化为:
. ├── package.json # 根脚本,委派进入 video-url-parser/ └── video-url-parser/ # 扩展本体 ├── manifest.json # Manifest V3 定义(权限、action、content scripts 等) ├── js/ │ ├── functions.js # 核心工具函数(单元测试覆盖) │ ├── constants.js # 共享常量(单元测试覆盖) │ ├── parsevideo.js # ParseVideo 解析引擎与站点解析器(单元测试覆盖) │ ├── getPagesSource.js # webpack 打包入口,产出 dist/dist.min.js │ ├── translate.js # 弹窗 UI 的语言切换与文本翻译逻辑 │ └── popup.js / background.js / video.js 等 # 弹窗、后台与页面脚本 ├── lang/ # 弹窗 UI 翻译文件(每种语言一个 .js 文件) ├── _locales/ # Chrome i18n messages(每个 locale 一个文件夹) ├── scripts/package.js # Chrome Web Store 打包脚本 ├── main.html # 弹窗页面,语言下拉框与脚本引用所在 └── test/ # Mocha + Chai 单元测试其中三个核心、被单测覆盖的库文件正是解析器运行时零依赖原则的落点:
- js/constants.js:定义
max_url_length = 95(长 URL 截断阈值)与steemit_domains域名列表,并通过module.exports导出供其他模块复用; - js/functions.js:提供
ValidURL(URL 合法性校验)、extractDomain(提取并去除www.前缀的域名)、FixURL(修复http:\/\/转义斜杠与//开头的协议相对地址)、getFileExtension、sanitizeFilename、suggestFilename、getMediaType(按扩展名将 URL 归类为 video/audio/image)、inferMediaExtension、isRestrictedUrl等一整套工具函数; - js/parsevideo.js:定义
ParseVideo类,包含站点专属解析器与通用提取器链(详见下文"新增站点解析器"章节)。
webpack.config.js以 js/getPagesSource.js 为入口,生产构建输出为video-url-parser/dist/dist.min.js(该产物不入库)。manifest.json采用 Manifest V3,声明permissions为activeTab、storage、scripting、downloads、contextMenus,并通过content_scripts匹配http://*/*与https://*/*(显式排除*.youtube.com/*,见 manifest.json)。
开发环境搭建:三步跑起来
环境要求:Node.js >= 18(根 package.json 与 video-url-parser/package.json 的engines.node均为>=18)。
安装依赖:先将仓库 fork 并 clone 到本地,进入仓库根目录后执行npm install,根目录的postinstall钩子会自动委派安装video-url-parser/下的依赖。
构建生产包并加载到浏览器:
cd video-url-parser npm run build # 产出 dist/dist.min.js(该文件不提交入库)随后打开chrome://extensions,开启右上角开发者模式(Developer mode),点击加载已解压的扩展程序(Load unpacked),选择video-url-parser/文件夹即可。manifest.json中已配置默认快捷键Alt+Shift+V(commands._execute_action)与默认弹窗main.html,加载后可直接点击工具栏图标或按快捷键唤起。
若要生成可提交 Chrome Web Store 的 zip 包,则在根目录或子目录运行:
npm run package # 构建并在仓库根目录写出 simple-video-download-helper-<version>.zip打包实现位于 scripts/package.js:它从manifest.json读取version拼出 zip 文件名,将manifest.json置于 zip 顶层,并排除两类内容——按名称匹配任意深度的目录(node_modules、test、coverage、.nyc_output、scripts、.git)以及仅用于开发/工具的根文件(eslint.config.js、webpack.config.js、.prettierrc.json、.prettierignore、.nycrc.json、.mocharc.json、package.json、package-lock.json、todo-urls.txt、some-video-sites.txt等)。若dist/dist.min.js不存在,打包脚本会报错并提示先执行npm run build。
可用脚本:一张表看懂工具链
CONTRIBUTING.md 列出的脚本可在仓库根目录或video-url-parser/任意一处执行(根目录脚本内部委派到子目录):
| Script | 说明 |
|---|---|
npm test | 运行 Mocha 单元测试套件 |
npm run coverage | 运行测试并强制覆盖率阈值 |
npm run lint | 使用 ESLint 检查源码与测试 |
npm run lint:fix | 尽可能自动修复 lint 问题 |
npm run format | 使用 Prettier 格式化整个代码库 |
npm run format:check | 仅校验格式,不写入改动 |
npm run build | 产出生产构建包(webpack production) |
npm run package | 构建并生成扩展 zip 到仓库根目录 |
npm run check | 依次执行 lint、format check、coverage 与 build |
打开 PR 之前,请务必确保npm run check通过。在 video-url-parser/package.json 中,check被定义为npm run lint && npm run format:check && npm run coverage && npm run build,即一条命令串起全部质量关卡。
底层工具链与配置如下(均可在仓库中核实):
- 测试:Mocha + Chai。
.mocharc.json指定spec: "test/*.js"、timeout: 5000、reporter: "spec"; - 覆盖率:nyc(
nyc mocha)。.nycrc.json限定统计范围为js/functions.js、js/constants.js、js/parsevideo.js,并强制阈值:lines、statements、functions均 ≥ 90%,branches≥ 70%,低于阈值即失败; - Lint:ESLint 9(flat config,见 eslint.config.js),叠加
eqeqeq、no-var、prefer-const等额外规则; - 格式化:Prettier(
.prettierrc.json),配套.prettierignore维护排除清单; - 构建:webpack(
webpack.config.js,entry 为js/getPagesSource.js); - 打包:adm-zip(
scripts/package.js)。
编码规范:范围受限的风格约束
代码风格由ESLint(flat config)与Prettier共同强制:4 空格缩进、双引号、分号、120 字符打印宽度(见.prettierrc.json的tabWidth: 4、singleQuote: false、semi: true、printWidth: 120)。
值得特别注意的是:lint 与格式化工具有意限定作用范围,只覆盖核心库(js/functions.js、js/constants.js、js/parsevideo.js)、测试套件与配置文件。第三方 vendored 库与遗留 UI 脚本被显式排除——在 eslint.config.js 的ignores中可以看到bs/**、images/**、lang/**、_locales/**、test/data/**、js/jquery-3.4.1.min.js、js/jquery-ui.js、js/MD5.js、js/m_inc.js、js/background.js、js/getPagesSource.js、js/popup.js、js/translate.js、js/video.js等均被排除;对应的.prettierignore也维护着同样思路的清单。当你新增文件时,请同步维护这两份忽略清单。
两条硬性约束:
- 核心库的新行为必须有单元测试覆盖——这由
.nycrc.json的 90%/70% 覆盖率阈值在机制上保证; - 解析器在运行时必须保持零依赖——
parsevideo.js只require("../js/functions")内部的工具函数,不依赖任何第三方包(video-url-parser/package.json的dependencies为空,所有工具链依赖均在devDependencies中)。
新增站点解析器:核心贡献路径
这是本项目最重要的贡献类型。要理解怎么做,先理解解析引擎本身。
理解ParseVideo引擎与Parse()调用链
js/parsevideo.js 中的ParseVideo类以constructor(url, html)接收页面 URL 与 HTML 源码,其入口方法Parse()(parsevideo.js#L23-L82)按以下顺序工作:
- 用
extractDomain(url)提取域名,与一张站点解析器注册表比对:miaopai.com、pearvideo.com、ted.com、msdn.com、weibo.com、xiaokaxiu.com、facebook.com、dailymotion.com、vimeo.com各自对应一个parse_<site>_com(...)静态方法;命中且解析结果通过ValidURL校验则立即返回; - 若没有专属解析器命中,则依次走通用提取器回退链:
extract_all_video_urls(匹配页面中"video_url": "..."形式的 JSON 字段);extract_all_mp4_urls(匹配"mp4","url":"..."形式);parse_header_og_video_url(匹配<meta property="og:video:url" content="...">等 Open Graph 标签,对应测试夹具见 test/data/html-header-og-video-url.html);parse_video_tag_in_html(匹配<video src="...">,测试夹具 test/data/html-video-tag.html);extract_all_source_tags(匹配<video>/<audio>下的<source src="...">子标签);extract_all_m3u8_urls(匹配页面内任意 HLS.m3u8播放列表地址);extract_all_media_urls(兜底:匹配页面中任意直链媒体文件,扩展名集合与functions.js共享VIDEO_EXTENSIONS/AUDIO_EXTENSIONS,.m3u8因有专属提取器而被排除)。
所有提取器都遵循同一模式:正则全局匹配 →FixURL修复 →ValidURL校验 →Array.prototype.uniq()去重,最后"0 个返回null,1 个返回字符串,多个返回数组"。
按四步新增一个站点解析器
CONTRIBUTING.md 给出了标准四步:
第 1 步:添加解析函数并注册到Parse()链。
在 js/parsevideo.js 中新增一个parse_<site>_com(url, html)静态方法,并在Parse()方法的handler注册表中加入"<site>.com": ParseVideo.parse_<site>_com条目。参考一个极简范例——parse_miaopai_com(parsevideo.js#L127-L134)直接从 URL 结构推导出视频地址:
// parse miaopai.com video e.g. https://miaopai.com/show/abcde.html static parse_miaopai_com(url, _html) { const re = /.*miaopai\.com\/show\/(.*)\.html?$/i; const found = re.exec(url); if (found !== null) { return "http://gslb.miaopai.com/stream/" + found[1] + ".mp4"; } return null; }站点专属解析器通常针对页面结构定制正则(如parse_weibo_com匹配video_src=、parse_dailymotion_com匹配播放器元数据 JSON 中的"type":"application/x-mpegURL"与"stream_h264*_url"、parse_vimeo_com提取"progressive":[{...,"url":"...mp4",...}]块),并复用FixURL+ValidURL保证结果可靠。
第 2 步:添加测试 spec 与 HTML 夹具。
在video-url-parser/test/下新增test_parsevideo_<site>.js,并在test/data/放置代表该站点真实页面的 HTML 夹具(现有夹具包括 test/data/pearvideo-1050733.html、test/data/ted-1.html、test/data/vimeo-151712690.html、test/data/weibo-1.html、test/data/xiaokaxiu-1.html 等)。测试写法可参考 test/test_parsevideo.js:
describe("pearvideo", function () { const url = "http://www.pearvideo.com/video_1050733"; it(url, function () { const html = fs.readFileSync("test/data/pearvideo-1050733.html").toString(); const video = new ParseVideo(url, html); assert.equal(video.Parse(), "http://video.pearvideo.com/mp4/short/20170320/cont-1050733-10294549-hd.mp4"); }); });第 3 步:把验证过的页面加入 tested-urls.txt。该文件同时被manifest.json的web_accessible_resources引用,随扩展发布。
第 4 步:运行npm run check并更新 README 中的"Supported sites"表格。
在 README.md 的受支持站点清单中登记新站点,随后确认npm run check(lint + format + coverage + build)全部通过。
新增或更新翻译:两套机制并行
弹窗 UI 的本地化由两套独立机制共同完成,两者都要维护:
- video-url-parser/lang/
.js:弹窗 UI 字符串。以lang/en-us.js为蓝本复制,翻译每个 value 并保持 key 集合完全一致(现有语言覆盖 zh-cn、zh-tw、de-de、es-sp、fr-fr、it-it、ru-ru、nl-nl、pt-br、pl-pl、ro-ro、tr-tr、ja-jp、ko-kr、ar-sa、hi-in、bn-in、id-id、vi-vn、th-th、uk-ua、cs-cz、el-gr、sv-se 等 20+ 语言); - video-url-parser/_locales/ /messages.json:Chrome 扩展商店中展示的扩展名称/描述(
manifest.json的default_locale为en),每个 locale 一个文件夹。
- video-url-parser/_locales/ /messages.json:Chrome 扩展商店中展示的扩展名称/描述(
当你在lang/中新增全新语言时,除了翻译文件本身,还必须完成 CONTRIBUTING.md 指出的三个联动修改:
- 在 main.html 中新增
<script src="lang/<code>.js"></script>引用; - 在 js/translate.js 的
get_lang()中新增case "<code>": return (translation_<name>);分支(现有 24 个分支一一对应lang/下的语言文件); - 在 main.html 的语言
<select id="lang">中添加<option value="<code>">Native name</option>选项。
弹窗的翻译执行逻辑集中在translate.js:ui_translate()通过get_lang()依据select#lang当前值选取对应翻译对象,再调用translation(lang)对#text_setting、#text_log、#text_dark_mode等 DOM 元素逐个执行translate_text替换文本。
提交信息与 Pull Request 流程
提交信息遵循简洁、祈使句风格(例如 "Add Vietnamese translation"),需要时可关联 issue(如 "Fixes #123"),并将无关改动拆分为独立 commit/PR。
PR 提交流程五步:
- Fork 仓库,从
master创建特性分支(topic branch); - 完成改动,并同步补充测试与文档;
- 本地确保
npm run check通过; - 使用 PR 模板提交 Pull Request,说明改了什么(what)与为什么(why);
- 积极回应评审反馈,配合维护者完成合并。
任何类型的贡献都受欢迎——bug 报告、功能请求、文档改进、新站点解析器、翻译与代码。在报告 bug 或请求功能时,请遵循仓库 issue 模板的格式描述问题;参与即默认遵守"互相尊重、无骚扰"的行为准则。
快速自检清单(提交 PR 前对照)
npm run check在本机通过(lint、format:check、coverage、build 全绿);- 新增的核心库行为有对应单元测试,且未降低 nyc 覆盖率阈值(lines/statements/functions ≥ 90%,branches ≥ 70%);
- 解析器未引入运行时第三方依赖;
- 新增文件已同步更新
eslint.config.js/.prettierignore的忽略清单(如适用); - 新增站点已登记
tested-urls.txt并更新 README 的 Supported sites 表格; - 新增语言已同步
main.html的 script 引用、translate.js的get_lang()分支与<select id="lang">选项; - 提交信息清晰、祈使句、按主题拆分,PR 描述包含 what 与 why。
遵循上述约定,你就可以稳定地为 Simple Video Download Helper 贡献新站点解析器、完善测试与覆盖率、扩充多语言支持,并顺利通过npm run check这条质量红线。
赞- 音视频
【免费下载链接】VideoDownloadHelper
Chrome Extension to Help Download Video for Some Video Sites.
项目地址:https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper点击查看免费下载相关推荐
参与 CodeBurn 开源贡献:从环境搭建到新增 Provider 的完整贡献指南
参与 CodeBurn 开源贡献:从环境搭建到新增 Provider 的完整贡献指南 CodeBurn 是一个免费、本地运行的 AI 编码 Token 用量与成
参与 OmniRoute 开源共建:从环境搭建到新增 Provider 的完整贡献指南
参与 OmniRoute 开源共建:从环境搭建到新增 Provider 的完整贡献指南 本文以 OmniRoute 官方贡献指南( docs/i18n/no/C
后端API网关LLM 网关人工智能大模型MCP 服务桌面应用参与 OpenAgent 开发:从环境搭建到贡献 AI Provider 的完整指南
参与 OpenAgent 开发:从环境搭建到贡献 AI Provider 的完整指南 导读 OpenAgent 是一款由 LLM、RAG 与 Agent 循环驱
AI 应用人工智能大模型AI AgentRAGMCP 服务后端前端语音
上一篇:如何使用OpenDrop实现跨平台无线文件传输:终极指南下一篇:Rufus 制作U盘启动盘在Windows 7打不开:3.22为什么是最后一个版本创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考