上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

尝试抹平Tampermonkey的VSCode开发体验(四)

[复制链接]
  • TA的每日心情
    开心
    2023-2-28 23:59
  • 签到天数: 191 天

    [LV.7]常住居民III

    637

    主题

    5204

    回帖

    6083

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6083

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2024-4-15 00:10:54 | 显示全部楼层 | 阅读模式

    之前我们确定了如何直接通过dispatch触发更新脚本
    所以可以直接编写上传和更新的代码

    async function setTMScript(uuid = "new-user-script", scriptContent) {
      return new Promise((resolve, reject) => {
        const isCreated = uuid === "new-user-script";
        const sender = JSON.parse(fakeMessageSender);
        if (!isCreated) {
          sender.tab.url =
            "chrome-extension://ppigooooicocpkikgggonplalbnnpkfj/options.html#nav=" +
            uuid +
            "+editor";
        }
        chrome.runtime.onMessage.dispatch(
          {
            auto_save: undefined,
            clean: false,
            code: scriptContent,
            force: undefined,
            lastModTime: isCreated ? undefined : new Date().getTime(),
            method: "saveScript",
            new_script: isCreated ? true : false,
            reload: true,
            restore: undefined,
            uuid: uuid,
          },
          sender,
          (response) => {
            if (response.uuid !== undefined) {
              //成功
              resolve({ uuid: response.uuid });
            } else {
              //失败
              reject();
            }
          }
        );
      });
    }

    然后在插件中声明一个socket监听发送脚本的数据,如果接收到了脚本就设置到油猴管理器中

    var socket = io("http://<%= socketURL %>");
    async function init() {
      const scriptData = {};
      socket.on("saveScript", (name, scriptContent) => {
        console.log("saveScript", name, scriptContent);
        setTMScript(scriptData[name], scriptContent)
          .then(({ uuid }) => {
            scriptData[name] = uuid;
            socket.emit("saveScriptResult", "success", name);
          })
          .catch(() => {
            socket.emit("saveScriptResult", "failed", name);
          });
      });
    }
    init();

    目前新建脚本已经搞定了,但是修改脚本会触发tampermonkey的冲突提示
    图片.png
    这个经过调试我没有找到太好的解决办法
    但是可以利用dispatch投递消息解除掉这个弹窗

    function allowAskCom(uuid) {
      const form = {
        method: "askCom",
        data: {
          aid: uuid,
          message: undefined,
          method: "install",
        },
      };
      const sender = JSON.parse(fakeMessageSender);
       chrome.runtime.onMessage.dispatch(form, sender, (response) => {
        console.log("response", response);
      });
    }

    但是必须在tabs开启后,所以可以对tabs.create做劫持,如果检测到ask.html启动就自动跳过
    这里传入-1是因为根据调试必须给一个返回才能继续流程,而我们传入伪造的id,就会导致remove无法正常运行,所以必须也将remove劫持掉

    const tabsCreate = chrome.tabs.create;
    const tabsRemovce = chrome.tabs.remove;
    
    chrome.tabs.remove = function (id, callback, ...args) {
      if (id === -1) {
        return;
      }
      const result = tabsCreate.call(this, id, callback, ...args);
      return result;
    };
    
    chrome.tabs.create = function (obj, callback, ...args) {
      const url = obj.url;
      if (url.indexOf("ask.html?") !== -1) {
        const uuid = url.split("aid=")[1];
    
        allowAskCom(uuid);
    
        //pass hook
        callback({
          id: -1,
        });
        return undefined;
      }
      const result = tabsCreate.call(this, obj, callback, ...args);
      return result;
    };

    那我们在插件端的工作就大功搞成了,接下来只需要在本地发送脚本数据即可

        function sendScriptContent(unionName, scriptContent) {
          if (unionName === undefined) {
            console.warn(unionName + "script unionName is not define");
            return;
          }
          io.emit("saveScript", unionName, scriptContent);
        }

    其余的文件监听等等可以视为进一步的封装,我们就不继续谈了

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表