使用GLM-4.6模型开发浏览器插件:实现视频滚动条自动跳到结尾功能

利用智谱AI最新推出的GLM-4.6大模型,快速开发智能浏览器插件,解决视频观看中的痛点问题。

在当今数字化时代,浏览器插件极大地增强了我们的网页浏览体验,而AI大模型的出现更是为插件开发带来了革命性的变化。本文将详细介绍如何利用GLM-4.6这一强大的AI模型,开发一个能够自动将视频滚动条跳到结尾的浏览器插件,适用于快速跳过片尾字幕或无关内容等场景。

在这里插入图片描述

GLM-4.6模型概述与技术优势

GLM-4.6是智谱AI于2025年9月推出的最新一代大语言模型,在多项关键能力上实现了显著提升。作为开发者,理解其核心优势对于构建高效的浏览器插件至关重要。

GLM-4.6的关键特性

与之前版本相比,GLM-4.6在以下几个方面表现突出:

  1. 更强大的编码能力:在真实开发工具环境中的编码与推理表现有显著提升,尤其在前端页面生成的观感质量上更为出色。
  2. 200K超长上下文:从GLM-4.5的128K扩展到200K tokens,非常适合复杂"agent工作流"和长代码库场景。
  3. 增强的Agent能力:推理时的工具调用和检索型智能体集成更加顺滑,对浏览器自动化任务尤其有用。
  4. 高效token消耗:相比GLM-4.5,token消耗进一步下降,对长会话/自动化开发更友好。

GLM-4.6与之前版本对比

特性 GLM-4.5 GLM-4.6 提升幅度
上下文长度 128K 200K 提升约56%
编码能力 更强 在真实任务集中有明显提升
工具调用 支持 原生优化 规划与执行更加结构化
前端代码质量 良好 优秀 输出结构更清晰、风格更现代
Token效率 基准 更优 消耗下降15%-30%

开发环境配置

在开始开发浏览器插件前,我们需要配置合适的开发环境,并确保能够高效使用GLM-4.6模型。

申请GLM-4.6 API访问权限

  1. 注册/登录开放平台:访问智谱开放平台或Z.AI平台,完成注册或登录。
  2. 创建API Key:进入"个人中心" → “API Keys”,点击"创建新的API Key",复制并妥善保存生成的密钥。
  3. 选择适合的套餐:根据预期使用量选择合适的套餐,对于插件开发测试阶段,可以从基础套餐开始。

配置GLM-4.6开发环境

以下是配置GLM-4.6到开发环境的详细步骤:

# 设置环境变量 - macOS/Linux
export ANTHROPIC_BASE_URL="https://open.bigmodel.cn/api/anthropic"
export ANTHROPIC_AUTH_TOKEN="你的API密钥"

# Windows PowerShell
$env:ANTHROPIC_BASE_URL = "https://open.bigmodel.cn/api/anthropic"
$env:ANTHROPIC_AUTH_TOKEN = "你的API密钥"

对于需要在代码中直接调用API的情况,可以创建以下配置类:

// glm-config.js
class GLMConfig {
  constructor() {
    this.baseURL = 'https://open.bigmodel.cn/api/anthropic';
    this.apiKey = process.env.ANTHROPIC_AUTH_TOKEN || '你的API密钥';
    this.model = 'glm-4.6';
  }

