mcpField
Z
zahori

zahori

本地服务
github.com/josesepulvedapino浏览器自动化44 周前更新

关于 zahori

zahori 通过真实浏览器操作网页并监视网络请求,解析页面背后的媒体流,供需要获取 HLS、DASH、MP4 或音频流的用户使用。它支持用 JSON 配置可复用的网站配置文件,并拒绝 DRM 内容。

主要功能

  1. 01浏览器驱动页面并捕获媒体请求
  2. 02返回流地址及重放请求所需标头
  3. 03识别 HLS、DASH、MP4 和音频
  4. 04按语言选择音轨
  5. 05用 JSON 配置并修复网站配置文件
  6. 06检测并拒绝 DRM 内容

适用场景

  1. 01获取网页播放器背后的媒体流地址
  2. 02为下载工具提供重放所需请求标头
  3. 03为难处理的网站建立可复用配置
  4. 04发现网站变更后测试并修复配置

MCP 相关

作为 MCP 服务向 Agent 提供探测网站、测试及保存配置文件等工具;Agent 可据此发现媒体流并学习网站操作流程。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"josesepulvedapino-zahori": {
"command": "npx",
"args": [
"-y",
"zahori"
]
}
}
}
启动命令npx -y zahori

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmzahori0.1.1

工具

6

收录的工具列表 · 更新于 2 周前

参数类型必填说明
urlstring是包含播放器的页面。
langstring否多语言流的首选音频语言(例如 es)。

详细介绍

zahori

找到任意网页背后的媒体流。

CI npm version node license

真实浏览器会打开网页、关闭浮层、点击播放,并持续监视网络,直到媒体请求出现。你将获得流 URL(HLS、DASH、MP4 或音频),以及重放所需的请求头。

$ npx zahori get https://example.org/live
https://cdn.example.org/hls/live/master.m3u8

无需为每个网站单独配置,也无需等待提取器。如果浏览器能播放,zahori 就能找到它。

目录

功能

  • 开箱即用,适用于任意 URL。 内置的通用流程无需配置即可处理大多数网页。
  • 真实浏览器引擎。 Playwright 在后台驱动无头浏览器;自动处理同意横幅、播放按钮和 iframe 播放器,并支持多种语言。
  • 包含重放所需的请求头。 从真实请求中捕获 Referer/Origin/UA/Cookie,因此 ffmpeg 等工具不会遇到 403 错误。
  • 支持 HLS。 可区分主播放列表和媒体播放列表、直播和 VOD,并按语言为多语言流选择音频版本。
  • 可学习。 将难处理的网站转换成小型 JSON 配置文件,保存一次,之后即可始终确定性地使用。
  • Agent 原生(MCP)。 编码 Agent 可以探测网站、编写配置文件、测试并保存。
  • 自我修复。 当网站发生变化时,zahori heal 会使用自带密钥的模型修复配置文件,并在保存前通过客观预言机验证。
  • 从设计上拒绝 DRM。 始终检测并拒绝受保护的内容。

为什么选择 zahori

网络上大量不常见的网站通过嵌入式播放器提供流媒体服务,而没有任何下载器认识这些播放器:地方电视台和广播电台、活动直播页面、小型视频门户。yt-dlp 对它精心维护了提取器的大型平台支持出色。但对于这些不常见的网站,没有现成的提取器;逐个手写也无法扩展。

yt-dlpzahori
覆盖范围约 1,800 个精选网站浏览器能打开的任意网页
方法针对各网站的提取器代码真实浏览器 + 网络嗅探
新网站等待维护者添加通用流程即可运行,或几分钟内完成学习
网站发生变化提取器会失效,直到修复补丁发布zahori heal 会修复配置文件

两者互为补充:用 yt-dlp 下载 YouTube,用 zahori 处理那些没人编写过提取器的网页。

安装

npm install -g zahori   # CLI
npm install zahori      # library

要求

Node≥ 22
浏览器运行一次 npx playwright install chromium --only-shell;否则会使用已安装的 Google Chrome
ffmpeg可选,仅用于 --validate、--download 和发现预言机

pnpm 用户: pnpm 默认会阻止依赖项的构建脚本,因此 Playwright 不会自动下载浏览器。运行上面的 playwright install 命令一次,或者使用系统 Chrome 作为备用浏览器。

CLI

# Resolve the stream URL behind a page (URL to stdout, everything else to stderr)
zahori get https://tv.example.org/live

