You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AutoHotkey 2与Tampermonkey脚本本地通信及CORS问题求解

解决方案

方案1:用Tampermonkey特权API绕过CORS

Tampermonkey自带不受浏览器CORS限制的网络请求API,完全避开前端同源策略限制,适合快速实现需求。

1.1 轮询方案(简单易实现)

Tampermonkey脚本部分:

// ==UserScript==
// @name         视频控制-本地命令轮询
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  轮询本地服务获取视频控制命令
// @author       You
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';

    const POLL_INTERVAL = 500; // 轮询间隔(毫秒)

    function pollCommand() {
        GM_xmlhttpRequest({
            method: "GET",
            url: "http://localhost:3000/get-command",
            onload: function(response) {
                if (response.status === 200) {
                    const command = response.responseText.trim();
                    if (command) {
                        executeVideoCommand(command);
                        // 执行后清除服务端命令
                        GM_xmlhttpRequest({method: "POST", url: "http://localhost:3000/clear-command"});
                    }
                }
                setTimeout(pollCommand, POLL_INTERVAL);
            },
            onerror: function() {
                setTimeout(pollCommand, POLL_INTERVAL);
            }
        });
    }

    function executeVideoCommand(cmd) {
        const videos = document.querySelectorAll('video');
        if (videos.length === 0) return;

        switch(cmd) {
            case 'play':
                videos.forEach(v => v.play());
                break;
            case 'pause':
                videos.forEach(v => v.pause());
                break;
            case 'forward':
                videos.forEach(v => v.currentTime += 5); // 快进5秒
                break;
            case 'backward':
                videos.forEach(v => v.currentTime -= 5); // 快退5秒
                break;
            case 'speed-up':
                videos.forEach(v => v.playbackRate = Math.min(v.playbackRate + 0.5, 4)); // 最大4倍速
                break;
            case 'speed-down':
                videos.forEach(v => v.playbackRate = Math.max(v.playbackRate - 0.5, 0.25)); // 最小0.25倍速
                break;
        }
    }

    pollCommand();
})();

本地Express服务(配合AHK调用):

const express = require('express');
const app = express();
let currentCommand = '';

// 允许AHK无限制调用
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    next();
});

// 获取当前命令
app.get('/get-command', (req, res) => {
    res.send(currentCommand);
});

// 设置命令(AHK调用此接口)
app.post('/set-command', express.text(), (req, res) => {
    currentCommand = req.body;
    res.send('ok');
});

// 清除命令
app.post('/clear-command', (req, res) => {
    currentCommand = '';
    res.send('ok');
});

app.listen(3000, () => {
    console.log('本地命令服务运行在 http://localhost:3000');
});

AHK2脚本(StreamDeck触发函数):

; 发送命令到本地服务
SendVideoCommand(cmd) {
    HttpRequest := ComObject("WinHttp.WinHttpRequest.5.1")
    HttpRequest.Open("POST", "http://localhost:3000/set-command")
    HttpRequest.SetRequestHeader("Content-Type", "text/plain")
    HttpRequest.Send(cmd)
}

; StreamDeck绑定的函数示例
PlayVideo() {
    SendVideoCommand("play")
}

PauseVideo() {
    SendVideoCommand("pause")
}

ForwardVideo() {
    SendVideoCommand("forward")
}

1.2 WebSocket实时方案(低延迟)

如果需要实时响应,用Tampermonkey的GM_webSocket:

Tampermonkey脚本部分:

// ==UserScript==
// @name         视频控制-WebSocket实时通信
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  通过WebSocket接收本地视频控制命令
// @author       You
// @match        *://*/*
// @grant        GM_webSocket
// ==/UserScript==

(function() {
    'use strict';

    const ws = GM_webSocket("ws://localhost:3001");

    ws.onopen = function() {
        console.log('WebSocket连接成功');
    };

    ws.onmessage = function(event) {
        const command = event.data.trim();
        executeVideoCommand(command);
    };

    ws.onerror = function() {
        console.log('WebSocket连接错误,3秒后重连');
        setTimeout(() => window.location.reload(), 3000);
    };

    function executeVideoCommand(cmd) {
        // 同轮询方案的executeVideoCommand函数
        const videos = document.querySelectorAll('video');
        if (videos.length === 0) return;

        switch(cmd) {
            case 'play':
                videos.forEach(v => v.play());
                break;
            case 'pause':
                videos.forEach(v => v.pause());
                break;
            case 'forward':
                videos.forEach(v => v.currentTime += 5);
                break;
            case 'backward':
                videos.forEach(v => v.currentTime -= 5);
                break;
            case 'speed-up':
                videos.forEach(v => v.playbackRate = Math.min(v.playbackRate + 0.5, 4));
                break;
            case 'speed-down':
                videos.forEach(v => v.playbackRate = Math.max(v.playbackRate - 0.5, 0.25));
                break;
        }
    }
})();

