{
  "schemaVersion": "1.0",
  "item": {
    "slug": "bilibili-messager",
    "name": "Bilibili Messager",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/Moroiser/bilibili-messager",
    "canonicalUrl": "https://clawhub.ai/Moroiser/bilibili-messager",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/bilibili-messager",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=bilibili-messager",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/bilibili-messager"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/bilibili-messager",
    "agentPageUrl": "https://openagent3.xyz/skills/bilibili-messager/agent",
    "manifestUrl": "https://openagent3.xyz/skills/bilibili-messager/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/bilibili-messager/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Bilibili Private Messaging",
        "body": "通过浏览器自动化发送B站私信、获取聊天记录。"
      },
      {
        "title": "⚠️ 执行模式",
        "body": "重要：连续执行所有步骤，中途不要停止！"
      },
      {
        "title": "⚠️ 减少快照",
        "body": "快照数据量大，可能导致网络超时。只在必要时获取快照：\n\n第一次：打开页面后，需要找到用户\n最后一次：发送后确认结果\n\n点击后不需要快照，直接发送消息！"
      },
      {
        "title": "前置条件",
        "body": "用户需要在浏览器中已登录 B站账号\n需要知道目标用户的用户名（支持部分匹配）"
      },
      {
        "title": "步骤 1：打开页面",
        "body": "browser action=open targetUrl=https://message.bilibili.com/#/whisper"
      },
      {
        "title": "步骤 2：获取快照，找到用户",
        "body": "browser action=snapshot\n\n在快照中找到目标用户（按用户名部分匹配），记录 ref。"
      },
      {
        "title": "步骤 3：点击进入对话",
        "body": "browser action=act request={\"kind\": \"click\", \"ref\": \"<用户ref>\"}"
      },
      {
        "title": "步骤 4：直接发送消息（不要获取快照！）",
        "body": "点击后立即用 JavaScript 发送，不要再获取快照：\n\n() => {\n  const inputArea = document.querySelector('[contenteditable=\"true\"]');\n  if (inputArea) {\n    inputArea.textContent = '消息内容';\n    inputArea.dispatchEvent(new InputEvent('input', { bubbles: true }));\n    const sendBtn = document.evaluate(\n      \"//div[contains(text(), '发送')]\", \n      document, \n      null, \n      XPathResult.FIRST_ORDERED_NODE_TYPE, \n      null\n    ).singleNodeValue;\n    if (sendBtn) sendBtn.click();\n    return 'Message sent';\n  }\n  return 'Input not found';\n}"
      },
      {
        "title": "步骤 5：获取快照确认发送成功",
        "body": "browser action=snapshot\n\n确认消息已出现在聊天记录中，然后向用户报告结果。"
      },
      {
        "title": "⚠️ 重要：确定发送方的方法",
        "body": "B站私信的 DOM class 哈希值（如 _MsgIsMe_o7f0t_9）可能因用户/会话不同而变化，不能硬编码！\n\n推荐方法：通过头像位置判断\n\n先获取快照或截图，观察消息布局\n左侧头像 = 对方发送的消息\n右侧头像 = 自己发送的消息"
      },
      {
        "title": "通过头像位置提取聊天记录",
        "body": "() => {\n  const main = document.querySelector('main');\n  if (!main) return 'No main';\n\n  const msgBlocks = main.querySelectorAll('[class*=\"_Msg_\"]');\n  const messages = [];\n\n  msgBlocks.forEach(block => {\n    const text = block.textContent.trim();\n    \n    // 提取日期\n    const dateMatch = text.match(/(202[56]年\\d+月\\d+日 \\d+:\\d+|今天 \\d+:\\d+)/);\n    \n    if (dateMatch) {\n      const date = dateMatch[1];\n      let content = text.replace(dateMatch[0], '').trim();\n      content = content.replace(/^(\\d+:\\d+)?/, '').trim();\n      \n      if (content && content.length > 1) {\n        // 通过头像位置判断发送方\n        const img = block.querySelector('img');\n        let sender = '对方'; // 默认\n        \n        if (img) {\n          const imgRect = img.getBoundingClientRect();\n          const blockRect = block.getBoundingClientRect();\n          // 如果头像在右侧，是自己发送的\n          if (imgRect.left > blockRect.left + blockRect.width / 2) {\n            sender = '自己';\n          }\n        }\n        \n        messages.push({\n          date,\n          sender,\n          content: content.substring(0, 200)\n        });\n      }\n    }\n  });\n\n  // 去重\n  const seen = new Set();\n  return messages.filter(msg => {\n    const key = msg.date + msg.content.substring(0, 50);\n    if (seen.has(key)) return false;\n    seen.add(key);\n    return true;\n  });\n}"
      },
      {
        "title": "备用方法：通过 class 名称包含 \"Me\" 判断",
        "body": "如果 class 名称包含 \"Me\" 或 \"Self\" 等关键词，可以辅助判断：\n\nconst className = block.className;\nconst isMe = className.toLowerCase().includes('me') || \n             className.toLowerCase().includes('self');\n\n但要注意： 哈希值部分可能变化，不要依赖完整的 class 名！"
      },
      {
        "title": "滚动加载历史记录",
        "body": "B站私信使用懒加载，需要滚动才能加载更早的记录：\n\n() => {\n  // 查找滚动容器（通过 overflow 样式）\n  const allElements = document.querySelectorAll('*');\n  for (const el of allElements) {\n    const style = window.getComputedStyle(el);\n    if ((style.overflow === 'auto' || style.overflowY === 'auto') && \n        el.scrollHeight > el.clientHeight &&\n        el.closest('main')) {\n      el.scrollTop = 0;\n      return 'Scrolled container: ' + el.className;\n    }\n  }\n  return 'No scroll container found';\n}\n\n滚动后等待 1-2 秒让内容加载，再获取快照或提取消息。"
      },
      {
        "title": "注意事项",
        "body": "消息长度限制：500字符（超过需分段发送）\n发送频率有限制，避免刷屏\n如果找不到用户，先向用户确认用户名是否正确\n获取历史记录时可能需要多次滚动触发懒加载\n不要硬编码 DOM class 的哈希值，它们可能变化！用头像位置或关键词判断更可靠"
      }
    ],
    "body": "Bilibili Private Messaging\n\n通过浏览器自动化发送B站私信、获取聊天记录。\n\n⚠️ 执行模式\n\n重要：连续执行所有步骤，中途不要停止！\n\n⚠️ 减少快照\n\n快照数据量大，可能导致网络超时。只在必要时获取快照：\n\n第一次：打开页面后，需要找到用户\n最后一次：发送后确认结果\n\n点击后不需要快照，直接发送消息！\n\n前置条件\n用户需要在浏览器中已登录 B站账号\n需要知道目标用户的用户名（支持部分匹配）\n发送私信流程\n步骤 1：打开页面\nbrowser action=open targetUrl=https://message.bilibili.com/#/whisper\n\n步骤 2：获取快照，找到用户\nbrowser action=snapshot\n\n\n在快照中找到目标用户（按用户名部分匹配），记录 ref。\n\n步骤 3：点击进入对话\nbrowser action=act request={\"kind\": \"click\", \"ref\": \"<用户ref>\"}\n\n步骤 4：直接发送消息（不要获取快照！）\n\n点击后立即用 JavaScript 发送，不要再获取快照：\n\n() => {\n  const inputArea = document.querySelector('[contenteditable=\"true\"]');\n  if (inputArea) {\n    inputArea.textContent = '消息内容';\n    inputArea.dispatchEvent(new InputEvent('input', { bubbles: true }));\n    const sendBtn = document.evaluate(\n      \"//div[contains(text(), '发送')]\", \n      document, \n      null, \n      XPathResult.FIRST_ORDERED_NODE_TYPE, \n      null\n    ).singleNodeValue;\n    if (sendBtn) sendBtn.click();\n    return 'Message sent';\n  }\n  return 'Input not found';\n}\n\n步骤 5：获取快照确认发送成功\nbrowser action=snapshot\n\n\n确认消息已出现在聊天记录中，然后向用户报告结果。\n\n获取聊天记录\n⚠️ 重要：确定发送方的方法\n\nB站私信的 DOM class 哈希值（如 _MsgIsMe_o7f0t_9）可能因用户/会话不同而变化，不能硬编码！\n\n推荐方法：通过头像位置判断\n\n先获取快照或截图，观察消息布局\n左侧头像 = 对方发送的消息\n右侧头像 = 自己发送的消息\n通过头像位置提取聊天记录\n() => {\n  const main = document.querySelector('main');\n  if (!main) return 'No main';\n\n  const msgBlocks = main.querySelectorAll('[class*=\"_Msg_\"]');\n  const messages = [];\n\n  msgBlocks.forEach(block => {\n    const text = block.textContent.trim();\n    \n    // 提取日期\n    const dateMatch = text.match(/(202[56]年\\d+月\\d+日 \\d+:\\d+|今天 \\d+:\\d+)/);\n    \n    if (dateMatch) {\n      const date = dateMatch[1];\n      let content = text.replace(dateMatch[0], '').trim();\n      content = content.replace(/^(\\d+:\\d+)?/, '').trim();\n      \n      if (content && content.length > 1) {\n        // 通过头像位置判断发送方\n        const img = block.querySelector('img');\n        let sender = '对方'; // 默认\n        \n        if (img) {\n          const imgRect = img.getBoundingClientRect();\n          const blockRect = block.getBoundingClientRect();\n          // 如果头像在右侧，是自己发送的\n          if (imgRect.left > blockRect.left + blockRect.width / 2) {\n            sender = '自己';\n          }\n        }\n        \n        messages.push({\n          date,\n          sender,\n          content: content.substring(0, 200)\n        });\n      }\n    }\n  });\n\n  // 去重\n  const seen = new Set();\n  return messages.filter(msg => {\n    const key = msg.date + msg.content.substring(0, 50);\n    if (seen.has(key)) return false;\n    seen.add(key);\n    return true;\n  });\n}\n\n备用方法：通过 class 名称包含 \"Me\" 判断\n\n如果 class 名称包含 \"Me\" 或 \"Self\" 等关键词，可以辅助判断：\n\nconst className = block.className;\nconst isMe = className.toLowerCase().includes('me') || \n             className.toLowerCase().includes('self');\n\n\n但要注意： 哈希值部分可能变化，不要依赖完整的 class 名！\n\n滚动加载历史记录\n\nB站私信使用懒加载，需要滚动才能加载更早的记录：\n\n() => {\n  // 查找滚动容器（通过 overflow 样式）\n  const allElements = document.querySelectorAll('*');\n  for (const el of allElements) {\n    const style = window.getComputedStyle(el);\n    if ((style.overflow === 'auto' || style.overflowY === 'auto') && \n        el.scrollHeight > el.clientHeight &&\n        el.closest('main')) {\n      el.scrollTop = 0;\n      return 'Scrolled container: ' + el.className;\n    }\n  }\n  return 'No scroll container found';\n}\n\n\n滚动后等待 1-2 秒让内容加载，再获取快照或提取消息。\n\n注意事项\n消息长度限制：500字符（超过需分段发送）\n发送频率有限制，避免刷屏\n如果找不到用户，先向用户确认用户名是否正确\n获取历史记录时可能需要多次滚动触发懒加载\n不要硬编码 DOM class 的哈希值，它们可能变化！用头像位置或关键词判断更可靠"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Moroiser/bilibili-messager",
    "publisherUrl": "https://clawhub.ai/Moroiser/bilibili-messager",
    "owner": "Moroiser",
    "version": "1.3.2",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/bilibili-messager",
    "downloadUrl": "https://openagent3.xyz/downloads/bilibili-messager",
    "agentUrl": "https://openagent3.xyz/skills/bilibili-messager/agent",
    "manifestUrl": "https://openagent3.xyz/skills/bilibili-messager/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/bilibili-messager/agent.md"
  }
}