// ==UserScript== // @name MutliQRCode // @namespace https://greasyfork.org/zh-CN/users/1073349 // @version 0.3.1 // @description PC端和移动端都可用的二维码识别 // @author 4ehex // @match *://*/* // @grant GM_addElement // @icon data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NjA1Ij48cGF0aCBkPSJNMTg2LjAyNjY2NyAwaDY1MS45NDY2NjZRMTAyNCAwIDEwMjQgMTg2LjAyNjY2N3Y2NTEuOTQ2NjY2UTEwMjQgMTAyNCA4MzcuOTczMzMzIDEwMjRIMTg2LjAyNjY2N1EwIDEwMjQgMCA4MzcuOTczMzMzVjE4Ni4wMjY2NjdRMCAwIDE4Ni4wMjY2NjcgMHoiIGZpbGw9IiMzNjg5RjUiIHAtaWQ9Ijc2MDYiPjwvcGF0aD48cGF0aCBkPSJNMjEzLjMzMzMzMyAzMDQuNjRBOTAuODggOTAuODggMCAwIDEgMzA0LjIxMzMzMyAyMTMuMzMzMzMzaDkwLjg4djQyLjY2NjY2N0gzMDYuMzQ2NjY3YTQ1LjY1MzMzMyA0NS42NTMzMzMgMCAwIDAtNDYuNTA2NjY3IDQ4LjY0djkxLjczMzMzM0gyMTMuMzMzMzMzek0zOTYuOCA4MTAuNjY2NjY3SDMwNi4zNDY2NjdhOTAuNDUzMzMzIDkwLjQ1MzMzMyAwIDAgMS05MC44OC05MS4zMDY2Njd2LTkxLjczMzMzM2g0Ni41MDY2NjZ2OTEuNzMzMzMzQTQ1LjY1MzMzMyA0NS42NTMzMzMgMCAwIDAgMzA4LjA1MzMzMyA3NjhoOTAuODhhMjk4LjY2NjY2NyAyOTguNjY2NjY3IDAgMCAwLTIuMTMzMzMzIDQyLjY2NjY2N3pNODEwLjY2NjY2NyA3MTkuMzZBOTAuNDUzMzMzIDkwLjQ1MzMzMyAwIDAgMSA3MTcuNjUzMzMzIDgxMC42NjY2NjdINjI3LjJ2LTQ2LjkzMzMzNGg5MC40NTMzMzNhNDUuNjUzMzMzIDQ1LjY1MzMzMyAwIDAgMCA0Ni41MDY2NjctNDYuNTA2NjY2di05MS4zMDY2NjdIODEwLjY2NjY2N3pNMjEzLjMzMzMzMyA0ODcuNjhoNTk1LjJ2NDYuOTMzMzMzSDIxMy4zMzMzMzN6TTgxMC42NjY2NjcgMzk2LjM3MzMzM2gtNDguNjRWMzA0LjY0YTQ1LjY1MzMzMyA0NS42NTMzMzMgMCAwIDAtNDYuMDgtNDYuNTA2NjY3aC05MC44OFYyMTMuMzMzMzMzaDkwLjg4YTkwLjg4IDkwLjg4IDAgMCAxIDkwLjg4IDkxLjMwNjY2N3oiIGZpbGw9IiNGRkZGRkYiIHAtaWQ9Ijc2MDciPjwvcGF0aD48L3N2Zz4= // @require https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js // @require https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js // @grant unsafeWindow // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; //全局变量 被选中的图片元素 var g_img_ele = null; var g_is_moblie_env = isPhone(); //适配移动端 很多移动端浏览器并没有实现油猴接口 //添加'识别二维码'按钮样式 let btn_style = document.createElement('style'); btn_style.type = 'text/css'; if (!g_is_moblie_env){ btn_style.innerText = `.idtfy_div{width:5.5vw;height:2.1vh;font-size:1vh;color:#000000;background:#F8F8FF;border-radius:1.5vh;border:0.12vh solid #f2cac9;line-height:2vh;text-align:center;vertical-align:middle;z-index:99999999;display:none;position:absolute;top:20;left:20;cursor:pointer;box-shadow:0.13vh 0.13vh 0.1vh #888888;}`; //GM_addStyle(`.idtfy_div{width:5.5vw;height:2.1vh;font-size:1vh;color:#000000;background:#F8F8FF;border-radius:1.5vh;border:0.12vh solid #f2cac9;line-height:2vh;text-align:center;vertical-align:middle;z-index:99999999;display:none;position:absolute;top:20;left:20;cursor:pointer;box-shadow:0.13vh 0.13vh 0.1vh #888888;}`); } else{ btn_style.innerText = `.idtfy_div{width:25vw;height:3vh;font-size:1.6vh;color:#000000;background:#F8F8FF;border-radius:1.5vh;border:0.14vw solid #f2cac9;line-height:3vh;text-align:center;vertical-align:middle;z-index:99999999;display:none;position:absolute;top:20;left:20;cursor:pointer;box-shadow:0.15vw 0.15vw 0.13vw #888888;}`; //GM_addStyle(`.idtfy_div{width:25vw;height:3vh;font-size:1.6vh;color:#000000;background:#F8F8FF;border-radius:1.5vh;border:0.14vw solid #f2cac9;line-height:3vh;text-align:center;vertical-align:middle;z-index:99999999;display:none;position:absolute;top:20;left:20;cursor:pointer;box-shadow:0.15vw 0.15vw 0.13vw #888888;}`); } document.head.appendChild(btn_style); //添加'识别二维码'按钮 var identify_div = document.createElement('div'); identify_div.id = 'identify_div'; identify_div.className = 'idtfy_div';//👇添加一个图标 identify_div.innerHTML = ` 识别二维码`; identify_div.onclick = OnClickedIdentifyBtn; document.body.appendChild(identify_div); //添加精简后的'notie.js' 一款纯js实现的消息弹窗 github: https://github.com/jaredreich/notie if (typeof GM_addElement == 'function'){//好像不用GM_addElement没法添加有CSP的网站 GM_addElement('script', { textContent: `var notie=function(){function D(a,b,c){document.activeElement.blur(),C++,setTimeout(function(){C--},1e3*e+10),1==C&&(z?(clearTimeout(A),clearTimeout(B),F(function(){E(a,b,c)})):E(a,b,c))}function E(b,c,d){var f;switch(z=!0,f=0,f="undefined"==typeof d?3e3:1>d?1e3:1e3*d,b){case 1:v.style.backgroundColor=g,v.onclick=function(){};break;case 2:v.style.backgroundColor=h,v.onclick=alert_outer_onclick;break;case 3:v.style.backgroundColor=i,v.onclick=alert_outer_onclick;break;case 4:v.style.backgroundColor=j,v.onclick=alert_outer_onclick}x.innerHTML=c,v.style.top="-10000px",v.style.display="table",v.style.top="-"+v.offsetHeight-5+"px",A=setTimeout(function(){a&&(v.style.boxShadow="0px 0px 10px 0px rgba(0,0,0,0.5)"),v.style.MozTransition="all "+e+"s ease",v.style.WebkitTransition="all "+e+"s ease",v.style.transition="all "+e+"s ease",v.style.top=0,B=setTimeout(function(){F(function(){})},f)},20)}function F(b){v.style.top="-"+v.offsetHeight-5+"px",setTimeout(function(){a&&(v.style.boxShadow=""),v.style.MozTransition="",v.style.WebkitTransition="",v.style.transition="",v.style.top="-10000px",z=!1,b&&b()},1e3*e+10)}var v,w,x,z,A,B,C,a=!0,b="18px",c="24px",d=600,e=.3,g="#57BF57",h="#E3B771",i="#E1715B",j="#4D82D6",k="#FFF",l="notie-alert-outer",m="notie-alert-inner",n="notie-alert-text",o=function(a){a.style.fontSize=window.innerWidth<=d?b:c},p=500,q=function(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,c||a.apply(e,f)},h=c&&!d;clearTimeout(d),d=setTimeout(g,b),h&&a.apply(e,f)}};return window.addEventListener("keydown",function(a){var b=13==a.which||13==a.keyCode,c=27==a.which||27==a.keyCode;z&&(b||c)&&(clearTimeout(A),clearTimeout(B),F())}),"undefined"==typeof Element.prototype.addEventListener&&(Element.prototype.addEventListener=Window.prototype.addEventListener=function(a,b){return a="on"+a,this.attachEvent(a,b)}),v=document.createElement("div"),v.id=l,v.style.position="fixed",v.style.top="0",v.style.left="0",v.style.zIndex="999999999",v.style.height="auto",v.style.width="100%",v.style.display="none",v.style.textAlign="center",v.style.cursor="default",v.style.MozTransition="",v.style.WebkitTransition="",v.style.transition="",v.style.cursor="pointer",alert_outer_onclick=function(){clearTimeout(A),clearTimeout(B),F()},w=document.createElement("div"),w.id=m,w.style.padding="20px",w.style.display="table-cell",w.style.verticalAlign="middle",v.appendChild(w),x=document.createElement("span"),x.id=n,x.style.color=k,x.style.fontSize=window.innerWidth<=d?b:c,window.addEventListener("resize",q(o.bind(null,x),p),!0),w.appendChild(x),document.body.appendChild(v),z=!1,C=0,{alert:D,alert_hide:F}}();` }); } else{ const notie_script = document.createElement('script') notie_script.innerText = `var notie=function(){function D(a,b,c){document.activeElement.blur(),C++,setTimeout(function(){C--},1e3*e+10),1==C&&(z?(clearTimeout(A),clearTimeout(B),F(function(){E(a,b,c)})):E(a,b,c))}function E(b,c,d){var f;switch(z=!0,f=0,f="undefined"==typeof d?3e3:1>d?1e3:1e3*d,b){case 1:v.style.backgroundColor=g,v.onclick=function(){};break;case 2:v.style.backgroundColor=h,v.onclick=alert_outer_onclick;break;case 3:v.style.backgroundColor=i,v.onclick=alert_outer_onclick;break;case 4:v.style.backgroundColor=j,v.onclick=alert_outer_onclick}x.innerHTML=c,v.style.top="-10000px",v.style.display="table",v.style.top="-"+v.offsetHeight-5+"px",A=setTimeout(function(){a&&(v.style.boxShadow="0px 0px 10px 0px rgba(0,0,0,0.5)"),v.style.MozTransition="all "+e+"s ease",v.style.WebkitTransition="all "+e+"s ease",v.style.transition="all "+e+"s ease",v.style.top=0,B=setTimeout(function(){F(function(){})},f)},20)}function F(b){v.style.top="-"+v.offsetHeight-5+"px",setTimeout(function(){a&&(v.style.boxShadow=""),v.style.MozTransition="",v.style.WebkitTransition="",v.style.transition="",v.style.top="-10000px",z=!1,b&&b()},1e3*e+10)}var v,w,x,z,A,B,C,a=!0,b="18px",c="24px",d=600,e=.3,g="#57BF57",h="#E3B771",i="#E1715B",j="#4D82D6",k="#FFF",l="notie-alert-outer",m="notie-alert-inner",n="notie-alert-text",o=function(a){a.style.fontSize=window.innerWidth<=d?b:c},p=500,q=function(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,c||a.apply(e,f)},h=c&&!d;clearTimeout(d),d=setTimeout(g,b),h&&a.apply(e,f)}};return window.addEventListener("keydown",function(a){var b=13==a.which||13==a.keyCode,c=27==a.which||27==a.keyCode;z&&(b||c)&&(clearTimeout(A),clearTimeout(B),F())}),"undefined"==typeof Element.prototype.addEventListener&&(Element.prototype.addEventListener=Window.prototype.addEventListener=function(a,b){return a="on"+a,this.attachEvent(a,b)}),v=document.createElement("div"),v.id=l,v.style.position="fixed",v.style.top="0",v.style.left="0",v.style.zIndex="999999999",v.style.height="auto",v.style.width="100%",v.style.display="none",v.style.textAlign="center",v.style.cursor="default",v.style.MozTransition="",v.style.WebkitTransition="",v.style.transition="",v.style.cursor="pointer",alert_outer_onclick=function(){clearTimeout(A),clearTimeout(B),F()},w=document.createElement("div"),w.id=m,w.style.padding="20px",w.style.display="table-cell",w.style.verticalAlign="middle",v.appendChild(w),x=document.createElement("span"),x.id=n,x.style.color=k,x.style.fontSize=window.innerWidth<=d?b:c,window.addEventListener("resize",q(o.bind(null,x),p),!0),w.appendChild(x),document.body.appendChild(v),z=!1,C=0,{alert:D,alert_hide:F}}();`; document.head.appendChild(notie_script); } if (!g_is_moblie_env){ //电脑端 右键弹出 双击隐藏 window.onmousedown = function(e) { if (e.button == 2) {//右键 var clickedElement = e.target; if ((g_img_ele = GetQREle(clickedElement)) != null){ document.getElementById("identify_div").style.top = (e.pageY + 10) + "px"; document.getElementById("identify_div").style.left = (e.pageX) + "px"; document.getElementById("identify_div").style.display = 'block'; } } }; window.ondblclick = function(e) {//双击隐藏按钮 document.getElementById("identify_div").style.display = 'none'; } } else{ //移动端 监听长按事件 let time_out = 0, touch_time = 800; window.addEventListener("touchstart", function(e){ time_out = setTimeout(function(){ var touchedElement = e.target; if ((g_img_ele = GetQREle(touchedElement)) != null) { document.getElementById("identify_div").style.top = (e.touches[0].pageY - 50) + "px"; document.getElementById("identify_div").style.left = (e.touches[0].pageX + 20) + "px"; document.getElementById("identify_div").style.display = 'block'; } }, touch_time);//touch_time毫秒后弹出识别按钮 //触碰其他地方则隐藏按钮 if (e.target.id != 'identify_div'){ g_img_ele = null; document.getElementById("identify_div").style.display = 'none'; } }); window.addEventListener("touchmove", function(e){ // 如果触摸未达到 touch_time ms且开始移动,则清除计时器 clearTimeout(time_out); time_out = 0; }); window.addEventListener("touchend", function(e){ // 如果触摸未达到 touch_time ms且离开屏幕,则清除计时器 clearTimeout(time_out); time_out = 0; }); } //通过UA判断是否是移动端 function isPhone() { var info = navigator.userAgent; var isPhone = /mobile/i.test(info); return isPhone; } //从传入的元素中获取存有图片的元素 若没有则返回null function GetQREle(ele){ let ret_ele = null; if (ele.tagName == 'IMG'){ if (ele.src != null) ret_ele = ele; } else{ //遍历子元素看看是否有图片 var childs = ele.childNodes; if (childs.length >= 6) return ret_ele; for(var i = childs.length - 1; i >= 0; i--) { if (childs[i].tagName == 'IMG' && childs[i].src != null){ ret_ele = childs[i]; break; } } } return ret_ele; } //通过html2canvs截图并识别 function Html2CanvasAndIndentify(ele){ html2canvas(ele,{ useCORS: true, //开启跨域配置 allowTaint: false, //允许跨域图片 }).then(function(canvas) { var imgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); const code = jsQR(imgData.data, imgData.width, imgData.height, { inversionAttempts: "dontInvert", }); if (code == null) { notie.alert(3, '识别失败!', 3); }else { let display_text = code.data, ope_html = '
复制[placeholder_]关闭
'; if (g_is_moblie_env && (code.data.length >= 40)){//如果是移动端 且识别内容过长 则隐藏一部分内容 display_text = code.data.substr(0, 35) + '...'; } if (isMaybeURL(code.data)){ let jump_url = code.data; if (jump_url.substr(0, 4) != 'http') jump_url = 'https://' + jump_url; ope_html = ope_html.replace("[placeholder_]", '转到'); } else{ ope_html = ope_html.replace("[placeholder_]", '搜索'); } notie.alert(1, '识别到以下文本:
' + display_text + '
' + ope_html, 20); document.getElementById("copy_btn").onclick = OnClickedCopyBtn; } }).catch(function(err){ notie.alert(3, 'html2canvas出错:
' + err, 5); }); } //'识别二维码'按钮事件 function OnClickedIdentifyBtn(){ if ((typeof jsQR != 'function') || (typeof html2canvas != 'function')){ notie.alert(3, '外部JS脚本未加载成功!', 3); return; } if (g_img_ele == null){ notie.alert(2, '未选中任何图片', 2); } else { Html2CanvasAndIndentify(g_img_ele); } document.getElementById("identify_div").style.display = 'none'; } //'复制'按钮单击事件 function OnClickedCopyBtn(){ //GM_setClipboard(document.getElementById("all_text").innerText); navigator.clipboard.writeText(document.getElementById("all_text").innerText) notie.alert_hide(); notie.alert(1, '复制成功!', 2); } //判字符串是否可能为URL function isMaybeURL(str) { let is_maybe = false; if ((str.substr(0, 4) == 'http') || (str.substr(0, 3) == 'www') || (str.indexOf('.com') != -1 || str.indexOf('.cn') != -1 || str.indexOf('.org') != -1 || str.indexOf('.net') != -1) || (str.indexOf('.') != -1 && str.indexOf('/') != -1)) is_maybe = true; return is_maybe; } })();