您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
X岛揭示板增强 快捷切饼/顶部添加页码/默认关闭图片水印/预览区真实饼干/当页回复编号/隐藏空标题与名称
当前为
// ==UserScript== // @name X岛-EX // @namespace http://tampermonkey.net/ // @version 1.2.9 // @description X岛揭示板增强 快捷切饼/顶部添加页码/默认关闭图片水印/预览区真实饼干/当页回复编号/隐藏空标题与名称 // @author XY // @match https://www.nmbxd1.com/*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM_deleteValue // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js // @license WTFPL // @note 致谢:切饼代码来自[XD-Enhance](http://greasyfork.icu/zh-CN/scripts/438164-xd-enhance) // @note 联动:可使[增强x岛匿名版](http://greasyfork.icu/zh-CN/scripts/513156-%E5%A2%9E%E5%BC%BAx%E5%B2%9B%E5%8C%BF%E5%90%8D%E7%89%88)添加的预览中显示当前饼名(如ID:cOoKiEs),而非ID:cookies // ==/UserScript== (function($) { 'use strict'; // -------------------- COOKIE 功能(切换饼干、复制翻页、关闭水印) -------------------- function toast(msg) { let toastDiv = $('#ae-toast-inline'); if (!toastDiv.length) { toastDiv = $('<div id="ae-toast-inline" style="position: fixed; top: 10px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.7); color: white; padding: 10px 20px; border-radius: 5px; z-index: 9999; display: none;"></div>'); $('body').append(toastDiv); } toastDiv.text(msg).fadeIn(300).delay(2000).fadeOut(300); } function getCookiesList() { return GM_getValue('cookies', {}); } function getCurrentCookie() { return GM_getValue('now-cookie', null); } // 辅助函数:去掉 cookie.name 末尾 " - 0000-00-00 00:00:00" 部分 function abbreviateName(name) { return name.replace(/\s*-\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}$/, ""); } function removeDateString() { $("#cookie-switcher-ui").find("*").addBack().contents().filter(function() { return this.nodeType === 3; }).each(function() { this.nodeValue = this.nodeValue.replace(/ - 0000-00-00 00:00:00/g, ''); }); } // 更新页面中用于显示当前饼干的区域 function updateCurrentCookieDisplay(currentCookie) { const cookieDisplay = $('#current-cookie-display'); if (cookieDisplay.length) { if (currentCookie) { const displayName = abbreviateName(currentCookie.name); const extra = currentCookie.desc ? (' - ' + currentCookie.desc) : ''; cookieDisplay.text(displayName + extra).css('color', 'black'); } else { cookieDisplay.text('已删除').css('color', 'red'); } } removeDateString(); } // 更新下拉菜单中的选项和默认选中 function updateDropdownUI(cookies) { const dropdown = $('#cookie-dropdown'); dropdown.empty(); //dropdown.append('<option value="">选择饼干</option>'); for (let id in cookies) { if (cookies.hasOwnProperty(id)) { const cookie = cookies[id]; const displayName = abbreviateName(cookie.name); const optionText = displayName + (cookie.desc ? (' - ' + cookie.desc) : ''); dropdown.append(`<option value="${id}">${optionText}</option>`); } } let currentCookie = getCurrentCookie(); if (currentCookie && cookies.hasOwnProperty(currentCookie.id)) { dropdown.val(currentCookie.id); } else { dropdown.val(""); } removeDateString(); } // 切换饼干(切换后更新预览区域中的饼干显示) function switch_cookie(cookie) { if (!cookie || !cookie.id) { toast('无效的饼干信息!'); return; } const url = 'https://www.nmbxd1.com/Member/User/Cookie/switchTo/id/' + cookie.id + '.html'; $.ajax({ type: 'GET', url: url, success: function() { toast('切换成功! 当前饼干为 ' + abbreviateName(cookie.name)); GM_setValue('now-cookie', cookie); updateCurrentCookieDisplay(cookie); updateDropdownUI(getCookiesList()); removeDateString(); updatePreviewCookieId(); // 新增:更新预览区中当前饼干显示 }, error: function() { toast('切换失败,请重试'); } }); } // 刷新饼干列表(解析页面后更新) function refreshCookies() { GM_xmlhttpRequest({ method: 'GET', url: 'https://www.nmbxd1.com/Member/User/Cookie/index.html', onload: function(response) { if (response.status === 200) { let parser = new DOMParser(); let doc = parser.parseFromString(response.responseText, "text/html"); let rows = doc.querySelectorAll('tbody > tr'); let newCookies = {}; rows.forEach(function(row) { let tds = row.querySelectorAll('td'); if (tds.length >= 4) { let id = tds[1].textContent.trim(); let nameLink = tds[2].querySelector('a'); let nameOriginal = nameLink ? nameLink.textContent.trim() : ''; let desc = tds[3].textContent.trim(); newCookies[id] = { id: id, name: nameOriginal, desc: desc }; } }); GM_setValue('cookies', newCookies); updateDropdownUI(newCookies); toast('饼干列表已刷新!'); let currentCookie = getCurrentCookie(); if (currentCookie && !newCookies[currentCookie.id]) { currentCookie = null; } GM_setValue('now-cookie', currentCookie); updateCurrentCookieDisplay(currentCookie); removeDateString(); updatePreviewCookieId(); } else { toast('刷新失败,HTTP状态码:' + response.status); } }, onerror: function() { toast('刷新失败,网络错误。'); } }); } // 构造并插入 Cookie 切换 UI——使用页面原有的 uk-grid 布局,确保按钮固定排列向右 function createCookieSwitcherUI() { // 查找"回应模式"标题所在的元素 const postFormTitle = $('.h-post-form-title:contains("回应模式")').first(); let postFormGrid = null; // 如果找到“回应模式”,则定位到包含它的表单网格 if (postFormTitle.length) { postFormGrid = postFormTitle.closest('.uk-grid.uk-grid-small.h-post-form-grid'); } // 如果没有找到“回应模式”,改为查找“名 称” if (!postFormGrid || !postFormGrid.length) { const nameLabel = $('.h-post-form-title:contains("名 称")').first(); if (nameLabel.length) { postFormGrid = nameLabel.closest('.uk-grid.uk-grid-small.h-post-form-grid'); } } // 如果仍然未找到合适的插入位置,停止函数执行 if (!postFormGrid || !postFormGrid.length) { return; } // 构造切换饼干的 UI const currentCookie = getCurrentCookie(); const cookiesList = getCookiesList(); const switcherUI = $(` <div class="uk-grid uk-grid-small h-post-form-grid" id="cookie-switcher-ui"> <div class="uk-width-1-5"> <div class="h-post-form-title">当前饼干</div> </div> <div class="uk-width-3-5 h-post-form-input" style="display: flex; align-items: center; justify-content: space-between;"> <div class="uk-flex uk-flex-middle"> <span id="current-cookie-display"></span> <select id="cookie-dropdown" style="margin-left: 10px;"> <!-- 饼干选项会通过 updateDropdownUI 填充 --> </select> </div> <div class="uk-flex uk-flex-right uk-flex-nowrap"> <button type="button" id="apply-cookie-button" class="uk-button uk-button-default" style="margin-right: 5px;">应用</button> <button type="button" id="refresh-cookie-button" class="uk-button uk-button-default">刷新</button> </div> </div> </div> `); // 将切换饼干的 UI 插入到表单网格上方 postFormGrid.before(switcherUI); // 更新当前饼干显示和下拉选项 updateCurrentCookieDisplay(currentCookie); updateDropdownUI(cookiesList); // 为“应用”按钮绑定点击事件 $('#apply-cookie-button').on('click', function(e) { e.preventDefault(); const selectedCookieId = $('#cookie-dropdown').val(); if (selectedCookieId) { let cookiesListUpdated = getCookiesList(); const selectedCookie = cookiesListUpdated[selectedCookieId]; if (selectedCookie) { switch_cookie(selectedCookie); } else { toast('选择的饼干信息无效!'); } } else { toast('请选择要切换的饼干!'); } }); // 为“刷新”按钮绑定点击事件 $('#refresh-cookie-button').on('click', function(e) { e.preventDefault(); refreshCookies(); }); } // -------------------- 分页与水印功能 -------------------- // 为页首添加翻页页码,以及显示末页具体页码 function duplicatePagination() { const targetElement = document.querySelector('h2.h-title'); const paginationElement = document.querySelector('ul.uk-pagination.uk-pagination-left.h-pagination'); if (targetElement && paginationElement) { const clonedPagination = paginationElement.cloneNode(true); targetElement.parentNode.insertBefore(clonedPagination, targetElement.nextSibling); // 遍历克隆分页中的所有链接,查找文本为“末页”的链接 const anchors = clonedPagination.getElementsByTagName("a"); for (let i = 0; i < anchors.length; i++) { if (anchors[i].textContent.trim() === "末页") { const href = anchors[i].getAttribute("href"); // 利用正则提取 URL 中的页码数字 const match = href.match(/page=(\d+)/); if (match && match[1]) { anchors[i].textContent = `末页(${match[1]})`; } break; // 找到后就退出循环 } } console.log('Pagination duplicated and last page updated successfully!'); } else { console.log('Could not find target or pagination element.'); } } function disableWatermark() { const watermarkCheckbox = document.querySelector('input[type="checkbox"][name="water"][value="true"]'); if (watermarkCheckbox) { watermarkCheckbox.checked = false; console.log('Watermark checkbox unchecked!'); } else { console.log('Could not find the watermark checkbox.'); } } // 程序入口(用于执行部分初始化操作) function mainCookie() { createCookieSwitcherUI(); duplicatePagination(); disableWatermark(); removeDateString(); } // -------------------- 新增功能 -------------------- // 检查页面是否存在 .h-preview-box,如果存在,则将其中的 "ID:cookies" 替换为当前实际显示的饼干 // “实际显示的饼干”取自当前饼干对象的名称经过 abbreviateName() 处理 function updatePreviewCookieId() { if ($('.h-preview-box').length > 0) { const currentCookie = getCurrentCookie(); if (currentCookie && currentCookie.name) { const displayName = abbreviateName(currentCookie.name); $('.h-preview-box .h-threads-info-uid').text("ID:" + displayName); } else { $('.h-preview-box .h-threads-info-uid').text("ID:cookies"); } } } // -------------------- 回复编号功能 -------------------- // 辅助函数:将数字转换为形如 『数字』 的格式 function circledNumber(n) { return '『' + n + '』'; } // 检查页面中 <div class="h-threads-item-reply-icon">…</div> 的个数,并将其中的 “…” 替换为其所在的『数字』 function updateReplyNumbers() { $('.h-threads-item-reply-icon').each(function(index) { $(this).text(circledNumber(index + 1)); }); console.log('回复编号更新成功!'); } // -------------------- 隐藏标题与邮箱功能 -------------------- // 当 <span class="h-threads-info-title"> 为 "无标题" ,或 <span class="h-threads-info-email"> 为 "无名氏" 时隐藏之 function hideEmptyTitleAndEmail() { $('.h-threads-info-title').each(function() { if ($(this).text().trim() === '无标题') { $(this).hide(); } }); $('.h-threads-info-email').each(function() { if ($(this).text().trim() === '无名氏') { $(this).hide(); } }); console.log('空标题与空邮箱已隐藏!'); } // -------------------- 新增:设置面板模块 -------------------- // 配置面板模块:提供脚本各功能的开关设置,设置通过 GM_setValue 本地保存 const SettingPanel = { name: 'SettingPanel', title: 'X岛-EX设置', // 默认设置项(可根据需要扩展) defaultSettings: { enableCookieSwitch: true, // 切换饼干 enablePaginationDuplication: true, // 添加页首页码 disableWatermark: true, // 关闭图片水印 updatePreviewCookie: true, // 预览区真实饼干 updateReplyNumbers: true, // 当页回复编号 hideEmptyTitleEmail: true // 隐藏空标题与名称 }, settings: {}, settingsKey: 'myScriptSettings', // 设置存储时使用的键 init: function () { // 加载已保存的设置,没有则使用默认设置 SettingPanel.settings = GM_getValue(SettingPanel.settingsKey, SettingPanel.defaultSettings); SettingPanel.renderPanel(); SettingPanel.renderButton(); }, renderPanel: function () { // 构造设置面板(覆盖层) const $panel = $(` <div id="my_setting_panel_cover" style="display:none; position: fixed; top: 0; left: 0; width:100%; height:100%; background: rgba(0,0,0,0.5); z-index: 10000;"> <div id="my_setting_panel" style="position: relative; margin: 10% auto; padding: 20px; background: white; width: 300px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.5);"> <h2 style="margin-top:0;">X岛-EX设置</h2> <div class="setting_item" style="margin-bottom: 10px;"> <input type="checkbox" id="sp_enableCookieSwitch"> <label for="sp_enableCookieSwitch">切换饼干</label> </div> <div class="setting_item" style="margin-bottom: 10px;"> <input type="checkbox" id="sp_enablePaginationDuplication"> <label for="sp_enablePaginationDuplication">添加页首页码</label> </div> <div class="setting_item" style="margin-bottom: 10px;"> <input type="checkbox" id="sp_disableWatermark"> <label for="sp_disableWatermark">关闭图片水印</label> </div> <div class="setting_item" style="margin-bottom: 10px;"> <input type="checkbox" id="sp_updatePreviewCookie"> <label for="sp_updatePreviewCookie">预览区真实饼干</label> </div> <div class="setting_item" style="margin-bottom: 10px;"> <input type="checkbox" id="sp_updateReplyNumbers"> <label for="sp_updateReplyNumbers">当页回复编号</label> </div> <div class="setting_item" style="margin-bottom: 10px;"> <input type="checkbox" id="sp_hideEmptyTitleEmail"> <label for="sp_hideEmptyTitleEmail">隐藏空标题与名称</label> </div> <div style="margin-top:20px; text-align: right;"> <button id="sp_save_button" style="margin-right:10px;">保存设置</button> <button id="sp_close_button">关闭</button> </div> </div> </div> `); $('body').append($panel); // 根据已保存的设置初始化各复选框状态 $('#sp_enableCookieSwitch').prop('checked', SettingPanel.settings.enableCookieSwitch); $('#sp_enablePaginationDuplication').prop('checked', SettingPanel.settings.enablePaginationDuplication); $('#sp_disableWatermark').prop('checked', SettingPanel.settings.disableWatermark); $('#sp_updatePreviewCookie').prop('checked', SettingPanel.settings.updatePreviewCookie); $('#sp_updateReplyNumbers').prop('checked', SettingPanel.settings.updateReplyNumbers); $('#sp_hideEmptyTitleEmail').prop('checked', SettingPanel.settings.hideEmptyTitleEmail); // 保存设置:读取各复选框状态并保存至 GM 存储,然后刷新页面以应用更改 $('#sp_save_button').on('click', function () { SettingPanel.settings.enableCookieSwitch = $('#sp_enableCookieSwitch').is(':checked'); SettingPanel.settings.enablePaginationDuplication = $('#sp_enablePaginationDuplication').is(':checked'); SettingPanel.settings.disableWatermark = $('#sp_disableWatermark').is(':checked'); SettingPanel.settings.updatePreviewCookie = $('#sp_updatePreviewCookie').is(':checked'); SettingPanel.settings.updateReplyNumbers = $('#sp_updateReplyNumbers').is(':checked'); SettingPanel.settings.hideEmptyTitleEmail = $('#sp_hideEmptyTitleEmail').is(':checked'); GM_setValue(SettingPanel.settingsKey, SettingPanel.settings); toast('设置已保存!页面即将刷新'); $('#my_setting_panel_cover').fadeOut(200, function(){ location.reload(); }); }); // 关闭面板 $('#sp_close_button').on('click', function () { $('#my_setting_panel_cover').fadeOut(); }); }, renderButton: function () { // 在页面右上角添加设置按钮,按钮文字改为 “EX设置” const $btn = $(` <button id="sp_config_button" title="打开配置面板" style="position: fixed; top: 10px; right: 10px; z-index: 10000; padding: 5px 10px; border: none; background: #2196F3; color: #fff; border-radius: 4px; cursor: pointer;">EX设置</button> `); $btn.on('click', function () { $('#my_setting_panel_cover').fadeIn(); }); $('body').append($btn); } }; // -------------------- 页面入口 -------------------- $(document).ready(function(){ // 初始化设置面板并添加设置按钮 SettingPanel.init(); // 读取设置,若用户未保存则使用默认配置 const mySettings = GM_getValue(SettingPanel.settingsKey, SettingPanel.defaultSettings); // 根据设置决定是否启用对应功能 if (mySettings.enableCookieSwitch) { createCookieSwitcherUI(); } if (mySettings.enablePaginationDuplication) { duplicatePagination(); } if (mySettings.disableWatermark) { disableWatermark(); } if (mySettings.updatePreviewCookie) { updatePreviewCookieId(); } if (mySettings.updateReplyNumbers) { updateReplyNumbers(); } if (mySettings.hideEmptyTitleEmail) { hideEmptyTitleAndEmail(); } }); })(jQuery);