将Firefox插件导入Edge/Chrome中

目录

将Firefox插件导入Edge/Chrome中

前言

因为博主本人想在edge/chrome中使用cph-submit插件

  • vscode中cph,实现一键将代码提交到Codeforces
  • 但是只有firefox的插件
  • 另外两个比较麻烦,nodejs还有版本问题。

写这篇文章有三个原因:

  1. 网上暂且没找到firefox插件导入edge/chrome的方法

  2. 博主个人感觉这个debug过程比较有意义

  3. 也希望能帮助到其他人。

省流:最终可用的版本如下 ,直接下载解压开发人员模式导入edge插件即可:

导出火狐插件.xpi格式

在火狐浏览器中打开这个about:profiles,就可以看到了

  • 这就是你当前浏览器用户的存储文件夹

然后点击打开文件夹

点击extensions,进去就可以看到你安装的插件的.xpi格式,这边我只安装了一个(名为cph-submit)。

但是其实你可以通过修改时间 来判断哪个是哪个(大不了卸掉再装一下,最新的那个)

  • 一般也就一两个

然后把这个文件复制出来,找个空的目录放一下,我将它重命名为cph-submit.xpi

右键解压到文件夹(我用的360解压软件)

  • 这一步如果没法完成,你可以修改后缀名为.zip
  • 然后再解压,效果一样

因为解压完的文件夹不一定直接用

  • 有些 Firefox 扩展可能需要进行一些代码修改才能在 Edge/Chrome 上运行,
  • 需要修改 manifest.json 文件以符合 Edge/Chrome 的格式。

插件导入edge/chorme中

随后在edge/chrome浏览器中,打开开发人员模式

  • 进入edge://extensions/

然后就会出现这些按钮

如果修改好了最终的插件版本,就可以点击从"加载解压缩的扩展"

随后应该就可以用了,可以跳转到"完工阶段"查看效果

下面是错误示范 ,以及修改过程

错误示范1

不能用.crx格式导入

  • 不要将刚解压的文件夹的路径 打包成为.crx格式,
  • 大概率会G掉

如下所示

选择解压后的路径

随后就可以看到

不过.crx才是我们要用的,.pem不需要

.crx直接拖进浏览器中,点击添加拓展

启动按键是灰色的,这是错误示范,所以不能这样

直接用解压好的就没下面这个问题

错误示范2

如果你修改的,有问题

  • 第一种情况,初始化的时候就有问题,那么一导入就是挂的
  • 第二种情况,运行到一半,用到才有问题

会先正常显示,然后在挂掉(错误/重新加载两个一开始不显示)

此时你其实可以点进去错误,查看哪里错了,然后修改

当然,一般修改工作量也挺大的

可以交给GPT来改


这些错误是可以展开的,直到报错后针对性修改

(无关紧要的)提醒:

要是你不知道firefox和edge他们的manifest.json的差别,其实你可以本地找一下edge拓展的源文件,然后对比下

当然,我都喂给了GPT,让他帮忙修改

C:\Users\<你的电脑用户名>\AppData\Local\Microsoft\Edge\User Data\Default\Extensions

有问题的话,得删除插件

然后再从文件夹导入这个插件

修改过程

manifest.json

点进文件夹,查看manifest.json如下

json 复制代码
{
  "name": "CPH Submit",
  "manifest_version": 2,
  "homepage_url": "https://github.com/agrawal-d/cph-submit",
  "version": "1.6.0",
  "description": "Codeforces Submit add-on for Competitive Programming Helper.",
  "background": {
    "scripts": ["dist/backgroundScript.js"]
  },
  "permissions": ["*://localhost/*", "*://codeforces.com/*", "webNavigation"],
  "icons": {
    "48": "icon-48.png"
  },
  "browser_specific_settings": {
    "gecko": {
      "id": "{5dd8fd6e-0733-41a7-abc4-e19fba703de9}",
      "strict_min_version": "49.0"
    }
  }
}

我将其修改为:

  • manifest_version :
    • 2 改为 3
  • background :
    • scripts 改为 service_worker,并增加 "type": "module"
  • action :
    • 添加 action 部分,用于定义插件的图标和默认标题。
  • host_permissions :
    • 添加 host_permissionsoptional_host_permissions 来管理插件的权限。
  • 删除key字段 :
    • 不再包含key字段,因为这是开发中的插件,不是发布到商店的版本。
  • permissions :
    • 保留 activeTabwebNavigationscripting 权限。
  • host_permissions :
    • 使用 host_permissions 来指定对 localhostcodeforces.com 的访问权限。
  • 删除 optional_host_permissions :
    • 移除 optional_host_permissions 字段,因为它包含的权限已经在 host_permissions 中。