  getHeaders() {
    return {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${this.apiKey}`
    };
  }
  
  // 构建GLM-4.6请求体
  buildRequestBody(messages, max_tokens = 2048, temperature = 0.7) {
    return {
      model: this.model,
      messages: messages,
      max_tokens: max_tokens,
      temperature: temperature,
      stream: false
    };
  }
}

module.exports = GLMConfig;

浏览器插件基础架构

在深入代码实现前,我们需要设计一个稳健且可扩展的浏览器插件架构。现代浏览器插件通常由多个部分组成,每个部分都有其特定的职责。

插件核心组件设计

一个完整的浏览器插件通常包含以下组件:

  1. Manifest文件:插件的配置文件,定义元数据、权限和资源。
  2. 内容脚本(Content Scripts):注入到网页中的脚本,可以直接与DOM交互。
  3. 后台脚本(Background Scripts):长期运行的脚本,管理插件状态和事件。
  4. 用户界面:包括浏览器按钮弹出界面、选项页面等。
  5. AI集成模块:负责与GLM-4.6模型通信的模块。

插件文件结构

以下是建议的插件文件结构:

video-skip-extension/
│
├── manifest.json          # 插件清单文件
├── background/            # 后台脚本目录
│   └── background.js      # 主要后台脚本
├── content/               # 内容脚本目录
│   ├── content.js         # 主要内容脚本
│   └── video-detector.js  # 视频检测逻辑
├── popup/                 # 弹出界面目录
│   ├── popup.html         # 弹出界面HTML
│   ├── popup.css          # 弹出界面样式
│   └── popup.js           # 弹出界面逻辑
├── options/               # 选项页面目录
│   ├── options.html       # 选项页面HTML
│   ├── options.css        # 选项页面样式
│   └── options.js         # 选项页面逻辑
├── ai/                    # AI集成目录
│   └── glm-client.js      # GLM-4.6客户端
└── icons/                 # 图标目录
    ├── icon-16.png        # 16x16图标
    ├── icon-48.png        # 48x48图标
    └── icon-128.png       # 128x128图标

实现视频自动跳转功能

浏览器插件开发的核心在于内容脚本,它负责检测页面中的视频元素并实现自动跳转功能。我们将结合GLM-4.6的智能分析能力,使插件能够更精准地判断何时进行跳转。

视频检测与DOM操作

首先实现基础的内容脚本,用于检测页面中的视频元素:

// content/video-detector.js
class VideoDetector {
  constructor() {
    this.videos = [];
    this.observer = null;
    this.isEnabled = true;
    this.skipThreshold = 0.95; // 当视频播放到95%时自动跳过
    this.init();
  }

  // 初始化视频检测
  init() {
    this.detectVideos();
    this.setupMutationObserver();
    this.setupVideoListeners();
  }

  // 检测页面中现有的视频元素
  detectVideos() {
    this.videos = Array.from(document.querySelectorAll('video'));
    console.log(`检测到 ${this.videos.length} 个视频元素`);
    
    this.videos.forEach((video, index) => {
      this.setupVideoListeners(video);
    });
  }

  // 设置Mutation Observer监听DOM变化
  setupMutationObserver() {
    this.observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === 1) { // Element node
            if (node.tagName === 'VIDEO') {
              this.addVideo(node);
            } else {
              const videos = node.querySelectorAll ? node.querySelectorAll('video') : [];
              videos.forEach(video => this.addVideo(video));
            }
          }
        });
      });
    });

    this.observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // 为视频元素添加监听器
  addVideo(video) {
    if (!this.videos.includes(video)) {
      this.videos.push(video);
      this.setupVideoListeners(video);
    }
  }

  // 设置视频事件监听
  setupVideoListeners(video) {
    // 监听时间更新事件
    video.addEventListener('timeupdate', () => {
      if (!this.isEnabled) return;
      
      // 检查是否应该跳过
      if (this.shouldSkip(video)) {
        this.skipToEnd(video);
      }
    });

    // 监听视频结束事件
    video.addEventListener('ended', () => {
      console.log('视频播放结束');
    });

    // 监听视频加载的元数据
    video.addEventListener('loadedmetadata', () => {
      console.log('视频加载完成,时长:', video.duration);
    });
  }

  // 判断是否应该跳过视频
  shouldSkip(video) {
    if (!video.duration || !video.currentTime) return false;
    
    const progress = video.currentTime / video.duration;
    return progress >= this.skipThreshold && progress < 1.0;
  }

  // 跳转到视频结尾
  skipToEnd(video) {
    const previousTime = video.currentTime;
    video.currentTime = video.duration - 0.1;
    
    console.log(`视频自动跳过: ${previousTime.toFixed(2)}s -> ${video.currentTime.toFixed(2)}s`);
    
    // 发送跳转事件到后台脚本
    chrome.runtime.sendMessage({
      action: 'videoSkipped',
      url: window.location.href,
      fromTime: previousTime,
      toTime: video.currentTime
    });
  }

  // 更新跳过阈值
  setSkipThreshold(threshold) {
    this.skipThreshold = threshold;
  }

  // 启用/禁用自动跳过
  setEnabled(enabled) {
    this.isEnabled = enabled;
  }
}

// 初始化视频检测器
const detector = new VideoDetector();

集成GLM-4.6智能分析

为了更智能地判断何时跳过视频,我们可以集成GLM-4.6模型分析页面上下文,识别片头、片尾或广告部分:

// ai/glm-client.js
class GLMClient {
  constructor() {
    this.config = {
      baseURL: 'https://open.bigmodel.cn/api/anthropic',
      model: 'glm-4.6',
      maxTokens: 2048,
      temperature: 0.3
    };
  }

  // 分析视频内容并判断最佳跳过点
  async analyzeVideoContext(pageContent, videoInfo) {
    const prompt = this.buildAnalysisPrompt(pageContent, videoInfo);
    
    try {
      const response = await this.callGLMAPI(prompt);
      return this.parseResponse(response);
    } catch (error) {
      console.error('调用GLM-4.6 API失败:', error);
      return this.getFallbackSkipPoint();
    }
  }

  // 构建分析提示词
  buildAnalysisPrompt(pageContent, videoInfo) {
    return {
      messages: [
        {
          role: "user",
          content: `你是一个专业的视频内容分析助手。请分析以下网页内容和视频信息,判断视频的最佳跳过点。

网页内容摘要: ${pageContent.substring(0, 1000)}...

视频信息:
- 时长: ${videoInfo.duration} 秒
- 当前播放位置: ${videoInfo.currentTime} 秒
- 网页标题: ${videoInfo.title}

请根据以下因素分析:
1. 视频类型(教程、电影、短视频、广告等)
2. 内容结构(是否有明显的片头片尾)
3. 用户可能的观看意图

请返回JSON格式的分析结果:
{
  "videoType": "视频类型",
  "hasIntro": "是否有片头",
  "hasOutro": "是否有片尾", 
  "recommendedSkipPoint": 推荐跳过点(0-1之间的小数),
  "confidence": 置信度(0-1),
  "reasoning": "分析理由"
}`
        }
      ]
    };
  }

  // 调用GLM-4.6 API
  async callGLMAPI(prompt) {
    const response = await fetch(this.config.baseURL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.getApiKey()}`
      },
      body: JSON.stringify({
        ...this.config,
        ...prompt
      })
    });

    if (!response.ok) {
      throw new Error(`API请求失败: ${response.status}`);
    }

    return await response.json();
  }

  // 解析API响应
  parseResponse(response) {
    try {
      const content = response.choices[0].message.content;
      return JSON.parse(content);
    } catch (error) {
      console.error('解析GLM响应失败:', error);
      return this.getFallbackSkipPoint();
    }
  }

  // 获取降级方案
  getFallbackSkipPoint() {
    return {
      videoType: "unknown",
      hasIntro: false,
      hasOutro: true,
      recommendedSkipPoint: 0.95,
      confidence: 0.5,
      reasoning: "使用默认跳过点"
    };
  }

  // 获取API密钥(从存储中)
  getApiKey() {
    // 在实际应用中,应从插件的存储中获取密钥
    return new Promise((resolve) => {
      chrome.storage.sync.get(['glmApiKey'], (result) => {
        resolve(result.glmApiKey || '');
      });
    });
  }
}

