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

前言

一键上传选中的网页内容,实现知识快速收藏。如飞书剪存,有道云剪报,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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Day32 进程Process

文章目录 1.什么是进程1.1 概念1.2 特点1.3 进程段1.4 进程分类1.5 进程状态1.6 进程状态切换图1.7 调度进程 2.进程函数接口2.1 创建进程 fork()2.2 回收资源函数2.3 结束进程2.4 获取进程号 3.exec函数族&#xff08;了解&#xff09;4.守护进程 Daemon4.1 守护进程的特点4.2…

提升技术栈的秘诀:Spring Cloud学习网站带你飞跃职业瓶颈!

介绍&#xff1a;Spring Cloud是一个基于Spring Boot实现的微服务架构开发工具集。 Spring Cloud利用Spring Boot的开发便利性简化了分布式系统基础设施的开发。例如&#xff0c;服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等都是其内置的功能。它的优势包括…

LangChain支持哔哩哔哩视频总结

是基于LangChain框架下的开发&#xff0c;所以最开始请先 pip install Langchain pip install bilibili-api-python 技术要点&#xff1a; 使用Langchain框架自带的Document loaders 修改BiliBiliLoader的源码&#xff0c;自带的并不支持当前b站的视频加载 源码文件修改&a…

前端架构: 实现脚手架终端UI样式之ANSI escape code, Chalk, Ora介绍

在脚手架当中实现命令行的UI显示 1 &#xff09;概述 在命令行中&#xff0c;如果想实现除传统的常规文本以外的内容比如想对字体进行加粗斜体下划线&#xff0c;包括对它改变颜色改变前景色改变后景色等等需要借助一个叫做 ANSI escape code 这样的一个概念它其实是一个标准&…

文献速递:GAN医学影像合成--基于生成对抗网络的肺部图像分类的多域医学图像翻译生成

文献速递&#xff1a;GAN医学影像合成–基于生成对抗网络的肺部图像分类的多域医学图像翻译生成 01 文献速递介绍 在2019年底&#xff0c;一种称为2019冠状病毒病&#xff08;COVID-19&#xff09;的新型冠状病毒肺炎出现&#xff0c;迅速成为全球性大流行。感染COVID-19可以…

18.贪心算法

排序贪心 区间贪心 删数贪心 统计二进制下有多少1 int Getbit_1(int n){int cnt0;while(n){nn&(n-1);cnt;}return cnt; }暴力加一维前缀和优化 #include <iostream> #include <climits> using namespace std; #define int long long const int N2e510; in…

热门游泳耳机哪个牌子好,吐血整理全网高口碑机型!

近年来&#xff0c;游泳已经成为众多人们喜爱的运动项目之一。而在游泳过程中&#xff0c;许多人希望能够享受到音乐的陪伴&#xff0c;以增加运动的乐趣。然而&#xff0c;由于阻力、防水和水压等问题&#xff0c;传统的耳机并不能满足游泳者的需求。因此&#xff0c;在市面上…

基于JAVA+SpringBoot+Vue的前后端分离的电子商城

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 在当今数字化时代&…

bat判断vmware 是否已安装

要通过批处理脚本&#xff08;.bat&#xff09;判断VMware是否已安装&#xff0c;您可以尝试以下方法&#xff1a; 检查VMware的进程 您可以检查VMware相关的进程是否在运行。例如&#xff0c;VMware Workstation的进程名通常是vmware-workstation.exe。 echo off tasklist /…

计网 - 域名解析的工作流程

文章目录 Pre引言1. DNS是什么2. 域名结构3. 域名解析的工作流程4. 常见的DNS记录类型5. DNS安全6. 未来的发展趋势 Pre 计网 - DNS 域名解析系统 引言 在我们日常使用互联网时&#xff0c;经常会输入各种域名来访问网站、发送电子邮件或连接其他网络服务。然而&#xff0c;我…

【命令行工具kubectl】

如何在k8s的任意节点使用用kubectl # 正常在node节点上是无法执行kubectl命令 [rootk8s-node-01 ~]# kubectl get pods The connection to the server localhost:8080 was refused - did you specify the right host or port?1、将master节点中/etc/kubernetes/,admin.conf拷…

性能分析5部曲:瓶颈分析与问题定位,如何快速解决瓶颈?

一、引言 很多做性能测试的同学都问过我这样一个问题&#xff1a;鱼哥(Carl_奕然)&#xff0c;你说性能测试的重点是什么? 我的回答很简单&#xff1a;瓶颈分析与问题定位。 在性能项目的整个周期&#xff0c;不管是脚本设计&#xff0c;脚本编写还是脚本执行&#xff0c;都…

fastjson解析自定义get方法导致空指针问题

背景 为了在日志中把出入参打印出来&#xff0c;以便验证链路和排查问题&#xff0c;在日志中将入参用fastjson格式化成字符串输出&#xff0c;结果遇到了NPE。 问题复现 示例代码 public static void main(String[] args) {OrganizationId orgId new OrganizationId();N…

Nginx -2

接着上文写 5.4.7 验证模块 需要输入用户名和密码 模块名称&#xff1a;ngx_http_auth_basic_module 访问控制基于模块 ngx_http_auth_basic_module 实现&#xff0c;可以通过匹配客户端资源进行限制 语法&#xff1a; Syntax: auth_basic string | off; Default: auth_ba…

RK3568平台开发系列讲解(Linux系统篇)编写I2C客户端驱动程序

🚀返回专栏总目录 文章目录 一、定义和注册I2C驱动程序二、在设备树中实例化I2C设备——新方法三、总结沉淀、分享、成长,让自己和他人都能有所收获!😄 配置I2C设备基本上分为两个步骤。 定义并注册I2C驱动程序定义并注册I2C设备在DT中,I2C设备属于非存储器映射设备系列…

MySQL报错:sql_mode=only_full_group_by解决方法

Linux环境 ubuntu 22.04 MySQL是8.0.35版本 问题描述 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column auth_system.t_class_temp_config.id which is not functionally dependent on columns in GROUP BY clause; this is inco…

OOTDiffusion:一个开源可控的虚拟服装试穿工具,效果接近商用!

目录 前言介绍 主要功能 相关链接 安装部署 效果展示 前言介绍 继谷歌推出了Tryon Diffusion,阿里推出了Outfit Anything, 亚马逊也推出了Diffuse to Choose。至此几大头部电商也都在虚拟试衣技术上完成了布局。基于扩散模型的技术基本已经成为现在主流应…

2024最佳住宅代理IP服务商推荐

跨境出海已成为了近几年的最热趋势&#xff0c;大批量的企业开始开拓海外市场&#xff0c;而海外电商领域则是最受欢迎的切入口。新兴的tiktok、Temu&#xff0c;老牌的Amazon、Ebay&#xff0c;热门的Etsy、Mecari等等都是蓝海一片。跨境入门并不难&#xff0c;前期的准备中不…

Leetcoder Day18| 二叉树 part07

语言&#xff1a;Java/Go 今天做了一个小决定&#xff0c;如果时间不够的话&#xff0c;可以先看go去找工作&#xff0c;所以现在加上用go去刷题 530.二叉搜索树的最小绝对差 给你一棵所有节点为非负值的二叉搜索树&#xff0c;请你计算树中任意两节点的差的绝对值的最小值。…

如何使用Docker部署开源Leanote蚂蚁笔记并发布个人博客至公网

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 1. 安装Docker2. Docker本地部署Leanote蚂蚁笔记3. 安装…