我的第一个浏览器插件网页一键上传的开发历史

前言

一键上传选中的网页内容,实现知识快速收藏。如飞书剪存,有道云剪报,MrDoc速记。早在2008年,我参考了有道云一键上传,实现了一个简单的浏览器插件,能方便保存网页内容到个人网站。这些插件目前都很难兼容全部的浏览器,Chrome支持好一些。

时移势迁,光阴荏苒,这一小插件已经使用了十多年。之前作为网页书签存在,现在已经变成浏览器插件了。但之前的插件版本只支持Chrome和Opera,不支持firefox,而我平常用Chrome访问国外站点,firefox访问国内站点和个人开发网站。所以近期终于得闲开发了firefox版本。

在这里插入图片描述
个人使用,所以也没美化。

实现原理

调用window.getSelection()获得选中的网页内容,然后发给popup脚本,再在popup里调用fetch()函数上传数据。

网页剪报功能简述

以飞书剪存为例,它是一个兼容于各大浏览器的扩展程序。它可以将网页正文保存至飞书文档,且自动剥离广告。
一键保存网页正文,告别手动复制粘贴: 浏览到喜欢的网页,点击飞书剪存,即可将网页内容保存至你的飞书文档中。
智能剥离网页广告,告别无用干扰信息: 飞书剪存可以智能识别并去除悬浮或嵌在网页中的广告,还你干净、无噪的网页内容。

插件定义

v2插件定义

这个是飞书的:

{"name": "__MSG_appName__","description": "__MSG_CreationDoc_Operation_AppStoreBrief__","version": "1.0.26","manifest_version": 2,"default_locale": "zh_CN","browser_action": {"default_icon": {"16": "assets/icons/48.png","24": "assets/icons/48.png","32": "assets/icons/48.png"},"default_title": "__MSG_appName__"},"icons": {"16": "assets/icons/48.png","32": "assets/icons/48.png","48": "assets/icons/48.png","128": "assets/icons/128.png"},"background": {"persistent": false,"scripts": ["background.js"]},"content_scripts": [{"matches": ["http://*/*","https://*/*"],"run_at": "document_idle","js": ["content.js"]}],"permissions": ["tabs","activeTab","contextMenus","cookies","storage","*://*/*"],"web_accessible_resources": ["assets/*","app.html","app.js","page-post-frame-id.html","page-post-frame-id.js"],"incognito": "not_allowed","content_security_policy": "script-src 'self' 'unsafe-eval' https://*.bytegoofy.com blob:  https://*.ibytedapm.com ; object-src 'self'","homepage_url": "https://www.feishu.cn/hc/zh-CN/articles/606278856233"
}

v3版本的插件定义

{"manifest_version": 3,"name": "CMS一键上传8.0","version": "8.0","homepage_url": "http://www.icodelib.cn","background": {"scripts": ["background.js"]},"content_scripts": [{"matches": ["<all_urls>"],"js": ["jquery-1.8.3.js","content-script.js", "inject.js"]}],// 浏览器右上角图标设置,browser_action、page_action、app必须三选一"action": {"default_title": "一键上传","default_popup": "popup.html","default_icon": {"16": "icons/16x16.png","48": "icons/48x48.png","128": "icons/128x128.png"}},"host_permissions": ["<all_urls>"],"web_accessible_resources": [{"resources": ["inject.js", "popup.js"], "matches": ["<all_urls>"]}],"permissions":["contextMenus", // 右键菜单"tabs", // 标签"activeTab","scripting","notifications", // 通知"webRequest", // web请求"webRequestBlocking","webNavigation","declarativeNetRequestWithHostAccess","declarativeNetRequest","declarativeNetRequestFeedback","storage"]
//    "content_security_policy": "script-src 'self' 'unsafe-eval'"
}

实现

在content-script里获得选中内容,然后发送:

// 发送消息给后台
async function sendMessageToBackground(html) {try {       await browser.runtime.sendMessage({src: window.location.href,title: document.title,content: html})// showMsg('上传完成')} catch (err) {console.error(err);// showMsg('上传失败')}}

在popup.js里监听消息,然后获得数据后,调用后端API:

browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => {	const formData = new FormData();formData.append('src', message.src);formData.append('title', message.title);formData.append('content', message.content);try {const response = await fetch(target_site, {method: 'POST',mode: "cors",body: formData,})const result = await response.json();debug(result)} catch (err) {debug(err)}// sendResponse({success: 'ok'})return true;
});

火狐需要用户选择接受外部访问

const permissions = {// This origin is listed in host_permissions:origins: ["<all_urls>"],
};const checkbox_host_permission = document.getElementById("checkbox_host_permission");
checkbox_host_permission.onchange = async () => {if (checkbox_host_permission.checked) {let granted = await browser.permissions.request(permissions);if (!granted) {// Permission request was denied by the user.checkbox_host_permission.checked = false;}} else {try {await browser.permissions.remove(permissions);} catch (e) {// While Chrome allows granting of host_permissions that have manually// been revoked by the user, it fails when revoking them, with// "Error: You cannot remove required permissions."console.error(e);checkbox_host_permission.checked = true;}}
};
browser.permissions.contains(permissions).then(granted => {checkbox_host_permission.checked = granted;
});

发布

对于Firefox而言,插件开发完后,需要上传到https://addons.mozilla.org/签名才能安装。
在这里插入图片描述
无品牌的firefox构建版本可以安装不用签名的插件。在about:config里将xpinstall.signatures.required设为false即可。此方法能装上,但功能有点问题,所以我还是选择了正式途径。

注意事项

  • 后端API需要使用https
    当使用manifest_version: 3时,fetch()函数会报错,TypeError: NetworkError when attacking to fetch resource,网上查了半天,发现v2和v3的诸多不同,且Content Security Policy (CSP) 的限制,需要以https或wss协议访问外部才行。
  • firefox需要插件有一个addon ID

链接

-Firefox插件开发文档
-火狐Unbranded_Builds

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/484510.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】三、日志控制

三、日志控制 使用Docker部署服务器&#xff0c;要对Docker日志定时处理。否则&#xff0c;服务器运行一段时间后&#xff0c;磁盘占比报警。 出现磁盘占比报警&#xff0c;大概率是大文件的问题&#xff0c;可查看服务器中的大文件&#xff0c;排除问题。 &#xff08;一&am…

C语言自定义类型:结构体的使用及其内存对齐【超详细建议点赞收藏】

目录 1. 结构体类型的声明1.1 结构的声明1.2 结构体变量的创建和初始化1.3 结构的特殊声明---匿名结构体1.4 结构的自引用 2.结构体内存对齐&#xff08;重点&#xff01;&#xff01;&#xff09;2.1 对齐规则2.2 例题讲解2.3 为什么存在内存对齐&#xff1f;2.4 修改默认对齐…

SpringBoot添加过滤器Filter

1. 拦截器和过滤器 先说一下&#xff0c;过滤器和拦截器的区别和联系。 1.1 相同点 首先过滤器和拦截器都能实现请求的筛选&#xff08;过滤或者拦截&#xff09;&#xff0c;然后根据自己的业务需求&#xff0c;添加自己的逻辑&#xff0c;保证请求往后走的时候数据能满足自己…

如何自定义一个协议

. 如何自定义一个协议 先有一个需求,有个场景,打开外卖软件,会显示商家列表,列表中有很多项,每一项都包含了一些信息,商家的名称,图片,好评率,距离你的位置,评分 这些信息都是通过网络,从服务器获取的, 客户端,需要给服务器发送一个请求,服务器收到请求之后,就给客户端返回一个…

HTTP攻击,该怎么防护

一般网络世界里为人们所熟知的DDoS攻击&#xff0c;多数是通过对带宽或网络计算资源的持续、大量消耗&#xff0c;最终导致目标网络与业务的瘫痪&#xff1b;这类DDOS攻击&#xff0c;工作在OSI模型的网络层与传输层&#xff0c;利用协议特点构造恶意的请求载荷来达成目标资源耗…

从底层理解MySQL-字符类型

目录 VARCHAR和CHAR VARCHAR CHAR 存储的长度超限 CHAR和VARCHAR的区别&#xff1a; BLOB和TEXT MySQL中除了数值类型外&#xff0c;另一个用的比较多的就是字符类型了。字符类型有很多不同种类&#xff1a;VARCHAR,CHAR,BLOB,TEXT VARCHAR和CHAR VARCHAR VARCHAR是变…

如何使用ArcGIS Pro生成等高线

无论在制图还是规划中&#xff0c;经常会使用到等高线&#xff0c;大多数情况下&#xff0c;从网上获取的高程数据都是DEM文件&#xff0c;我们可以通过ArcGIS Pro来生成等高线&#xff0c;这里为大家介绍一下生成方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的…

springboot206基于SpringBoot的农商对接系统的设计与实现

基于Spring Boot的农商对接系统的设计与实现 Design and implementation of agricultural business docking system based on Spring Boot 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离…

【Chrono Engine学习总结】4-vehicle-4.3-两个vehicle碰撞测试

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 今天突发奇想&#xff0c;想试一下&#xff0c;是否可以实现两个vehicle的碰撞&#xff1f; 1、两辆vehicle的仿真 官方提供了demo_VEH_TwoCars这个demo&#xff0c…

React -- useEffect

React - useEffect 概念理解 useEffect是一个React Hook函数&#xff0c;用于在React组件中创建不是由事件引起而是由渲染本身引起的操作&#xff08;副作用&#xff09;, 比 如发送AJAX请求&#xff0c;更改DOM等等 :::warning 说明&#xff1a;上面的组件中没有发生任何的用…

暴风一期 黑群晖折腾流水账

起因是想和女友一起分享各自手机中的小猫照片&#xff0c;经过上网查资料了解到了群晖&#xff0c;可惜正版白群晖售价太高&#xff1a; 无奈选择了黑群晖&#xff0c;白群晖其实也可以简单理解为一台电脑多装了几块硬盘&#xff0c;然后装了一个文件服务器系统&#xff0c;这个…

CoordConv(NeurIPS 2018)

paper&#xff1a;An Intriguing Failing of Convolutional Neural Networks and the CoordConv Solution official implementation&#xff1a;https://github.com/uber-research/coordconv 存在的问题 本文揭示并分析了CNN在两种不同类型空间表示之间转换能力的欠缺&#…