Fit Rule34 post images to screen, click to toggle original size, and stably auto-scroll to image
// ==UserScript==
// @name Rule34 Auto Fit Image Toggle + Auto Scroll
// @namespace https://rule34.xxx/
// @version 1.3
// @description Fit Rule34 post images to screen, click to toggle original size, and stably auto-scroll to image
// @author icynic
// @match https://rule34.xxx/index.php?page=post&s=view*
// @grant none
// ==/UserScript==
(function () {
'use strict';
let fitted = true;
let initialized = false;
let autoScrolled = false;
function getImage() {
return document.querySelector('#image');
}
function applyFit(img) {
img.removeAttribute('width');
img.removeAttribute('height');
img.style.maxWidth = 'calc(100vw - 40px)';
img.style.maxHeight = 'calc(100vh - 40px)';
img.style.width = 'auto';
img.style.height = 'auto';
img.style.objectFit = 'contain';
img.style.display = 'block';
img.style.cursor = 'zoom-in';
fitted = true;
}
function applyOriginal(img) {
img.style.maxWidth = 'none';
img.style.maxHeight = 'none';
img.style.width = img.naturalWidth + 'px';
img.style.height = img.naturalHeight + 'px';
img.style.cursor = 'zoom-out';
fitted = false;
}
function scrollToImageStable(img) {
// 这里控制图片顶部距离屏幕顶部的空隙
const topGap = 8;
const rect = img.getBoundingClientRect();
const targetY = window.scrollY + rect.top - topGap;
window.scrollTo({
top: targetY,
left: 0,
behavior: 'auto'
});
}
function stableAutoScroll() {
const img = getImage();
if (!img) return;
applyFit(img);
let attempts = 0;
const maxAttempts = 12;
const topGap = 8;
const timer = setInterval(() => {
const rect = img.getBoundingClientRect();
// 如果图片顶部已经接近目标位置,就停止修正
if (Math.abs(rect.top - topGap) <= 2) {
clearInterval(timer);
autoScrolled = true;
return;
}
scrollToImageStable(img);
attempts++;
if (attempts >= maxAttempts) {
clearInterval(timer);
autoScrolled = true;
}
}, 150);
}
function init(shouldAutoScroll = false) {
const img = getImage();
if (!img) return;
applyFit(img);
if (!initialized) {
initialized = true;
img.addEventListener('click', function (event) {
event.preventDefault();
event.stopPropagation();
if (fitted) {
applyOriginal(img);
} else {
applyFit(img);
setTimeout(() => scrollToImageStable(img), 50);
}
}, true);
}
if (shouldAutoScroll && !autoScrolled) {
stableAutoScroll();
}
}
document.addEventListener('DOMContentLoaded', () => {
init(true);
});
window.addEventListener('load', () => {
init(true);
});
// 等页面自己的脚本、广告、图片尺寸变化稳定一点
setTimeout(() => init(true), 300);
setTimeout(() => init(true), 800);
setTimeout(() => init(true), 1500);
})();