分享一个自己使用的论坛脚本,功能不多(显示楼层、自动滚屏),同类型论坛通用
// ==UserScript==
// @name Auto Reading
// @namespace http://tampermonkey.net/
// @version 2024-11-02
// @author 0x6
// @match https://linux.do/*
// @match https://idcflare.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=www.discourse.org/
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
if (window.top !== window) {
return;
}
const styles = `
.topic-post {
position: relative;
}
.topic-post:not(:first-child):before {
position: absolute;
top: 0;
right: calc(100% - 1px);
font-size: 13px;
min-width: var(--d-main-content-gap);
height: 2em;
line-height: 2em;
text-align: center;
color: var(--primary-medium);
border: 1px solid var(--content-border-color);
content: attr(data-post-number) !important;
}
`
if ('GM_addStyle' in window) {
GM_addStyle(styles);
} else {
const style = document.createElement('style');
style.textContent = styles;
document.head.appendChild(style);
}
const AUTO_READ_INTERVAL_MIN = 500;
const AUTO_READ_INTERVAL_MAX = 1000;
const AUTO_READ_DISPLACEMENT_MIN = 100;
const AUTO_READ_DISPLACEMENT_MAX = 180;
const INITIAL_BUTTON_RIGHT = '20px';
const INITIAL_BUTTON_BOTTOM = '100px';
let reading = false;
let dragging = false;
let scrollTimeout;
let lastScrollTop = window.pageYOffset;
let startX, startY;
const button = document.createElement('button');
button.setAttribute('tabindex', '-1');
const playIcon = `
<svg width="20px" height="20px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 5v14l11-7L8 5z" fill="currentColor"/>
</svg>`;
const pauseIcon = `
<svg width="20px" height="20px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" fill="currentColor"/>
</svg>`;
button.innerHTML = playIcon;
Object.assign(button.style, {
position: 'fixed',
width: '38px',
height: '38px',
borderRadius: '50%',
outline: 'none',
background: 'linear-gradient(135deg, #6D5DFB, #8F6AF8)',
color: '#fff',
border: 'none',
cursor: 'pointer',
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.3)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'transform 0.2s ease, box-shadow 0.2s ease',
zIndex: '1000'
});
const savedPosition = JSON.parse(localStorage.getItem('x-read-pos'));
if (savedPosition) {
button.style.left = savedPosition.left;
button.style.top = savedPosition.top;
} else {
button.style.right = INITIAL_BUTTON_RIGHT;
button.style.bottom = INITIAL_BUTTON_BOTTOM;
}
button.addEventListener('mouseenter', () => {
button.style.transform = 'scale(1.1)';
button.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.4)';
});
button.addEventListener('mouseleave', () => {
button.style.transform = 'scale(1)';
button.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.3)';
});
function autoRead() {
if (reading) {
const dis = Math.floor(Math.random() * (AUTO_READ_DISPLACEMENT_MAX - AUTO_READ_DISPLACEMENT_MIN + 1)) + AUTO_READ_DISPLACEMENT_MIN;
const interval = Math.floor(Math.random() * (AUTO_READ_INTERVAL_MAX - AUTO_READ_INTERVAL_MIN + 1)) + AUTO_READ_INTERVAL_MIN;
window.scrollBy({ top: dis, left: 0, behavior: "smooth" });
scrollTimeout = setTimeout(autoRead, interval);
}
}
function toggleAutoRead() {
reading = !reading;
button.innerHTML = reading ? pauseIcon : playIcon;
button.style.background = reading
? 'linear-gradient(135deg, #FF6B6B, #FF8A5B)'
: 'linear-gradient(135deg, #6D5DFB, #8F6AF8)';
if (reading) autoRead(); else clearTimeout(scrollTimeout);
}
window.addEventListener('scroll', () => {
const currentScrollTop = window.pageYOffset;
if (currentScrollTop < lastScrollTop && reading) toggleAutoRead();
lastScrollTop = currentScrollTop;
});
button.addEventListener('pointerdown', (e) => {
dragging = false;
startX = e.clientX;
startY = e.clientY;
const offsetX = e.clientX - button.getBoundingClientRect().left;
const offsetY = e.clientY - button.getBoundingClientRect().top;
const pointerMoveHandler = (e) => {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
if (Math.abs(dx) > 1 || Math.abs(dy) > 1) {
dragging = true;
button.style.transition = 'none';
button.style.left = `${e.clientX - offsetX}px`;
button.style.top = `${e.clientY - offsetY}px`;
}
}
const pointerUpHandler = () => {
if (dragging) {
const position = { left: button.style.left, top: button.style.top };
localStorage.setItem('x-read-pos', JSON.stringify(position));
}
else {
toggleAutoRead();
}
button.style.transition = 'transform 0.2s ease, box-shadow 0.2s ease';
document.removeEventListener('pointermove', pointerMoveHandler);
document.removeEventListener('pointerup', pointerUpHandler);
}
document.addEventListener('pointermove', pointerMoveHandler);
document.addEventListener('pointerup', pointerUpHandler);
});
document.body.appendChild(button);
})();