插件核心实现

Manifest文件配置

Manifest文件是浏览器插件的核心配置文件,定义了插件的基本信息、权限和资源:

{
  "manifest_version": 3,
  "name": "智能视频跳过助手",
  "version": "1.0.0",
  "description": "基于GLM-4.6AI智能跳过视频无关内容,提升观看体验",
  
  "permissions": [
    "activeTab",
    "storage",
    "scripting"
  ],
  
  "host_permissions": [
    "https://open.bigmodel.cn/*"
  ],
  
  "background": {
    "service_worker": "background/background.js"
  },
  
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": [
        "content/video-detector.js",
        "content/content.js"
      ],
      "run_at": "document_idle"
    }
  ],
  
  "action": {
    "default_popup": "popup/popup.html",
    "default_title": "智能视频跳过助手"
  },
  
  "options_ui": {
    "page": "options/options.html",
    "open_in_tab": false
  },
  
  "icons": {
    "16": "icons/icon-16.png",
    "48": "icons/icon-48.png",
    "128": "icons/icon-128.png"
  },
  
  "web_accessible_resources": [
    {
      "resources": ["ai/glm-client.js"],
      "matches": ["<all_urls>"]
    }
  ]
}

后台脚本实现

后台脚本负责管理插件的状态、处理消息通信和存储数据:

