1212// @description:ja 画像を強力に閲覧できるツール。ポップアップ表示、拡大・縮小、回転、一括保存などの機能を自動で実行できます
1313// @description:pt-BR Poderosa ferramenta de visualização de imagens on-line, que pode pop-up/dimensionar/girar/salvar em lote imagens automaticamente
1414// @description:ru Мощный онлайн-инструмент для просмотра изображений, который может автоматически отображать/масштабировать/вращать/пакетно сохранять изображения
15- // @version 2025.9.27.2
15+ // @version 2025.9.30.1
1616// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAV1BMVEUAAAD////29vbKysoqKioiIiKysrKhoaGTk5N9fX3z8/Pv7+/r6+vk5OTb29vOzs6Ojo5UVFQzMzMZGRkREREMDAy4uLisrKylpaV4eHhkZGRPT08/Pz/IfxjQAAAAgklEQVQoz53RRw7DIBBAUb5pxr2m3/+ckfDImwyJlL9DDzQgDIUMRu1vWOxTBdeM+onApENF0qHjpkOk2VTwLVEF40Kbfj1wK8AVu2pQA1aBBYDHJ1wy9Cf4cXD5chzNAvsAnc8TjoLAhIzsBao9w1rlVTIvkOYMd9nm6xPi168t9AYkbANdajpjcwAAAABJRU5ErkJggg==
1717// @namespace https://github.com/hoothin/UserScripts
1818// @homepage https://github.com/hoothin/UserScripts/tree/master/Picviewer%20CE%2B
4646// @grant GM.notification
4747// @grant unsafeWindow
4848// @require https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/GM_config%20CN.js?v=23710
49- // @require https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_rules.js?v=1666736
49+ // @require https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_rules.js?v=1669339
5050// @require https://hoothin.github.io/UserScripts/Picviewer%20CE%2B/pvcep_lang.js?v=1653424
5151// @match *://*/*
5252// @exclude http://www.toodledo.com/tasks/*
@@ -12675,7 +12675,7 @@ ImgOps | https://imgops.com/#b#`;
1267512675 }
1267612676 ];
1267712677
12678- const imageReg = /^\s*(https?|ftp):\/\/.*?\/[^\.]*\.(avi|avif|avifs|bmp|gif|gifv|ico|jfif|jpe|jpeg|jpg|jif|jfi|a?png|svgz?|webp|xbm|dib|divx|3gpp|m3u|m4v|mkv|mp4|mpe?g|ogv|webm|flv|flac|m4a|m4b|mpa|mp3|aac|cda|oga|ogg|opus|wma|wav)(&|\?|#|\/?$|\s)/i;
12678+ const imageReg = /^\s*(https?|ftp):\/\/.*?\/[^\.:: ]*\.(avi|avif|avifs|bmp|gif|gifv|ico|jfif|jpe|jpeg|jpg|jif|jfi|a?png|svgz?|webp|xbm|dib|divx|3gpp|m3u|m4v|mkv|mp4|mpe?g|ogv|webm|flv|flac|m4a|m4b|mpa|mp3|aac|cda|oga|ogg|opus|wma|wav)(&|\?|#|\/?$|\s)/i;
1267912679
1268012680 const ruleImportHost = ["greasyfork.org", "github.com", "reddit.com"];
1268112681 const ruleImportUrlReg = /greasyfork\.org\/.*scripts\/24204(\-[^\/]*)?(\/discussions|\/?$|\/feedback)|github\.com\/hoothin\/UserScripts\/(tree\/master\/Picviewer%20CE%2B|issues|discussions)|\.reddit\.com\/r\/PicviewerCE/i;
@@ -13451,6 +13451,7 @@ ImgOps | https://imgops.com/#b#`;
1345113451
1345213452
1345313453
13454+ var errorList = {}, errorBlobList = {};
1345413455 var imgReady=function(img,opts){
1345513456
1345613457 if(/NodeList|HTMLCollection/.test(Object.prototype.toString.call(img)) || Array.isArray(img)){
@@ -13596,6 +13597,42 @@ ImgOps | https://imgops.com/#b#`;
1359613597
1359713598 function errorHandler(e){
1359813599 if(aborted)return;
13600+
13601+ if (!errorBlobList[img.src] && !/^blob:/.test(img.src)) {
13602+ errorList[img.src]=true;
13603+ _GM_xmlhttpRequest({
13604+ method: 'GET',
13605+ url: img.src,
13606+ responseType: 'blob',
13607+ onload: function(response) {
13608+ const blobUrl = URL.createObjectURL(response.response);
13609+ const releaseBlob = () => URL.revokeObjectURL(blobUrl);
13610+ window.addEventListener('beforeunload', releaseBlob);
13611+
13612+ let orgSrc = img.src;
13613+ img.src = blobUrl;
13614+ setTimeout(() => {
13615+ if (aborted) return;
13616+ if (typeof img.width == 'number' && img.width && img.height) {
13617+ go('load', {
13618+ type:'load',
13619+ target: img,
13620+ });
13621+ } else {
13622+ errorBlobList[orgSrc] = true;
13623+ go('error',e);
13624+ }
13625+ }, 0);
13626+ },
13627+ onerror: function() {
13628+ if (aborted) return;
13629+ errorBlobList[orgSrc] = true;
13630+ go('error',e);
13631+ }
13632+ });
13633+ return;
13634+ }
13635+
1359913636 go('error',e);
1360013637 };
1360113638
@@ -13616,6 +13653,7 @@ ImgOps | https://imgops.com/#b#`;
1361613653 });
1361713654 },0);
1361813655 }else{//这不是图片.opera会识别错误.
13656+ errorList[img.src]=true;
1361913657 setTimeout(function(){
1362013658 if(aborted)return;
1362113659 go('error',{
@@ -13646,6 +13684,12 @@ ImgOps | https://imgops.com/#b#`;
1364613684 iRInterval=setInterval(checkReady,66);
1364713685 };
1364813686 };
13687+ if (errorList[img.src]) {
13688+ go('error',{
13689+ type:'error',
13690+ target:img,
13691+ });
13692+ }
1364913693
1365013694 return ret;
1365113695 };
@@ -14947,7 +14991,7 @@ ImgOps | https://imgops.com/#b#`;
1494714991 self.img.style.display = "";
1494814992 }
1494914993 });
14950- },
14994+ }
1495114995 });
1495214996 } else {
1495314997 let target = self.img;
@@ -16345,36 +16389,8 @@ ImgOps | https://imgops.com/#b#`;
1634516389 popupImgWin(this);
1634616390 },
1634716391 error:function(e){
16348- if (/^blob:/.test(imgSrc)) {
16349- self.showTips("");
16350- loadError();
16351- } else if (mode == "image" || mode == "") {
16352- _GM_xmlhttpRequest({
16353- method: 'GET',
16354- url: imgSrc,
16355- responseType: 'blob',
16356- onload: function(response) {
16357- if (response.response && response.response.type == "text/html") {
16358- self.showTips("");
16359- loadError();
16360- return;
16361- }
16362- const blobUrl = URL.createObjectURL(response.response);
16363- self.showTips("");
16364- let img = document.createElement("img");
16365- popupImgWin(img);
16366- const releaseBlob = () => URL.revokeObjectURL(blobUrl);
16367- window.addEventListener('beforeunload', releaseBlob);
16368- },
16369- onerror: function() {
16370- self.showTips("");
16371- loadError();
16372- }
16373- });
16374- } else {
16375- self.showTips("");
16376- loadError();
16377- }
16392+ self.showTips("");
16393+ loadError();
1637816394 }
1637916395 });
1638016396 }
@@ -16807,42 +16823,9 @@ ImgOps | https://imgops.com/#b#`;
1680716823
1680816824 if(e.type=='error'){
1680916825 if (loadingIndicator && loadingIndicator.style) loadingIndicator.style.display='';
16810- if (/^blob:/.test(src)) {
16811- self.errorSpan=ele;
16812- if(preImgR)preImgR.abort();
16813- self.loadImg(img, ele,true);
16814- } else {
16815- _GM_xmlhttpRequest({
16816- method: 'GET',
16817- url: src,
16818- responseType: 'blob',
16819- onload: function(response) {
16820- if (response.response && response.response.type == "text/html") {
16821- self.errorSpan=ele;
16822- if(preImgR)preImgR.abort();
16823- self.loadImg(img, ele, true);
16824- return;
16825- }
16826- const blobUrl = URL.createObjectURL(response.response);
16827- self.slideShow.run('loadEnd');
16828- let img = document.createElement("img");
16829- img.src = blobUrl;
16830- imgReady(blobUrl, {
16831- ready:function(){
16832- self.loadImg(img, ele, false);
16833- self.slideShow.run('loadEnd');
16834- }
16835- });
16836- const releaseBlob = () => URL.revokeObjectURL(blobUrl);
16837- window.addEventListener('beforeunload', releaseBlob);
16838- },
16839- onerror: function() {
16840- self.errorSpan=ele;
16841- if(preImgR)preImgR.abort();
16842- self.loadImg(img, ele, true);
16843- }
16844- });
16845- }
16826+ self.errorSpan=ele;
16827+ if(preImgR)preImgR.abort();
16828+ self.loadImg(img, ele,true);
1684616829 };
1684716830
1684816831 self.slideShow.run('loadEnd');
@@ -23553,44 +23536,16 @@ ImgOps | https://imgops.com/#b#`;
2355323536
2355423537 var opts = {
2355523538 error: function(e) {
23556- if (/^blob:/.test(imgSrc)) {
23557- if (Array.isArray(imgSrcs)) {
23558- var src = imgSrcs.shift();
23559- if (src) {
23560- self.loadImg(src, imgSrcs, nextFun);
23561- return;
23562- }
23539+ if (Array.isArray(imgSrcs)) {
23540+ var src = imgSrcs.shift();
23541+ if (src) {
23542+ self.loadImg(src, imgSrcs, nextFun);
23543+ return;
2356323544 }
23564- } else if (mode == "image" || mode == "") {
23565- _GM_xmlhttpRequest({
23566- method: 'GET',
23567- url: media.src,
23568- responseType: 'blob',
23569- onload: function(response) {
23570- const blobUrl = URL.createObjectURL(response.response);
23571- self.loadImg(blobUrl, imgSrcs, nextFun);
23572- const releaseBlob = () => URL.revokeObjectURL(blobUrl);
23573- window.addEventListener('beforeunload', releaseBlob);
23574- },
23575- onerror: function() {
23576- if (Array.isArray(imgSrcs)) {
23577- var src = imgSrcs.shift();
23578- if (src) {
23579- self.loadImg(src, imgSrcs, nextFun);
23580- return;
23581- }
23582- } else {
23583- self.error('', this, e);
23584- }
23585- }
23586- });
23587- return;
2358823545 } else {
23589- self.error('', this, e);
23546+ if(nextFun) nextFun();
23547+ else self.error('', this, e);
2359023548 }
23591-
23592- if(nextFun) nextFun();
23593- else self.error('', this, e);
2359423549 },
2359523550 };
2359623551
@@ -25278,7 +25233,7 @@ ImgOps | https://imgops.com/#b#`;
2527825233 }, prefs.floatBar.showDelay || 0)
2527925234 }
2528025235
25281- function checkFloatBar(_target, type, canPreview, clientX, clientY, altKey) {
25236+ function checkFloatBar(_target, type, canPreview, clientX, clientY, altKey, composedTarget ) {
2528225237 let target = _target;
2528325238 if (!target || target.id == "pv-float-bar-container" ||
2528425239 (target.parentNode && (target.parentNode.id == "icons" || target.parentNode.className == "search-jumper-btn")) ||
@@ -25335,7 +25290,7 @@ ImgOps | https://imgops.com/#b#`;
2533525290 let bgReg = /.*url\(\s*["']?([^ad\s'"#].+?)["']?\s*\)([^'"]|$)/i;
2533625291 let bgRegLong = /^\s*url\(\s*["']?([^ad\s'"#].+?)["']?\s*\)([^'"]|$)/i;
2533725292 let result, targetBg, hasBg = node => {
25338- if(node.nodeName.toUpperCase() == "HTML" || node.nodeName == "#document"){
25293+ if(node.nodeName.toUpperCase() == "HTML" || node.nodeName == "#document" || node.nodeType != 1 ){
2533925294 return false;
2534025295 }
2534125296 if (node.clientWidth <= prefs.floatBar.minSizeLimit.w || node.clientHeight <= prefs.floatBar.minSizeLimit.h) {
@@ -25503,17 +25458,18 @@ ImgOps | https://imgops.com/#b#`;
2550325458
2550425459 return;
2550525460 }
25461+ if (composedTarget) target = composedTarget;
2550625462 let found = false;
2550725463 if (target.nodeName.toUpperCase() == "AREA") target = target.parentNode;
2550825464 var broEle, broImg;
25509- if (target.nodeName.toUpperCase() != 'A' && target. parentNode && target.parentNode.style && !/flex|grid|table/.test(getComputedStyle(target.parentNode).display)) {
25465+ if (target.parentNode && target.parentNode.style && !/flex|grid|table/.test(getComputedStyle(target.parentNode).display)) {
2551025466 broEle = target.previousElementSibling;
2551125467 while (broEle) {
2551225468 if (broEle.offsetWidth && broEle.offsetWidth > target.offsetWidth>>1) {
2551325469 if (broEle.nodeName == "IMG") broImg = broEle;
2551425470 else if (broEle.nodeName == "PICTURE") broImg = broEle.querySelector("img");
2551525471 }
25516- if (getComputedStyle(broEle).position !== "absolute") break;
25472+ if (broEle.offsetWidth && broEle.offsetHeight && getComputedStyle(broEle).position !== "absolute") break;
2551725473 broEle = broEle.previousElementSibling;
2551825474 }
2551925475 if (broEle == target) broEle = null;
@@ -25861,7 +25817,7 @@ ImgOps | https://imgops.com/#b#`;
2586125817 }
2586225818 }
2586325819
25864- var checkFloatBarTimer, initMouse = false, lastEvent;
25820+ var checkFloatBarTimer, initMouse = false, lastEvent, composedTarget ;
2586525821 function globalMouseoverHandler(e) {
2586625822 if (galleryMode) return;//库模式全屏中......
2586725823 if (e.target == ImgWindowC.overlayer) return;
@@ -25871,6 +25827,8 @@ ImgOps | https://imgops.com/#b#`;
2587125827 e = lastEvent;
2587225828 } else {
2587325829 lastEvent = e;
25830+ let path = e && e.composedPath && e.composedPath();
25831+ composedTarget = path && path[0];
2587425832 }
2587525833 if (e.type == "mousemove") {
2587625834 if (!initMouse) {
@@ -25900,7 +25858,7 @@ ImgOps | https://imgops.com/#b#`;
2590025858 checkFloatBarTimer = setTimeout(function() {
2590125859 if (!e || !e.target || !e.target.parentNode) return;
2590225860 if (gallery && gallery.shown) return;
25903- checkFloatBar(e.target, e.type, canPreview, e.clientX, e.clientY, e.altKey);
25861+ checkFloatBar(e.target, e.type, canPreview, e.clientX, e.clientY, e.altKey, composedTarget );
2590425862 }, 50);
2590525863 }
2590625864
0 commit comments