// ==UserScript== // @name B站评论AI分析 // @version 1.0 // @namespace https://cnb.cool/IIIStudio/Code/Greasemonkey/BiliInsight // @description 获取B站视频热门评论并进行AI分析 // @author IIIStudio // @match https://www.bilibili.com/video/* // @match https://bilibili.com/video/* // @match https://www.bilibili.com/v/av* // @match https://bilibili.com/v/av* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @connect api.bilibili.com // @connect * // ==/UserScript== (function() { 'use strict'; const DEFAULT_CONFIG = { api_url: "https://cloudapi.wdyu.eu.cc/v1/chat/completions", api_key: "", model: "grok-4.1-fast", system_prompt: `你是一位经验丰富的B站视频内容分析师和评论解读专家。你的任务是深入分析用户对某个哔哩哔哩视频的评论数据,并基于这些分析,客观公正地判断该视频是否值得推荐观看。 请你综合考虑以下几个维度进行分析: 1. **整体情感倾向**:评论是普遍积极、消极、中立,还是褒贬不一、情感复杂? 2. **核心讨论主题**:评论中用户主要关注和讨论的是视频的哪些方面?(例如:内容质量、剧情走向、UP主表现、剪辑效果、音效、信息准确性、产品体验、争议点等)。 3. **普遍赞扬点**:用户最常称赞的视频亮点、优点或"加分项"是什么? 4. **普遍吐槽/批评点**:用户最常抱怨、批评或认为不足的视频缺点、槽点或"减分项"是什么? 5. **B站社区文化影响**:评论中是否有B站特有的梗、黑话、二创文化、特定圈层(如:泛知识、游戏、动画、生活区等)的反馈,这些是否影响了评论的倾向或解读?是否存在"逆反心理"评论或"反向安利"现象? 6. **争议性内容**:视频或评论中是否存在引发争议、误解或需要警惕的内容? 7. **潜在受众偏好**:根据评论,该视频更适合哪类观众群体?(例如:特定粉丝、学习者、娱乐党、技术爱好者等)。 请你以以下结构输出分析结果和最终推荐: --- **【视频评论分析报告】** **【是否推荐观看】**:[是 / 否 / 谨慎推荐] **【推荐指数】**:[⭐ ⭐ ⭐ ⭐ ⭐] (请给出1到5星的评价,五星为强烈推荐) **【推荐理由/不推荐理由】**: [此处AI将综合上述分析,详细阐述给出该推荐结论的**核心理由**,包括视频的突出优点和明显的缺点/风险,以及视频可能适合或不适合的观众群体。请用150-250字总结。] **【观看前须知/建议】**: [如果选择"谨慎推荐"或视频有特定观看门槛,此处AI将提供具体建议,例如:"如果你是XXX类型的观众,可能会喜欢,但请注意YYY问题。"或者"请跳过视频的ZZZ部分以获得更好的体验。"]` }; let savedPosition = null; try { savedPosition = JSON.parse(GM_getValue('panel_position', 'null')); } catch (e) {} GM_addStyle(` .bili-comment-fetcher-wrapper { position: fixed; top: 50%; left: 20px; transform: translateY(-50%); z-index: 9999; transition: all 0.2s; } .bili-comment-fetcher-toggle { width: 50px; height: 50px; border-radius: 50%; background: #111827; cursor: pointer; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); transition: all 0.2s; border: none; padding: 0; } .bili-comment-fetcher-toggle:hover { background: #1f2937; box-shadow: 0 6px 8px -1px rgba(0, 0, 0, 0.15); } .bili-comment-fetcher-toggle svg { width: 24px; height: 24px; fill: white; } .bili-comment-fetcher { position: absolute; left: 60px; top: -10px; z-index: 9999; background: #ffffff; border: 1px solid #e5e7eb; border-radius: 4px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); padding: 12px; width: 360px; max-height: 600px; overflow-y: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; font-size: 13px; display: none; } .bili-comment-fetcher.show { display: block; } .bili-comment-fetcher.dragging { cursor: move; user-select: none; } .bili-comment-fetcher::-webkit-scrollbar { width: 4px; } .bili-comment-fetcher::-webkit-scrollbar-track { background: #f5f5f5; } .bili-comment-fetcher::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; } .bili-comment-fetcher .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid #e5e7eb; cursor: move; } .bili-comment-fetcher .header h3 { margin: 0; font-size: 14px; color: #111827; font-weight: 600; } .bili-comment-fetcher .close-btn { cursor: pointer; font-size: 16px; color: #9ca3af; line-height: 1; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; border-radius: 2px; transition: all 0.15s; } .bili-comment-fetcher .close-btn:hover { color: #374151; background: #f3f4f6; } .bili-comment-fetcher .config-btn { background-color: #f9fafb; color: #374151; border: 1px solid #e5e7eb; padding: 4px 10px; border-radius: 3px; cursor: pointer; font-size: 11px; margin-bottom: 10px; transition: all 0.15s; } .bili-comment-fetcher .config-btn:hover { background-color: #f3f4f6; border-color: #d1d5db; } .bili-comment-fetcher .config-panel { background-color: #f9fafb; border-radius: 3px; padding: 10px; margin-bottom: 10px; border: 1px solid #e5e7eb; display: none; } .bili-comment-fetcher .config-panel.show { display: block; } .bili-comment-fetcher .config-item { margin-bottom: 8px; } .bili-comment-fetcher .config-item:last-child { margin-bottom: 0; } .bili-comment-fetcher .config-item label { display: block; font-size: 11px; color: #6b7280; margin-bottom: 3px; } .bili-comment-fetcher .config-item input, .bili-comment-fetcher .config-item textarea { width: 100%; padding: 5px 7px; border: 1px solid #e5e7eb; border-radius: 3px; font-size: 12px; box-sizing: border-box; background: #ffffff; transition: border-color 0.15s; } .bili-comment-fetcher .config-item input:focus, .bili-comment-fetcher .config-item textarea:focus { outline: none; border-color: #374151; } .bili-comment-fetcher .config-item textarea { height: 50px; resize: vertical; } .bili-comment-fetcher .config-save { background-color: #111827; color: white; border: none; padding: 5px 10px; border-radius: 3px; cursor: pointer; font-size: 11px; width: 100%; margin-top: 8px; transition: background-color 0.15s; } .bili-comment-fetcher .config-save:hover { background-color: #1f2937; } .bili-comment-fetcher .button-group { display: flex; gap: 6px; margin-bottom: 10px; } .bili-comment-fetcher .analyze-btn { flex: 1; color: white; border: none; padding: 6px 0; border-radius: 3px; cursor: pointer; font-size: 12px; transition: background-color 0.15s; background-color: #111827; } .bili-comment-fetcher .analyze-btn:hover { background-color: #1f2937; } .bili-comment-fetcher .analyze-btn:disabled { background-color: #e5e7eb; color: #9ca3af; cursor: not-allowed; } .bili-comment-fetcher .loading { text-align: center; color: #9ca3af; padding: 15px; font-size: 12px; } .bili-comment-fetcher .error { color: #dc2626; text-align: center; padding: 10px; font-size: 12px; background: #fef2f2; border-radius: 3px; } .bili-comment-fetcher .analysis-result { background-color: #f9fafb; border-radius: 3px; padding: 12px; margin-top: 10px; border: 1px solid #e5e7eb; font-size: 13px; line-height: 1.6; color: #374151; } .bili-comment-fetcher .analysis-result h1, .bili-comment-fetcher .analysis-result h2, .bili-comment-fetcher .analysis-result h3, .bili-comment-fetcher .analysis-result h4 { color: #111827; margin: 12px 0 8px 0; font-weight: 600; } .bili-comment-fetcher .analysis-result h1 { font-size: 16px; } .bili-comment-fetcher .analysis-result h2 { font-size: 15px; } .bili-comment-fetcher .analysis-result h3 { font-size: 14px; } .bili-comment-fetcher .analysis-result h4 { font-size: 13px; } .bili-comment-fetcher .analysis-result p { margin: 8px 0; } .bili-comment-fetcher .analysis-result ul, .bili-comment-fetcher .analysis-result ol { margin: 8px 0; padding-left: 18px; } .bili-comment-fetcher .analysis-result li { margin: 4px 0; } .bili-comment-fetcher .analysis-result code { background: #f3f4f6; padding: 2px 4px; border-radius: 2px; font-size: 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; } .bili-comment-fetcher .analysis-result pre { background: #1f2937; color: #f9fafb; padding: 10px; border-radius: 3px; overflow-x: auto; margin: 8px 0; } .bili-comment-fetcher .analysis-result pre code { background: transparent; padding: 0; color: inherit; } .bili-comment-fetcher .analysis-result blockquote { border-left: 3px solid #e5e7eb; padding-left: 10px; margin: 8px 0; color: #6b7280; } .bili-comment-fetcher .analysis-result strong { font-weight: 600; color: #111827; } .bili-comment-fetcher .analysis-result em { font-style: italic; } .bili-comment-fetcher .analysis-result hr { border: none; border-top: 1px solid #e5e7eb; margin: 12px 0; } .bili-comment-fetcher .copy-btn { background-color: #f9fafb; border: 1px solid #e5e7eb; color: #6b7280; padding: 3px 8px; border-radius: 3px; cursor: pointer; font-size: 11px; transition: all 0.15s; } .bili-comment-fetcher .copy-btn:hover { background-color: #f3f4f6; border-color: #d1d5db; color: #374151; } `); function saveConfig(config) { GM_setValue('api_config', JSON.stringify(config)); } function loadConfig() { try { const saved = GM_getValue('api_config', '{}'); return { ...DEFAULT_CONFIG, ...JSON.parse(saved) }; } catch (e) { return DEFAULT_CONFIG; } } function savePosition(x, y) { GM_setValue('panel_position', JSON.stringify({ x, y })); } function getVideoId() { const url = window.location.href; const bvMatch = url.match(/BV\w+/); if (bvMatch) { return { type: 'bv', id: bvMatch[0] }; } const avMatch = url.match(/av(\d+)/); return { type: 'av', id: avMatch ? avMatch[1] : null }; } function bvToAv(bvid) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: `https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`, onload: (response) => { try { const data = JSON.parse(response.responseText); resolve(data.code === 0 ? data.data.aid : null); } catch (e) { reject('解析视频信息失败'); } }, onerror: () => reject('网络请求失败') }); }); } function getHotComments(aid) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: `https://api.bilibili.com/x/v2/reply?type=1&oid=${aid}&sort=2&pn=1&ps=20`, onload: (response) => { try { const data = JSON.parse(response.responseText); resolve(data.code === 0 && data.data.replies ? data.data.replies : []); } catch (e) { reject('解析评论数据失败'); } }, onerror: () => reject('网络请求失败') }); }); } function markdownToHTML(markdown) { if (!markdown) return ''; let html = markdown .replace(/&/g, '&') .replace(//g, '>') .replace(/^#### (.*$)/gm, '

$1

') .replace(/^### (.*$)/gm, '

$1

') .replace(/^## (.*$)/gm, '

$1

') .replace(/^# (.*$)/gm, '

$1

') .replace(/\*\*(.*?)\*\*/g, '$1') .replace(/__(.*?)__/g, '$1') .replace(/\*(.*?)\*/g, '$1') .replace(/_(.*?)_/g, '$1') .replace(/~~(.*?)~~/g, '$1') .replace(/```(\w*)([\s\S]*?)```/g, '
$2
') .replace(/`([^`]+)`/g, '$1') .replace(/^> (.*$)/gm, '
$1
') .replace(/^\- (.*$)/gm, '
  • $1
  • ') .replace(/^\* (.*$)/gm, '
  • $1
  • ') .replace(/^\d+\. (.*$)/gm, '
  • $1
  • ') .replace(/^---$/gm, '
    ') .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1') .replace(/\n\n/g, '

    ') .replace(/\n/g, '
    '); html = html.replace(/(

  • .*<\/li>)/g, ''); html = html.replace(/<\/ul>