json 复制代码
{
  "name": "CPH Submit",
  "manifest_version": 3,
  "homepage_url": "https://github.com/agrawal-d/cph-submit",
  "version": "1.6.0",
  "description": "Codeforces Submit add-on for Competitive Programming Helper.",
  "background": {
    "service_worker": "dist/backgroundScript.js",
    "type": "module"
  },
  "permissions": ["activeTab", "webNavigation", "scripting"],
  "icons": {
    "48": "icon-48.png"
  },
  "action": {
    "default_icon": {
      "48": "icon-48.png"
    },
    "default_title": "CPH Submit"
  },
  "host_permissions": ["*://localhost/*", "*://codeforces.com/*"]
}

dict文件夹修改

还需要修改解压文件夹中的dictbackgroundScript.jsinjectedScript.js

  • 并不能从火狐直接移植到chrome/edge
  • 里面的browser API 需要修改为chrome API
    • **Edge浏览器现在基于Chromium,所以使用与Chrome相同的API。**二者可以共享,但是与火狐不行
    • 因此,只需要将代码中的 browser 替换为 chrome,并使用 chrome.scripting.executeScript 来代替 browser.tabs.executeScript
  • 需要修改的地方可能还有
    • browser 替换为 chrome :所有 browser API 调用替换为 chrome
      • browser.tabs.create 修改为 chrome.tabs.create
      • browser.windows.update 修改为 chrome.windows.update
      • 使用 chrome.scripting.executeScript 代替 browser.tabs.executeScript
      • browser.tabs.sendMessage 修改为 chrome.tabs.sendMessage
backgroundScript.js

backgroundScript.js 是浏览器扩展的背景脚本,负责处理一些全局的后台任务,例如:

  1. 后台逻辑:处理定时任务、全局事件监听器等。
  2. 与服务器通信:从服务器获取数据,处理服务器响应。
  3. 管理浏览器标签页:创建、更新或关闭标签页。
  4. 在不同页面间传递消息 :与内容脚本(如 injectedScript.js)进行通信。

在该扩展中,backgroundScript.js 主要负责从服务器获取提交信息,并在相应的 Codeforces 页面中自动提交代码。

代码在"最终backgroundScript.js和injectedScript.js代码"(

injectedScript.js

injectedScript.js 是注入到目标网页中的脚本,负责与网页内容进行交互,例如:

  1. 操作网页的 DOM:读取和修改网页中的元素,例如表单字段。
  2. 接收消息并执行操作:从背景脚本接收消息,并根据消息内容执行相应的操作。
  3. 模拟用户行为:自动填写表单、点击按钮等。

在该扩展中,injectedScript.js 主要负责在 Codeforces 提交页面上自动填写表单,并模拟用户点击提交按钮。

代码在"最终backgroundScript.js和injectedScript.js代码"(

debug过程

个人修改的debug过程

  • 解压文件夹中的dictbackgroundScript.jsinjectedScript.js

先将其改为最简单的.js,确保backgroundScript.js导入没问题

console.log('Service worker registered successfully');

监听下控制台

看起来可以导入

逐渐加入代码

最终backgroundScript.js和injectedScript.js代码

最后backgroundScript.js修改结果如下

js 复制代码
const config = {
  cphServerEndpoint: new URL("http://localhost:27121/getSubmit"),
  cfSubmitPage: new URL("https://codeforces.com/problemset/submit"),
  loopTimeOut: 3000,
  debug: false
};

const log = (...args) => {
  if (config.debug) {
    console.log(...args);
  }
};

const isContestProblem = (problemUrl) => {
  return problemUrl.indexOf("contest") !== -1;
};

const getSubmitUrl = (problemUrl) => {
  if (!isContestProblem(problemUrl)) {
    return config.cfSubmitPage.href;
  }
  const url = new URL(problemUrl);
  const contestNumber = url.pathname.split("/")[2];
  const submitURL = `https://codeforces.com/contest/${contestNumber}/submit`;
  return submitURL;
};

const handleSubmit = async (problemName, languageId, sourceCode, problemUrl) => {
  if (problemName === "" || languageId === -1 || sourceCode === "") {
    log("Invalid arguments to handleSubmit");
    return;
  }

  log("isContestProblem", isContestProblem(problemUrl));

  chrome.tabs.create({ active: true, url: getSubmitUrl(problemUrl) }, (tab) => {
    chrome.windows.update(tab.windowId, { focused: true });

    if (tab.id === undefined) {
      log("No tab id to send message to", tab);
      return;
    }

    chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo) {
      if (tabId === tab.id && changeInfo.status === 'complete') {
        chrome.tabs.onUpdated.removeListener(listener);

        chrome.scripting.executeScript({
          target: { tabId: tab.id },
          files: ["/dist/injectedScript.js"]
        }, () => {
          chrome.tabs.sendMessage(tab.id, {
            type: "cph-submit",
            problemName,
            languageId,
            sourceCode,
            url: problemUrl,
          }, () => {
            if (chrome.runtime.lastError) {
              console.error("Error sending message:", chrome.runtime.lastError);
            } else {
              log("Message sent to tab with script");
            }
          });
        });
      }
    });
  });
};

