您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Save a click or two by viewing Dropbox images directly within Picarto's "leaving" pages.
当前为
// ==UserScript== // @name Dropbox image viewer in Picarto - by StevenRoy // @namespace http://michrev.com/ // @description Save a click or two by viewing Dropbox images directly within Picarto's "leaving" pages. // @include https://www.dropbox.com/* // @include https://dropbox.com/* // @include https://www.picarto.tv/site/referrer* // @include https://picarto.tv/site/referrer* // @version 1.12 // @grant none // ==/UserScript== "use strict"; // _____________ __ __ // / ___________/ / \,-' / // / /__ ___ / /\,-/ / // \___ \ / __\ / / / / //______/ / / / / / / / StevenRoy was here //_______/ /_/ /_/ /_/ 02022.09.21 // when a is 200, returns true when b is >=197 and <=204 // when a is 1000, returns true when b is >=981 and <=1020 // sensitivity is proportional to the sum of the numbers being compared // (Can also be adjusted by changing the 100 constant but I like it where it is now.) function ratherclose(a,b) { return Math.abs(a-b)*100<(a+b); } var img,mcx,mcy,ww,wh,dw,dh,dx,dy,isl,imgfit=0; // window and image size function resized() { if (!img) { return; } // TSNH - throw()? alert()? var de=document.documentElement; if (window.innerWidth) { // Preferred in FF because it doesn't shrink when a scrollbar is present. ww=window.innerWidth; wh=window.innerHeight; } else { if (de && de.clientWidth) { // Also exists in FF; this one excludes scrollbar if present. ww=de.clientWidth; // (Though that's kinda moot when we're using overflow:hidden) wh=de.clientHeight; } else { return false; // TSNH? Am I forgetting anything? } } // if (mcx===undefined && mcy===undefined) { mcx=ww>>1; mcy=wh>>1; } // until we get mouse coords var iw=img.w,ih=img.h; // We use these a lot. // var war=ww/wh; // window aspect ratio (1=square, >1=wide) var iar=iw/ih; // image aspect ratio (1920x800 -> 12/5 which is 2.4) var wscw=wh*iar; // resulting width from scaling window height to image's AR. // image smaller than window: original size (centered), or enlarged to fit (letterboxed) // image larger than window: original size (pan), or shrunk to fit (letterboxed) // These are actually pretty much the same... except pan is only enabled in 1/4 cases // But there's a trickier case: Image smaller in one dimension but larger in the other. // I could give it two zoom states but neither is original-size ... or should I do the opposite? // Let's just always assume three zoom-states: original (iw,ih), fit-x (ww,ww/iar), and fit-y (wh*iar,wh) // ...And then sort 'em. But first eliminate any that are nearly identical. isl=[iw]; // image size list, start with original image size var am=ratherclose(ww,wscw); // aspect ratio match between image and window? if (!ratherclose(iw,ww)) { // but not actual size match. if (am) { console.log("Aspect ratio match"); // isl.push(Math.floor(ww+wh*iar+1)>>1); // use average for near-match (This is actually bad.) // Assuming a very-near-but-not-perfect match: Which size is further from iw? Let's use that one. isl.push(Math.abs(iw-ww) > Math.abs(iw-wscw) ? ww : wscw); } else { isl.push(ww); } } if (!am && !ratherclose(iw,wscw)) { isl.push(wscw); } if (isl.length>1) { if (imgfit>=isl.length) { imgfit=isl.length-1; } // for those times when a size vanishes isl.sort((a,b) => a-b); img.style.cursor=(imgfit==isl.length-1)?"zoom-out":"zoom-in"; // How to affect blank space around img? (But do we want that?) } else { imgfit=0; img.style.cursor="default"; } dw=isl[imgfit]; dh=(dw==iw)?ih:(dw/iar); // dh=dw/(iw/ih) ... dh/ih=dw/iw // panned(); // setting image size is done in here too now. Except it's now part of the animation process. } function panned() { // Animated response to Mouse movement with requestAnimationFrame() if (mcx!==undefined && dw>ww) { dx=mcx*(ww-dw)/ww; } else { dx=(ww-dw)/2; } if (mcy!==undefined && dh>wh) { dy=mcy*(wh-dh)/wh; } else { dy=(wh-dh)/2; } var ics=img.style; ics.width=Math.round(dw)+"px"; // TODO: These can be animated for awesomer zooming. (Except for large images that crash FF!!!) ics.height=Math.round(dh)+"px"; ics.left=Math.round(dx)+"px"; // always negative when panning, otherwise positive and centered ics.top=Math.round(dy)+"px"; } function animate() { panned(); // var c=coordstoimg(); requestAnimationFrame(animate); // Uh oh, now we're doing it! } // ** ** ** EVENTS function shutup(e) { if (!e) { e=window.event; if (!e) { return false; } } e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); // For when "return true" just isn't good enough? e.preventDefault(); // And I mean it! return e; } function smother(evt) { shutup(evt); return false; } /* from AwShirt JS: (Thanks Jackbox!) var a=o.canvas.getBoundingClientRect(), e={x:t.clientX-a.left,y:t.clientY-a.top}; e.x=e.x*(o.canvas.width/parseInt(o.canvas.style.width,10)), e.y=e.y*(o.canvas.height/parseInt(o.canvas.style.height,10)), o[t.type](e) Note: image width/height is fixed and in img.w/h ...values set in style are dw/dh and ratios are the same - just divide img.w/dw once In case we forget any of these, getBoundingClientRect() also gives us width and height (from style) NOTE: top/left values in the DOMRect are relative to the viewport and change if the document is scrolled! Also: We don't need any of this because we set all those values already! (And we don't even have scrollbars.) */ function mousecoords(e) { // event if ("pageX" in e && "pageY" in e) { mcx = e.pageX; mcy = e.pageY; } else { // We want coords relative to top (origin) of document, this should do it: mcx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; mcy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; } // x -= c.offsetLeft; // y -= c.offsetTop; // return [x,y]; } function smdown(evt) { // var e=shutup(evt); imgfit++; if (imgfit>=isl.length) { imgfit=0; } // Select next (or first) size resized(); smmove(evt); // trigger move() after coordinates change return false; // Does this value do anything? } /* ** ** Not currently used: function smup(evt) { var e=evt||window.event; // return false; } ** ** */ function smmove(evt) { var e=shutup(evt); mousecoords(e); // panned(); return false; } function makezoomableimage(i) { img=i; img.w=img.naturalWidth; img.h=img.naturalHeight; window.onresize=resized; resized(); // i.onmousedown=smdown; i.onmousedown=smother; i.onmouseup=smother; // not used! window.onmousemove=smmove; // i.onclick=smother; // none of these used either i.onclick=smdown; // alternative strategy, maybe less good, maybe not? i.ondblclick=smother; // i.oncontextmenu=smother; animate(); // This starts the maaaaagic! img.style.position="fixed"; img.style.maxWidth="unset"; // Leave it to Picarto to screw with zooms... return i; } const c64pal="000 fff c05 6ef c5d 6c5 42b fe7 c84 641 f79 555 888 cfa a9f ccc"; // That's my c64 palette. I'm going for a balance of authentic and vivid. var waitindicator=function(){ var waittimer,wc=4,wde,wrefc=0; return function(){ if(!wde) { document.body.appendChild(wde=Object.assign(document.createElement("div"),{ innerHTML:'W<span>a</span><span>i</span><span>t</span><span>.</span><span>.</span><span>.</span>', // id:'loading', style:"z-index:90999;box-sizing:border-box;font-size:20pt;line-height:18pt;font-family:" /* 'Roboto', */ +"'Andale Mono',monospace;"+ "position:fixed;height:30px;width:160px;top:50%;left:50%;text-align:center;"+ "margin:-15px 0 0 -80px;background:#000;color:#fff" })); } if (wde && !waittimer) { waittimer=setInterval(function(){ if (!wde) { return clearInterval(waittimer); } // never underestimate the capacity of browsers to screw up wc=(wc+4)&60; var wcc=wc; wde.style.color="#"+c64pal.substr(wc,3); // A very specific set of colors... Array.prototype.forEach.call(wde.children,(e)=>{ wcc=wcc+4&60; e.style.color="#"+c64pal.substr(wcc,3); }); },150); } wrefc++; return function(){ if (wrefc>0) { wrefc--; } setTimeout(()=>{ if (wrefc==0 && wde) { wde.parentNode.removeChild(wde); wde=false; } },250); // in case of sequential busy-states, delay vanish of busy indicator }; }; }(); // So much gutting of previous code because we don't // need -any- of the canvas functions... function loadimage(src,cb) { var wi=waitindicator(); var ix=document.createElement("img"); // ix=new Image(); ix.onload=function() { wi(); cb(ix); // pass img to callback } ix.src=src; } // that basically replaces an entire image manipulation library! // (Although replacing <canvas> with <image> does seem to make this perform worse in FF52 // if my awesome animation function is used... I just won't use it then. Problem solved.) // Freaking dummkopfs Picarto seems to like to lazy-load all its actual page content, // meaning things we want to replace won't exist at this function's execute-time. // Of course there's a stupid workaround... function itsapicartopage(addr){ // addr will look like: "https:// www.dropbox.com/s/y88o006k1ol8ryj/alkalithemorningafter.png?dl=0" var m=parsedbaddr(addr); if (m) { var keeplink=document.links; if (keeplink && keeplink[0] && keeplink[0].href==addr) { keeplink=keeplink[0].parentNode; loadimage(m,(ix)=>{ var mb=document.getElementById("main-container"); // within div#root within body if (mb && mb.children) mb=mb.childNodes[0]; console.log(mb,keeplink); if (mb && keeplink) { mb.innerHTML=''; mb.style="position:fixed; overflow:hidden; min-height:100vh; height:100vh; width:100%; padding:0; margin:0; display:block"; keeplink.style="position:fixed;right:0;bottom:0;margin:20px"; mb.appendChild(makezoomableimage(ix)); mb.appendChild(keeplink); var d1=document.createElement("div"); // additional UI element, mainly for aesthetics! d1.className=keeplink.className; // This may vary! d1.style="position:fixed;left:0;bottom:0;margin:20px"; keeplink.style.backgroundColor=d1.style.backgroundColor=getComputedStyle(document.body).backgroundColor; d1.innerHTML=img.w+" x "+img.h; mb.appendChild(d1); } else console.log("Fail"); }); } else { console.log("Retrying"); setTimeout(itsapicartopage,200,addr); } } } function parsedbaddr(a){ var m=a.match(/\/\/(?:www\.)?dropbox\.com\/.+\/[^/?.]*\.(jpg|jpeg|png|gif|webp)(\?dl=0)?$/); if (m && m.length && m[1]) { // It's a valid address... if (m[2] == '?dl=0') a=a.replace(/\?dl=0/,''); else if (m[2]) throw ("TSNH: Weird query in db addr"); return a+'?dl=1'; // Functioning link to the image itself } return false; } var l=top.location.href; var m=l.match(/\/\/(?:www\.)?picarto\.tv\/.+?go=(http(?:s)?%3A%2F%2F[0-9A-Za-z%.]+)/); if (m && m.length && m[1]) itsapicartopage(decodeURIComponent(m[1])); // (Also, the Dropbox site is broken in Firefox 52 but we can detect that // and force images to appear there anyway. This one's for the WinXP users. Shrug.) else if (m=parsedbaddr(l)) { // If we're on the dropbox site... var bv=navigator.userAgent.match(/Firefox\/([0-9]+)/); // but using a browser that db WON'T WORK ON if (bv && bv[1] && (bv[1]-0)<=52) { var i0=document.createElement("img"); // Just dump the image i0.src=m; document.body.appendChild(i0); } }