WebSocket服务(Node.js):

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3001 });

let clients = [];

wss.on('connection', (ws) => {
    clients.push(ws);
    ws.on('close', () => {
        clients = clients.filter(client => client !== ws);
    });
});

// 提供HTTP接口给AHK发送命令
const express = require('express');
const app = express();
app.use(express.text());

app.post('/send-command', (req, res) => {
    const cmd = req.body;
    clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(cmd);
        }
    });
    res.send('ok');
});

app.listen(3002, () => {
    console.log('命令转发服务运行在 http://localhost:3002');
});

AHK2调用脚本:

SendVideoCommand(cmd) {
    HttpRequest := ComObject("WinHttp.WinHttpRequest.5.1")
    HttpRequest.Open("POST", "http://localhost:3002/send-command")
    HttpRequest.SetRequestHeader("Content-Type", "text/plain")
    HttpRequest.Send(cmd)
}

方案2:AHK直接操控Chrome视频(无需Web服务)

跳过Web通信,用Chrome远程调试协议直接控制标签页,效率更高:

步骤1:开启Chrome远程调试

右键Chrome快捷方式,在目标后添加参数: --remote-debugging-port=9222,示例:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222

步骤2:AHK2脚本

; 获取Chrome活动标签页的调试地址
GetChromeDebugUrl() {
    HttpRequest := ComObject("WinHttp.WinHttpRequest.5.1")
    HttpRequest.Open("GET", "http://localhost:9222/json")
    HttpRequest.Send()
    Tabs := HttpRequest.ResponseText.Parse()
    for _, Tab in Tabs {
        if Tab.type = "page" && Tab.active {
            return Tab.webSocketDebuggerUrl
        }
    }
    return ""
}

; 直接发送视频控制命令到Chrome
ControlChromeVideo(cmd) {
    DebugUrl := GetChromeDebugUrl()
    if DebugUrl = "" {
        MsgBox "未找到活动Chrome标签页"
        return
    }

    Ws := ComObject("WebSocket")
    Ws.Connect(DebugUrl)
    if !Ws.ReadyState = 1 {
        MsgBox "无法连接Chrome调试端口"
        return
    }

    ; 生成调试协议命令
    CmdId := Random(1, 9999)
    Command := {
        id: CmdId,
        method: "Runtime.evaluate",
        params: {
            expression: "(() => {const videos = document.querySelectorAll('video'); if(videos.length ===0) return; switch('" cmd "'){case 'play': videos.forEach(v=>v.play()); break; case 'pause': videos.forEach(v=>v.pause()); break; case 'forward': videos.forEach(v=>v.currentTime+=5); break; case 'backward': videos.forEach(v=>v.currentTime-=5); break; case 'speed-up': videos.forEach(v=>v.playbackRate=Math.min(v.playbackRate+0.5,4)); break; case 'speed-down': videos.forEach(v=>v.playbackRate=Math.max(v.playbackRate-0.5,0.25)); break;}})()"
        }
    }

    Ws.Send(Command.Stringify())
    Ws.Close()
}

; StreamDeck绑定的函数示例
PlayVideo() {
    ControlChromeVideo("play")
}

PauseVideo() {
    ControlChromeVideo("pause")
}

ForwardVideo() {
    ControlChromeVideo("forward")
}

方案3:修改本地服务CORS配置(不推荐)

如果坚持用原生fetch/XHR,可在Express服务中添加CORS规则允许Tampermonkey来源:

const cors = require('cors');
app.use(cors({
    origin: function(origin, callback) {
        if (!origin || origin.includes('tampermonkey.net')) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    }
}));

此方案需适配不同网站的origin,不如Tampermonkey特权API省心。


内容的提问来源于stack exchange,提问作者FlexXx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:32:07