const mainLoop = async () => {
  let cphResponse;
  try {
    const headers = new Headers();
    headers.append("cph-submit", "true");

    const request = new Request(config.cphServerEndpoint.href, {
      method: "GET",
      headers,
    });

    cphResponse = await fetch(request);
  } catch (err) {
    log("Error while fetching cph response", err);
    return;
  }

  if (!cphResponse.ok) {
    log("Error while fetching cph response", cphResponse);
    return;
  }

  const response = await cphResponse.json();

  if (response.empty) {
    log("Got empty valid response from CPH");
    return;
  }

  log("Got non-empty valid response from CPH");
  handleSubmit(response.problemName, response.languageId, response.sourceCode, response.url);
};

setInterval(mainLoop, config.loopTimeOut);

console.log('Service worker registered successfully');

以及injectedScript.js修改结果如下

js 复制代码
console.log("cph-submit script injected");

const isContestProblem = (problemUrl) => {
  return problemUrl.indexOf("contest") !== -1;
};

const handleData = (data) => {
  console.log("Handling submit message");
  const languageEl = document.getElementsByName("programTypeId")[0];
  const sourceCodeEl = document.getElementById("sourceCodeTextarea");

  sourceCodeEl.value = data.sourceCode;
  languageEl.value = data.languageId.toString();

  if (!isContestProblem(data.url)) {
    const problemNameEl = document.getElementsByName("submittedProblemCode")[0];
    problemNameEl.value = data.problemName;
  } else {
    const problemIndexEl = document.getElementsByName("submittedProblemIndex")[0];
    let problemName = data.url.split("/problem/")[1];

    if (problemName == "0") {
      problemName = "A";
    }
    problemIndexEl.value = problemName;
  }

  console.log("Submitting problem");
  const submitBtn = document.querySelector(".submit");
  submitBtn.disabled = false;
  submitBtn.click();
};

console.log("Adding event listener");

chrome.runtime.onMessage.addListener((data, sender) => {
  console.log("Got message", data, sender);
  if (data.type === "cph-submit") {
    handleData(data);
  }
});

完工阶段

点击competitive Companion,将样例一键导入vscode中

随后,在右侧编写代码

然后点击Submit提交代码

就成功在edge上,先自动跳转到提交界面,然后自动填写代码,提交表单

最后自动跳转到这个界面,提交成功

修改后的源码

上面其实也可以复制下来

我整理了可以直接用的版本

https://wwf.lanzout.com/iJ3Gl21r9vja

蓝奏云盘下载

相关推荐
anyup_前端梦工厂3 小时前
从浏览器层面看前端性能:了解 Chrome 组件、多进程与多线程
前端·chrome
chengpei1473 小时前
chrome游览器JSON Formatter插件无效问题排查,FastJsonHttpMessageConverter导致Content-Type返回不正确
java·前端·chrome·spring boot·json
奇舞精选8 小时前
在 Chrome 浏览器里获取用户真实硬件信息的方法
前端·chrome
易林示9 小时前
chrome小插件:长图片等分切割
前端·chrome
P7进阶路19 小时前
Tomcat异常日志中文乱码怎么解决
java·tomcat·firefox
lee57621 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
dfh00l1 天前
firefox屏蔽debugger()
前端·firefox
hunter2062062 天前
ubuntu终端当一段时间内没有程序运行时,自动关闭终端。
linux·chrome·ubuntu
梦魇梦狸º2 天前
mac 配置 python 环境变量
chrome·python·macos
守城小轩2 天前
Chromium 132 编译指南 Mac 篇(四)- 获取源代码
chrome·chrome devtools·指纹浏览器·浏览器开发