# Full result as JSON: url, kind, live/VOD, replay headers, all candidates
zahori get https://tv.example.org/live --json

# Prefer an audio language on multilingual streams
zahori get https://tv.example.eu/live --lang es

# Record it (replays the captured headers; needs ffmpeg)
zahori get https://tv.example.org/live --download session.mp4
zahori get https://tv.example.org/live --audio session.m4a

# Check the stream is real media, not a bumper or geo-block slate
zahori get https://tv.example.org/live --validate

# Watch the browser work
zahori get https://tv.example.org/live --headful

--json 输出示例如下:

$ zahori get https://example.org/watch --json
{
  "url": "https://cdn.example.org/hls/master.m3u8",
  "kind": "hls",
  "headers": {
    "referer": "https://example.org/",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/150.0.0.0 Safari/537.36"
  },
  "profileId": "generic",
  "candidates": [
    "https://cdn.example.org/hls/master.m3u8",
    "https://cdn.example.org/hls/720p/index.m3u8",
    "https://cdn.example.org/hls/1080p/index.m3u8"
  ]
}

解析出的 URL 通常带有签名,且有效期很短。zahori 每次运行时都会重新获取流,因此请立即使用该 URL,切勿保存。

库

import { resolve } from 'zahori';

const stream = await resolve('https://tv.example.org/live', {
  audioLanguage: 'es', // optional, for multilingual masters
});

stream.url;     // the media URL
stream.kind;    // 'hls' | 'dash' | 'mp4' | 'audio'
stream.live;    // true = live, false = VOD, undefined = unknown
stream.headers; // Referer/Origin/UA/Cookie to replay (many CDNs 403 without them)

将 stream.headers 传给任何用于获取该 URL 的工具。使用 ffmpeg 的示例:

import { download } from 'zahori';
await download(stream, 'session.mp4');

错误采用类型化处理:NoStreamError(未捕获到内容)和 DrmError(检测到受保护内容,已拒绝)。

自带浏览器

对于需要登录的网站,可在你控制的 Playwright 上下文中(例如包含存储状态的上下文)运行 zahori:

import { runProfileOnPage, GENERIC_PROFILE } from 'zahori';

const ctx = await browser.newContext({ storageState: 'auth.json' });
const page = await ctx.newPage();
const stream = await runProfileOnPage(page, GENERIC_PROFILE, url);

配置文件:zahori 如何学习网站

zahori 不内置任何网站知识。大多数页面都能通过内置的通用流程解析。遇到无法解析的页面时,解决方法是创建一个 配置文件:一个描述如何打开该网站的小型 JSON 文件(要点击哪些元素、如何识别媒体请求、要选择哪个候选项)。配置文件是数据,而非代码;引擎会以确定性的方式解释它们,运行时不会使用 AI。

{
  "id": "tv-example-org",
  "match": ["^https?://([^/]*\\.)?tv\\.example\\.org([/:?#]|$)"],
  "steps": [
    { "action": "goto" },
    { "action": "dismissOverlays", "selectors": [] },
    { "action": "click", "selector": ".broadcast-start" }
  ],
  "sniff": { "kinds": ["hls"], "urlPattern": "/live/" }
}

配置文件存放在项目中的 .zahori/profiles/(请将它们提交到版本库,以便在生产环境和团队成员之间共享),或全局存放在 ~/.zahori/profiles/。配置文件保存的是 如何重新获取 流媒体,而不是流媒体 URL,因此签名 URL 或过期 URL 都不会造成问题。

教 zahori 识别网站

使用你的编码 Agent(MCP)

zahori 是一个 MCP 服务:任何支持 MCP 的 Agent 都可以探测网站、提出配置文件、使用预言机进行测试,并在测试通过后保存配置文件。整个过程使用你已有的订阅,无需 API 密钥。服务会在协议握手期间向 Agent 发送工作流说明,因此在所有客户端中的操作方式都相同。

大多数客户端使用标准配置:

{
  "mcpServers": {
    "zahori": { "command": "npx", "args": ["-y", "zahori", "mcp"] }
  }
}
客户端设置
Cursor将上面的代码块添加到 ~/.cursor/mcp.json(或项目级 .cursor/mcp.json)
VS Code / Copilot使用 .vscode/mcp.json,并将配置放在 "servers" 键下,而非 "mcpServers"
Windsurf~/.codeium/windsurf/mcp_config.json
Claude Codeclaude mcp add zahori -- npx -y zahori mcp
Codex CLIcodex mcp add zahori -- npx -y zahori mcp
Gemini CLIgemini mcp add zahori npx -y zahori mcp
Claude Desktop将上面的代码块添加到 claude_desktop_config.json