// background/background.js
class BackgroundManager {
  constructor() {
    this.settings = {
      autoSkipEnabled: true,
      skipThreshold: 0.95,
      useAIAnalysis: true,
      blacklist: []
    };
    
    this.stats = {
      totalSkipped: 0,
      totalTimeSaved: 0,
      lastSkip: null
    };
    
    this.init();
  }

  async init() {
    await this.loadSettings();
    await this.loadStats();
    this.setupMessageListeners();
    this.setupContextMenus();
  }

  // 加载设置
  async loadSettings() {
    return new Promise((resolve) => {
      chrome.storage.sync.get(['settings'], (result) => {
        if (result.settings) {
          this.settings = { ...this.settings, ...result.settings };
        }
        resolve();
      });
    });
  }

  // 加载统计信息
  async loadStats() {
    return new Promise((resolve) => {
      chrome.storage.sync.get(['stats'], (result) => {
        if (result.stats) {
          this.stats = { ...this.stats, ...result.stats };
        }
        resolve();
      });
    });
  }

  // 设置消息监听器
  setupMessageListeners() {
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
      switch (request.action) {
        case 'videoSkipped':
          this.handleVideoSkipped(request, sender);
          break;
          
        case 'getSettings':
          sendResponse(this.settings);
          break;
          
        case 'updateSettings':
          this.updateSettings(request.settings);
          break;
          
        case 'getStats':
          sendResponse(this.stats);
          break;
          
        default:
          console.warn('未知的消息类型:', request.action);
      }
    });
  }

  // 处理视频跳过事件
  handleVideoSkipped(request, sender) {
    const timeSaved = request.toTime - request.fromTime;
    
    this.stats.totalSkipped++;
    this.stats.totalTimeSaved += timeSaved;
    this.stats.lastSkip = {
      url: request.url,
      time: Date.now(),
      timeSaved: timeSaved
    };
    
    // 保存更新后的统计信息
    this.saveStats();
    
    console.log(`视频跳过处理完成,节省时间: ${timeSaved.toFixed(2)}`);
  }

  // 更新设置
  updateSettings(newSettings) {
    this.settings = { ...this.settings, ...newSettings };
    
    chrome.storage.sync.set({ settings: this.settings }, () => {
      console.log('设置已更新', this.settings);
    });
    
    // 通知所有标签页设置已更新
    chrome.tabs.query({}, (tabs) => {
      tabs.forEach(tab => {
        chrome.tabs.sendMessage(tab.id, {
          action: 'settingsUpdated',
          settings: this.settings
        }).catch(() => {
          // 忽略发送到没有内容脚本的页面的错误
        });
      });
    });
  }

  // 保存统计信息
  saveStats() {
    chrome.storage.sync.set({ stats: this.stats });
  }

  // 设置右键菜单
  setupContextMenus() {
    chrome.contextMenus.create({
      id: 'toggle-auto-skip',
      title: '切换自动跳过',
      contexts: ['video']
    });
    
    chrome.contextMenus.onClicked.addListener((info, tab) => {
      if (info.menuItemId === 'toggle-auto-skip') {
        this.settings.autoSkipEnabled = !this.settings.autoSkipEnabled;
        this.updateSettings(this.settings);
        
        // 通知当前标签页
        chrome.tabs.sendMessage(tab.id, {
          action: 'settingsUpdated',
          settings: this.settings
        });
      }
    });
  }
}

// 初始化后台管理器
const backgroundManager = new BackgroundManager();

弹出界面实现

弹出界面为用户提供快速控制和反馈:

<!-- popup/popup.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body {
      width: 320px;
      padding: 16px;
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }
    .header {
      display: flex;
      align-items: center;
      margin-bottom: 16px;
    }
    .header h1 {
      margin: 0;
      font-size: 16px;
      color: #333;
    }
    .status {
      padding: 8px 12px;
      border-radius: 4px;
      margin-bottom: 12px;
      font-size: 14px;
    }
    .status.enabled {
      background-color: #e8f5e8;
      color: #2e7d32;
    }
    .status.disabled {
      background-color: #ffebee;
      color: #c62828;
    }
    .controls {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
    .control-group {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .slider-container {
      display: flex;
      align-items: center;
      gap: 8px;
    }
    .stats {
      margin-top: 16px;
      padding: 12px;
      background-color: #f5f5f5;
      border-radius: 4px;
      font-size: 12px;
    }
    .switch {
      position: relative;
      display: inline-block;
      width: 50px;
      height: 24px;
    }
    .switch input {
      opacity: 0;
      width: 0;
      height: 0;
    }
    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      transition: .4s;
      border-radius: 24px;
    }
    .slider:before {
      position: absolute;
      content: "";
      height: 16px;
      width: 16px;
      left: 4px;
      bottom: 4px;
      background-color: white;
      transition: .4s;
      border-radius: 50%;
    }
    input:checked + .slider {
      background-color: #2196F3;
    }
    input:checked + .slider:before {
      transform: translateX(26px);
    }
  </style>
</head>
<body>
  <div class="header">
    <h1>智能视频跳过助手</h1>
  </div>
  
  <div id="status" class="status">
    正在检查页面状态...
  </div>
  
  <div class="controls">
    <div class="control-group">
      <label for="autoSkip">自动跳过</label>
      <label class="switch">
        <input type="checkbox" id="autoSkip">
        <span class="slider"></span>
      </label>
    </div>
    
    <div class="control-group">
      <label for="skipThreshold">跳过阈值</label>
      <div class="slider-container">
        <span id="thresholdValue">95%</span>
        <input type="range" id="skipThreshold" min="80" max="99" value="95">
      </div>
    </div>
    
    <div class="control-group">
      <label for="useAI">AI智能分析</label>
      <label class="switch">
        <input type="checkbox" id="useAI">
        <span class="slider"></span>
      </label>
    </div>
  </div>
  
  <div class="stats">
    <div>已跳过视频: <span id="totalSkipped">0</span></div>
    <div>累计节省时间: <span id="totalTimeSaved">0</span></div>
  </div>

  <script src="popup.js"></script>
</body>
</html>
// popup/popup.js
document.addEventListener('DOMContentLoaded', async () => {
  await initPopup();
});

async function initPopup() {
  // 获取当前标签页
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  
  // 获取设置和统计信息
  const settings = await getSettings();
  const stats = await getStats();
  
  // 更新UI
  updateUI(settings, stats);
  
  // 检查当前页面状态
  checkPageStatus(tab.id);
  
  // 设置事件监听器
  setupEventListeners(tab.id);
}

// 获取设置
function getSettings() {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage({ action: 'getSettings' }, resolve);
  });
}

// 获取统计信息
function getStats() {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage({ action: 'getStats' }, resolve);
  });
}

// 更新UI
function updateUI(settings, stats) {
  // 更新开关状态
  document.getElementById('autoSkip').checked = settings.autoSkipEnabled;
  document.getElementById('useAI').checked = settings.useAIAnalysis;
  
  // 更新滑块
  const thresholdSlider = document.getElementById('skipThreshold');
  const thresholdValue = document.getElementById('thresholdValue');
  thresholdSlider.value = settings.skipThreshold * 100;
  thresholdValue.textContent = `${Math.round(settings.skipThreshold * 100)}%`;
  
  // 更新统计信息
  document.getElementById('totalSkipped').textContent = stats.totalSkipped || 0;
  document.getElementById('totalTimeSaved').textContent = Math.round(stats.totalTimeSaved || 0);
}

// 检查页面状态
function checkPageStatus(tabId) {
  chrome.tabs.sendMessage(tabId, { action: 'getStatus' }, (response) => {
    const statusElement = document.getElementById('status');
    
    if (chrome.runtime.lastError) {
      statusElement.textContent = '当前页面不支持视频跳过';
      statusElement.className = 'status disabled';
      return;
    }
    
    if (response && response.hasVideos) {
      statusElement.textContent = `已检测到 ${response.videoCount} 个视频`;
      statusElement.className = 'status enabled';
    } else {
      statusElement.textContent = '未检测到视频元素';
      statusElement.className = 'status disabled';
    }
  });
}

