// ==UserScript==
// @name JAVBUS助手
// @namespace http://tampermonkey.net/
// @version 1.5
// @description JAVBUS网站增加自动翻页,论坛页面精简
// @author A9
// @match https://www.javbus.com/
// @include /^https?:\/\/(?:[A-Za-z0-9]+\.)*(?:javbus|busjav|busfan|fanbus|buscdn|cdnbus|dmmsee|seedmm|busdmm|dmmbus|javsee|seejav)(?:\.[A-Za-z0-9]+)(?:[\S]*)$/
// @grant GM_addStyle
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABFElEQVQ4ja2TMU4CQRSGvzfuKkQ2bqORRpKNV6CjIaGgovQK1LRs7R24AoECbrAHWE7glhQkJO4SEgt1GQsCBhmG1fjKee//8v/zZiSGJ+AZeOR3lQChxPDyB/EeIjFo28SuKSf6jk0sjoPXaHDh+6yjiDzLjmaUDaDKZe77fR4GAy5rNaNVK2DnQlwXEXOIs4Bz9f8AU85TG4CfW1AKv93mul7ndTjkfT4HETSgN5sCAK256XS47XZRlQrrKOIqCMjTlDxNjU7UoV6TTSZ8Lpfc9XoEoxFutUo6HvOxWBgdHL1EcRy8ZhOv1UKVSrzNZmTTKflqVQwA2wOBbX6trZeo2P6qQ+p3JqsYSBQQmiAFKgHCL3I+UIXeDJynAAAAAElFTkSuQmCC
// @license MIT
// ==/UserScript==
(function () {
"use strict";
//脚本设置项
let settings = {
enable_forum_style_override: 1, // 是否开启论坛排版样式优化,0 关闭;1 开启。开启后页面间距更紧凑,可使浏览更加高效
enable_forum_auto_pager: 1, // 是否开启论坛自动翻页功能,0 关闭;1 开启
enable_main_auto_pager: 1, // 是否开启主站自动翻页功能,0 关闭;1 开启
enable_hide_sign_image: 0, // 是否开启隐藏签名图
enable_debug_mode: 0,
};
/**
* 当前页面的浏览模式 forumdisplay 板块列表页 | viewthread 帖子详情页 | default 默认适用于其他所有页面 | actresses 演员页 | favorite 收藏页(论坛) | forum 论坛搜索结果 | thread 个人主题/回复页 | guide 新帖导读页 | friend 好友页 | notice 我的通知
* @type { "forumdisplay" | "viewthread" | "default" | "actresses" | "favorite" | "forum" | "thread" | "guide" | "friend" | "notice"}
*/
let PAGE_MOD = "default";
let CURRENT_SETTING = null; //当前页翻页规则
let isForum = false; //当前页是否是论坛页面
let authorLink = null; //楼主个人空间链接(用于判断用户是否为楼主)
let loadedURLSet = null; //已加载过的页面URL(防止重复加载)
const PAGE_SETTINGS = {
default: {
listDomSelector: "#waterfall.masonry",
itemDomSelector: "#waterfall > .item:has(.movie-box)",
pagerDomSelector: ".pagination.pagination-lg",
nextPageDomSelector: "#next",
nodeAfterAddCall: () => {
//重新计算瀑布流的布局
jQuery("#waterfall").masonry("reload");
},
},
actresses: {
listDomSelector: "#waterfall.masonry",
itemDomSelector: "#waterfall > .item:has(.avatar-box)",
pagerDomSelector: ".pagination.pagination-lg",
nextPageDomSelector: "#next",
nodeAfterAddCall: () => {
//重新计算瀑布流的布局
jQuery("#waterfall").masonry("reload");
},
},
viewthread: {
listDomSelector: "#postlist",
itemDomSelector: "#postlist > .nthread_postbox:not(.nthread_firstpostbox)",
pagerDomSelector: ".mn > .pgs.mtm.mbm.cl > .pg",
nextPageDomSelector: ".nxt",
nodeBeforeAddCall: (node) => {
node.querySelector(".imicn a[title='查看個人網站']")?.remove(); //删除多余的元素
node.querySelector(".showmenu").style.display = "none"; //隐藏‘使用道具’菜单
//标记楼主
markAuthor(node);
//删除签名图
if (settings.enable_hide_sign_image) {
removeSignImage(node);
}
//移动‘举报’按钮
moveReportButton(node);
},
},
forumdisplay: {
listDomSelector: "#threadlisttableid",
itemDomSelector: "#threadlisttableid > tbody",
pagerDomSelector: "#fd_page_bottom > .pg",
nextPageDomSelector: ".nxt",
},
forum: {
listDomSelector: "#threadlist ul",
itemDomSelector: "#threadlist ul > li",
pagerDomSelector: "div.pgs.cl.mbm > .pg",
nextPageDomSelector: ".nxt",
},
guide: {
listDomSelector: "#threadlist table",
itemDomSelector: "#threadlist table > tbody",
pagerDomSelector: ".pg:has(.nxt)",
nextPageDomSelector: ".nxt",
},
favorite: {
listDomSelector: "#favorite_ul",
itemDomSelector: "#favorite_ul > li",
pagerDomSelector: "div.pgs.cl.mtm > .pg",
nextPageDomSelector: ".nxt",
},
thread: {
listDomSelector: ".tl table tbody",
itemDomSelector: ".tl table tbody > tr:not(.th)",
pagerDomSelector: "div.pgs.cl.mtm > .pg",
nextPageDomSelector: ".nxt",
},
friend: {
listDomSelector: "ul.buddy.cl",
itemDomSelector: "ul.buddy.cl > li",
pagerDomSelector: "div.mtm.pgs.cl > .pg",
nextPageDomSelector: ".nxt",
},
notice: {
listDomSelector: "div.nts",
itemDomSelector: "div.nts > dl",
pagerDomSelector: "div.pgs.cl > .pg",
nextPageDomSelector: ".nxt",
},
};
//脚本入口点,排除frame或iframe
if (window !== window.top) return;
initialized();
overrideForumStyle();
autoPager();
function initialized() {
let url = new URL(window.location.href);
//根据 url 中的 mod 参数来判断当前页面类型
let mod = url.searchParams.get("mod");
if (mod) {
isForum = true;
//论坛中的二级页面
let doType = url.searchParams.get("do");
if (doType) {
PAGE_MOD = doType;
} else {
PAGE_MOD = mod;
}
} else if (
url.pathname.includes("actresses") ||
url.pathname.includes("searchstar")
) {
PAGE_MOD = "actresses";
}
//根据不同的页面,使用不同的翻页规则
CURRENT_SETTING = PAGE_SETTINGS[PAGE_MOD];
//帖子查看模式
if (PAGE_MOD === "viewthread") {
//读取楼主个人空间链接
authorLink = document.querySelector(".authi.mb5 .au")?.href;
}
//将当前页面添加到已加载过的页面集合中
loadedURLSet = new Set([window.location.href]);
}
function autoPager() {
if (!CURRENT_SETTING) return;
//翻页dom
const obTarget = document.querySelector(CURRENT_SETTING.pagerDomSelector);
//当前页面只有一页或已经是最后一页,无需翻页
if (!obTarget || !obTarget.querySelector(CURRENT_SETTING.nextPageDomSelector)) {
log("当前页面只有一页或已经是最后一页,无需翻页");
return;
}
//观察器配置
const observerOptions = {
root: null,
rootMargin: "0px",
};
//观察器回调
const intersectionCallback = function (entries) {
if (entries[0].intersectionRatio <= 0) return;
//下一页的链接
let nextPageLink = obTarget.querySelector(
CURRENT_SETTING.nextPageDomSelector
)?.href;
//到尾页,停止观察器
if (!nextPageLink) {
autoPagerOB.disconnect();
log("停止观察器");
} else {
//加载下一页的内容
loadNextPage(nextPageLink);
}
};
//创建交叉观察器
let autoPagerOB = new IntersectionObserver(intersectionCallback, observerOptions);
//在顶部导航栏的右侧增加控制按钮
let navBar = document.querySelector(isForum ? "#toptb" : "#navbar");
let toggleAutoPager = document.createElement("a");
toggleAutoPager.href = "javascript:void(0)";
toggleAutoPager.innerText = `${
settings.enable_main_auto_pager ? "关闭" : "开启"
}自动翻页`;
toggleAutoPager.className = "nav navbar-nav navbar-right";
toggleAutoPager.style.cssText = `
display: block;
padding: ${isForum ? "11" : "15"}px;
color: rgb(119, 119, 119);
float: right;
font-size: 14px;
`;
toggleAutoPager.addEventListener("click", () => {
if (settings.enable_main_auto_pager) {
autoPagerOB?.unobserve(obTarget); //停止观察
settings.enable_main_auto_pager = 0;
} else {
autoPagerOB?.observe(obTarget); //继续观察
settings.enable_main_auto_pager = 1;
}
toggleAutoPager.innerText = `${
settings.enable_main_auto_pager ? "关闭" : "开启"
}自动翻页`;
});
navBar?.append(toggleAutoPager);
if (
(settings.enable_main_auto_pager && !isForum) ||
(settings.enable_forum_auto_pager && isForum)
)
autoPagerOB.observe(obTarget);
}
function loadNextPage(nextPageURL, retryTime = 2, isRetry = false) {
log(
"nextPageURL:" +
nextPageURL +
"\t此次是否为重试请求:" +
isRetry +
"\t重试次数: " +
retryTime
);
//忽略掉已加载过的页面地址,和当前正在加载的URL
if (loadedURLSet.has(nextPageURL) && isRetry === false) {
log("已加载过此页面的数据或正在加载此页面的数据,忽略本次请求");
return;
}
if (isRetry === false) {
//将第一次发起的请求页面添加到已访问页面集合中(非重试请求)
loadedURLSet.add(nextPageURL);
}
fetch(nextPageURL)
.then((resp) => {
if (resp.redirected) {
//服务器有一定概率会在访问时出现重定向
log("请求被重定向\r\n目标链接: " + nextPageURL + "\r\n重定向地址: " + resp.url);
if (loadedURLSet.has(resp.url) && retryTime > 0) {
//重试
return loadNextPage(nextPageURL, --retryTime, true);
}
}
return resp.text();
})
.then((text) => {
if (!text) return;
let nextPageDocument = convertTextToDOM(text);
log(
"title:" + nextPageDocument?.head.getElementsByTagName("title")[0]?.innerText
);
const comments = nextPageDocument.querySelectorAll(
CURRENT_SETTING.itemDomSelector
);
//追加内容之前对每个item的预处理回调
if (CURRENT_SETTING.nodeBeforeAddCall) {
comments.forEach(CURRENT_SETTING.nodeBeforeAddCall);
}
let postlist = document.querySelector(CURRENT_SETTING.listDomSelector);
//用新页面的分页DOM元素来替换上一页的分页DOM
document.querySelector(CURRENT_SETTING.pagerDomSelector).innerHTML =
nextPageDocument.querySelector(CURRENT_SETTING.pagerDomSelector).innerHTML;
postlist?.append(...Array.from(comments));
//追加内容之后的处理回调
if (CURRENT_SETTING.nodeAfterAddCall) {
CURRENT_SETTING.nodeAfterAddCall.call();
}
})
.catch((e) => {
log("加载内容出错");
//从集合中删除请求地址
loadedURLSet.delete(nextPageURL);
return;
});
}
function convertTextToDOM(text) {
const parser = new DOMParser();
return parser.parseFromString(text, "text/html");
}
/**
* 标记楼主
* @param {HTMLElement} node 回复消息元素
*/
function markAuthor(node) {
const authorDom = node.querySelector(".authi .xw1");
//如果与作者的个人空间链接相同,则说明当前回复内容是由楼主发布的
if (authorDom?.href === authorLink) {
authorDom.insertAdjacentElement("afterend", _createOPTag());
}
//点评区域的内容也同样进行楼主标记
node.querySelectorAll(".pstl.xs1.cl a:is(.xi2.xw1)").forEach((commentAuthorDom) => {
if (commentAuthorDom?.href === authorLink) {
commentAuthorDom.insertAdjacentElement(
"afterend",
_createOPTag("margin:0 0 0 4px")
);
}
});
//创建一个标识楼主的Tag元素
function _createOPTag(tagStyle = "") {
//楼主标识元素,用于在帖子中显示楼主
let authorTagDOM = document.createElement("span");
authorTagDOM.style.cssText = `
color: #55b624;
border: 1px solid #55b624;
padding: 1px 3px;
border-radius: 2px;
margin: 0 6px;
`;
if (tagStyle) {
authorTagDOM.style.cssText += tagStyle;
}
authorTagDOM.textContent = "楼主";
return authorTagDOM;
}
}
/**
* 在新位置添加举报按钮,并将原始位置的容器元素隐藏,从而使页面布局更加紧凑
* @param {HTMLElement} node 回复消息元素
*/
function moveReportButton(node) {
//如果当前回复没有‘点评’和‘回复’按钮,也没有‘管理’按钮;则表明帖子已经被归档,无法修改,此时可以移动举报按钮到右上角来节省空间
if (
node.querySelector(".fastre") ||
node.querySelector(".cmmnt") ||
node.querySelector(".po.hin")?.innerText.includes("管理")
)
return;
//移动‘举报’按钮的位置
const report = node.querySelector("td.plc p > a:nth-child(2)");
if (report?.innerText === "舉報") {
report.style.marginTop = "-2px";
report.style.color = "#ccc";
node.querySelector("td.plc > div.pi strong")?.appendChild(report);
node.querySelector(".po.hin")?.style.setProperty("display", "none");
}
}
/**
* 删除签名图
* @param {HTMLElement} node 回复消息元素
*/
function removeSignImage(node) {
node.querySelector(".sign")?.remove();
}
function overrideForumStyle() {
//只对论坛页面生效
if (!isForum) return;
if (PAGE_MOD === "viewthread") {
//将上传图片和发表评论组合到一起
//#Form1.parentElement 表示的是上传图片附件的DOM元素
let f_pst = document.querySelector("#f_pst");
f_pst?.append(document.querySelector("#Form1").parentElement);
let firstPost = document.querySelector(".nthread_firstpost"); //#1楼的帖子
//将回复帖子的Form移动到1楼下面
firstPost?.insertAdjacentElement("afterend", f_pst);
//增加一个快速定位回复框的按钮
let goReply = document.createElement("a");
goReply.id = "goReply";
goReply.href = "javascript:void(0)";
goReply.addEventListener("click", () => {
f_pst.scrollIntoView();
});
goReply.style.cssText = `
display: block;
position: fixed;
bottom: 370px;
width: 50px;
height: 50px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAD1BMVEUAAADvSETxSETySEPxSEOfb+sGAAAABHRSTlMAQIC/o1TdDAAAAGJJREFUeNrty4EGgEAQBuFp/3v/Zw4r54rVL6LuBgx8tDsFvQW+DiLT8BUgi+EfgdypQd0CPwKKou0KRN0ZCA8IDwgPiKNodQmEB4QHhAl4D9TJBcgFhAW6wBW4AlfgClyxA0shFWNNOTW7AAAAAElFTkSuQmCC) no-repeat 50% 50%;
background-color: #fff;
background-size: 28px 28px;
`;
document.querySelector(".biaoqi-fix-area").appendChild(goReply);
//遍历第一页的所有帖子消息
const nodes = document.querySelectorAll("#postlist > .nthread_postbox");
for (const node of nodes) {
if (settings.enable_hide_sign_image) {
//删除签名图
removeSignImage(node);
}
//标记楼主
markAuthor(node);
//移动‘举报’按钮
moveReportButton(node);
}
}
let styleRules = `
#goReply:hover{background-blend-mode: screen;background-color: #F14843 !important;}
#toptb{position: sticky; top: 0; z-index: 99;}
`;
if (settings.enable_forum_style_override) {
styleRules += `
.psth {margin:1em 0 1em 0px}
.pls .avatar img { border-radius:50%; height: 50px; }
tr .plm { padding-top: 10px !important }
.hin .pob { padding-bottom: 4px; padding-top: 4px;}
.nthread_postbox .pi strong a { margin-top: -6px; }
.t_fsz { min-height: auto; }
.pct { padding-bottom: 0em; }
#postlist .ad .pls, #postlist .ad .plc { display: none; }
.pcb .cm .psth { margin-top: 0px; }
.pcb .cm .psth { margin-bottom: 10px; }
.t_f, .t_f td { line-height: 1.6; }
.pcb .psth { font-size: 14px !important; font-weight: 500; }
#p_btn { padding:0 0 10px 0; }
.jav-footer { display: none; }
#postlist { padding: 0 20px 0px 20px; }
a[rel="nofollow"]{display:none;}
.ct2 .mn {margin-bottom: 0;}
.authi em { color:#ccc; }
.pob { line-height: 32px; }
`;
}
GM_addStyle(styleRules);
}
function log(msg) {
if (settings.enable_debug_mode == true) {
if (typeof msg === "object") {
console.dir(msg);
} else {
console.log(msg);
}
}
}
})();