// ==UserScript==
// @name 纯净视界 - 原生级图片探索器
// @version 3.0
// @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==
(async function() {
'use strict';
// Retrieve settings from storage
let enableImageClick = await GM_getValue('enableImageClick', true);
let shortcut = await GM_getValue('shortcut', 'Ctrl+Shift+I');
let windowWidth = await GM_getValue('windowWidth', screen.width);
let windowHeight = await GM_getValue('windowHeight', screen.height);
let adaptiveWindowSize = await GM_getValue('adaptiveWindowSize', true);
let enableAcrylicBlur = await GM_getValue('enableAcrylicBlur', true);
const shiftRequiredSites = ['www.pinterest.com', 'www.douyin.com', 'm.weibo.cn'];
function shouldRequireShift() {
return shiftRequiredSites.includes(window.location.hostname);
}
async function toggleSetting(settingKey, settingName) {
const currentValue = await GM_getValue(settingKey, true);
const newValue = !currentValue;
await GM_setValue(settingKey, newValue);
GM_notification({
text: `${settingName}现已${newValue ? '启用' : '禁用'}`,
title: '图片浏览',
timeout: 3000
});
}
function toggleImageClick() {
toggleSetting('enableImageClick', '点击图片开启功能');
}
function toggleAdaptiveWindowSize() {
toggleSetting('adaptiveWindowSize', '智能自适应窗口大小');
}
function toggleAcrylicBlur() {
toggleSetting('enableAcrylicBlur', '丙烯酸模糊背景');
}
async function setShortcut() {
const newShortcut = prompt('输入新的快捷键组合 (如: Ctrl+Shift+I):', shortcut);
if (newShortcut) {
shortcut = newShortcut;
await 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);
await GM_setValue('windowWidth', windowWidth);
await GM_setValue('windowHeight', windowHeight);
GM_notification({
text: `窗口大小设置为: ${windowWidth}x${windowHeight}`,
title: '图片浏览',
timeout: 3000
});
}
}
GM_registerMenuCommand("切换图片点击开启功能", toggleImageClick);
GM_registerMenuCommand("设置快捷键", setShortcut);
GM_registerMenuCommand("设置窗口大小", setWindowSize);
GM_registerMenuCommand("切换智能自适应窗口大小", toggleAdaptiveWindowSize);
GM_registerMenuCommand("切换丙烯酸模糊背景", toggleAcrylicBlur);
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();
toggleImageClick();
}
}
document.addEventListener('keydown', onKeyDown);
function calculateWindowSize(imageWidth, imageHeight) {
const screenWidth = screen.width;
const screenHeight = screen.height;
const minWidth = screenWidth * 0.3;
const minHeight = screenHeight * 0.3;
const maxWidth = screenWidth * 0.7;
const maxHeight = screenHeight * 0.7;
const aspectRatio = imageWidth / imageHeight;
let width = imageWidth;
let height = imageHeight;
if (width > maxWidth) {
width = maxWidth;
height = width / aspectRatio;
}
if (height > maxHeight) {
height = maxHeight;
width = height * aspectRatio;
}
if (width < minWidth) {
width = minWidth;
height = width / aspectRatio;
}
if (height < minHeight) {
height = minHeight;
width = height * aspectRatio;
}
return { width, height };
}
function createImageViewer(url) {
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();
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);
});
}
};
}
function onClick(event) {
const target = event.target;
if (target.tagName === 'A' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.href)) {
event.preventDefault();
event.stopPropagation();
createImageViewer(target.href);
} else if (enableImageClick && target.tagName === 'IMG' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.src)) {
if (!shouldRequireShift() || (shouldRequireShift() && event.shiftKey)) {
event.preventDefault();
event.stopPropagation();
createImageViewer(target.src);
}
} else if (enableImageClick && target.tagName === 'IMG' && target.src) {
if (!shouldRequireShift() || (shouldRequireShift() && event.shiftKey)) {
event.preventDefault();
event.stopPropagation();
createImageViewer(target.src);
}
}
}
document.addEventListener('click', onClick, true);
function cleanUp() {
document.removeEventListener('keydown', onKeyDown);
document.removeEventListener('click', onClick, true);
}
window.addEventListener('unload', cleanUp);
})();