之前2级时候,发现其他都达标了,主要就是阅读帖子两万的量少了一点点。
灵机一动,想着多刷刷帖子,后来发现拉鼠标好麻烦,就开发了一个自动滚屏的浏览器插件。
感觉挺方便,分享给大家。
zip文件,按照readme安装就行。
我用夸克网盘分享了「Auto Scroll.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:夸克网盘分享
提取码:pgKp
之前2级时候,发现其他都达标了,主要就是阅读帖子两万的量少了一点点。
灵机一动,想着多刷刷帖子,后来发现拉鼠标好麻烦,就开发了一个自动滚屏的浏览器插件。
感觉挺方便,分享给大家。
zip文件,按照readme安装就行。
我用夸克网盘分享了「Auto Scroll.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:夸克网盘分享
提取码:pgKp
按一些鼠标中间,然后往下拖动一点也会自动往下滚动 ![]()
这个很简单的呀,没必要自动化
这个插件可以后台运行,鼠标可以干其他事
嗯呐,这要试一下,找个很多回复的帖子,几下就刷满了 ![]()
真的吗,还有这种神器啊,可怜我辛辛苦苦一个一个看帖
隐隐感觉要被和谐
有脚本的嘿嘿
佬给一个就差帖子数量了
// ==UserScript==
// @name Linux.do 自动标记已读
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 自动将 Linux.do 论坛的帖子标记为已读
// @author by.三文鱼
// @match https://linux.do/*
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_notification
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// 使用 localStorage 存储运行状态
const STORAGE_KEY = 'linux_do_auto_reader';
let csrfToken = null;
let isRunning = false;
let lastCheckTime = 0;
// 状态管理
const StateManager = {
save: () => {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
isRunning,
lastCheckTime: Date.now()
}));
},
load: () => {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
const data = JSON.parse(saved);
isRunning = data.isRunning;
lastCheckTime = data.lastCheckTime;
}
},
clear: () => {
localStorage.removeItem(STORAGE_KEY);
}
};
// 添加心跳检测
function heartbeat() {
if (!isRunning) return;
const now = Date.now();
if (now - lastCheckTime > 35000) { // 如果超过35秒没有检查
doCheck();
}
setTimeout(heartbeat, 5000); // 每5秒检查一次
}
// 获取最新的帖子列表
async function getLastTopics() {
try {
const response = await fetch("https://linux.do/latest.json?no_definitions=true&page=0");
return await response.json();
} catch (error) {
log(`获取帖子列表失败: ${error.message},将在3秒后刷新页面`, 'error');
setTimeout(() => {
window.location.reload();
}, 3000);
throw error;
}
}
// 更新帖子为已读状态
async function updateRead(id) {
if (!csrfToken) {
csrfToken = document.querySelector("meta[name=csrf-token]").content; // 首次获取并缓存 CSRF token
}
try {
const response = await fetch("https://linux.do/topics/timings", {
headers: {
"accept": "*/*",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-csrf-token": csrfToken,
"x-requested-with": "XMLHttpRequest",
"x-silence-logger": "true"
},
referrer: `https://linux.do/t/topic/${id}`,
referrerPolicy: "strict-origin-when-cross-origin",
body: `timings%5B1%5D=1023&topic_time=1023&topic_id=${id}`,
method: "POST",
mode: "cors",
credentials: "include"
});
if (response.ok) {
console.log(`Topic ${id} marked as read successfully.`);
} else {
console.error(`Failed to mark topic ${id} as read. Status: ${response.status}`);
}
} catch (error) {
console.error(`Error updating read status for topic ${id}:`, error);
}
}
// 修改 doCheck 函数
async function doCheck() {
if (!isRunning) return;
try {
const res = await getLastTopics();
// 添加调试日志
console.log('获取到的帖子列表:', res.topic_list.topics);
const unseenTopics = res.topic_list.topics.filter(topic => topic.unseen);
// 添加调试日志
console.log('未读帖子:', unseenTopics);
// 更新帖子列表显示
updateTopicsList(res.topic_list.topics);
// 修改日志输出,显示更多信息
if (unseenTopics.length === 0) {
log(`获取到 ${res.topic_list.topics.length} 个帖子,其中未读帖子:0`, 'info');
} else {
log(`获取到 ${res.topic_list.topics.length} 个帖子,其中未读帖子:${unseenTopics.length}`, 'info');
GM_notification({
title: 'Linux.do 自动阅读器',
text: `发现 ${unseenTopics.length} 个未读帖子`,
timeout: 3000
});
}
for (let topic of unseenTopics) {
if (!isRunning) break;
log(`正在标记帖子: ${topic.id} - ${topic.title}`, 'info');
await updateRead(topic.id);
await new Promise(resolve => setTimeout(resolve, 3000));
}
} catch (error) {
log(`获取帖子列表失败: ${error.message}`, 'error');
console.error('完整错误信息:', error);
}
lastCheckTime = Date.now();
StateManager.save();
if (isRunning) {
setTimeout(doCheck, 30000);
}
}
// 修改帖子列表更新函数,显示已读帖子
function updateTopicsList(topics) {
const topicsListDiv = document.getElementById('auto-reader-topics');
topicsListDiv.innerHTML = '';
// 过滤出已读帖子,并最多显示10个
const readTopics = topics.filter(topic => !topic.unseen).slice(0, 10);
if (readTopics.length === 0) {
const emptyMessage = document.createElement('div');
emptyMessage.className = 'empty-message';
emptyMessage.textContent = '暂无已读帖子';
topicsListDiv.appendChild(emptyMessage);
return;
}
readTopics.forEach(topic => {
const topicItem = document.createElement('div');
topicItem.className = 'topic-item read';
topicItem.innerHTML = `
<a href="https://linux.do/t/topic/${topic.id}" target="_blank">${topic.title}</a>
`;
topicsListDiv.appendChild(topicItem);
});
}
// 修改初始化函数
function init() {
createConsole();
StateManager.load(); // 加载保存的状态
// 开始按钮
document.getElementById('start-button').addEventListener('click', () => {
if (!isRunning) {
isRunning = true;
StateManager.save();
log('开始自动标记...', 'success'); // 修改为 success 类型
updateStatusIndicator();
doCheck();
heartbeat();
// 添加按钮状态反馈
const startBtn = document.getElementById('start-button');
startBtn.style.opacity = '0.6';
startBtn.disabled = true;
const stopBtn = document.getElementById('stop-button');
stopBtn.style.opacity = '1';
stopBtn.disabled = false;
}
});
// 停止按钮
document.getElementById('stop-button').addEventListener('click', () => {
isRunning = false;
StateManager.save();
log('已停止自动标记', 'info');
updateStatusIndicator();
// 添加按钮状态反馈
const startBtn = document.getElementById('start-button');
startBtn.style.opacity = '1';
startBtn.disabled = false;
const stopBtn = document.getElementById('stop-button');
stopBtn.style.opacity = '0.6';
stopBtn.disabled = true;
});
// 清除日志按钮
document.getElementById('clear-button').addEventListener('click', () => {
const logDiv = document.getElementById('auto-reader-log');
logDiv.innerHTML = '';
log('日志已清除', 'info');
});
// 如果之前是运行状态,自动启动
if (isRunning) {
log('恢复自动标记...', 'info');
doCheck();
heartbeat();
// 设置按钮初始状态
const startBtn = document.getElementById('start-button');
startBtn.style.opacity = '0.6';
startBtn.disabled = true;
const stopBtn = document.getElementById('stop-button');
stopBtn.style.opacity = '1';
stopBtn.disabled = false;
} else {
// 初始状态下停止按钮禁用
const stopBtn = document.getElementById('stop-button');
stopBtn.style.opacity = '0.6';
stopBtn.disabled = true;
}
// 页面关闭前保存状态
window.addEventListener('beforeunload', () => {
if (isRunning) {
StateManager.save();
}
});
}
// 页面可见性变化处理
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible' && isRunning) {
const now = Date.now();
if (now - lastCheckTime > 35000) {
doCheck(); // 如果太久没检查,立即检查
}
}
});
// 初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
// 在 'use strict'; 后添加样式代码
GM_addStyle(`
#auto-reader-console {
position: fixed;
bottom: 20px;
right: 20px;
width: 320px;
background: rgba(28, 30, 35, 0.95);
color: #e1e1e1;
padding: 15px;
border-radius: 12px;
font-size: 13px;
z-index: 9999;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
#auto-reader-console.folded {
width: 10px;
padding: 10px;
right: 0;
border-radius: 12px 0 0 12px;
}
#auto-reader-console.folded #auto-reader-header {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
#auto-reader-console.folded #auto-reader-title,
#auto-reader-console.folded #status-indicator {
display: none;
}
#fold-controls {
display: flex;
justify-content: center;
align-items: center;
}
#auto-reader-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
#auto-reader-title {
font-weight: 600;
font-size: 14px;
color: #fff;
}
#fold-button {
background: none;
border: none;
color: #fff;
cursor: pointer;
padding: 0;
font-size: 14px;
}
#auto-reader-log {
max-height: 150px;
overflow-y: auto;
margin-bottom: 12px;
padding: 8px;
background: rgba(0, 0, 0, 0.2);
border-radius: 6px;
font-size: 12px;
line-height: 1.5;
}
#auto-reader-topics-container {
margin-bottom: 12px;
}
.topics-title {
font-weight: 600;
margin-bottom: 5px;
color: #fff;
}
#auto-reader-topics {
max-height: 150px;
overflow-y: auto;
padding: 8px;
background: rgba(0, 0, 0, 0.2);
border-radius: 6px;
font-size: 12px;
}
.topic-item {
padding: 4px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.topic-item:last-child {
border-bottom: none;
}
.topic-item a {
color: #64B5F6;
text-decoration: none;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.topic-item a:hover {
text-decoration: underline;
}
.topic-item.unseen a {
color: #81C784;
font-weight: 500;
}
#auto-reader-log::-webkit-scrollbar,
#auto-reader-topics::-webkit-scrollbar {
width: 6px;
}
#auto-reader-log::-webkit-scrollbar-thumb,
#auto-reader-topics::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}
#auto-reader-controls {
display: flex;
gap: 8px;
}
.auto-reader-button {
padding: 6px 12px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
font-weight: 500;
transition: all 0.2s ease;
flex: 1;
text-align: center;
color: #fff;
}
#start-button {
background: #4CAF50;
}
#start-button:hover {
background: #43A047;
}
#stop-button {
background: #f44336;
}
#stop-button:hover {
background: #e53935;
}
#clear-button {
background: #607D8B;
}
#clear-button:hover {
background: #546E7A;
}
.success {
color: #81C784;
padding: 4px 0;
}
.error {
color: #E57373;
padding: 4px 0;
}
.info {
color: #64B5F6;
padding: 4px 0;
}
#status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: #f44336;
margin-left: 8px;
transition: background 0.3s ease;
}
#status-indicator.active {
background: #4CAF50;
}
.auto-reader-button:disabled {
cursor: not-allowed;
opacity: 0.6;
}
#start-button:disabled {
background: #4CAF50;
}
#stop-button:disabled {
background: #f44336;
}
.empty-message {
color: #888;
text-align: center;
padding: 10px 0;
font-style: italic;
}
.topic-item.read a {
color: #ddd;
}
`);
// 修改创建控制台UI的函数
function createConsole() {
const console = document.createElement('div');
console.id = 'auto-reader-console';
console.innerHTML = `
<div id="auto-reader-header">
<div style="display: flex; align-items: center;">
<span id="auto-reader-title">Linux.do 自动阅读器</span>
<div id="status-indicator"></div>
</div>
<div id="fold-controls">
<button id="fold-button">◀</button>
</div>
</div>
<div id="auto-reader-content">
<div id="auto-reader-log"></div>
<div id="auto-reader-topics-container">
<div class="topics-title">最近已读帖子</div>
<div id="auto-reader-topics"></div>
</div>
<div id="auto-reader-controls">
<button class="auto-reader-button" id="start-button">开始</button>
<button class="auto-reader-button" id="stop-button">停止</button>
<button class="auto-reader-button" id="clear-button">清除日志</button>
</div>
</div>
`;
document.body.appendChild(console);
// 添加折叠事件监听
document.getElementById('fold-button').addEventListener('click', toggleFold);
}
// 修改折叠控制函数
function toggleFold() {
const console = document.getElementById('auto-reader-console');
const foldButton = document.getElementById('fold-button');
const content = document.getElementById('auto-reader-content');
if (console.classList.contains('folded')) {
// 展开
console.classList.remove('folded');
foldButton.textContent = '◀';
content.style.display = 'block';
} else {
// 折叠
console.classList.add('folded');
foldButton.textContent = '▶';
content.style.display = 'none';
}
}
// 添加日志函数
function log(message, type = 'info') {
const logDiv = document.getElementById('auto-reader-log');
const time = new Date().toLocaleTimeString();
const newLog = document.createElement('div');
newLog.className = type;
newLog.innerHTML = `[${time}] ${message}`;
logDiv.appendChild(newLog);
logDiv.scrollTop = logDiv.scrollHeight;
}
// 在 init 函数中添加状态指示器更新
function updateStatusIndicator() {
const indicator = document.getElementById('status-indicator');
if (indicator) {
indicator.className = isRunning ? 'active' : '';
}
}
})();
之前别人分享的
ok谢谢佬我去试试
但这玩意还没我自己水的快
佬太强了,我还是不够努力,1.8w帖子卡半个月了
佬儿无敌哈~
一直用RSS看帖,为的不用后退时看重复的贴,只看不发贴,2级3级无所谓
这是加主题数不是帖子数的吧
别人贴的代码,我还没看代码内容
推广 保存网盘有钱获得,不然一段代码。。。粘出来就是了