// ==UserScript==
// @name 查找图片
// @namespace http://tampermonkey.net/
// @version 0.2
// @description 查找图片哦
// @author Chengguan
// @match https://*.huaban.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=huaban.com
// @grant GM_registerMenuCommand
// @run-at document-body
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const styleEle = document.createElement('style');
styleEle.innerText = `
.hb-img {outline: #F007 dashed 5px; outline-offset: -5px;}
.hb-imgTip { font-size: 11px; position: absolute; z-index: 999999; opacity: 0.8; color: #F00; background-color: #FFF; word-break: break-all; padding: 4px;}
.hb-imgTip:hover { z-index: 9999999999; opacity: 1;}
.hb-container { position: fixed; top: 50px; left: 50px; width: 320px; box-shadow: 0px 0px 20px 4px #686868; background-color: #FFF; z-index: 99999999999; padding: 10px; resize: both; overflow: auto; text-align: center; border: 1px solid #CCC; border-radius: 5px; user-select: none; }
.hb-container h1 { font-size: 22px; cursor: move; background-color: #efefef }
.hb-container h1:hover { background-color: #d9d9d9 }
.hb-container h2 { font-size: 18px; }
.hb-container label { padding: 8px; display: block; text-align: left;}
.hb-container label:hover { background-color: #efefef}
.hb-container label select { margin-left: 5px; padding: 3px; }
`;
document.head.appendChild(styleEle);
let allTips = [];
let allImages = [];
let allFileSizePromises = [];
function mark(
reg = /./,
{
reverseSelect = false,
showImageSrc = false,
showImageSize = false,
domainReplace = '',
urlReplaceInput = false,
urlReplaceFrom = '',
urlReplaceTo = '',
} = {},
) {
allTips.forEach((tip) => tip.remove());
allImages.forEach((img) => img.classList.remove('hb-img'));
allTips = [];
allImages = [];
allFileSizePromises = [];
[...document.querySelectorAll('img')].forEach((img) => {
console.count('Image');
const src =
(img.dataset.bakSrc || '') + (img.dataset.bakSrcset || '') ||
img.currentSrc;
let testValue = reg.test(src);
testValue = reverseSelect ? !testValue : testValue;
if (testValue) {
img.classList.add('hb-img');
// 替换域名 或 替换文件地址
if (domainReplace || urlReplaceInput) {
const urlObj = new URL(src);
const oldHost = urlObj.host;
// 备份
if (!img.getAttribute('data-bak-src')) {
img.src && img.setAttribute('data-bak-src', img.src);
img.srcset && img.setAttribute('data-bak-srcset', img.srcset);
}
let newSrc = img.getAttribute('data-bak-src') || img.src;
let newSrcset = img.getAttribute('data-bak-srcset') || img.srcset;
// 替换
if (domainReplace) {
newSrc = newSrc.replace(oldHost, domainReplace);
newSrcset = newSrcset.replace(oldHost, domainReplace);
}
if (urlReplaceInput) {
newSrc = newSrc.replace(urlReplaceFrom, urlReplaceTo);
newSrcset = newSrcset.replace(urlReplaceFrom, urlReplaceTo);
}
const srcAddRandom = (src) => {
const random = Math.random()
.toString(36)
.substring(2, 15)
.replace('.', '');
const srcParts = src.split(' ');
srcParts[0] =
srcParts[0] + (srcParts[0].includes('?') ? '&' : '?') + random;
return srcParts.join(' ');
};
newSrc && img.setAttribute('src', srcAddRandom(newSrc));
newSrcset && img.setAttribute('srcset', srcAddRandom(newSrcset));
} else if (img.getAttribute('data-bak-src')) {
// 恢复
img.dataset.bakSrc && (img.src = img.getAttribute('data-bak-src'));
img.dataset.bakSrcset &&
(img.srcset = img.getAttribute('data-bak-srcset'));
// // 清除
// img.removeAttribute('data-bak-src');
// img.removeAttribute('data-bak-srcset');
}
function imageCompleted() {
if (showImageSrc || showImageSize) {
const { tip, fileSize } = createImgTip(img, {
showImageSrc,
showImageSize,
});
document.scrollingElement.appendChild(tip);
allTips.push(tip);
allFileSizePromises.push(fileSize);
}
img.removeEventListener('onload', imageCompleted);
}
imageCompleted();
allImages.push(img);
}
});
return allImages;
}
function createImgTip(img, { showImageSrc, showImageSize }) {
let tip = document.createElement('p');
tip.className = 'hb-imgTip';
tip.style.top =
img.getBoundingClientRect().top +
document.scrollingElement.scrollTop +
'px';
tip.style.left =
img.getBoundingClientRect().left +
document.scrollingElement.scrollLeft +
'px';
tip.style.maxWidth =
Math.max(img.getBoundingClientRect().width, 200) + 'px';
let fileSize;
if (showImageSrc) {
tip.innerText = img.currentSrc.startsWith('data:image')
? 'data:image/ xxxx'
: img.currentSrc + '\n';
}
if (showImageSize) {
let currentSrc = img.currentSrc.startsWith('data:image')
? ''
: img.currentSrc;
if (currentSrc) {
fileSize = getImageSize(currentSrc).then((result) => {
let size = (result / 1024).toFixed(2);
tip.innerText += ' 尺寸:' + size + 'KB';
return size;
});
}
}
return { tip, fileSize };
}
// 拖拽元素
function dragableElement({ element, trigger }) {
trigger = trigger || element;
let sx = 0;
let sy = 0;
trigger.addEventListener('mousedown', (e) => {
let x = parseInt(window.getComputedStyle(element).left, 10);
let y = parseInt(window.getComputedStyle(element).top, 10);
sx = e.clientX;
sy = e.clientY;
const moveHandler = (e) => {
console.info(e.clientX, e.clientY);
console.info(e.clientX - sx, e.clientY - sy);
element.style.left = x + (e.clientX - sx) + 'px';
element.style.top = y + (e.clientY - sy) + 'px';
};
const upHandler = () => {
document.body.removeEventListener('mousemove', moveHandler);
document.body.removeEventListener('mouseup', upHandler);
};
document.body.addEventListener('mousemove', moveHandler);
document.body.addEventListener('mouseup', upHandler);
});
}
// 获取文件大小
function getImageSize(url) {
return fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.headers.get('content-length');
})
.then((contentLength) => {
// console.log('远程图片大小为: ' + contentLength + ' 字节');
return contentLength;
})
.catch((error) => {
console.error(
'There has been a problem with your fetch operation:',
error,
);
});
}
GM_registerMenuCommand(
'查找图片',
() => {
// 容器
const container = document.createElement('div');
container.className = 'hb-container';
document.body.appendChild(container);
// 标题
const titleEle = document.createElement('h1');
titleEle.innerText = '查找图片';
container.appendChild(titleEle);
dragableElement({ element: container, trigger: titleEle });
// 匹配图片数量
const matchCount = document.createElement('h2');
container.appendChild(matchCount);
// 匹配正则
const matchRegLabel = document.createElement('label');
matchRegLabel.innerText = '匹配图片:';
container.appendChild(matchRegLabel);
const input = document.createElement('input');
matchRegLabel.appendChild(input);
// 显示图片地址
const showSrcLabel = document.createElement('label');
showSrcLabel.innerText = ' 显示图片地址 ';
container.appendChild(showSrcLabel);
const showSrcInput = document.createElement('input');
showSrcInput.setAttribute('type', 'checkbox');
showSrcLabel.prepend(showSrcInput);
// 显示图片文件大小
const showFileSizeLabel = document.createElement('label');
showFileSizeLabel.innerText = ' 显示图片大小';
container.appendChild(showFileSizeLabel);
const showFileSizeInput = document.createElement('input');
showFileSizeInput.setAttribute('type', 'checkbox');
// showFileSizeInput.setAttribute('checked', true);
showFileSizeLabel.prepend(showFileSizeInput);
// 反选图片
const reverseLabel = document.createElement('label');
reverseLabel.innerText = ' 反选';
container.appendChild(reverseLabel);
const reverseSelect = document.createElement('input');
reverseSelect.setAttribute('type', 'checkbox');
reverseLabel.prepend(reverseSelect);
// 域名替换
const domainReplaceLabel = document.createElement('label');
domainReplaceLabel.innerText = ' 域名替换';
container.appendChild(domainReplaceLabel);
const domainReplaceInput = document.createElement('input');
domainReplaceInput.setAttribute('type', 'checkbox');
domainReplaceLabel.prepend(domainReplaceInput);
const domainReplaceSelect = document.createElement('select');
domainReplaceSelect.innerHTML = `
<option value=''>默认</option>
<option value='gd-hbimg.huaban.com'>gd-hbimg.huaban.com</option>
<option value='gd-hbimg.huabanimg.com'>gd-hbimg.huabanimg.com</option>
`;
domainReplaceLabel.appendChild(domainReplaceSelect);
// 图片URL替换
const urlReplaceLabel = document.createElement('label');
urlReplaceLabel.innerText = ' 图片URL替换 ';
container.appendChild(urlReplaceLabel);
const urlReplaceInput = document.createElement('input');
urlReplaceInput.setAttribute('type', 'checkbox');
urlReplaceLabel.prepend(urlReplaceInput);
const urlReplaceFromInput = document.createElement('input');
urlReplaceLabel.appendChild(urlReplaceFromInput);
const urlReplaceToInput = document.createElement('input');
urlReplaceToInput.style.width = '100%';
urlReplaceLabel.appendChild(urlReplaceToInput);
function render() {
try {
const reg = new RegExp(input.value);
mark(reg, {
reverseSelect: reverseSelect.checked,
showImageSrc: showSrcInput.checked,
showImageSize: showFileSizeInput.checked,
domainReplace: domainReplaceInput.checked
? domainReplaceSelect.value
: '',
urlReplaceInput: urlReplaceInput.checked,
urlReplaceFrom: urlReplaceFromInput.value,
urlReplaceTo: urlReplaceToInput.value,
});
matchCount.innerText = `匹配文件数:${allImages.length}`;
Promise.all(allFileSizePromises).then((allSizes) => {
const result = allSizes.reduce((total, size) => {
return total + Number(size);
}, 0);
matchCount.innerText += `,总大小:${result.toFixed(2)}KB`;
});
} catch (e) {
// nothing;
}
}
input.addEventListener('input', render);
container.addEventListener('click', (e) => {
if (e.target === container) {
render();
}
});
showSrcInput.addEventListener('change', render);
showFileSizeInput.addEventListener('change', render);
reverseSelect.addEventListener('change', render);
domainReplaceInput.addEventListener('change', render);
domainReplaceSelect.addEventListener('change', render);
urlReplaceInput.addEventListener('change', render);
render();
},
's',
);
})();