您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
本脚本不再更新,功能已集成到 https://gf.qytechs.cn/zh-CN/scripts/499393-linuxdo-enhancex 。 Adds customizable features such as logos, click count visualization, image resize, and quick bookmarking to LinuxDo.
当前为
// ==UserScript== // @name LinuxDo EnhanceX (LinuxDo Quick Bookmark) // @name:zh-CN LinuxDo 增强X (原LinuxDo快速收藏) // @description 本脚本不再更新,功能已集成到 https://gf.qytechs.cn/zh-CN/scripts/499393-linuxdo-enhancex 。 Adds customizable features such as logos, click count visualization, image resize, and quick bookmarking to LinuxDo. // @description:zh-CN 本脚本不再更新,功能已集成到 https://gf.qytechs.cn/zh-CN/scripts/499393-linuxdo-enhancex 。在帖子中添加了快速收藏功能。用户可以通过星形图标快速收藏或取消收藏帖子。为 LinuxDo 添加自定义徽标、点击数可视化、图像缩放和快速书签等功能。 // @namespace http://tampermonkey.net/ // @version 0.2.5 // @author Yearly // @match https://linux.do/* // @icon data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjZWVlIiBkPSJNMCAwaDEwMHYxMDBIMHoiLz48cGF0aCBkPSJNNCA0aDkydjMwSDR6Ii8+PHBhdGggZmlsbD0iI0ZBMCIgZD0iTTQgNjZoOTJ2MzBINHoiLz48L3N2Zz4= // @license AGPL-v3.0 // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { var settings = {}; (function() { 'use strict'; const settingsConfig = { quick_mark : { type: 'checkbox', label: '快速收藏 ', default: true }, image_view : { type: 'checkbox', label: '增强大图查看 ', default: true }, cnts_colorful : { type: 'checkbox', label: '链接点击次数高亮色阶', default: true }, raw_search : { type: 'checkbox', label: '默认使用浏览器自带CTRL+F搜索', default: true }, icon_custom : { type: 'checkbox', label: '自定义LOGO图标 ', default: true }, icon_main : { type: 'text', label: 'icon main', default: GM_info.script.icon, dependentOn: 'icon_custom' }, icon_wide : { type: 'text', label: 'icon wide', default: GM_info.script.icon, dependentOn: 'icon_custom' }, }; Object.keys(settingsConfig).forEach(key => { settings[key] = GM_getValue(key, settingsConfig[key].default); }); GM_registerMenuCommand('Open Settings', openSettings); function openSettings() { const panel = document.createElement('div'); panel.style = `position: fixed; top: 40%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 10px 20px; border: 1px solid #ccc; z-index: 10000; color:#000`; let html = `<style type="text/css"> :scope label {display:flex; justify-content:space-between; align-items:center; margin-top:15px;} :scope label input[type=text] {width:200px; padding:1px 5px; margin:0 5px;} :scope label input[disabled] {background: #CCC;} :scope label button {user-select: none; color: #000; padding: 2px 10px; margin-top:10px;} </style>`; html += '<h2 style="text-align:center; margin-top:.5rem;">Settings</h2>'; Object.keys(settingsConfig).forEach(key => { const cfg = settingsConfig[key]; const val = settings[key]; const checked = cfg.type === 'checkbox' && val ? 'checked' : ''; const disabled = cfg.dependentOn && !settings[cfg.dependentOn] ? 'disabled' : ''; html += `<label>${cfg.label}: <input type="${cfg.type}" id="userjs_setting_${key}" value="${val}" ${checked} ${disabled}></label>`; }); html += `<label><button id="ld_userjs_save">保存</button> <span></span><button id="ld_userjs_apply">保存并刷新</button> <span></span><button id="ld_userjs_close">取消</button></label>`; panel.innerHTML = html; document.body.appendChild(panel); Object.keys(settingsConfig).forEach(key => { if (settingsConfig[key].dependentOn) { document.getElementById(`userjs_setting_${settingsConfig[key].dependentOn}`).addEventListener('change', updateDependencies); } }); function updateDependencies() { Object.keys(settingsConfig).forEach(key => { if (settingsConfig[key].dependentOn) { document.getElementById(`userjs_setting_${key}`).disabled = !document.getElementById(`userjs_setting_${settingsConfig[key].dependentOn}`).checked; } }); } document.querySelector('button#ld_userjs_save').addEventListener('click', () => { Object.keys(settingsConfig).forEach(key => { const element = document.getElementById(`userjs_setting_${key}`); settings[key] = element.type === 'checkbox' ? element.checked : element.value; GM_setValue(key, settings[key]); }); alert('Settings saved!'); panel.remove(); }); document.querySelector('button#ld_userjs_apply').addEventListener('click', () => { Object.keys(settingsConfig).forEach(key => { const element = document.getElementById(`userjs_setting_${key}`); settings[key] = element.type === 'checkbox' ? element.checked : element.value; GM_setValue(key, settings[key]); }); panel.remove(); window.location.reload(); }); document.querySelector('button#ld_userjs_close').addEventListener('click', () => panel.remove()); updateDependencies(); } })(); // Function 1: Custom Logo if (settings.icon_custom) { GM_addStyle(` #site-logo { object-fit: scale-down; object-position: -999vw; background-size: contain; background-repeat: no-repeat; } #site-logo.logo-small { background-image: url('${settings.icon_main}'); } #site-logo.logo-big { background-image: url('${settings.icon_wide}'); } #site-logo:hover { object-position: unset; background-image: none; } `); function replaceIcon() { document.querySelector('link[rel="icon"]').href = settings.icon_main; } const observer = new MutationObserver(replaceIcon); observer.observe(document.head, { childList: true, subtree: true }); replaceIcon(); } // Function 2: Click Counts Visualization if (settings.cnts_colorful) { (function countsColorful() { const badges = document.querySelectorAll("span.badge.badge-notification.clicks"); let values = Array.from(badges, badge => parseInt(badge.title || badge.textContent)); let maxValue = Math.max(...values); let minValue = Math.min(...values); if (maxValue < 100 || (maxValue - minValue < 10)) maxValue = maxValue * 1.5; badges.forEach(badge => { if (!badge.style.backgroundColor) { const number = parseInt(badge.title || badge.textContent); const hue = 180 - (number / maxValue) * 180; badge.style.backgroundColor = `hsl(${hue}, 50%, 50%)`; badge.style.color = "#fff"; const sl = document.createElement('span'); sl.style = `height: 1em; display: inline-block; float: right; background: hsl(${hue}, 50%, 50%); width: ${100 * (number / maxValue)}px;`; badge.after(sl); } }); setTimeout(countsColorful, 1500); })(); } // Function 3: Image Resize and Drag if (settings.image_view) { let sizePercent = 80; let isDragging = false; let startX, startY, initialX, initialY; function adjustSize(event) { let contentImg = document.querySelector('div.mfp-content img'); let contentDiv = document.querySelector('div.mfp-content'); if (contentImg) { let delta = event.deltaY > 0 ? -10 : 10; sizePercent += delta; if (sizePercent > 150) sizePercent = 150; if (sizePercent < 5) sizePercent = 5; contentImg.style.width = sizePercent + '%'; contentImg.style.maxWidth = sizePercent + '%'; contentImg.style.height = sizePercent + '%'; contentImg.style.maxHeight = sizePercent + '%'; contentDiv.style.width = contentImg.clientWidth; } } function startDrag(event) { let contentDiv = document.querySelector('div.mfp-content img'); if (contentDiv) { isDragging = true; startX = event.clientX; startY = event.clientY; initialX = contentDiv.offsetLeft; initialY = contentDiv.offsetTop; event.preventDefault(); } } function drag(event) { if (isDragging) { let contentImg = document.querySelector('div.mfp-content img'); let contentDiv = document.querySelector('div.mfp-content'); if (contentImg) { let dx = event.clientX - startX; let dy = event.clientY - startY; contentImg.style.left = (initialX + dx) + 'px'; contentImg.style.top = (initialY + dy) + 'px'; } } } function stopDrag(event) { isDragging = false; } let observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { mutation.addedNodes.forEach(function(node) { if (document.querySelector('div.mfp-content img')) { let contentDiv = document.querySelector('div.mfp-content img'); contentDiv.onwheel = adjustSize; } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); } // Function 4: Quick Bookmark if (settings.quick_mark) { const starSvg = `<svg class="svg-icon" aria-hidden="true" style="text-indent: 1px; transform: scale(1); width:18px; height:18px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"> <path d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"></path></svg></svg> `; let markMap = new Map(); function handleResponse(xhr, successCallback, errorCallback) { xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { successCallback(xhr); } else { errorCallback(xhr); } } }; } function deleteStarMark(mark_btn, data_id) { if (markMap.has(data_id)) { const mark_id = markMap.get(data_id); var xhr = new XMLHttpRequest(); xhr.open('DELETE', `/bookmarks/${mark_id}`, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('x-requested-with', 'XMLHttpRequest'); xhr.setRequestHeader("x-csrf-token", document.head.querySelector("meta[name=csrf-token]")?.content); handleResponse(xhr, (xhr) => { mark_btn.style.color = '#777'; mark_btn.title = "收藏"; mark_btn.onclick = () => addStarMark(mark_btn, data_id); }, (xhr) => { alert('删除失败!' + xhr.statusText + "\n" + TryParseJson(xhr.responseText)); }); xhr.send(); } } function TryParseJson(str) { try { const jsonObj = JSON.parse(str); return JSON.stringify(jsonObj, null, 1); } catch (error) { return str; } } function addStarMark(mark_btn, data_id) { const xhr = new XMLHttpRequest(); xhr.open('POST', '/bookmarks', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); xhr.setRequestHeader('x-requested-with', 'XMLHttpRequest'); xhr.setRequestHeader('discourse-logged-in', ' true'); xhr.setRequestHeader('discourse-present', ' true'); xhr.setRequestHeader("x-csrf-token", document.head.querySelector("meta[name=csrf-token]")?.content); const postData = `name=%E6%94%B6%E8%97%8F&auto_delete_preference=3&bookmarkable_id=${data_id}&bookmarkable_type=Post`; handleResponse(xhr, (xhr) => { mark_btn.style.color = '#fdd459'; mark_btn.title = "删除收藏"; mark_btn.onclick = () => deleteStarMark(mark_btn, data_id); }, (xhr) => { alert('收藏失败!' + xhr.statusText + "\n" + TryParseJson(xhr.responseText)); }); xhr.send(postData); } function addMarkBtn() { let articles = document.querySelectorAll("article[data-post-id]"); if (articles.length <= 0) return; articles.forEach(article => { const target = article.querySelector("div.topic-body.clearfix > div.regular.contents > section > nav > div.actions"); if (target && !article.querySelector("div.topic-body.clearfix > div.regular.contents > section > nav > span.star-bookmark")) { const dataPostId = article.getAttribute('data-post-id'); const starButton = document.createElement('span'); starButton.innerHTML = starSvg; starButton.className = "star-bookmark"; starButton.style.cursor = 'pointer'; starButton.style.margin = '0px 12px'; if (markMap.has(dataPostId)) { starButton.style.color = '#fdd459'; starButton.title = "删除收藏"; starButton.onclick = () => deleteStarMark(starButton, dataPostId); } else { starButton.style.color = '#777'; starButton.title = "收藏"; starButton.onclick = () => addStarMark(starButton, dataPostId); } target.after(starButton); } }); } function getStarMark() { let articles = document.querySelectorAll("article[data-post-id]"); if (articles.length <= 0) return; const currentUserElement = document.querySelector('#current-user button'); const currentUsername = currentUserElement ? currentUserElement.getAttribute('href').replace('/u/', '') : null; const xhr = new XMLHttpRequest(); xhr.open('GET', `/u/${currentUsername}/user-menu-bookmarks`, true); xhr.setRequestHeader("x-csrf-token", document.head.querySelector("meta[name=csrf-token]")?.content); handleResponse(xhr, (xhr) => { var response = JSON.parse(xhr.responseText); response.bookmarks.forEach(mark => { markMap.set(mark.bookmarkable_id.toString(), mark.id.toString()); }); addMarkBtn(); }, (xhr) => { console.error('GET请求失败:', xhr.statusText); }); xhr.send(); } let lastUpdateMarkTime = 0; let lastUpdateButnTime = 0; function mutationCallback() { const currentTime = Date.now(); if (currentTime - lastUpdateMarkTime > 9000) { setTimeout(getStarMark, 500); lastUpdateMarkTime = currentTime; } if (currentTime - lastUpdateButnTime > 1000) { setTimeout(addMarkBtn, 500); lastUpdateButnTime = currentTime; } } const mainNode = document.querySelector("#main-outlet"); if (mainNode) { const observer = new MutationObserver(mutationCallback); observer.observe(mainNode, { childList: true, subtree: true }); } getStarMark(); } //Function 5: restore Browser Default Ctrl+F Search, Removes custom Ctrl+F event listeners。 if (settings.raw_search) { function preventCtrlF(e) { if (e.ctrlKey && e.key === 'f') { e.stopPropagation(); return false; } } document.addEventListener('keydown', preventCtrlF, true); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址