您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
都是一些简简单单的功能
// ==UserScript== // @name Linux.do 浏览助手 // @namespace http://tampermonkey.net/ // @version 1.4 // @description 都是一些简简单单的功能 // @author LiNFERS // @match https://linux.do/* // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function () { 'use strict'; // 工具函数:设置样式 function setElementStyle(element, styles) { for (const [key, value] of Object.entries(styles)) { element.style[key] = value; } } // 标记已浏览帖子的函数 function markVisitedPosts() { const history = GM_getValue('postHistory', []); const visitedIds = history.map(item => item.id); // 查找所有帖子链接 const topicLinks = document.querySelectorAll('a[href*="/t/topic/"], a[href*="/topic/"]'); topicLinks.forEach(link => { const postId = link.href.match(/\/t\/topic\/(\d+)|\/topic\/(\d+)/)?.[1] || link.href.match(/\/t\/topic\/(\d+)|\/topic\/(\d+)/)?.[2]; if (postId && visitedIds.includes(postId)) { // 找到包含帖子标题的父元素并标记 let postElement = link; while (postElement && !postElement.classList.contains('topic-list-item') && !postElement.classList.contains('topic-body')) { postElement = postElement.parentElement; } if (postElement) { postElement.style.backgroundColor = 'rgba(144, 238, 144, 0.2)'; postElement.style.transition = 'background-color 0.3s ease'; } } }); } // 创建随机看帖按钮 const randomBtn = document.createElement('button'); randomBtn.innerHTML = '<span style="display:inline-block;animation:pulse 2s infinite">R</span>'; setElementStyle(randomBtn, { position: 'fixed', bottom: '80px', right: '0', zIndex: '10000', width: '25px', // 减小宽度 height: '40px', // 减小高度 background: 'rgba(255, 255, 255, 0.8)', color: '#333', border: 'none', borderRadius: '25px 0 0 25px', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', transition: 'all 0.3s ease', fontSize: '14px', // 减小字体大小 fontWeight: 'bold', userSelect: 'none' }); document.body.appendChild(randomBtn); // 创建主控制按钮 const mainBtn = document.createElement('button'); mainBtn.innerHTML = '<span style="display:inline-block;animation:pulse 2s infinite">L</span>'; setElementStyle(mainBtn, { position: 'fixed', bottom: '130px', // 调整位置以适应新的大小 right: '0', zIndex: '10000', width: '25px', // 减小宽度 height: '40px', // 减小高度 background: 'rgba(255, 255, 255, 0.8)', color: '#333', border: 'none', borderRadius: '25px 0 0 25px', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', transition: 'all 0.3s ease', fontSize: '14px', // 减小字体大小 fontWeight: 'bold', userSelect: 'none' }); document.body.appendChild(mainBtn); // 创建已阅按钮 const readBtn = document.createElement('button'); readBtn.innerHTML = '<span style="display:inline-block;animation:pulse 2s infinite">✓</span>'; setElementStyle(readBtn, { position: 'fixed', bottom: '180px', right: '0', zIndex: '10000', width: '25px', height: '40px', background: 'rgba(255, 255, 255, 0.8)', color: '#333', border: 'none', borderRadius: '25px 0 0 25px', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', transition: 'all 0.3s ease', fontSize: '14px', fontWeight: 'bold', userSelect: 'none' }); document.body.appendChild(readBtn); // 添加主控制按钮的动画样式 const style = document.createElement('style'); style.textContent = ` @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } @keyframes textGlow { 0% { text-shadow: 0 0 5px rgba(255,255,255,0.8); } 50% { text-shadow: 0 0 15px rgba(255,255,255,1); } 100% { text-shadow: 0 0 5px rgba(255,255,255,0.8); } } `; document.head.appendChild(style); // 创建浮动按钮容器 const buttonContainer = document.createElement('div'); setElementStyle(buttonContainer, { position: 'fixed', bottom: '80px', right: '50px', // 增加与主按钮的距离 zIndex: '9999', display: 'flex', flexDirection: 'column', gap: '10px', transition: 'all 0.3s ease', transform: 'translateX(100%)', // 初始位置在屏幕右侧 opacity: '0', pointerEvents: 'none' }); document.body.appendChild(buttonContainer); // 创建浏览记录按钮 const btn = document.createElement('button'); btn.innerHTML = '最近浏览'; setElementStyle(btn, { padding: '8px 15px', background: 'rgba(255, 255, 255, 0.6)', color: '#333', border: 'none', borderRadius: '20px', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', width: '115px', animation: 'textGlow 2s infinite', fontWeight: 'bold' }); buttonContainer.appendChild(btn); // 创建插眼按钮 const markBtn = document.createElement('button'); markBtn.innerHTML = '插眼'; setElementStyle(markBtn, { padding: '8px 15px', background: 'rgba(255, 255, 255, 0.6)', color: '#333', border: 'none', borderRadius: '20px', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', width: '115px', animation: 'textGlow 2s infinite', fontWeight: 'bold' }); buttonContainer.appendChild(markBtn); // 创建导航按钮容器 const navBtnContainer = document.createElement('div'); setElementStyle(navBtnContainer, { display: 'flex', gap: '5px', justifyContent: 'center' }); buttonContainer.appendChild(navBtnContainer); // 创建返回按钮 const backBtn = document.createElement('button'); backBtn.innerHTML = '←'; setElementStyle(backBtn, { width: '35px', height: '35px', background: 'rgba(255, 255, 255, 0.6)', color: '#333', border: 'none', borderRadius: '50%', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', fontSize: '16px', animation: 'textGlow 2s infinite', fontWeight: 'bold' }); navBtnContainer.appendChild(backBtn); // 创建回到顶部按钮 const topBtn = document.createElement('button'); topBtn.innerHTML = '↑'; setElementStyle(topBtn, { width: '35px', height: '35px', background: 'rgba(255, 255, 255, 0.6)', color: '#333', border: 'none', borderRadius: '50%', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', fontSize: '16px', animation: 'textGlow 2s infinite', fontWeight: 'bold' }); navBtnContainer.appendChild(topBtn); // 创建到达底部按钮 const bottomBtn = document.createElement('button'); bottomBtn.innerHTML = '↓'; setElementStyle(bottomBtn, { width: '35px', height: '35px', background: 'rgba(255, 255, 255, 0.6)', color: '#333', border: 'none', borderRadius: '50%', cursor: 'pointer', backdropFilter: 'blur(5px)', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', fontSize: '16px', animation: 'textGlow 2s infinite', fontWeight: 'bold' }); navBtnContainer.appendChild(bottomBtn); // 按钮控制 let isExpanded = false; let lastClickTime = 0; function showButtons() { buttonContainer.style.opacity = '1'; buttonContainer.style.transform = 'translateX(0)'; // 向左滑动显示 buttonContainer.style.pointerEvents = 'auto'; } function hideButtons() { buttonContainer.style.opacity = '0'; buttonContainer.style.transform = 'translateX(100%)'; // 向右滑动隐藏 buttonContainer.style.pointerEvents = 'none'; } // 设置透明度函数 function setButtonsOpacity(opacity) { mainBtn.style.opacity = opacity; randomBtn.style.opacity = opacity; readBtn.style.opacity = opacity; buttonContainer.style.opacity = isExpanded ? opacity : '0'; } // 透明度控制 let fadeTimeout; function resetFadeTimeout() { clearTimeout(fadeTimeout); setButtonsOpacity('1'); fadeTimeout = setTimeout(() => { if (!isNearButton) { setButtonsOpacity('0.2'); } }, 20000); } // 监听鼠标移动 let isNearButton = false; document.addEventListener('mousemove', (e) => { const btnRect = mainBtn.getBoundingClientRect(); const randomBtnRect = randomBtn.getBoundingClientRect(); const readBtnRect = readBtn.getBoundingClientRect(); const containerRect = buttonContainer.getBoundingClientRect(); // 检查鼠标是否在主按钮或按钮容器附近 const isNearMainBtn = Math.sqrt( Math.pow(e.clientX - (btnRect.left + btnRect.width/2), 2) + Math.pow(e.clientY - (btnRect.top + btnRect.height/2), 2) ) < 100; const isNearRandomBtn = Math.sqrt( Math.pow(e.clientX - (randomBtnRect.left + randomBtnRect.width/2), 2) + Math.pow(e.clientY - (randomBtnRect.top + randomBtnRect.height/2), 2) ) < 100; const isNearReadBtn = Math.sqrt( Math.pow(e.clientX - (readBtnRect.left + readBtnRect.width/2), 2) + Math.pow(e.clientY - (readBtnRect.top + readBtnRect.height/2), 2) ) < 100; const isNearContainer = isExpanded && ( e.clientX >= containerRect.left - 50 && e.clientX <= containerRect.right + 50 && e.clientY >= containerRect.top - 50 && e.clientY <= containerRect.bottom + 50 ); if (isNearMainBtn || isNearRandomBtn || isNearReadBtn || isNearContainer) { isNearButton = true; resetFadeTimeout(); } else { isNearButton = false; } }); mainBtn.onclick = (e) => { const currentTime = new Date().getTime(); if (currentTime - lastClickTime < 200) { return; } lastClickTime = currentTime; isExpanded = !isExpanded; if (isExpanded) { showButtons(); } else { hideButtons(); } }; // 初始化透明度 resetFadeTimeout(); // 插眼功能 markBtn.onclick = async () => { const path = window.location.pathname; const postId = path.match(/\/t\/topic\/(\d+)/)?.[1] || path.match(/\/topic\/(\d+)/)?.[1]; if (!postId) { alert('请在帖子页面使用此功能'); return; } try { // 获取 CSRF token const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (!csrfToken) { throw new Error('无法获取 CSRF token'); } // 发送回复请求 const response = await fetch('https://linux.do/posts', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken, }, body: JSON.stringify({ raw: 'LiNFERSmark~~~', topic_id: postId, }), credentials: 'include' }); if (!response.ok) { throw new Error('回复失败'); } alert('插眼成功!'); // 刷新页面以显示新回复 window.location.reload(); } catch (error) { alert('插眼失败:' + error.message); } }; // 已阅功能 readBtn.onclick = () => { const path = window.location.pathname; const postId = path.match(/\/t\/topic\/(\d+)/)?.[1] || path.match(/\/topic\/(\d+)/)?.[1]; if (!postId) { alert('请在帖子页面使用此功能'); return; } let readPosts = GM_getValue('readPosts', []); if (!readPosts.includes(postId)) { readPosts.push(postId); GM_setValue('readPosts', readPosts); readBtn.style.background = 'rgba(144, 238, 144, 0.8)'; // 标记为已读后变成浅绿色 } else { readPosts = readPosts.filter(id => id !== postId); GM_setValue('readPosts', readPosts); readBtn.style.background = 'rgba(255, 255, 255, 0.8)'; } }; // 随机看帖功能 randomBtn.onclick = async () => { // 获取最新帖子列表 const response = await fetch('https://linux.do/latest.json'); const data = await response.json(); if (data.topic_list && data.topic_list.topics.length > 0) { const readPosts = GM_getValue('readPosts', []); // 过滤掉已阅的帖子 const unreadTopics = data.topic_list.topics.filter(topic => !readPosts.includes(topic.id.toString())); if (unreadTopics.length === 0) { alert('所有帖子都已阅读过了!'); return; } // 从未读帖子列表中随机选择一个 const randomIndex = Math.floor(Math.random() * unreadTopics.length); const randomTopic = unreadTopics[randomIndex]; // 导航到随机选择的帖子 window.location.href = `https://linux.do/t/topic/${randomTopic.id}`; } }; // 回到顶部功能 topBtn.onclick = () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }; // 到达底部功能 bottomBtn.onclick = () => { window.scrollTo({ top: document.documentElement.scrollHeight, behavior: 'smooth' }); }; // 返回功能 backBtn.onclick = () => { history.back(); }; // 创建弹窗 const popup = document.createElement('div'); setElementStyle(popup, { display: 'none', position: 'fixed', bottom: '80px', right: '220px', width: '300px', maxHeight: '400px', background: 'rgba(255, 255, 255, 0.95)', borderRadius: '15px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)', zIndex: '9999', overflowY: 'auto', padding: '10px', backdropFilter: 'blur(10px)', opacity: '0', transform: 'translateX(20px)', transition: 'opacity 0.3s ease, transform 0.3s ease', }); document.body.appendChild(popup); let lastRecordedId = ''; // 记录最后一次记录的帖子 ID function recordVisit() { setTimeout(() => { const path = window.location.pathname; const postId = path.match(/\/t\/topic\/(\d+)/)?.[1] || path.match(/\/topic\/(\d+)/)?.[1]; if (!postId) return; const title = document.querySelector('h1')?.textContent || document.title; const url = window.location.href; if (postId === lastRecordedId) return; // 避免重复记录 lastRecordedId = postId; let history = GM_getValue('postHistory', []); // 检查是否存在相同帖子 ID const existingIndex = history.findIndex(item => item.id === postId); if (existingIndex !== -1) { history.splice(existingIndex, 1); // 删除重复记录 } history.unshift({ id: postId, title: title, url: url, time: new Date().toISOString(), }); const maxRecords = Math.min(GM_getValue('maxRecords', 10), 20); if (history.length > maxRecords) { history = history.slice(0, maxRecords); } GM_setValue('postHistory', history); // 检查当前帖子是否已阅,更新按钮颜色 const readPosts = GM_getValue('readPosts', []); if (readPosts.includes(postId)) { readBtn.style.background = 'rgba(144, 238, 144, 0.8)'; } else { readBtn.style.background = 'rgba(255, 255, 255, 0.8)'; } // 标记已浏览的帖子 markVisitedPosts(); }, 1000); } function showHistory() { const history = GM_getValue('postHistory', []); popup.innerHTML = ''; // 设置区域 const settingsDiv = document.createElement('div'); setElementStyle(settingsDiv, { marginBottom: '10px', padding: '5px', borderBottom: '1px solid #eee', display: 'flex', justifyContent: 'space-between', alignItems: 'center', }); const settingsLabel = document.createElement('label'); settingsLabel.textContent = '记录条数: '; const settingsInput = document.createElement('input'); settingsInput.type = 'number'; settingsInput.min = 1; settingsInput.max = 20; settingsInput.value = GM_getValue('maxRecords', 10); setElementStyle(settingsInput, { width: '60px', margin: '0 5px', padding: '3px', borderRadius: '4px', border: '1px solid #ddd', }); settingsInput.onchange = (e) => { let value = parseInt(e.target.value, 10); value = Math.min(20, Math.max(1, value)); e.target.value = value; GM_setValue('maxRecords', value); }; const clearBtn = document.createElement('button'); clearBtn.textContent = '清空记录'; setElementStyle(clearBtn, { padding: '5px 10px', background: 'rgba(255, 68, 68, 0.9)', color: 'white', border: 'none', borderRadius: '15px', cursor: 'pointer', transition: 'all 0.3s ease', }); clearBtn.onclick = () => { if (confirm('确定要清空所有浏览记录吗?')) { GM_setValue('postHistory', []); showHistory(); // 清空记录后重新加载页面以更新标记 window.location.reload(); } }; settingsDiv.appendChild(settingsLabel); settingsDiv.appendChild(settingsInput); settingsDiv.appendChild(clearBtn); popup.appendChild(settingsDiv); if (history.length === 0) { popup.innerHTML += '<p style="text-align:center;color:#666;">暂无浏览记录</p>'; return; } // 展示记录 const ul = document.createElement('ul'); setElementStyle(ul, { listStyle: 'none', margin: '0', padding: '0', }); history.forEach((item, index) => { const li = document.createElement('li'); setElementStyle(li, { padding: '10px', borderBottom: '1px solid #eee', cursor: 'pointer', transition: 'all 0.3s ease', borderRadius: '8px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', }); const time = new Date(item.time).toLocaleString(); const titleDiv = document.createElement('div'); titleDiv.innerHTML = ` <div style="font-size:14px;margin-bottom:5px;">${item.title}</div> <div style="font-size:12px;color:#666;">${time}</div> `; titleDiv.style.flex = '1'; titleDiv.onclick = () => { window.location.href = item.url; }; const deleteBtn = document.createElement('button'); deleteBtn.textContent = '删除'; setElementStyle(deleteBtn, { padding: '5px 10px', background: 'rgba(255, 68, 68, 0.9)', color: 'white', border: 'none', borderRadius: '8px', cursor: 'pointer', marginLeft: '10px', }); deleteBtn.onclick = (e) => { e.stopPropagation(); // 防止触发跳转 if (confirm(`确定删除记录 "${item.title}" 吗?`)) { history.splice(index, 1); GM_setValue('postHistory', history); showHistory(); // 删除记录后重新加载页面以更新标记 window.location.reload(); } }; li.appendChild(titleDiv); li.appendChild(deleteBtn); ul.appendChild(li); }); popup.appendChild(ul); } // 弹窗显示控制 let isPopupVisible = false; btn.onclick = () => { isPopupVisible = !isPopupVisible; popup.style.display = isPopupVisible ? 'block' : 'none'; if (isPopupVisible) { showHistory(); // 添加一个小延迟以确保过渡动画生效 setTimeout(() => { popup.style.opacity = '1'; popup.style.transform = 'translateX(0)'; }, 10); } else { popup.style.opacity = '0'; popup.style.transform = 'translateX(20px)'; // 等待过渡动画完成后隐藏弹窗 setTimeout(() => { if (!isPopupVisible) { popup.style.display = 'none'; } }, 300); } }; // 点击外部关闭弹窗 document.addEventListener('click', (e) => { if (!popup.contains(e.target) && e.target !== btn) { if (isPopupVisible) { isPopupVisible = false; popup.style.opacity = '0'; popup.style.transform = 'translateX(20px)'; setTimeout(() => { if (!isPopupVisible) { popup.style.display = 'none'; } }, 300); } } }); // 初始记录 recordVisit(); // 监听 URL 变化 let lastUrl = location.href; new MutationObserver(() => { if (location.href !== lastUrl) { lastUrl = location.href; recordVisit(); } }).observe(document.body, { childList: true, subtree: true }); // 初始化时标记已浏览的帖子 markVisitedPosts(); // 监听 DOM 变化以处理动态加载的内容 new MutationObserver(() => { markVisitedPosts(); }).observe(document.body, { childList: true, subtree: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址