// ==UserScript==
// @name X岛-EX
// @namespace http://tampermonkey.net/
// @version 1.2.10
// @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/jquery@3.6.0/dist/jquery.min.js
// @license WTFPL
// @note 致谢:切饼代码来自[XD-Enhance](https://greasyfork.org/zh-CN/scripts/438164-xd-enhance)
// @note 联动:可使[增强x岛匿名版](https://greasyfork.org/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
// @downloadURL none
// ==/UserScript==
(function($) {
'use strict';
// -------------------- COOKIE 功能(切换饼干、复制翻页、关闭水印) --------------------
function toast(msg) {
let toastDiv = $('#ae-toast-inline');
if (!toastDiv.length) {
toastDiv = $('
');
$('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('');
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(``);
}
}
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(callback) {
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();
if (callback) callback();
} else {
toast('刷新失败,HTTP状态码:' + response.status);
if (callback) callback();
}
},
onerror: function() {
toast('刷新失败,网络错误。');
if (callback) callback();
}
});
}
// 弹出登录提示面板
function showLoginPrompt() {
const $loginModal = $(`
提示
当前已退出登录,无法切换饼干。
`);
$('body').append($loginModal);
$('#login-btn').on('click', function() {
window.open("https://www.nmbxd1.com/Member/User/Index/login.html", '_blank');
$('#login-prompt-modal').fadeOut(200, function(){ $(this).remove(); });
});
$('#close-login-btn').on('click', function() {
$('#login-prompt-modal').fadeOut(200, function(){ $(this).remove(); });
});
}
// 构造并插入 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 = $(`
`);
// 将切换饼干的 UI 插入到表单网格上方
postFormGrid.before(switcherUI);
// 更新当前饼干显示和下拉选项
updateCurrentCookieDisplay(currentCookie);
updateDropdownUI(cookiesList);
// 为“应用”按钮绑定点击事件
$('#apply-cookie-button').on('click', function(e) {
e.preventDefault();
const selectedCookieId = $('#cookie-dropdown').val();
// 先执行刷新操作,然后再执行切换操作
refreshCookies(function() {
let cookiesListUpdated = getCookiesList();
if (Object.keys(cookiesListUpdated).length === 0) {
// 饼干列表为空,可能已退出登录,弹出登录提示
showLoginPrompt();
} else {
if (selectedCookieId) {
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 + '』';
}
// 检查页面中 …
的个数,并将其中的 “…” 替换为其所在的『数字』
function updateReplyNumbers() {
$('.h-threads-item-reply-icon').each(function(index) {
$(this).text(circledNumber(index + 1));
});
console.log('回复编号更新成功!');
}
// -------------------- 隐藏标题与邮箱功能 --------------------
// 当 为 "无标题" ,或 为 "无名氏" 时隐藏之
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 = $(`
`);
$('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 = $(`
`);
$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);