樱花动漫 文档
返回官网 GitHub
本站为 Kazumi 官方文档站的克隆参考站,内容整理自开源项目,仅作学习与参考;本应用规则格式完全兼容 Kazumi。

需要登录后才能观看

本文面向规则作者,讲解「搜索或观看前必须登录的站点」怎么写规则:在规则里声明 needLogin: true 与 loginURL,由 App 在搜索前引导用户在内置 WebView 完成登录,并自动托管登录 Cookie。

适用场景(先给结论)

结论

当一个站点在搜索、详情或播放前强制要求登录(未登录就跳登录页 / 返回空结果 / 直接 403),就在该规则里加上 needLogin: true 和 loginURL:App 会在搜索前先拦截,引导用户在内置 WebView 里登录一次,之后该插件的搜索、观看请求自动携带登录 Cookie。

这不只针对次元城(ciyuancheng)这一个站点——任何「不登录就用不了」的同类站点都这么配。写法完全通用,只是每个站的 loginURL 与搜索 / 选集字段要换成该站自己的。

【fork 源码】这是本应用的扩展字段

官方 Kazumi 规则模型里没有 needLogin、loginURL 这两个字段。樱花动漫 fork 在插件模型(my/lib/plugins/plugins.dart)上扩展了这两个字段,用于标记「本规则必须登录后才能搜索 / 播放」。官方文档对「需要登录」的原话是【官方原文】:

在目标网站中使用任意作品名称执行搜索,确认网站能够直接返回结果。若搜索前必须登录、完成验证码或经过复杂的人机验证,需要额外配置 Cookie 或反爬虫验证,不属于本教程的基础流程。

也就是说,官方版规则 JSON 本身不描述登录流程;是本 fork 把「登录态」做成了内置能力。下面的字段与行为均为【fork 源码】口径。

字段说明

按插件模型的 JSON 解析与序列化实现,只需在规则根级加两个字段:

JSON 键类型默认值说明
needLoginboolfalse为 true 时表示本规则需要登录验证:搜索前必须先登录,否则搜索被拦截。
loginURLstring""登录页地址。解析时兼容旧键名 loginUrl(json['loginURL'] ?? json['loginUrl'] ?? ''),序列化时统一写回 loginURL。

新旧键兼容:历史规则里若写成小写驼峰 loginUrl,App 仍能读出来;但新建或导出规则时请统一使用 loginURL(大写 URL)。

行为说明

标记 needLogin: true 后,App 按下面的流程工作(【fork 源码】,搜索拦截逻辑见 plugin_search_service.dart):

  1. 搜索拦截、不发请求:执行搜索时,若 needLogin == true 且该插件尚未保存有效 Cookie,搜索直接被拦截,不发起任何网络请求;插件状态被标记为「需要登录」。
  2. 内置 WebView 打开登录页:用户在插件页触发登录后,应用通过内置 WebView 打开 loginURL 加载登录页。
  3. 登录跳转后按插件名存 Cookie:用户在 WebView 内完成登录、页面发生跳转后,应用抓取该 WebView 中的 Cookie,并以插件名(plugin.name)为键保存;之后该插件的搜索、观看请求自动携带这些 Cookie。
  4. Cookie 过期后重新登录:Cookie 有效期由 cookieTtlDays 控制,可在规则设置中调整;过期后视同「未登录」,再次触发第 1 步拦截,需重新走 WebView 登录一次即可。
MCP 字段白名单

MCP 服务的字段白名单(mcp_server.dart)已把 needLogin、loginURL 列为「本 App 扩展字段」:通过 MCP 生成规则时,这两个字段会被正常识别,不会被当成未知字段丢弃。

真实示例:次元城(ciyuancheng)

下面是仓库里正在使用的次元城插件完整规则,逐字照抄:API 模式(api: "8"),用 searchApiConfig / chapterApiConfig 配 JSON 接口,并开启 useWebview 走真实浏览器内核。重点看根级的 needLogin、loginURL 与 icon。