// 设置事件监听器
function setupEventListeners(tabId) {
  // 自动跳过开关
  document.getElementById('autoSkip').addEventListener('change', (e) => {
    updateSetting('autoSkipEnabled', e.target.checked);
  });
  
  // AI分析开关
  document.getElementById('useAI').addEventListener('change', (e) => {
    updateSetting('useAIAnalysis', e.target.checked);
  });
  
  // 跳过阈值滑块
  document.getElementById('skipThreshold').addEventListener('input', (e) => {
    const value = e.target.value;
    document.getElementById('thresholdValue').textContent = `${value}%`;
    updateSetting('skipThreshold', value / 100);
  });
}

// 更新设置
function updateSetting(key, value) {
  chrome.runtime.sendMessage({
    action: 'updateSettings',
    settings: { [key]: value }
  });
}

高级功能与优化

智能跳过策略

基于GLM-4.6的分析能力,我们可以实现更智能的跳过策略,不仅基于播放进度,还考虑内容类型和用户习惯:

// content/enhanced-video-processor.js
class EnhancedVideoProcessor {
  constructor() {
    this.glmClient = new GLMClient();
    this.videoContexts = new Map();
    this.userPreferences = {
      skipIntros: true,
      skipOutros: true,
      skipAds: true,
      skipCredits: true
    };
  }

  // 分析视频上下文
  async analyzeVideoContext(videoElement) {
    const pageContent = this.extractPageContent();
    const videoInfo = this.extractVideoInfo(videoElement);
    
    const contextKey = this.getVideoKey(videoElement);
    
    if (!this.videoContexts.has(contextKey)) {
      const analysis = await this.glmClient.analyzeVideoContext(pageContent, videoInfo);
      this.videoContexts.set(contextKey, analysis);
    }
    
    return this.videoContexts.get(contextKey);
  }

  // 提取页面内容
  extractPageContent() {
    const title = document.title;
    const description = document.querySelector('meta[name="description"]')?.content || '';
    const bodyText = document.body.innerText.substring(0, 2000);
    
    return `标题: ${title}\n描述: ${description}\n内容: ${bodyText}`;
  }

  // 提取视频信息
  extractVideoInfo(videoElement) {
    return {
      duration: videoElement.duration,
      currentTime: videoElement.currentTime,
      title: document.title,
      src: videoElement.src,
      currentSrc: videoElement.currentSrc
    };
  }

  // 生成视频唯一标识
  getVideoKey(videoElement) {
    return `${videoElement.src}-${videoElement.duration}`;
  }

  // 智能判断跳过点
  async getIntelligentSkipPoint(videoElement) {
    const context = await this.analyzeVideoContext(videoElement);
    const progress = videoElement.currentTime / videoElement.duration;
    
    // 基于AI分析调整跳过点
    let skipPoint = 0.95; // 默认值
    
    if (context.hasOutro && this.userPreferences.skipOutros) {
      skipPoint = Math.min(skipPoint, 0.90); // 对于有片尾的视频,提前跳过
    }
    
    if (context.videoType === 'tutorial' && progress > 0.85) {
      // 教程类视频在85%后可能已经是总结,可以提前结束
      skipPoint = 0.85;
    }
    
    return {
      skipPoint,
      confidence: context.confidence,
      reasoning: context.reasoning
    };
  }

  // 处理视频时间更新
  async handleTimeUpdate(videoElement) {
    const progress = videoElement.currentTime / videoElement.duration;
    
    if (progress < 0.5) return; // 前半部分不处理
    
    const { skipPoint, reasoning } = await this.getIntelligentSkipPoint(videoElement);
    
    if (progress >= skipPoint && progress < 1.0) {
      console.log(`智能跳过视频: ${reasoning}`);
      this.skipToEnd(videoElement);
    }
  }
}

性能优化与缓存策略

为了保证插件的响应速度,我们需要实现合适的缓存和性能优化策略:

// utils/cache-manager.js
class CacheManager {
  constructor() {
    this.analysisCache = new Map();
    this.settingsCache = null;
    this.cacheTimeout = 5 * 60 * 1000; // 5分钟缓存
  }

