// ==UserScript==
// @name 图片预览
// @version 3.2.1
// @description 平庸与极限,究竟哪种是你的风格?随心所欲,不受拘束,此时此刻突破极限。
// @author hiisme
// @match https://image.baidu.com/*
// @match https://unsplash.com/*
// @match https://www.google.com/*
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_notification
// @namespace https://greasyfork.org/users/217852
// ==/UserScript==
(function() {
'use strict';
// Retrieve settings from storage
let shortcut = GM_getValue('shortcut', 'Ctrl+Shift+I');
let windowWidth = GM_getValue('windowWidth', screen.width);
let windowHeight = GM_getValue('windowHeight', screen.height);
let adaptiveWindowSize = GM_getValue('adaptiveWindowSize', true);
let enableAcrylicBlur = GM_getValue('enableAcrylicBlur', true);
let mode = GM_getValue('mode', 'Extreme');
// Util to toggle settings
function toggleSetting(settingKey, settingName) {
const currentValue = GM_getValue(settingKey, true);
const newValue = !currentValue;
GM_setValue(settingKey, newValue);
GM_notification({
text: `${settingName}现已${newValue ? '启用' : '禁用'}`,
title: '图片浏览',
timeout: 3000
});
}
function toggleAdaptiveWindowSize() {
toggleSetting('adaptiveWindowSize', '智能自适应窗口大小');
}
function toggleAcrylicBlur() {
toggleSetting('enableAcrylicBlur', 'Acrylic模糊');
}
function toggleMode() {
mode = (mode === 'Extreme') ? 'Normal' : 'Extreme';
GM_setValue('mode', mode);
GM_notification({
text: `模式已切换为: ${mode === 'Extreme' ? '极限模式' : '普通模式'}`,
title: '图片浏览',
timeout: 3000
});
}
async function setShortcut() {
const newShortcut = prompt('输入新的快捷键组合以切换模式 (如: Ctrl+Shift+I):', shortcut);
if (newShortcut) {
shortcut = newShortcut;
GM_setValue('shortcut', shortcut);
GM_notification({
text: `快捷键已设置为: ${shortcut}`,
title: '图片浏览',
timeout: 3000
});
}
}
async function setWindowSize() {
const newWidth = prompt('输入新窗口宽度 (像素):', windowWidth);
const newHeight = prompt('输入新窗口高度 (像素):', windowHeight);
if (newWidth && newHeight) {
windowWidth = parseInt(newWidth, 10);
windowHeight = parseInt(newHeight, 10);
GM_setValue('windowWidth', windowWidth);
GM_setValue('windowHeight', windowHeight);
GM_notification({
text: `窗口大小设置为: ${windowWidth}x${windowHeight}`,
title: '图片浏览',
timeout: 3000
});
}
}
// Register Menu Commands
GM_registerMenuCommand("设定极限平庸的按钮", setShortcut);
GM_registerMenuCommand("一成不变的画布大小", setWindowSize);
GM_registerMenuCommand("自由的天地不受拘束", toggleAdaptiveWindowSize);
GM_registerMenuCommand("模糊画布之下的风景", toggleAcrylicBlur);
GM_registerMenuCommand("极限与平庸不可兼得", toggleMode);
function parseShortcut(shortcut, event) {
const keys = shortcut.toLowerCase().split('+').map(k => k.trim());
return keys.includes(event.key.toLowerCase()) &&
(keys.includes('ctrl') === event.ctrlKey) &&
(keys.includes('shift') === event.shiftKey) &&
(keys.includes('alt') === event.altKey) &&
(keys.includes('meta') || keys.includes('cmd') || keys.includes('command') === event.metaKey);
}
function onKeyDown(event) {
if (parseShortcut(shortcut, event)) {
event.preventDefault();
toggleMode(); // Toggle mode on shortcut
}
}
document.addEventListener('keydown', onKeyDown);
function calculateWindowSize(imageWidth, imageHeight) {
const screenWidth = screen.width;
const screenHeight = screen.height;
const minWidth = screenWidth * 0.2;
const minHeight = screenHeight * 0.2;
const maxWidth = screenWidth * 0.9;
const maxHeight = screenHeight * 0.9;
const aspectRatio = imageWidth / imageHeight;
let width = Math.max(minWidth, Math.min(imageWidth, maxWidth));
let height = width / aspectRatio;
if (height > maxHeight) {
height = maxHeight;
width = height * aspectRatio;
}
return { width, height };
}
function createLoadingSpinner() {
const spinner = document.createElement('div');
spinner.style.position = 'fixed';
spinner.style.top = '50%';
spinner.style.left = '50%';
spinner.style.transform = 'translate(-50%, -50%)';
spinner.style.width = '50px';
spinner.style.height = '50px';
spinner.style.border = '4px solid rgba(0, 0, 0, 0.1)';
spinner.style.borderTop = '4px solid #fff';
spinner.style.borderRadius = '50%';
spinner.style.animation = 'spin 0.6s linear infinite';
spinner.style.zIndex = '9999';
const style = document.createElement('style');
style.innerHTML = `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`;
document.head.appendChild(style);
return spinner;
}
function createImageViewer(url) {
const spinner = createLoadingSpinner();
document.body.appendChild(spinner);
const img = new Image();
img.src = url;
img.onload = function() {
let newWindowWidth = windowWidth;
let newWindowHeight = windowHeight;
if (adaptiveWindowSize) {
const size = calculateWindowSize(img.width, img.height);
newWindowWidth = size.width;
newWindowHeight = size.height;
}
const leftOffset = (screen.width - newWindowWidth) / 2;
const topPosition = (screen.height - newWindowHeight) / 2 - 40;
const newWindow = window.open('', 'Image Preview', `width=${newWindowWidth},height=${newWindowHeight},top=${topPosition},left=${leftOffset},resizable=yes,scrollbars=no`);
if (newWindow) {
newWindow.document.title = '图片预览';
// Apply modern CSS layout and acrylic blur
newWindow.document.open();
newWindow.document.write(`
<html>
<head>
<title>图片预览</title>
<style>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
background-color: black;
height: 100vh;
position: relative;
}
${enableAcrylicBlur ? `
.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('${url}') center/cover no-repeat;
filter: blur(20px);
z-index: -2;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
backdrop-filter: blur(20px) saturate(150%);
background-color: rgba(255, 255, 255, 0.3);
z-index: -1;
}` : ''}
img {
max-width: 100%;
max-height: 100%;
cursor: grab;
transition: transform 0.1s ease;
position: relative;
user-select: none;
z-index: 1;
}
</style>
<meta name="theme-color" content="#000000">
</head>
<body>
${enableAcrylicBlur ? `<div class="background"></div><div class="overlay"></div>` : ''}
<img src="${url}" alt="图片" />
</body>
</html>
`);
newWindow.document.close();
// Remove the spinner after the image is displayed
document.body.removeChild(spinner);
let scale = 1;
let imgX = 0, imgY = 0;
let isDragging = false;
let lastMouseX = 0, lastMouseY = 0;
const imgElement = newWindow.document.querySelector('img');
function onMouseMove(event) {
if (isDragging) {
const deltaX = event.clientX - lastMouseX;
const deltaY = event.clientY - lastMouseY;
imgX += deltaX;
imgY += deltaY;
imgElement.style.transform = `translate(${imgX}px, ${imgY}px) scale(${scale})`;
lastMouseX = event.clientX;
lastMouseY = event.clientY;
}
}
function onMouseUp() {
isDragging = false;
imgElement.style.cursor = 'grab';
newWindow.removeEventListener('mousemove', onMouseMove);
newWindow.removeEventListener('mouseup', onMouseUp);
}
function onWheel(event) {
event.preventDefault();
const scaleAmount = event.deltaY > 0 ? 0.9 : 1.1;
scale *= scaleAmount;
imgElement.style.transform = `translate(${imgX}px, ${imgY}px) scale(${scale})`;
}
function onMouseDown(event) {
event.preventDefault();
isDragging = true;
imgElement.style.cursor = 'grabbing';
lastMouseX = event.clientX;
lastMouseY = event.clientY;
newWindow.addEventListener('mousemove', onMouseMove);
newWindow.addEventListener('mouseup', onMouseUp);
}
function onDoubleClick() {
newWindow.close();
}
imgElement.addEventListener('wheel', onWheel, { passive: false });
imgElement.addEventListener('mousedown', onMouseDown);
imgElement.addEventListener('dblclick', onDoubleClick);
newWindow.addEventListener('beforeunload', () => {
imgElement.removeEventListener('wheel', onWheel);
imgElement.removeEventListener('mousedown', onMouseDown);
imgElement.removeEventListener('dblclick', onDoubleClick);
newWindow.removeEventListener('mousemove', onMouseMove);
newWindow.removeEventListener('mouseup', onMouseUp);
});
} else {
// Remove the spinner if the window failed to open
document.body.removeChild(spinner);
}
};
img.onerror = function() {
// Remove the spinner if the image failed to load
document.body.removeChild(spinner);
GM_notification({
text: '图片加载失败',
title: '图片浏览',
timeout: 3000
});
};
}
// Optimized Intersection Observer for preloading images
function preloadImage(element) {
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
createImageViewer(entry.target.src || entry.target.href);
obs.unobserve(entry.target);
}
});
}, {
rootMargin: '50px',
threshold: 0.1
});
observer.observe(element);
}
function onClick(event) {
const target = event.target;
if (event.shiftKey) {
return; // If Shift is pressed, use the default behavior
}
if (mode === 'Extreme') {
// Extreme Mode: Handle images and links aggressively
if (target.tagName === 'A' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.href)) {
event.preventDefault();
event.stopPropagation();
preloadImage(target);
} else if (target.tagName === 'IMG' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.src)) {
event.preventDefault();
event.stopPropagation();
preloadImage(target);
} else if (target.tagName === 'IMG' && target.src) {
event.preventDefault();
event.stopPropagation();
preloadImage(target);
}
} else {
// Normal Mode: Handle only image elements and image links
if (target.tagName === 'IMG' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.src)) {
event.preventDefault();
event.stopPropagation();
preloadImage(target);
} else if (target.tagName === 'A' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.href)) {
event.preventDefault();
event.stopPropagation();
preloadImage(target);
}
}
}
document.addEventListener('click', onClick, true);
function cleanUp() {
document.removeEventListener('keydown', onKeyDown);
document.removeEventListener('click', onClick, true);
}
window.addEventListener('unload', cleanUp);
})();