{
  "api": "8",
  "type": "anime",
  "name": "ciyuancheng",
  "version": "3.0",
  "muliSources": false,
  "useWebview": true,
  "useNativePlayer": true,
  "usePost": false,
  "useLegacyParser": false,
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
  "baseURL": "https://www.cycani.org/",
  "referer": "https://www.cycani.org/",
  "searchURL": "",
  "searchList": "",
  "searchName": "",
  "searchResult": "",
  "chapterRoads": "",
  "chapterResult": "",
  "searchMode": "api",
  "chapterMode": "api",
  "searchApiConfig": {
    "request": {
      "method": "GET",
      "url": "https://www.cycani.org/api/videos/search",
      "query": {
        "q": "@keyword",
        "page": 1,
        "page_size": 24
      },
      "headers": {
        "Accept": "application/json",
        "X-App-Name": "cyc_web",
        "X-App-Version": "cycweb",
        "X-Time-Zone": "Asia/Shanghai"
      }
    },
    "listPath": "$.data.list[*]",
    "namePath": "$.title",
    "sourcePath": "$.video_id"
  },
  "chapterApiConfig": {
    "request": {
      "method": "GET",
      "url": "https://www.cycani.org/api/videos/@source/sections",
      "query": {
        "player_code": "cychub",
        "page": 1,
        "page_size": 48
      },
      "headers": {
        "Accept": "application/json",
        "X-App-Name": "cyc_web",
        "X-App-Version": "cycweb",
        "X-Time-Zone": "Asia/Shanghai"
      }
    },
    "format": "nested",
    "roadsPath": "$.data",
    "roadNamePath": "",
    "episodesPath": "$.list[*]",
    "episodeNamePath": "$.title",
    "episodeUrlPath": "",
    "episodePage": {
      "url": "/anime/@source/play/@episodeNumber?from=cychub",
      "query": {}
    }
  },
  "needLogin": true,
  "loginURL": "https://www.cycani.org/login",
  "icon": "https://www.cycani.org/favicon.ico"
}
  • 导入后先在 App 内登录再搜索:这份规则导入后第一次搜索会被拦到「需要登录」,在插件页点进去用 WebView 登录次元城账号,之后搜索、选集才正常。
  • loginURL 指向 https://www.cycani.org/login 这个独立登录页;登录跳转后 App 自动抓取 Cookie 并按插件名 ciyuancheng 保存。
  • useWebview: true:整站走真实 WebView 内核加载,和登录态、JS 渲染配合更稳。
  • API 搜索 / 选集各自带了 X-App-Name、X-App-Version 等请求头——这类头是该站接口自己要求的,不是登录字段,照抄该站即可。

通用写法:XPath 站怎么配

次元城是 API 模式的真实例子。如果你写的是普通 XPath 规则,同样只要在根级加 needLogin + loginURL,其余 XPath 字段照常规写:

{
  "api": "1",
  "type": "anime",
  "name": "示例需登录站点",
  "version": "1.0",
  "baseURL": "https://login-required.example.com/",
  "needLogin": true,
  "loginURL": "https://login-required.example.com/login",
  "searchURL": "https://login-required.example.com/search?wd=@keyword",
  "searchList": "//div[@class='search-item']",
  "searchName": "//h3/a",
  "searchResult": "//h3/a",
  "chapterRoads": "//div[@class='playlist-box']",
  "chapterResult": "//ul/li/a",
  "userAgent": "",
  "referer": "https://login-required.example.com/",
  "searchMode": "xpath",
  "chapterMode": "xpath",
  "antiCrawlerConfig": {
    "enabled": false,
    "captchaType": 1,
    "captchaImage": "",
    "captchaInput": "",
    "captchaButton": "",
    "captchaDetectType": 1,
    "captchaDetectValue": "",
    "captchaScript": ""
  }
}

给任意一个「要登录才能用」的新站写规则时,走这三步即可(不限于次元城):

  1. 实测确认登录拦截:先用浏览器 / curl 不登录直接搜索,确认确实是「未登录就跳登录页 / 空结果 / 403」,而不是验证码或别的反爬。
  2. 加上 needLogin: true + loginURL:loginURL 填该站真实登录页地址,搜索 / 选集字段仍按常规 XPath 或 API 方式写好。
  3. 提示用户在 App 内登录:在规则说明里提醒用户——导入后先在插件页用内置 WebView 登录一次,再回来搜索。

判定不清时先别急着加 needLogin:如果搜索被拦后出现的是图片验证码 / 滑块 / Cloudflare 风控而不是登录页,那是「人机验证」问题,请看 人机验证应对,不要和登录态混为一谈。

注意事项

  • 不要在规则 JSON 里硬编码账号密码:登录动作由用户在 WebView 里人工完成,规则只声明「需要登录 + 登录页地址」。Cookie 由应用托管、按插件名保存在本机,不会随规则文件泄露。
  • loginURL 可以填首页:若站点的登录入口是首页弹窗而不是独立的 /login 页,直接把 loginURL 填成首页地址也行——App 只是用 WebView 打开它,登录完成跳转后照样抓取 Cookie。
  • Cookie 有有效期,过期重登即可、不必改 JSON:过期后搜索会被重新拦回「需要登录」状态,重新打开登录页登录一次就行,不需要修改规则 JSON。TTL 天数可在规则设置里调。
  • 可与 antiCrawlerConfig 并存:一个站点完全可能既要登录、又有验证码(登录后搜索还弹验证码)。两类配置互不冲突,按需同时配置即可;反爬只作用于 XPath 搜索阶段被验证页替换的情形。
  • Cookie 是个人会话凭据:按插件名保存在本机,不要把他人导出的 Cookie 或登录态带进自己公开的规则里。

相关文档

  • 人机验证应对——搜索被拦后出现的是验证码 / 滑块 / 智能风控,而不是登录页时,按这篇处理。
  • API 规则开发——次元城这类 api: "8" JSON 接口站点的搜索 / 选集字段写法。

樱花动漫 · 基于 Flutter · 开源 GPL-3.0 · 规则格式兼容 Kazumi