  // 缓存视频分析结果
  cacheVideoAnalysis(videoKey, analysis) {
    this.analysisCache.set(videoKey, {
      data: analysis,
      timestamp: Date.now()
    });
  }

  // 获取缓存的视频分析
  getCachedVideoAnalysis(videoKey) {
    const cached = this.analysisCache.get(videoKey);
    
    if (!cached) return null;
    
    // 检查缓存是否过期
    if (Date.now() - cached.timestamp > this.cacheTimeout) {
      this.analysisCache.delete(videoKey);
      return null;
    }
    
    return cached.data;
  }

  // 清理过期缓存
  cleanupExpiredCache() {
    const now = Date.now();
    
    for (const [key, value] of this.analysisCache.entries()) {
      if (now - value.timestamp > this.cacheTimeout) {
        this.analysisCache.delete(key);
      }
    }
  }
}

// utils/performance-monitor.js
class PerformanceMonitor {
  constructor() {
    this.metrics = {
      apiCallDuration: [],
      domProcessingTime: [],
      memoryUsage: []
    };
  }

  // 记录API调用时间
  recordAPICallDuration(duration) {
    this.metrics.apiCallDuration.push({
      duration,
      timestamp: Date.now()
    });
    
    // 保持最近100次记录
    if (this.metrics.apiCallDuration.length > 100) {
      this.metrics.apiCallDuration.shift();
    }
  }

  // 获取平均API调用时间
  getAverageAPICallDuration() {
    if (this.metrics.apiCallDuration.length === 0) return 0;
    
    const sum = this.metrics.apiCallDuration.reduce((acc, curr) => 
      acc + curr.duration, 0);
    return sum / this.metrics.apiCallDuration.length;
  }

  // 检查性能是否可接受
  isPerformanceAcceptable() {
    const avgAPIDuration = this.getAverageAPICallDuration();
    return avgAPIDuration < 2000; // 2秒内可接受
  }
}

测试与调试

单元测试与集成测试

为了保证插件质量,我们需要实现全面的测试:

// tests/video-detector.test.js
describe('VideoDetector', () => {
  let detector;
  let mockVideo;

  beforeEach(() => {
    // 创建模拟视频元素
    mockVideo = {
      duration: 100,
      currentTime: 0,
      addEventListener: jest.fn(),
      querySelectorAll: jest.fn()
    };
    
    detector = new VideoDetector();
  });

  test('应该正确检测视频元素', () => {
    document.querySelectorAll = jest.fn().mockReturnValue([mockVideo]);
    
    detector.detectVideos();
    
    expect(detector.videos.length).toBe(1);
  });

  test('应该在达到阈值时跳过视频', () => {
    mockVideo.currentTime = 96; // 96% 进度
    mockVideo.duration = 100;
    
    const shouldSkip = detector.shouldSkip(mockVideo);
    
    expect(shouldSkip).toBe(true);
  });

  test('不应该在阈值以下时跳过视频', () => {
    mockVideo.currentTime = 80; // 80% 进度
    mockVideo.duration = 100;
    
    const shouldSkip = detector.shouldSkip(mockVideo);
    
    expect(shouldSkip).toBe(false);
  });
});

// tests/glm-client.test.js
describe('GLMClient', () => {
  let glmClient;
  let mockFetch;

  beforeEach(() => {
    glmClient = new GLMClient();
    mockFetch = jest.fn();
    global.fetch = mockFetch;
  });

  test('应该正确构建API请求', async () => {
    mockFetch.mockResolvedValue({
      ok: true,
      json: () => Promise.resolve({
        choices: [{ message: { content: '{"result": "test"}' } }]
      })
    });

    const response = await glmClient.analyzeVideoContext('test content', {});
    
    expect(mockFetch).toHaveBeenCalled();
    expect(response.result).toBe('test');
  });

  test('应该在API失败时返回降级方案', async () => {
    mockFetch.mockRejectedValue(new Error('API Error'));

    const response = await glmClient.analyzeVideoContext('test content', {});
    
    expect(response.recommendedSkipPoint).toBe(0.95);
  });
});

浏览器的兼容性处理

不同浏览器对插件API的支持有所差异,需要进行兼容性处理:

// utils/compatibility.js
class CompatibilityHelper {
  static isChrome() {
    return !!chrome.runtime;
  }

  static isFirefox() {
    return typeof InstallTrigger !== 'undefined';
  }

  static isEdge() {
    return !!(window.chrome && (window.chrome.webstore || window.chrome.runtime));
  }

  // 获取兼容的API
  static getStorageAPI() {
    if (this.isFirefox()) {
      return browser.storage;
    } else {
      return chrome.storage;
    }
  }

  // 兼容的消息发送
  static sendMessage(tabId, message) {
    return new Promise((resolve, reject) => {
      const callback = (response) => {
        if (chrome.runtime.lastError) {
          reject(chrome.runtime.lastError);
        } else {
          resolve(response);
        }
      };

      if (this.isFirefox()) {
        browser.tabs.sendMessage(tabId, message).then(resolve).catch(reject);
      } else {
        chrome.tabs.sendMessage(tabId, message, callback);
      }
    });
  }
}

部署与发布

插件打包与发布

在发布插件前,需要进行代码打包和优化:

// package.json
{
  "name": "video-skip-extension",
  "version": "1.0.0",
  "description": "基于GLM-4.6的智能视频跳过浏览器插件",
  "scripts": {
    "build": "node build.js",
    "test": "jest",
    "pack": "zip -r video-skip-extension.zip dist/",
    "dev": "webpack --mode development --watch"
  },
  "devDependencies": {
    "webpack": "^5.0.0",
    "jest": "^29.0.0",
    "eslint": "^8.0.0"
  }
}
// build.js
const fs = require('fs-extra');
const path = require('path');
const { exec } = require('child_process');

async function buildExtension() {
  const distDir = path.join(__dirname, 'dist');
  
  // 清空构建目录
  await fs.emptyDir(distDir);
  
  // 复制必要文件
  const filesToCopy = [
    'manifest.json',
    'content/',
    'background/',
    'popup/',
    'options/',
    'ai/',
    'icons/',
    'utils/'
  ];
  
  for (const file of filesToCopy) {
    const src = path.join(__dirname, file);
    const dest = path.join(distDir, file);
    
    if (file.endsWith('/')) {
      await fs.copy(src, dest);
    } else {
      await fs.copy(src, dest);
    }
  }
  
  // 压缩图片
  await compressImages();
  
  console.log('扩展构建完成!');
}

buildExtension().catch(console.error);

不同浏览器商店发布指南

浏览器平台 发布地址 审核时间 特殊要求
Chrome Web Store chrome.google.com/webstore 1-7天 需要开发者注册费$5
Firefox Add-ons addons.mozilla.org 1-5天 需要代码开源审查
Edge Add-ons microsoftedge.microsoft.com/addons 3-7天 与Chrome商店类似
Opera Add-ons addons.opera.com 1-3天 基于Chromium,兼容性好

总结与展望

本文详细介绍了如何使用GLM-4.6大模型开发一个智能视频跳过浏览器插件,从环境配置、架构设计到具体实现和测试发布,涵盖了完整开发流程的关键环节。

通过本项目的实现,我们展示了GLM-4.6在以下方面的卓越表现:

  1. 强大的代码生成能力:能够快速生成高质量的前端代码和浏览器插件逻辑。
  2. 智能的内容分析:利用200K长上下文理解网页内容,做出精准的视频跳过决策。
  3. 高效的开发流程:显著减少了开发过程中的重复编码工作,提高了开发效率。

项目优化方向

未来可以考虑的优化方向包括:

  1. 个性化学习:基于用户的跳过行为训练个性化模型,更精准预测用户的跳过需求。
  2. 多模态分析:结合视觉分析,直接识别视频中的片头片尾标记。
  3. 社交功能:允许用户共享跳过点数据,构建群体智能。
  4. 跨平台支持:扩展到移动端和智能电视平台。

随着GLM系列模型的持续进化,AI辅助开发的能力边界还将不断拓展,为开发者创造更多可能性。

资源链接

通过本文的指导,您不仅可以构建一个实用的视频跳过插件,还能掌握基于GLM-4.6进行浏览器插件开发的核心方法论,为开发更复杂的AI增强型浏览器扩展奠定坚实基础。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