打造自己的盗图利器(chrome插件开发)
1.前言
有没有时常写文章需要引用其他人的图片,但是又还怕他人图片链接失效,所以需要把图片保存下载再上传到图床.非常麻烦
有没有时常看到他人优秀的知识图谱,亦或者保存不下来的背景图,想一键存储到自己的专属图床.
总结一下,想要做的就是快速保存网页上的图片资源到自己私有的存储容器上.
2.技术方案
2.1 定位图片资源
所以如何做到快速获取页面图片资源呢? 图片资源从远程服务器加载到本地浏览器上的各个过程都可以做一些不同层面的拦截.但是我们需要做到是用户选择想要的图片再来保存,所以定位具体的图片的资源的步骤一定是等待页面加载完成之后的操作.因此,我们需要把目光投向DOM节点.
DOM节点显示图片最常用的方式有以下几种.
IMG标签
background属性
chrmoe插件可以提供给我一个右击选项新增,所以我们可以通过用户的右击点击事件,去定位到具体承载图片的节点上. 但往往很多时候,冒泡的节点并非是承载图片的节点,例如清除浮动,一切浮起元素等都会引起用户右击事件 并未直接发生在承载图片资源显示的dom上.所以我么需要上下求索.
2.2 保存图片到私有存储容器上
这里我选择了七牛云作为我们的图床容器.不管任何品牌对象存储的SDK都没有提供纯JS前端上传方法(安全问题),所以这里我们依旧需要仔细阅读文档.对信息的加密都需要在本地做好.
3.CODING
mainfest.html
{"manifest_version": 2,"name": "一键图床","version": "1.0.0","description": "右击保存图床","icons":{"16": "icon.png","48": "icon.png","32": "icon.png","128": "icon.png"},"background":{"scripts": ["background.js"]},"browser_action": {"default_icon": "icon.png","default_title": "一键图床","default_popup": "popup.html"},"permissions":["contextMenus","notifications","*://*/*","webRequest","webRequestBlocking"],"content_scripts": [{"matches": ["<all_urls>"],"js": ["content.js"],"run_at": "document_start"}],"homepage_url": "http://www.dishenghk.cn"
}复制代码
background.js
用户将图片的URL转换为BLOB,上传图片,接受和发送CONTENT的信息.
const qiniu = require("qiniu-js")
const util=require("./util")
const getUpToken = require("./getUpToken")
const urlToBlob = require("./urlToBlob")
const {sendMessageToNowTab} = require("./sendMessageToTab")
var { logImgHttp, getImglogs } = require("./logImgHttp")
//记录图片请求地址
logImgHttp()var imglogs = getImglogs()
console.log(imglogs)
//记录来自div背景的图片
let divBackGroundImgUrl=''
chrome.runtime.onMessage.addListener(function(request)
{if (request.messageType == 'logBackImageUrl') {divBackGroundImgUrl=request.value}});
chrome.contextMenus.create({title: "复制图片地址",contexts: ['all'],onclick: (e) => {let srcUrl = e.srcUrl || divBackGroundImgUrldivBackGroundImgUrl=''if (!srcUrl) {chrome.notifications.create(null, {type: 'basic',iconUrl: 'icon.png',title: '图床提示',message: '没有找到图片哦'});return}//对于一些特殊的URL格式做处理srcUrl = srcUrl.replace('"', '').replace("'", '')if (srcUrl.startsWith('//')) {srcUrl='http:'+srcUrl}sendMessageToNowTab({ messageType: "copyDate", value: srcUrl }, function (repsonse) {chrome.notifications.create(null, {type: 'basic',iconUrl: 'icon.png',title: '图床提示',message: '图片远程地址复制成功',contextMessage:srcUrl }); })}
})
chrome.contextMenus.create({title: "保存图片到云端",contexts:["all"],onclick: function (e) {console.log(e)let srcUrl = e.srcUrl || divBackGroundImgUrldivBackGroundImgUrl=''if (!srcUrl) {chrome.notifications.create(null, {type: 'basic',iconUrl: 'icon.png',title: '图床提示',message: '没有找到图片哦'});return}srcUrl = srcUrl.replace('"', '').replace("'", '')if (srcUrl.startsWith('//')) {srcUrl='http:'+srcUrl}const nowDate = new Date()const fileName=`${nowDate.getFullYear()}/${nowDate.getMonth()+1}/${nowDate.getDate()}/${util.uuid()}.png`const putPolicy = {scope: "tuchuang:"+fileName,deadline:3600+Math.round(new Date().getTime()/1000),returnBody:'{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'}const token = getUpToken(putPolicy)urlToBlob(srcUrl, (blob) => {var observable = qiniu.upload(blob, fileName, token)var subscription = observable.subscribe({next: (response) => {console.log(response)},complete: (response) => {sendMessageToNowTab({ messageType: "copyDate", value: `http://tuchuang.dishenghk.cn/${response.key}` }, function (repsonse) {chrome.notifications.create(null, {type: 'basic',iconUrl: 'icon.png',title: '图床提示',message: '保存成功,地址已经被复制',contextMessage:`http://tuchuang.dishenghk.cn/${response.key}` });})}}) // 上传开始})}
});复制代码
content.js
注入到用户界面的JS.
chrome.runtime.onMessage.addListener(function(request,sneder,sendResponse)
{if (request.messageType == 'copyDate') {navigator.clipboard.writeText(request.value).then(() => {console.log('文本已经成功复制到剪切板');sendResponse("xxx")}).catch(err => {console.error('无法复制此文本:', err);});}});
document.onmousedown = (e) => {const { backgroundImage } = e.target.styleconst { target } = eif (backgroundImage) {backgroundImage.match(/url\((?:"|')(.+)(?:"|')\)/g)if (RegExp.$1) {console.log(RegExp.$1)sendBackImageUrl(RegExp.$1)return }}//往下检查子节点是否存在img标签let firstImgNode = new Object()findImg(target, firstImgNode, 1)if (firstImgNode && firstImgNode.currentSrc) {sendBackImageUrl(firstImgNode.currentSrc)return} }
function sendBackImageUrl(image){chrome.runtime.sendMessage({messageType:"logBackImageUrl",value:image})
}
//递归找到第一个img标签
function findImg(nowNode, imgNode, deep = 0) {if (imgNode.currentSrc) return //对于伪元素顶起高度时点击事件落到::after 上的优化if (nowNode.nodeName.toLowerCase().indexOf("text") !== -1 && deep==1) {nowNode=nowNode.parentNode}const { childNodes } = nowNodefor (let i = 0; i < childNodes.length && !imgNode.currentSrc; i++){let node = childNodes[i]if (node.nodeName.toLowerCase().indexOf("img") !== -1) {imgNode.currentSrc=node.currentSrcbreak}if (node.childNodes.length) {findImg(node,imgNode)}}return
}
复制代码
4.打包程序
上面分享了主要的两个插件规范所必须的JS主文件,但是实际上插件也不支持ES moudle,所以我们需要打包我们的模块为UMD形式.这里我们选择rollup来打包的我们的插件.
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import copy from "rollup-copy-plugin"const packages = require('./package.json');const ENV = process.env.NODE_ENV;
export default [{input: 'src/background.js',output: {file: `dist/background.js`,format: 'umd',name: 'bundle-name'},plugins: [resolve(),commonjs(),babel({exclude: 'node_modules/**',runtimeHelpers: true,})],},{input: 'src/content.js',output: {file: `dist/content.js`,format: 'umd',name: 'content-name'},plugins: [resolve(),commonjs(),babel({exclude: 'node_modules/**',runtimeHelpers: true,})],},{input: "src/popup.js",output: {file: "dist/popup.js",format: "umd",name:"popup=name"},plugins: [resolve(),commonjs(),babel({exclude: 'node_modules/**',runtimeHelpers: true,}),copy({"src/popup.html":"dist/popup.html"})],}]
复制代码
5.TODO
- 对于程序的精简优化
- 图床管理页面,配置密钥界面.
- 引入插件化,支持多品牌对象存储.
6.使用办法
gitee.com/dishenghk/t…
clone代码后修改 getUpToken.js 中的密钥,然后执行roollup 命令打包文件到dist中,浏览器加载dist文件夹即可.
打造自己的盗图利器(chrome插件开发)相关推荐
- SuperSpider——打造功能强大的爬虫利器
SuperSpider--打造功能强大的爬虫利器 博文作者:加菲 发布日期:2013-12-11 阅读次数:4506 博文内容: 1.爬虫的介绍 图1-1 爬虫(spider) 网络爬虫(web s ...
- vue.js 初体验— Chrome 插件开发实录
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:陈纬杰 背景 对于经常和动画开发打交道的开发者对于Animate.css这个动画库不会陌生,它把一些常见 ...
- Chrome 插件开发小记
文章目录 前言 manifest.json 常用配置项 常用API 脚本注入 网站与插件通信 网站端 插件端 打包 .crx QA 其他参考链接 前言 群里闲逛,看见有人发了个图,感觉还挺有意思,抽空 ...
- 【Chrome插件开发作品】用户信息及验证码自动填充插件
GitHub链接 文章目录 作品演示 Never mind插件概述 Nerver Mind插件功能 Never Mind插件涉及技术 Never Mind技术相关介绍 1. chrome浏览器插件开发 ...
- chrome插件开发:为页面添加点击事件
目录 上面说了些什么? 示例 插件示例 应用示例 插件安装 打开开发者模式 添加本地插件包 安装后的效果 插件开发 插件介绍 目录结构 manifest.json index.html addToke ...
- chrome插件开发(转)
作者原文:https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html 写在前面 我花了将近一个多月的时间断断续续写下这篇博文,并精心写 ...
- chrome 插件开发各种功能demo_Chrome 插件开发全攻略
Chrome 浏览器相信大家都用得比较多,有很多的优点,比如简洁.强大的开发者工具等,但是更让大家映像深刻的是有各种各样有趣.有用的插件,今天要给大家推荐的开源项目是 Chrome 插件开发全攻略,你 ...
- chrome插件开发记录(1)——解决问题“清单文件缺失或不可读”
chrome插件开发记录(1)--解决问题"清单文件缺失或不可读" 参考文章: (1)chrome插件开发记录(1)--解决问题"清单文件缺失或不可读" (2) ...
- Chrome 插件开发-右键菜单开发实战演示,浏览器页面右键菜单选项设置,插件右键菜单点击插件名跳转主页设置
Chrome 插件开发 - 菜单选项 浏览器页面右键菜单选项设置 ① 核心代码演示 ② 效果展示 ③ 详细参数文档 插件右键菜单点击插件名跳转主页设置 ① 核心代码演示 ② 演示效果图 浏览器页面右键 ...
最新文章
- java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)
- 深度学习~生成式对抗神经网络GAN
- 百度Apollo赋能的威马W6,自主泊车体验如何?
- 【转】TYVJ 1695 计算系数(NOIP2011 TG DAY2 1)
- 局域网文件传输方式分析
- 风雨萧关道【电视专题片解说词】
- 阿里云服务器安全组配置
- [英语阅读]英国13岁男孩当爹引各界热议
- c++11伪随机数生成库:random
- New Concept English3 Lesson 2. Thirteen equals one【精讲学习笔记】
- 1024人工智能和大数据应用高峰论坛
- Compilation failure:错误: 找不到符号
- 计算机游戏软件使用说明书,虚贝游戏上号器怎么用 使用方法详解
- 硬盘清理利器TreeSize Free
- AFNetworking源码简单分析
- 微信小程序前端调用python后端的模型
- 知乎:为什么我的成绩那么好,最终还是成了一个没用的人
- css 使图像变成灰色的技巧
- 苏菲的世界-Part1
- 苹果x和xsmax有什么区别_手机资讯:Apple 认证的翻新产品是什么苹果官方翻新机和全新设备有什么区别...
热门文章
- Effective LSTMs for Target-Dependent Sentiment Classification
- 3.3.2 Arc Consistency Algorithms
- 一觉醒来,我掉入了计算机之中···
- IntelliJ Idea优秀插件
- AppUI自动化iOS WDA证书签名
- CPU使用率高,如何快速定位
- Android Dialog中监听返回键事件
- 分布式中hash取模算法
- 【全志T113-S3_100ask】16-1 linux系统驱动四线电阻屏(tpadc、tslib)
- 国家精品课程注册邀请~