然后提出请求:"找出 https://tricky.example.org 上的流媒体,并保存配置文件"。提供的工具:zahori_get、zahori_probe、zahori_test_profile、zahori_save_profile、zahori_validate、zahori_list_profiles。

无头模式,使用你自己的密钥

对于无人值守的流水线(cron、CI),zahori 可以自行驱动模型。它总是先尝试免费的确定性路径,只有失败时才会消耗令牌:

export ANTHROPIC_API_KEY=...   # or OPENAI_API_KEY, or a local Ollama
zahori discover https://tricky.example.org --model anthropic:claude-sonnet-5
zahori heal     https://tricky.example.org   # when a saved profile stops working

模型规格:anthropic:<model>、openai:<model>、ollama:<model>、compat:<model>(任何兼容 OpenAI 的端点),也可以只设置一次 ZAHORI_MODEL。模型只负责 提出 配置文件;引擎会运行每个提案,并由预言机进行评估,因此绝不会保存未经验证的配置文件。

预言机

“是否有内容下载”是一个不可靠的测试:它可能会把广告片头、背景音乐和地理区域限制提示页误判为有效内容。预言机会综合更可靠的信号,再判断流媒体是否可信。

  • 解码探测。 ffmpeg 会解码一个有时长限制的片段并测量音量。
  • 清单检查。 正常的播放会话包含许多分段;提示页则只有 4 个。
  • 静音容忍。 如果检测到的片段没有声音,会在更靠后的位置再次探测(静音可能是正常的中场休息);仅凭静音绝不会判定流媒体失败。
  • 明确报告失败。 对 403/401 响应会报告为标头问题,而不是无法解释的异常。

判定结果为 pass、fail 或 inconclusive;发现流程只会保存通过预言机测试的配置文件。

负责任地使用

zahori 专为公开可访问、未受保护的流打造:这些页面在普通浏览器中可供任何访客播放。它解析浏览器本就能播放的内容,不会入侵任何系统。

zahori 的设计原则是拒绝 DRM。 它会检测清单中的 Widevine、PlayReady 和 FairPlay 标记,并通过明确的 DrmError 拒绝处理。它绝不会尝试绕过加密或访问控制;这是不可逾越的底线,不是可调整的设置。

安全范围。 最明确的适用场景是网站向所有访客提供的开放 HLS/DASH,并将其用于合法目的,例如存档、无障碍访问、转录和研究。在使用前,有几件事值得了解:

  • “公开”不等于“公有领域”。 流可以免费观看,并不代表可以自由重复使用;有些网站会对其视听内容单独授权。请查看网站的重复使用条款。
  • 没有 DRM 不等于法律上不受保护。 在某些司法管辖区,绕过轻量级令牌或签名机制也可能引发反规避方面的问题(美国《数字千年版权法》第 1201 条)。zahori 通过拒绝 DRM 且绝不绕过访问限制来确保安全。请继续遵守这一原则。
  • 在欧盟,文本和数据挖掘例外(DSM 指令第 3 和第 4 条)允许复制合法访问的作品,除非权利人以机器可读的方式选择退出。请尊重退出声明。

您有责任遵守所用网站的服务条款、版权规定和当地法律。如有疑问,请优先选择明确开放的内容,并咨询相关机构。

API

导出项功能
resolve(url, opts?)解析页面背后的流(配置文件或通用流程)
validate(stream, opts?)验证:这是真实媒体吗?
download(stream, path, opts?)使用 ffmpeg 录制,并重放请求头
probe(url, opts?)结构化页面盘点,用于编写配置文件
testProfile(profile, url, opts?)运行候选配置文件并对其评分
saveProfile(profile, dir) / loadProfiles()保存 / 加载配置文件
discoverProfile(url, opts?) / healProfile(profile, url, opts?)借助模型学习 / 修复
runProfile(profile, url, opts?) / runProfileOnPage(page, ...)执行配置文件(使用自有浏览器 / 您的浏览器)
hostPattern(url) / profileIdFromUrl(url)编写配置文件的辅助函数

软件包附带完整的 TypeScript 类型。

文档

完整指南位于 docs/:

贡献

欢迎提交问题和 PR。有关开发环境设置、测试套件和发布流程,请参阅 CONTRIBUTING.md。

许可证

MIT © Jose Sepulveda

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。