- // ==UserScript==
- // @name Soul++
- // @namespace SoulPlusPlus
- // @version 1.0.2
- // @description 提升你的魂+使用体验
- // @run-at document-start
- // @author 镜花水中捞月
- // @homepage https://github.com/FetchTheMoon
- // @icon64 https://cdn.jsdelivr.net/gh/FetchTheMoon/UserScript/LOGO.png
- // @supportURL https://github.com/FetchTheMoon/UserScript/issues
- // ----------------COPY START---------------------
- // @match https://*.spring-plus.net/*
- // @match https://*.summer-plus.net/*
- // @match https://*.soul-plus.net/*
- // @match https://*.south-plus.net/*
- // @match https://*.north-plus.net/*
- // @match https://*.snow-plus.net/*
- // @match https://*.level-plus.net/*
- // @match https://*.white-plus.net/*
- // @match https://*.imoutolove.me/*
- // @match https://*.south-plus.org/*
- // @match https://*.east-plus.net/*
- // --------------------------------------------
- // @match https://spring-plus.net/*
- // @match https://summer-plus.net/*
- // @match https://soul-plus.net/*
- // @match https://south-plus.net/*
- // @match https://north-plus.net/*
- // @match https://snow-plus.net/*
- // @match https://level-plus.net/*
- // @match https://white-plus.net/*
- // @match https://imoutolove.me/*
- // @match https://south-plus.org/*
- // @match https://east-plus.net/*
- // --------------------------------------------
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_listValues
- // @grant GM_addValueChangeListener
- // @grant GM_removeValueChangeListener
- // @grant GM_notification
- // @grant GM_deleteValue
- // @grant GM_addStyle
- // @grant GM_getResourceText
- // @grant unsafeWindow
- // --------------------------------------------
- // @require https://cdn.jsdelivr.net/npm/toastify-js@1.11.2/src/toastify.min.js
- // @resource TOASTIFY_CSS https://cdn.jsdelivr.net/npm/toastify-js@1.11.2/src/toastify.css
- // ----------------COPY END---------------------
- // @license GPL-3.0 License
- // ==/UserScript==
-
- 'use strict';
-
- const PageType = Object.freeze({
- THREADS_PAGE: Symbol("普通主题列表"),
- PIC_WALL_PAGE: Symbol("图墙区主题列表"),
- POSTS_PAGE: Symbol("帖子列表"),
- SEARCH_RESULT: Symbol("搜索结果")
- });
-
- const ToastType = Object.freeze({
- INFO: Symbol("信息"),
- SUCCESS: Symbol("成功"),
- DANGER: Symbol("危险,失败"),
- WARNING: Symbol("警告")
- });
-
- const FETCH_CONFIG = {
- credentials: 'include',
- mode: "no-cors"
- };
-
- function getElementByXpath(from, xpath) {
- return from.evaluate(xpath, from, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
- }
-
- function waitForImageToLoad(imageElement) {
- return new Promise(resolve => {
- imageElement.onload = resolve
- })
- }
-
- function toast(info, toastType, time = 3000, close = true) {
- let t;
- switch (toastType) {
- case ToastType.INFO:
- t = "linear-gradient(109deg, #3da1e0, #004dc1)";
- break;
- case ToastType.SUCCESS:
- t = "linear-gradient(213deg, #5daa16, #05bb1b)";
- break;
- case ToastType.DANGER:
- t = "linear-gradient(18deg, #cb3131, #ac1415)";
- break;
- case ToastType.WARNING:
- t = "linear-gradient(180deg, #e98202, #fe5e00)";
- break;
- default:
- t = "linear-gradient(109deg, #3da1e0, #004dc1)";
- }
- Toastify({
- text: info,
- duration: time,
- close: close,
- gravity: "bottom", // `top` or `bottom`
- position: "right", // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- background: t,
- },
- onClick: function () {
- } // Callback after click
- }).showToast();
-
- }
-
- function getTimeStamp() {
- return new Date().getTime();
- }
-
- function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms))
- }
-
-
- function getRandomInt(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min + 1)) + min;
- }
-
- async function fetchRetry(url, options, n = 1) {
- try {
- return await fetch(url, options)
- } catch (err) {
- if (n <= 1) throw err;
- return await fetchRetry(url, options, n - 1);
- }
- }
-
- async function getPage(url, dummy = false, retry = 3, toastPop = false) {
- return await fetchRetry(url, FETCH_CONFIG, retry)
- .then(resp => resp.text())
- .then(html => {
- if (dummy) {
- let dummy = document.createElement("html");
- dummy.insertAdjacentHTML('afterbegin', html);
- return dummy
- } else {
- return html
- }
- }).catch(e => {
- if (toastPop) {
- toast(`访问 ${url} 失败\n${e}`, ToastType.WARNING);
- } else {
- console.error(`访问 ${url} 失败\n${e}`);
- }
- }
- );
- }
-
- class GMK {
-
- static addStyle(css) {
- return GM_addStyle(css);
- }
-
- static setValue(key, value) {
- return GM_setValue(key, value)
- }
-
- static getValue(key) {
- return GM_getValue(key)
- }
-
- static getResourceText(key) {
- return GM_getResourceText(key);
- }
-
- static listValues() {
- return GM_listValues();
- }
-
- static deleteValue(_name) {
- return GM_deleteValue(_name);
- }
-
- // listener_id = GM_addValueChangeListener(name, function(name, old_value, new_value, remote) {})
- static addValueChangeListener(_name, callback) {
- return GM_addValueChangeListener(_name, callback);
- }
-
- static removeValueChangeListener(listener_id) {
- return GM_removeValueChangeListener(listener_id);
- }
- }
-
- class MppManager {
- static TASK_KEY = "Soul++:MppThreadsStatus";
-
- constructor() {
- }
-
- static isThreadExist(_tid) {
- return this.getMarkList().hasOwnProperty(_tid);
- }
-
- static getMarkList() {
- return GMK.getValue(this.TASK_KEY) || {}
- }
-
- static addMarkThread(_tid) {
- GMK.setValue(this.TASK_KEY, { ...this.getMarkList(), ...{ [_tid]: {} } })
- }
-
- static deleteMarkedThread(_tid) {
- let markList = this.getMarkList();
- delete markList[_tid];
- GMK.setValue(this.TASK_KEY, markList)
- }
-
- static isMarked(_tid) {
- return this.getMarkList().hasOwnProperty(_tid)
- }
-
- static getAllThreadStatus() {
- return this.getMarkList();
- }
-
- static setThreadStatus(_tid, threadStatus) {
- GMK.setValue(this.TASK_KEY, {
- ...this.getMarkList(),
- [_tid]: threadStatus
- });
- }
-
- static getLastFetchTime(_tid) {
- let res = Object.entries(GMK.getValue(this.TASK_KEY)).filter(e => e[0] === _tid);
- return res[0][1]["lastFetchTime"];
- };
-
- static isAllChecked() {
- let res = Object.entries(GMK.getValue(this.TASK_KEY)).filter(e => !e[1]["allPagesChecked"]);
- return res.length === 0;
- };
- }
-
- //##############################################################
- // 功能
- //##############################################################
-
- function buyRefresh_free(target = document) {
- let buyButtons = target.querySelectorAll(".quote.jumbotron>.btn.btn-danger")
- buyButtons.forEach(button => {
- // 获取GET购买地址
- const urlRegex = /location\.href='(.+)'/
- const buyUrl = button.getAttribute("onclick");
- if (buyUrl === null) return;
- let m = buyUrl.match(urlRegex);
- if (m === null) return;
- let url = m[1];
- // 避免点击按钮的时候跳转,删掉这个属性
- button.setAttribute("onclick", "null");
- // 拿到帖子ID
- let postContainer = button.closest(".tpc_content .f14")
- let post_id = postContainer.getAttribute("id");
- // 添加点击事件,用fetch发送请求,然后读取页面再直接修改当前页面
- let customPurchase = (e => {
- e.stopPropagation();
- let btn = e.target;
- btn.setAttribute("value", "正在购买……请稍等………");
- try {
- fetch(url, FETCH_CONFIG)
- .then(resp => resp.text())
- .then(text => {
- if (!text.includes("操作完成")) {
- toast("购买失败!", ToastType.DANGER);
- return;
- }
- let threadID = postContainer.getAttribute("tid");
- let pg = postContainer.getAttribute("page");
- let resultURL = `./read.php?tid=${threadID}&page=${pg}`;
- fetch(resultURL, FETCH_CONFIG).then(resp => resp.text())
- .then(html => {
- let dummy = document.createElement("html");
- dummy.innerHTML = html;
- if (GMK.getValue("hidePostImage")) {
- hidePostImage(dummy);
- }
- let purchased = dummy.querySelector("#" + post_id);
- let notPurchased = document.querySelector("#" + post_id);
- notPurchased.parentNode.replaceChild(purchased, notPurchased);
-
- });
-
- btn.style.display = "none";
-
- });
-
- } catch (error) {
- toast(`发送请求出错,购买失败!\n${error}`, ToastType.DANGER);
- console.log('Request Failed', error);
- }
- })
-
- button.addEventListener("click", customPurchase);
- });
- }
-
- function hideImg(img) {
- // 避免折叠论坛表情
- const emojiPathReg = /images\/post\/smile\//;
- if (img.getAttribute("src").match(emojiPathReg)) {
- return
- }
- // 避免折叠论坛自带的文件图标
- const fileIconPathReg = /images\/colorImagination\/file\//;
- if (img.getAttribute("src").match(fileIconPathReg)) {
- return
- }
-
- // 避免重复处理
- let p = img.parentNode;
- if (p.getAttribute("class") === "spp-img-mask") return;
-
- // 如果开启了按需加载
- if (GMK.getValue("loadImageOnDemand")) {
- img.dataset.src = img.getAttribute("src");
- img.setAttribute("src", "")
- }
-
- // 如果图片的父元素是A标签,去掉它
- if (img.parentNode.tagName === "A") img.parentNode.replaceWith(img);
- // 创建包裹元素
- let wrapper = document.createElement('div');
- wrapper.setAttribute("class", "spp-img-mask");
- wrapper.style.display = "grid";
- wrapper.style.gridTemplateRows = "auto auto";
- wrapper.style.justifyItems = "center";
-
- // 将父元素下的图片元素替换成包裹元素
- img.parentNode.replaceChild(wrapper, img);
-
- // 将图片元素当成子元素放入包裹元素
- wrapper.appendChild(img);
-
- img.style.width = "100%";
-
- // 添加类名
- img.setAttribute("class", "spp-thread-imgs spp-hide");
-
- // 包裹元素样式
- wrapper.style.borderStyle = "dashed";
- wrapper.style.width = "auto";
- wrapper.style.height = "20";
- wrapper.style.textAlign = "center";
- wrapper.style.verticalAlign = "center";
- wrapper.style.cursor = "pointer";
-
- // 创建遮罩小人儿表情
- let icon_hide = document.createElement("img");
- icon_hide.setAttribute("src", "images/post/smile/smallface/face106.gif");
-
- let icon_show = document.createElement("img");
- icon_show.setAttribute("src", "images/post/smile/smallface/face109.gif");
-
-
- // 创建遮罩文本
- let tip = document.createElement("span");
- let tip_text = document.createElement("span");
- tip_text.innerText = "看看是啥";
-
- // 凑一堆儿来
- tip.appendChild(icon_hide);
- tip.appendChild(icon_show);
- tip.appendChild(tip_text);
-
- // 添加类名
- icon_hide.setAttribute("class", "spp-img-mask-icon-hide");
- icon_show.setAttribute("class", "spp-img-mask-icon-show spp-hide");
- tip.setAttribute("class", "ssp-img-mask-text");
-
- // 插入元素
- wrapper.insertBefore(tip, img);
- // 防止点击图片打开新窗口
- document.querySelector(".spp-thread-imgs").addEventListener("click", e => e.preventDefault());
- // 事件监听
- wrapper.addEventListener("click", (e) => {
- e.stopPropagation();
- // console.log(e.target);
- // console.log(e.currentTarget);
- let img = e.currentTarget.querySelector(".spp-thread-imgs");
- img.classList.toggle("spp-hide");
- // 按需加载
- if (GMK.getValue("loadImageOnDemand") && !img.classList.contains("spp-hide")) {
- let loading = document.createElement("div");
- loading.innerHTML = `<div class="spp-loading-animation">
- <div class="dot1"></div>
- <div class="dot2"></div>
- <div class="dot3"></div>
- </div>`;
- loading = loading.firstChild;
- img.parentNode.append(loading);
- img.setAttribute("src", img.dataset.src);
- waitForImageToLoad(img).then(() => {
- loading.parentNode.removeChild(loading);
- });
- }
- e.currentTarget.querySelector(".spp-img-mask-icon-hide").classList.toggle("spp-hide");
- e.currentTarget.querySelector(".spp-img-mask-icon-show").classList.toggle("spp-hide");
- });
-
- }
-
- function hideAvatar(avatar) {
- let src = avatar.getAttribute("src");
- if (src === "images/face/none.gif") return;
-
- // 如果开启了按需加载
- if (GMK.getValue("loadImageOnDemand")) {
- avatar.dataset.src = avatar.getAttribute("src");
- avatar.setAttribute("src", "")
- }
-
- // 创建包裹元素
- let wrapper = document.createElement('div');
- wrapper.setAttribute("class", "spp-avatar-mask");
- wrapper.style.minWidth = "162px";
- wrapper.style.minHeight = "162px";
- wrapper.style.display = "grid";
- wrapper.style.justifyItems = "center";
- wrapper.style.alignItems = "center";
-
- // 创建一个假头像
- let fakeAvatarElement = document.createElement("img");
- fakeAvatarElement.setAttribute("src", "images/face/none.gif");
- fakeAvatarElement.style.borderStyle = "dashed";
- fakeAvatarElement.style.borderRadius = "3";
- fakeAvatarElement.style.borderWidth = "3px";
- fakeAvatarElement.style.borderColor = "Orange";
-
- // 替换包裹元素
- avatar.parentNode.replaceChild(wrapper, avatar);
-
- // 将假头像和真头像插到包裹元素中
- wrapper.appendChild(avatar);
- wrapper.appendChild(fakeAvatarElement);
-
- // 隐藏真头像
- avatar.classList.add("spp-hide");
-
- // 设置类名
- avatar.classList.add("spp-avatar-real");
- fakeAvatarElement.classList.add("spp-avatar-fake");
-
- // 事件监听
- wrapper.addEventListener("mouseenter", (e) => {
- e.stopPropagation();
- e.currentTarget.querySelector(".spp-avatar-fake").classList.add("spp-hide");
- e.currentTarget.querySelector(".spp-avatar-real").classList.remove("spp-hide");
- // 按需加载
- if (GMK.getValue("loadImageOnDemand") && !avatar.classList.contains("spp-hide")) {
- let loading = document.createElement("div");
- loading.innerHTML = `<div class="spp-loading-animation">
- <div class="dot1"></div>
- <div class="dot2"></div>
- <div class="dot3"></div>
- </div>`;
- loading = loading.firstChild;
- e.currentTarget.append(loading);
- avatar.setAttribute("src", avatar.dataset.src);
- waitForImageToLoad(avatar).then(() => {
- loading.parentNode.removeChild(loading);
- });
- }
- });
-
- wrapper.addEventListener("mouseleave", (e) => {
- e.stopPropagation();
- e.currentTarget.querySelector(".spp-avatar-fake").classList.remove("spp-hide");
- e.currentTarget.querySelector(".spp-avatar-real").classList.add("spp-hide");
- e.currentTarget.querySelectorAll(".spp-loading-animation").forEach(ele => ele.parentNode.removeChild(ele));
- });
-
-
- }
-
- function hidePostImage(target = document) {
- let thread_user_post_images = target.querySelectorAll(".t5.t2 .r_one img");
-
- thread_user_post_images.forEach(hideImg);
- }
-
- function hideUserAvatar(target = document) {
- let user_avatars = target.querySelectorAll(".user-pic img");
- user_avatars.forEach(hideAvatar);
- }
-
- function dynamicLoadingNextPage(pageType) {
-
- class NextPageLoader {
-
- constructor() {
- this.isFetching = false;
- this.nextPageDummy = null;
- }
-
- GetURLDummy(url) {
- this.nextPageDummy = document.createElement("html");
- this.isFetching = true;
- return fetch(url, FETCH_CONFIG)
- .then(response => response.text())
-
- }
-
- AppendNextPageItems(itemSelector, divider) {
-
- let postsFragment = document.createDocumentFragment();
- this.nextPageDummy.querySelectorAll(itemSelector).forEach(ele => postsFragment.appendChild(ele));
- // 追加下一页的所有子项追加到分割线下面
- divider.parentNode.appendChild(postsFragment);
- }
-
- UpdatePageList() {
- // 主动更新帖子列表上下方的当前页码数
- let pagesOld = document.querySelectorAll(".pages");
- let pagesNew = this.nextPageDummy.querySelectorAll(".pages");
- for (let i = 0; i < pagesOld.length; i++) {
- pagesOld[i].parentNode.replaceChild(pagesNew[i], pagesOld[i]);
- }
- }
-
- }
-
-
- function getNextPageUrl() {
- let pageSeq = document.querySelector(".pages b");
- if (!pageSeq) return null;
- let pageNum = pageSeq.parentNode;
- let url = pageNum.nextSibling.firstChild.getAttribute("href");
- if (pageNum.nextSibling.nextSibling.classList.contains("pagesone")) return null;
- if (document.URL.includes(url)) return null;
- return url;
- }
-
-
- function makeDivider(itemsSelector, dividerMaker) {
- let divider = dividerMaker();
- let allItem = document.querySelectorAll(itemsSelector);
- let lastItem = allItem[allItem.length - 1];
- lastItem.parentNode.appendChild(divider);
- return divider;
- }
-
- let nextPageLoader;
- let nextPageURL;
- nextPageLoader = nextPageLoader || new NextPageLoader()
- // 处理搜索结果页面
- if (pageType === PageType.SEARCH_RESULT) {
- document.addEventListener('wheel', (e) => {
- e.stopPropagation();
- const itemListSelector = ".tr3.tac";
- if (e.deltaY < 0 || nextPageLoader.isFetching) return;
- if (!nextPageLoader.nextPageDummy) {
- nextPageURL = getNextPageUrl();
- if (!nextPageURL) return;
- let divider = makeDivider(itemListSelector, () => {
- let divider = document.createElement("tr");
- let dividerContent = document.createElement("td");
- divider.setAttribute("class", "tr2 spp-next-page-loader-divider")
- divider.appendChild(dividerContent);
- dividerContent.colSpan = 7;
- dividerContent.style.textAlign = "center";
- dividerContent.style.fontWeight = "bold";
- dividerContent.innerText = "...";
- return divider;
- });
- divider.firstChild.innerText = "正在获取下一页的帖子......";
- let p = nextPageLoader.GetURLDummy(nextPageURL);
- p
- .then(html => {
- nextPageLoader.nextPageDummy.innerHTML = html
- if (GMK.getValue("blockAdforumSearchResult")) blockAdforumSearchResult(nextPageLoader.nextPageDummy);
- })
- .catch(err => {
- console.error(err);
- divider.firstChild.innerText = "获取下一页的帖子出错,请手动刷新";
- })
- .finally(() => {
- nextPageLoader.isFetching = false;
- divider.firstChild.innerText = "滚动条到底后继续向下滚动将会加载下一页的帖子";
- });
-
- }
- // 否则判断一下是否到底了,到底了就追加下一页的内容
- else if (Math.abs(document.documentElement.scrollHeight - (window.pageYOffset + window.innerHeight)) < 20) {
- let divider = getElementByXpath(document, "//tr[@class='tr2 spp-next-page-loader-divider'][last()]");
- nextPageLoader.AppendNextPageItems(itemListSelector, divider);
- nextPageLoader.UpdatePageList();
-
- divider.firstChild.innerText = `以下是第${nextPageURL.match(/page-(\d+)/)[1]}页`;
- window.history.pushState({}, 0, nextPageURL); // 将地址栏也改变了
- nextPageLoader.nextPageDummy = null;
- }
-
- })
- }
- // 处理主题列表页面
- if (pageType === PageType.THREADS_PAGE) {
- document.addEventListener('wheel', (e) => {
- e.stopPropagation();
- const itemListSelector = ".tr3.t_one";
- if (e.deltaY < 0 || nextPageLoader.isFetching) return;
- if (!nextPageLoader.nextPageDummy) {
- nextPageURL = getNextPageUrl();
- if (!nextPageURL) return;
- let divider = makeDivider(itemListSelector, () => {
- let divider = document.createElement("tr");
- let dividerContent = document.createElement("td");
- divider.setAttribute("class", "tr2 spp-next-page-loader-divider")
- divider.appendChild(dividerContent);
- dividerContent.colSpan = 5;
- dividerContent.style.textAlign = "center";
- dividerContent.style.fontWeight = "bold";
- dividerContent.innerText = "...";
- return divider;
- });
- divider.firstChild.innerText = "正在获取下一页的帖子......";
- let p = nextPageLoader.GetURLDummy(nextPageURL);
- p
- .then(html => {
- nextPageLoader.nextPageDummy.innerHTML = html;
- threadAddAnchorAttribute(nextPageLoader.nextPageDummy, page + 1, fid);
- if (GMK.getValue("highlightViewedThread")) highlightViewedThread(nextPageLoader.nextPageDummy);
- })
- .catch(err => {
- console.error(err);
- divider.firstChild.innerText = "获取下一页的帖子出错,请手动刷新";
- })
- .finally(() => {
- nextPageLoader.isFetching = false;
- divider.firstChild.innerText = "滚动条到底后继续向下滚动将会加载下一页的帖子";
- });
-
- }
- // 否则判断一下是否到底了,到底了就追加下一页的内容
- else if (Math.abs(document.documentElement.scrollHeight - (window.pageYOffset + window.innerHeight)) < 20) {
- let divider = getElementByXpath(document, "//tr[@class='tr2 spp-next-page-loader-divider'][last()]");
- nextPageLoader.AppendNextPageItems(itemListSelector, divider);
- nextPageLoader.UpdatePageList();
- divider.firstChild.innerText = `以下是第${page + 1}页`;
- window.history.pushState({}, 0, nextPageURL); // 将地址栏也改变了
- page += 1;
- nextPageLoader.nextPageDummy = null;
- }
-
- })
- }
- // 处理楼层列表页面
- if (pageType === PageType.POSTS_PAGE) {
- document.addEventListener('wheel', (e) => {
- e.stopPropagation();
- const itemListSelector = ".t5.t2";
- if (e.deltaY < 0 || nextPageLoader.isFetching) return;
- if (!nextPageLoader.nextPageDummy) {
- nextPageURL = getNextPageUrl();
- if (!nextPageURL) return;
- let divider = makeDivider(itemListSelector, () => {
- let divider = document.createElement("div");
- let dividerContent = document.createElement("span");
- divider.setAttribute("class", "t5 t2 spp-next-page-loader-divider")
- divider.appendChild(dividerContent);
- divider.style.textAlign = "center";
- divider.style.fontWeight = "bold";
- divider.style.fontSize = "14px";
- divider.innerText = "...";
- return divider;
- });
- divider.innerText = "加载中..";
- nextPageLoader.GetURLDummy(nextPageURL)
- .then(html => {
- nextPageLoader.nextPageDummy.innerHTML = html
- postAddAnchorAttribute(nextPageLoader.nextPageDummy, page + 1, tid);
- if (GMK.getValue("buyRefresh_free")) buyRefresh_free(nextPageLoader.nextPageDummy);
- if (GMK.getValue("hidePostImage")) hidePostImage(nextPageLoader.nextPageDummy);
- if (GMK.getValue("hideUserAvatar")) hideUserAvatar(nextPageLoader.nextPageDummy);
- if (GMK.getValue("hoistingResourcePost")) hoistingResourcePost(nextPageLoader.nextPageDummy);
- })
- .catch(err => {
- console.error(err);
- divider.innerText = "获取下一页的帖子出错,请手动刷新";
- })
- .finally(() => {
- nextPageLoader.isFetching = false;
- divider.innerText = "滚动条到底后继续向下滚动将会加载下一页的帖子";
- });
-
- }
- // 否则判断一下是否到底了,到底了就追加下一页的内容
- else if (Math.abs(document.documentElement.scrollHeight - (window.pageYOffset + window.innerHeight)) < 20) {
- let divider = getElementByXpath(document, "//div[@class='t5 t2 spp-next-page-loader-divider'][last()]");
- nextPageLoader.AppendNextPageItems(itemListSelector, divider);
- nextPageLoader.UpdatePageList();
- divider.innerText = `以下是第${page + 1}页`;
- // window.history.pushState({}, 0, nextPageURL); // 将地址栏也改变了
- page += 1;
- nextPageLoader.nextPageDummy = null;
- }
-
- })
- }
- // 处理图墙区主题列表页面
- if (pageType === PageType.PIC_WALL_PAGE) {
- document.addEventListener('wheel', (e) => {
- e.stopPropagation();
- const itemListSelector = ".dcsns-li.dcsns-rss.dcsns-feed-0";
- if (e.deltaY < 0 || nextPageLoader.isFetching) return;
- if (!nextPageLoader.nextPageDummy) {
- nextPageURL = getNextPageUrl();
- if (!nextPageURL) return;
- let divider = makeDivider(itemListSelector, () => {
- let divider = document.createElement("tr");
- let dividerContent = document.createElement("td");
- divider.setAttribute("class", "tr2 spp-next-page-loader-divider")
- divider.appendChild(dividerContent);
- dividerContent.colSpan = 5;
- dividerContent.style.textAlign = "center";
- dividerContent.style.fontWeight = "bold";
- dividerContent.innerText = "...";
- return divider;
- });
- divider.firstChild.innerText = "正在获取下一页的帖子......";
- let p = nextPageLoader.GetURLDummy(nextPageURL);
- p
- .then(html => {
- nextPageLoader.nextPageDummy.innerHTML = html;
- nextPageLoader.nextPageDummy.querySelectorAll(".dcsns-li.dcsns-rss.dcsns-feed-0 .lazy").forEach(ele => {
- ele.setAttribute("loading", "lazy");
- ele.setAttribute("class", "");
- ele.setAttribute("src", ele.getAttribute("data-original"));
- ele.setAttribute("data-original", "");
- ele.style.display = "inline";
- });
-
- })
- .catch(err => {
- console.error(err);
- divider.firstChild.innerText = "获取下一页的帖子出错,请手动刷新";
- })
- .finally(() => {
- nextPageLoader.isFetching = false;
- divider.firstChild.innerText = "滚动条到底后继续向下滚动将会加载下一页的帖子";
- });
-
- }
- // 否则判断一下是否到底了,到底了就追加下一页的内容
- else if (Math.abs(document.documentElement.scrollHeight - (window.pageYOffset + window.innerHeight)) < 20) {
- let divider = getElementByXpath(document, "//tr[@class='tr2 spp-next-page-loader-divider'][last()]");
- nextPageLoader.AppendNextPageItems(itemListSelector, divider);
- nextPageLoader.UpdatePageList();
- divider.firstChild.innerText = `以下是第${page + 1}页`;
- window.history.pushState({}, 0, nextPageURL); // 将地址栏也改变了
- page += 1;
- nextPageLoader.nextPageDummy = null;
- }
-
- })
- }
- }
-
- async function automaticTaskCollection() {
-
- function setUIDsValue(uid, value) {
- let tmp = GMK.getValue("LastAutomaticTaskCollectionDate") || {};
- tmp[uid] = value;
- GMK.setValue("LastAutomaticTaskCollectionDate", tmp);
- }
-
- if (document.querySelector("#login_0")) {
- console.log(`尚未登录,不接任务`);
- return
- }
-
- let uid = document.querySelector("#menu_profile .ul2").innerHTML.match(/u\.php\?action-show-uid-(\d+)\.html/)[1];
- let uname = document.querySelector("#user-login a").innerText;
-
- console.log(GMK.getValue("LastAutomaticTaskCollectionDate"));
- let lastTime = GMK.getValue("LastAutomaticTaskCollectionDate") ?
- (parseInt(GMK.getValue("LastAutomaticTaskCollectionDate")[uid]) || 0) : 0;
- console.log(`${uname}[${uid}] 上次:${new Date(lastTime).toLocaleDateString()} ${new Date(lastTime).toLocaleTimeString()}`);
-
-
- if (new Date().getTime() - lastTime < (3600 * 1000)) {
- console.log("再等等……");
- return;
- }
-
-
- async function forumTask(pageURL, selector, jobType) {
- let dummy = await fetch(
- pageURL,
- FETCH_CONFIG)
- .then(response => response.text())
- .then(html => {
- let dummy = document.createElement("html");
- dummy.innerHTML = html;
- return dummy
- })
- .catch(err => console.error(err));
-
- async function t(task) {
- let job = task.getAttribute("onclick");
- let r = job.match(/startjob\('(\d+)'\);/);
- let jobID = r[1];
- let taskURL = `/plugin.php?H_name=tasks&action=ajax&actions=${jobType}&cid=${jobID}&nowtime=${new Date().getTime()}&verify=${verifyhash}`;
-
-
- await fetch(taskURL, FETCH_CONFIG)
- .then(response => response.text())
- .then(html => {
- console.log(html);
- if (html.includes("success\t")) toast(html.match(/!\[CDATA\[success\t(.+)]]>/)[1], ToastType.SUCCESS);
- }
- )
- .catch(err => console.error(err));
- }
-
- await dummy.querySelectorAll(selector).forEach(t);
-
- console.log(`${pageURL} done, ${new Date().getTime()}`)
- }
-
- for (let i = 0; i < 2; i++) {
- forumTask(
- "/plugin.php?H_name-tasks.html",
- "a[title=按这申请此任务]",
- "job"
- ).catch(err => console.error(err));
- await sleep(3000);
- forumTask(
- "/plugin.php?H_name-tasks-actions-newtasks.html.html",
- "a[title=领取此奖励]",
- "job2"
- ).catch(err => console.error(err));
- }
- console.log(`${uname}[${uid}], 本次领取时间:${new Date().getTime()}`);
- setUIDsValue(uid, new Date().getTime());
-
- }
-
- function blockAdforumSearchResult(target = document) {
- target.querySelectorAll(".tr3.tac").forEach(ele => {
- let forum = ele.childNodes[2];
- if (forum.firstChild.getAttribute("href").match(/fid-17[1-4]/)) {
- ele.style.display = "none";
- }
- });
- }
-
- function createFloatDraggableButton(text, GMKey, style) {
- let btn = document.createElement("button");
- let main = document.getElementById("main");
- main.appendChild(btn);
-
- btn.innerText = text;
- btn.setAttribute("id", "spp-float-draggable-button");
- btn.setAttribute("draggable", "true");
- btn.style.display = "block";
- btn.style.position = "fixed";
- btn.style.background = "#efefef";
- btn.style.zIndex = "99";
- btn.style.width = "30px";
- btn.style.padding = "10";
- btn.style.borderRadius = "1px";
-
- if (style) {
- for (const k in style) {
- btn.style[k] = style[k];
- }
- }
-
- let GM_style;
- if (GMKey) GM_style = GMK.getValue(GMKey);
- if (GM_style) {
- for (const k in GM_style) {
- btn.style[k] = GM_style[k];
- }
- }
-
- return btn;
-
- }
-
- function mark() {
- if (document.location.href.includes("/read.php")) {
-
- const GREY = "linear-gradient(to top, rgb(184 184 184), rgb(188 188 188))";
- const BLACK = "linear-gradient(to top, #313131,#000000)";
- const GMKey = "Style_markPlusPlus";
-
- let markButton = createFloatDraggableButton(
- MppManager.isMarked(tid) ? "MARKED" : "MARK",
- GMKey,
- {
- left: "calc(50vw + 470px)",
- top: "234px",
- background: MppManager.isMarked(tid) ? GREY : BLACK,
- color: "white",
- fontWeight: "bold",
- outline: "none",
- border: "none",
- borderRadius: "3px",
- width: "30px",
- opacity: MppManager.isMarked(tid) ? "0.4" : "0.8",
- cursor: "pointer",
- },
- );
-
- let dragStart = {};
- let dragEnd = {};
- // 防止拖到视口以外了
- AddIntersectionObserver(([entry]) => {
- if (!entry.isIntersecting) {
- // console.log('LEAVE');
- markButton.style.left = dragStart['saved']['left'];
- markButton.style.top = dragStart['saved']['top'];
- }
- }, markButton)
-
- markButton.addEventListener("click", async evt => {
- evt.stopPropagation();
-
- if (MppManager.isMarked(tid)) {
- MppManager.deleteMarkedThread(tid);
- evt.target.style.background = BLACK;
- evt.target.innerText = "MARK";
- evt.target.style.opacity = "0.8";
- } else {
- MppManager.addMarkThread(tid);
- evt.target.style.background = GREY;
- evt.target.innerText = "MARKED";
- evt.target.style.opacity = "0.4";
- // 第一次mark就先把基本内容给收录了
- let threadStatus = {};
-
- threadStatus['page'] = 1;
- threadStatus['lastFetchTime'] = 0;
- threadStatus['maxPage'] = totalpage;
- threadStatus['title'] = document.querySelector('.crumbs-item.current strong>a').textContent;
- threadStatus["markTime"] = new Date().toLocaleDateString();
- MppManager.setThreadStatus(tid, threadStatus);
- console.log(MppManager.getMarkList());
- }
-
-
- });
-
- markButton.addEventListener("contextmenu", openStatus);
-
- markButton.addEventListener("dragstart", (e) => {
- e.stopPropagation();
- dragStart = {
- clientX: e.clientX,
- clientY: e.clientY,
- saved: {
- left: e.target.style.left,
- top: e.target.style.top,
- }
- }
- });
-
- markButton.addEventListener("dragend", (e) => {
- e.stopPropagation();
- // 获得丅的交叉点坐标
- let startX = window.innerWidth / 2;
- let startY = 0;
- dragEnd = {
- clientX: e.clientX,
- clientY: e.clientY,
- }
- let newLeft = parseFloat(e.target.style.left.match(/(-?\d+)px/)[1]) + (dragEnd.clientX - dragStart.clientX)
- let newTop = parseFloat(e.target.style.top.match(/(-?\d+)px/)[1]) + (dragEnd.clientY - dragStart.clientY);
-
-
- e.target.style.left = `calc(50vw + ${newLeft}px)`;
- e.target.style.top = `${newTop}px`;
-
- let tmp = {
- ...GMK.getValue(GMKey),
- ...{
- left: `calc(50vw + ${newLeft}px)`,
- top: `${newTop}px`,
- }
- };
- GMK.setValue(GMKey, tmp);
- });
- }
- let menuButton = document.createElement("li");
- let a = document.createElement("a");
- a.innerText = "我的MARK";
- a.style.cursor = "pointer";
- a.classList.add("mpp-status");
- menuButton.appendChild(a);
- document.querySelector("#main").insertAdjacentHTML("afterbegin", `
- <style>
- .mpp{
- position: fixed;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- background: white;
- z-index: 2000000;
- }
- .mpp-mask{
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background: black;
- opacity: 0.5;
- user-select: none;
- z-index: 1000000;
- }
- .mpp-container{
- background: #eeeeee;
- display:grid;
- grid-template-areas:
- "title"
- "main";
- grid-template-rows: 28px auto;
- grid-gap: 10px;
- min-height: 80vh;
- max-height: 80vh;
- width: 900px;
- overflow-y: hidden;
- }
- .mpp-title{
- grid-area: title;
- background: #111111;
- border-left: black;
- border-right: black;
- text-align: center;
- font-weight: bold;
- height: 100%;
- color: white;
- padding-top: 5px;
- margin: 0;
- }
-
- .mpp-main{
- grid-area: main;
- height: 75vh;
- overflow-y: scroll;
- overflow-x: hidden;
-
- }
-
-
- .spp-hide{
- display: none;
- }
-
- .mpp-accordion{
- width: 100%;
- border: none;
- outline: none;
- background-color: whitesmoke;
- text-align: left;
- padding: 10px 10px;
- font-size: 12px;
- /*font-weight: bold;*/
- color: #444;
- cursor: pointer;
- transition: background-color 0.2s linear;
- display: inline-grid;
- grid-template-columns:1fr 4fr 1fr 1fr 1fr 1fr 1fr;
- align-items: center;
- justify-items: center;
- margin-bottom: 4px;
- box-shadow: 1px 2px 2px #AAAAAA;
-
- }
- .mpp-header{
- width: 100%;
- display: inline-grid;
- grid-template-columns:1fr 4fr 1fr 1fr 1fr 1fr 1fr;
- padding: 10px 10px;
- font-size: 12px;
- align-items: center;
- justify-items: left;
- }
-
- /*.mpp-accordion-plus{ */
- /* font-size: 14px;*/
- /* float: right;*/
- /*}*/
-
- button.mpp-accordion:before{
- content: '无';
- font-size: 10px;
- color: gray;
- }
- button.mpp-accordion.have-content:before{
- content: '+';
- font-size: 14px;
- font-weight: bold;
- color: black;
- }
- button.mpp-accordion.have-content.mpp-accordion-is-open:before{
- content: '-';
- font-size: 14px;
- font-weight: bold;
- color: black;
- }
- button.mpp-accordion:hover, button.mpp-accordion.mpp-accordion-is-open{
- background-color: #ddd;
- }
-
- .mpp-accordion-content{
- background: #eeeeee;
- border-left: 1px solid whitesmoke;
- border-right: 1px solid whitesmoke;
- padding: 0 20px;
- margin-bottom: 1px;
- max-height: 0;
- overflow: hidden;
- font-size: 10px;
- }
-
- .mpp-accordion-content.mpp-accordion-is-open{
- max-height: fit-content;
- }
-
- .mpp-sticky{
- position: sticky;
- top: 0;
- }
-
- .mpp-accordion-op{
- display: flex;
-
- justify-content: end;
- align-content: center;
- }
- .mpp-accordion-op a{
- padding: 5px;
- margin-left: 20px;
- font-size: 12px;
- cursor: pointer;
- }
- a.mpp-delete{
- text-align: right;
- color: brown;
- }
-
- a.mpp-sell{
- color: blueviolet;
- font-weight: bold;
- }
-
- a.mpp-hyperlink{
- color: blue;
- }
- a.mpp-hash{
- color: forestgreen;
- }
-
- .mpp-content-cell.mpp-content-title,
- .mpp-content-cell.mpp-content-last-fetch-time{
- justify-self: left;
- }
- .mpp-content-cell.mpp-content-last-fetch-time{
- padding-left: 1em;
- }
- a.mpp-status{
- /*font-weight: bold;*/
- color: dodgerblue;
- cursor:pointer;
- }
- span.mpp-content-result{
- justify-self: center;
- }
-
- </style>
- <div class="mpp-mask spp-hide"></div>
- <div class="mpp spp-hide">
- <div class="mpp-container">
- <p class="mpp-title">我的Mark(保持此窗口开启才会运行)</p>
- <div class="mpp-main">
- <div class="mpp-accordion-op mpp-sticky">
- <a class="mpp-accordion-expand-all">全部展开</a>
- <a class="mpp-accordion-collapse-all">全部折叠</a>
- </div>
- <div class="mpp-header" >
- <span class="mpp-header-cell mpp-content-result"></span>
- <span class="mpp-header-cell mpp-content-title" >帖子标题</span>
- <span class="mpp-header-cell">页数</span>
- <span class="mpp-header-cell mpp-content-last-fetch-time">检查时间</span>
- <span class="mpp-header-cell">悬赏状态</span>
- <span class="mpp-header-cell">MARK时间</span>
- <a class="mpp-delete mpp-content-cell" data-tid="1274464"></a>
- </div>
- <div class="mpp-content-container">
-
- </div>
- </div>
- </div>
- </div>
-
- `);
- document.querySelector("#guide").prepend(menuButton);
- // document.querySelector('.fl>.gray2>.fl:first-child').insertAdjacentText("beforeend",
- // `, `);
- // document.querySelector('.fl>.gray2>.fl:first-child').insertAdjacentHTML("beforeend",
- // `<a class="mpp-status">我的MARK</a>`);
- document.querySelector(".mpp-accordion-expand-all").addEventListener("click", evt => {
-
- document.querySelectorAll(".mpp-accordion").forEach(ele => {
- if (!ele.nextElementSibling.querySelectorAll("p>a").length) return;
- if (!ele.classList.contains(" mpp-accordion-is-open")) ele.classList.add("mpp-accordion-is-open");
- });
- document.querySelectorAll(".mpp-accordion-content").forEach(ele => {
- if (!ele.querySelectorAll("p>a").length) return;
- if (!ele.classList.contains("mpp-accordion-is-open")) ele.classList.add("mpp-accordion-is-open");
- ele.style.maxHeight = ele.scrollHeight + 'px';
- });
- });
- document.querySelector(".mpp-accordion-collapse-all").addEventListener("click", evt => {
- document.querySelectorAll(".mpp-accordion").forEach(ele => {
- if (ele.classList.contains("mpp-accordion-is-open")) ele.classList.remove("mpp-accordion-is-open")
- });
- document.querySelectorAll(".mpp-accordion-content").forEach(ele => {
- if (ele.classList.contains("mpp-accordion-is-open")) ele.classList.remove("mpp-accordion-is-open")
- ele.style.maxHeight = null;
- });
- });
-
- // 用于tab之间广播通讯,只允许一个tab运行mark++
- const bc = new BroadcastChannel("Soul++:MppTaskStart");
-
-
- let refreshID;
-
-
- // 自己不会接到
- bc.onmessage = async msg => {
- console.log('BroadcastChannel:', msg.data);
- if (msg.data.includes("mppTaskStart")) {
- closeMenu(null);
- // toast("由于你在别的标签打开了“我的MARK”,此标签的“我的MARK”被关闭了",ToastType.WARNING, 99999 * 1000);
- }
- };
-
-
- function insertDataHTML() {
- let container = document.querySelector(".mpp-content-container");
- let threadsStatus = MppManager.getAllThreadStatus()
- let insertHTML = ``;
- for (const [_tid, status] of Object.entries(threadsStatus)) {
- let posts = "";
- if (status['sell']) status["sell"].forEach(ele => posts += `<p><a class="mpp-sell" href="${ele}" target="_blank">[出售]${ele}</a></p>`);
- if (status['hyperlink']) status["hyperlink"].forEach(ele => posts += `<p><a class="mpp-hyperlink" href="${ele}" target="_blank">[超链]${ele}</a></p>`);
- if (status["magnetOrMiaochuan"]) status["magnetOrMiaochuan"].forEach(ele => posts += `<p><a class="mpp-hash" href="${ele}" target="_blank">[磁力或秒传]${ele}</a></p>`);
- let button = container.querySelector(`button.mpp-accordion[data-tid="${_tid}"`);
- if (button) button.classList.remove("have-content");
- let content = container.querySelector(`div.mpp-accordion-content[data-tid="${_tid}"`);
- // console.log(button ? button.classList.toString() : "mpp-accordion");
- // console.log(content ? content.classList.toString() : "mpp-accordion-content");
- // <span class="mpp-content-cell mpp-accordion-plus">${posts === "" ? "" : button.classList.contains("") ? "-" : "+"}</span>
- insertHTML += `
- <button type="button" class="${button ? button.classList.toString() : "mpp-accordion"} ${posts ? "have-content" : ""}" data-tid="${_tid}">
- <a
- class="mpp-content-cell mpp-content-title"
- href="/read.php?tid=${_tid}"
- target="_blank"
- >${status["title"].slice(0, 20)}${status["title"].length > 20 ? "..." : ""}</a>
- <span class="mpp-content-cell">${status["page"] || 0} / ${status["maxPage"]}</span>
- <span class="mpp-content-cell mpp-content-last-fetch-time">${status["lastFetchTime"] ? `${Math.round((getTimeStamp() - parseInt(status["lastFetchTime"])) / 1000 / 60)} 分钟之前` : '尚未检查'}</span>
- <span class="mpp-content-cell">${status["offerState"]}</span>
- <span class="mpp-content-cell">${status["markTime"]}</span>
- <a class="mpp-delete mpp-content-cell" data-tid="${_tid}">删除</a>
- </button>
-
- <div class="${content ? content.classList.toString() : "mpp-accordion-content"}" data-tid="${_tid}">
- ` + posts + `
- </div>
- `;
-
- }
- container.innerHTML = insertHTML;
- document.querySelectorAll("button.mpp-accordion").forEach(ele => {
- ele.addEventListener("click", evt => {
- evt.stopPropagation();
- if (!evt.currentTarget.nextElementSibling.querySelectorAll("p>a").length) return;
- let btn = evt.currentTarget;
- let content = btn.nextElementSibling;
- btn.classList.toggle("mpp-accordion-is-open");
- content.classList.toggle("mpp-accordion-is-open");
- content.style.maxHeight = content.classList.contains("mpp-accordion-is-open") ? content.scrollHeight + 'px' : null;
- // evt.currentTarget.querySelector(".mpp-accordion-plus").textContent = content.classList.contains("mpp-accordion-is-open") ? "-" : "+";
- });
-
- });
- document.querySelectorAll(".mpp-delete.mpp-content-cell").forEach(ele => {
- ele.addEventListener("click", evt => {
- evt.stopPropagation();
- evt.preventDefault();
- if (!confirm("删除后无法撤销,确定删除?")) return;
- const parentButton = evt.currentTarget.closest("button")
- const content = parentButton.nextElementSibling;
- parentButton.remove();
- content.remove();
- MppManager.deleteMarkedThread(evt.currentTarget.dataset.tid);
-
- })
- });
- }
-
- function openStatus(evt) {
- evt.stopPropagation();
- evt.preventDefault();
- // 显示数据
- insertDataHTML();
-
- // 显示菜单
- let sppMenu = document.querySelector(".mpp");
- sppMenu.classList.remove("spp-hide");
- // 显示遮罩
- let sppMenuMask = document.querySelector(".mpp-mask");
- sppMenuMask.classList.remove("spp-hide");
- // 防止滚动到菜单后面的页面
- document.body.style.overflow = "hidden";
-
- bc.postMessage('mppTaskStart');
- setTimeout(mppTask, 5000);
- sessionStorage.setItem("Soul++:MppTaskID", 'start');
- refreshID = setInterval(insertDataHTML, 1000);
- }
-
- function closeMenu(evt) {
- if (evt) evt.stopPropagation();
- document.body.style.overflow = null;
- let sppMenu = document.querySelector(".mpp");
- sppMenu.classList.add("spp-hide");
- let sppMenuMask = document.querySelector(".mpp-mask");
- sppMenuMask.classList.add("spp-hide");
- // clearInterval(parseInt(sessionStorage.getItem("Soul++:MppTaskID")));
- sessionStorage.setItem("Soul++:MppTaskID", 'stop');
- clearInterval(refreshID);
- }
-
- document.querySelector("a.mpp-status").addEventListener("click", openStatus)
-
- document.querySelector(".mpp-mask").addEventListener("click", closeMenu);
-
-
- }
-
- function backToTop() {
-
- const GMKey = "Style_backToTop";
- let backToTopButton = createFloatDraggableButton(
- "回到顶部",
- GMKey,
- {
- left: "calc(50vw + 470px)",
- bottom: "40px",
- background: "linear-gradient(to top, #eeeeee,#ffffff)",
- color: "black",
- fontWeight: "bold",
- outline: "none",
- border: "none",
- borderRadius: "3px",
- width: "30px",
- opacity: "80%",
- cursor: "pointer",
- }
- );
-
- let dragStart = {};
- let dragEnd = {};
-
- // 防止拖到视口以外了
- AddIntersectionObserver(([entry]) => {
- if (!entry.isIntersecting) {
- console.log('LEAVE');
- backToTopButton.style.left = dragStart.saved.left;
- backToTopButton.style.bottom = dragStart.saved.bottom;
- }
- }, backToTopButton)
-
- backToTopButton.addEventListener("click", (e) => {
- e.stopPropagation();
- window.scrollTo({ top: 0, behavior: "smooth" });
- });
-
- backToTopButton.addEventListener("dragstart", (e) => {
- e.stopPropagation();
-
- dragStart = {
- clientX: e.clientX,
- clientY: e.clientY,
- saved: {
- left: e.target.style.left,
- bottom: e.target.style.bottom,
- }
- }
- });
-
- backToTopButton.addEventListener("dragend", (e) => {
- e.stopPropagation();
- // 获得丅的交叉点坐标
- dragEnd = {
- clientX: e.clientX,
- clientY: e.clientY,
- }
- let newLeft = parseFloat(e.target.style.left.match(/(-?\d+)px/)[1]) + (dragEnd.clientX - dragStart.clientX);
- // bottom从下往上算的,所以要减
- let newBottom = parseFloat(e.target.style.bottom.match(/(-?\d+)px/)[1]) - (dragEnd.clientY - dragStart.clientY);
-
-
- e.target.style.left = `calc(50vw + ${newLeft}px)`;
- e.target.style.bottom = `${newBottom}px`;
-
- let tmp = {
- ...GMK.getValue(GMKey),
- ...{
- left: `calc(50vw + ${newLeft}px)`,
- bottom: `${newBottom}px`,
- }
- };
- GMK.setValue(GMKey, tmp);
-
-
- });
-
- }
-
- function postAddAnchorAttribute(target, pg, threadID) {
- target.querySelectorAll(".tpc_content .f14").forEach(ele => {
- ele.setAttribute("page", pg);
- ele.setAttribute("tid", threadID);
- let pid = ele.previousElementSibling.getAttribute("name");
- ele.setAttribute("pid", pid);
-
- });
- }
-
- function threadAddAnchorAttribute(target, pg, forumID) {
- target.querySelectorAll(".tr3.t_one").forEach(ele => {
- ele.setAttribute("page", pg);
- ele.setAttribute("fid", forumID);
- let tid_m = ele.querySelector("a").getAttribute("href").match(/tid-(\d+)/);
- if (!tid_m) return;
- let tid = tid_m[1];
- ele.setAttribute("tid", tid);
-
- });
- }
-
- function highlightViewedThread() {
-
- function removeCurrent() {
- let prev = document.querySelector(".spp-last-viewed-thread");
- if (prev) prev.classList.remove("spp-last-viewed-thread");
- }
-
- function setLastViewed() {
- let tmp = GMK.getValue("Soul++:lastViewedThread") || {};
- tmp[fid] = tid;
- GMK.setValue("Soul++:lastViewedThread", tmp);
- }
-
- function setViewed() {
- let tmp = GMK.getValue("Soul++:viewedThreads") || {};
- tmp[fid] = tmp[fid] || [];
- if (!tmp[fid].includes(tid)) tmp[fid].push(tid);
- GMK.setValue("Soul++:viewedThreads", tmp);
- }
-
- // 帖子阅读页面处理
- if ((document.location.href.includes("/read.php"))) {
- // 直接打开页面的话不会触发visibilitychange事件
- if (!document.hidden) setViewed();
- // 当visibilitychange触发时,hidden代表用户关闭或者离开了当前页面
- document.addEventListener("visibilitychange", () => {
- if (document.hidden) {
- setLastViewed();
- } else {
- setViewed();
- }
- });
- }
- // 帖子列表页面处理
- else if ((document.location.href.includes("/thread.php") || document.location.href.includes("/thread_new.php"))) {
- // 在帖子列表页面会主动滚动到最后浏览的帖子的位置
- document.addEventListener('readystatechange', (event) => {
- if (document.readyState === "complete") {
- history.scrollRestoration = "manual";
- let ele = document.querySelector(".spp-last-viewed-thread");
- if (!ele) return;
- ele.scrollIntoView({ behavior: "auto", block: "center" });
- }
- });
-
- // 主动更新帖子列表页
- // GM_addValueChangeListener(name, function(name, old_value, new_value, remote) {})
- GMK.addValueChangeListener("Soul++:viewedThreads", (_name, oldVal, newVal, remote) => {
- console.log(`本版块已阅帖:${newVal[fid]}`);
- document.querySelectorAll(".tr3.t_one").forEach(ele => {
- if (newVal[fid].includes(ele.getAttribute("tid"))) {
- ele.querySelector("h3 a").classList.add("spp-viewed-thread");
- }
- });
- })
- GMK.addValueChangeListener("Soul++:lastViewedThread", (_name, oldVal, newVal, remote) => {
- // 新记录中当前fid下正在阅读的tid和DOM树中一致的话则返回
- if (document.querySelector(".spp-last-viewed-thread").getAttribute("tid") === newVal[fid]) return;
- console.log(`正在本版块阅读新帖:${newVal[fid]}`);
- removeCurrent();
- document.querySelectorAll(".tr3.t_one").forEach(ele => {
- if (ele.getAttribute("tid") === newVal[fid]) {
- ele.classList.add("spp-last-viewed-thread");
- ele.scrollIntoView({ behavior: "auto", block: "center" });
- }
- });
- })
-
- // 将已经阅读过的帖子改成灰色
- let readedThreads = GMK.getValue("Soul++:viewedThreads") || {};
- let thisForumReadedThreads = readedThreads[fid] || [];
- // console.log(`当前版块已读帖子:${thisForumReadedThreads}`);
- document.querySelectorAll("h3 a").forEach(ele => {
- let container = ele.closest(".tr3.t_one");
- if (!container) return;
-
- if (thisForumReadedThreads.includes(container.getAttribute("tid"))) {
- console.log(`${container.getAttribute("tid")} 已读`);
- ele.classList.add("spp-viewed-thread");
- }
- if (ele.getAttribute("id") === `a_ajax_${GMK.getValue("Soul++:lastViewedThread")[fid]}`) {
- container.classList.add("spp-last-viewed-thread");
- }
- ele.addEventListener("click", e => {
- e.stopPropagation();
- removeCurrent();
- e.target.closest(".tr3.t_one").classList.add("spp-last-viewed-thread");
- });
- });
- }
- }
-
- function createSettingMenu() {
- let menuBox = document.createElement("div");
- document.querySelector("#main").prepend(menuBox);
-
- let menuButton = document.createElement("li");
- let a = document.createElement("a");
- a.innerText = "Soul++";
- a.style.cursor = "pointer";
- menuButton.appendChild(a);
- a.addEventListener("click", e => {
- e.stopPropagation();
- // 读取数据更显选项显示
- document.querySelectorAll(".spp-accordion-content").forEach(ele => {
- ele.querySelectorAll(".spp-menu-checkbox").forEach(ele => {
- let checkbox = ele.querySelector("input");
- if (checkbox) {
- let key = checkbox.dataset.funckey;
- checkbox.checked = GMK.getValue(key);
- }
- })
- });
-
- // 显示菜单
- let sppMenu = document.querySelector(".spp-menu");
- sppMenu.classList.remove("spp-hide");
- // 显示遮罩
- let sppMenuMask = document.querySelector(".spp-menu-mask");
- sppMenuMask.classList.remove("spp-hide");
- // 防止滚动到菜单后面的页面
- document.body.style.overflow = "hidden";
-
- });
- document.querySelector("#guide").prepend(menuButton);
-
- menuBox.outerHTML = `
- <div class="spp-menu-mask spp-hide"></div>
- <div class="spp-menu spp-hide">
- <div class="spp-menu-container">
- <p class="spp-menu-title">Soul++ 设置</p>
- <div class="spp-menu-main">
- <div class="spp-menu-accordion-op spp-sticky">
- <a class="spp-menu-accordion-support-me" style="grid-column-start: 1">支持作者</a>
- <a class="spp-menu-accordion-expand-all" style="grid-column-start: 4">全部展开</a>
- <a class="spp-menu-accordion-collapse-all" style="grid-column-start: 5">全部折叠</a>
- </div>
- <button type="button" class="spp-accordion spp-accordion-is-open">🔄 免刷新</button>
- <div class="spp-accordion-content spp-accordion-is-open">
- <div class="spp-menu-checkbox"><label><input data-funcKey="buyRefresh_free" type="checkbox" id="buy-refresh-free">购买免刷新</label></div>
- </div>
-
-
- <button type="button" class="spp-accordion spp-accordion-is-open">♾️ 无缝加载</button>
- <div class="spp-accordion-content spp-accordion-is-open">
- <div class="spp-menu-checkbox"><label><input data-funcKey="dynamicLoadingThreads" type="checkbox" id="dynamic-load-posts">无缝加载板块帖子列表</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="dynamicLoadingPosts" type="checkbox" id="dynamic-load-threads">无缝加载贴内楼层列表</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="dynamicLoadingSearchResult" type="checkbox" id="dynamic-load-search-result">无缝加载搜索页结果</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="dynamicLoadingPicWall" type="checkbox" id="dynamic-load-pic-wall">无缝加载图墙模式帖子</label></div>
- </div>
-
- <button type="button" class="spp-accordion spp-accordion-is-open">🛑 屏蔽</button>
- <div class="spp-accordion-content spp-accordion-is-open">
- <div class="spp-menu-checkbox"><label><input data-funcKey="blockAdforumSearchResult" type="checkbox" id="block-adforum-search-result">屏蔽网赚区搜索结果</label></div>
- </div>
-
- <button type="button" class="spp-accordion spp-accordion-is-open">🔞 SFW安全模式</button>
- <div class="spp-accordion-content spp-accordion-is-open">
- <div class="spp-menu-checkbox"><label><input data-funcKey="hidePostImage" type="checkbox" id="hide-post-image">折叠贴内图片(点击虚线框 展开/折叠 图片)</label></div>
- <div class="spp-menu-checkbox spp-menu-sub-item"><label><input data-funcKey="loadImageOnDemand" type="checkbox" id="load-image-on-demand">按需加载头像、图片(展开后才开始加载)</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="hideForumRules" type="checkbox" id="hide-chaguan-poster">折叠板块公告(其实板块公告右边有个小箭头,我只是帮你们点了一下)</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="hideUserAvatar" type="checkbox" id="hide-user-avatar">替换用户头像为默认(鼠标滑入查看)</label></div>
- </div>
- <button type="button" class="spp-accordion spp-accordion-is-open">🔖 mark++</button>
- <div class="spp-accordion-content spp-accordion-is-open">
- <div class="spp-menu-checkbox"><label><input data-funcKey="markPlusPlus" type="checkbox" id="mark-plus-plus">开启MARK++</label></div>
- <div class="spp-menu-checkbox"><label class="spp-menu-description">- 打开后查看帖子页面右边会出现MARK按钮(可拖到任意位置)</label></div>
- <div class="spp-menu-checkbox"><label class="spp-menu-description">- 点击MARK之后,当前帖子会加入到“我的MARK”列表里</label></div>
- <div class="spp-menu-checkbox"><label class="spp-menu-description">- 在导航栏可以找到“我的MARK”入口,右键点击MARK按钮也可以打开“我的MARK”</label></div>
- <div class="spp-menu-checkbox"><label class="spp-menu-description" style="color: brown">- 保持打开“我的MARK”窗口,脚本会以5秒/帖的频率检查MARK列表</label></div>
- <div class="spp-menu-checkbox"><label class="spp-menu-description" style="color: brown">- 同一时间只允许一个浏览器标签打开“我的MARK”</label></div>
- </div>
- <button type="button" class="spp-accordion spp-accordion-is-open">💠 其它</button>
- <div class="spp-accordion-content spp-accordion-is-open">
- <div class="spp-menu-checkbox"><label><input data-funcKey="automaticTaskCollection" type="checkbox" id="automatic-task-collection">自动领取和完成论坛任务</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="hoistingResourcePost" type="checkbox" id="hoisting-resource-post">将当前页包含[购买/秒传/磁力链/超链]的楼层提升到前面</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="replaceAllDomainToTheSame" type="checkbox" id="replace-all-plus-to-the-same">统一替换所有plus链接为当前正在使用的域名</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="highlightViewedThread" type="checkbox" id="highlight-viewed-threads">标记已阅读过的帖子</label></div>
- <div class="spp-menu-checkbox"><label><input data-funcKey="linkToReplyAndQuote" type="checkbox" id="link-to-reply-and-quote">给[回复第X楼/引用第X楼]增加跳转到该楼层的链接</label></div>
- </div>
- <button type="button" class="spp-accordion spp-danger">❗</button>
- <div class="spp-accordion-content spp-danger-content">
- <button class="spp-btn-danger" data-funcKey="resetAll" id="spp-reset-all">清空所有设置</button>
- </div>
-
- </div>
- <div class="spp-menu-op-zone">
- <button id="spp-menu-close"><img alt="" src="images/post/smile/smallface/face099.jpg"/> 我好了</button>
- </div>
- </div>
- </div>
-
- `;
-
- (function () {
- function closeMenu(evt, saveAndRefresh) {
- evt.stopPropagation();
- document.body.style.overflow = null;
- let sppMenu = document.querySelector(".spp-menu");
- sppMenu.classList.add("spp-hide");
- let sppMenuMask = document.querySelector(".spp-menu-mask");
- sppMenuMask.classList.add("spp-hide");
- if (saveAndRefresh) {
- changes.forEach(e => GMK.setValue(e[0], e[1]))
- document.location.reload();
- }
- changes = [];
-
- }
-
- window.addEventListener("keydown", evt => {
- if (evt.key === "Escape") closeMenu(evt, false);
- });
- let changes = [];
- document.querySelectorAll(".spp-menu-checkbox input").forEach(ele => {
- ele.addEventListener("change", evt => {
- changes.push([evt.currentTarget.dataset.funckey, evt.currentTarget.checked]);
- });
- });
-
- document.querySelector("#spp-menu-close").addEventListener("click", evt => closeMenu(evt, true));
- document.querySelector(".spp-menu-mask").addEventListener("click", evt => closeMenu(evt, false));
- document.querySelector("#spp-reset-all").addEventListener("click", evt => {
- evt.stopPropagation();
-
- if (confirm(
- `
- 【警告】
- 这将会清空你在所有的数据和设置,包括:
- - 已读的帖子
- - 可拖放按钮的位置
- - 已经MARK过的帖子
-
- 你确定要这样做?`
- )) {
- GMK.listValues().forEach(vName => {
- console.log(vName);
- GMK.deleteValue(vName);
- });
- console.log(GMK.listValues());
- document.location.reload();
- }
- });
- document.querySelector(".spp-menu-accordion-support-me").addEventListener("click", evt => {
- evt.stopPropagation();
- let toastTip = Toastify({
- text: "点我或者点击图片即可关闭",
- duration: 15000,
- close: true,
- gravity: "top", // `top` or `bottom`
- position: "center", // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {},
- onClick: function () {
- toastTip.hideToast();
- toastRedEnvelop.hideToast();
- }
- })
- toastTip.showToast();
- let img = document.createElement("img");
- img.style.background = "none";
- img.style.boxShadow = "none";
- img.style.borderRadius = "10px";
- img.style.width = "300px";
- img.style.height = "435px";
- img.src = 'https://cdn.jsdelivr.net/gh/FetchTheMoon/UserScript/images/RedEnvelope.jpg';
- let toastRedEnvelop = Toastify({
- node: img,
- duration: 9999999,
- close: false,
- gravity: "top", // `top` or `bottom`
- position: "center", // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- background: "none",
- boxShadow: "none",
- },
- onClick: function () {
- toastTip.hideToast();
- toastRedEnvelop.hideToast();
- }
- });
- toastRedEnvelop.showToast();
- });
- document.querySelector(".spp-menu-accordion-expand-all").addEventListener("click", evt => {
-
- document.querySelectorAll(".spp-accordion").forEach(ele => {
- if (ele.classList.contains("spp-danger")) return;
- if (!ele.classList.contains(" spp-accordion-is-open")) ele.classList.add("spp-accordion-is-open");
- });
- document.querySelectorAll(".spp-accordion-content").forEach(ele => {
- if (ele.classList.contains("spp-danger-content")) return;
- if (!ele.classList.contains("spp-accordion-is-open")) ele.classList.add("spp-accordion-is-open");
- ele.style.maxHeight = ele.scrollHeight + 'px';
- });
- });
- document.querySelector(".spp-menu-accordion-collapse-all").addEventListener("click", evt => {
- document.querySelectorAll(".spp-accordion").forEach(ele => {
- if (ele.classList.contains("spp-accordion-is-open")) ele.classList.remove("spp-accordion-is-open")
- });
- document.querySelectorAll(".spp-accordion-content").forEach(ele => {
- if (ele.classList.contains("spp-accordion-is-open")) ele.classList.remove("spp-accordion-is-open")
- ele.style.maxHeight = null;
- });
- });
- document.querySelectorAll("button.spp-accordion").forEach(ele => {
- ele.addEventListener("click", evt => {
- evt.stopPropagation();
- let btn = evt.target;
- let content = btn.nextElementSibling;
- btn.classList.toggle("spp-accordion-is-open");
- content.classList.toggle("spp-accordion-is-open");
- content.style.maxHeight = content.classList.contains("spp-accordion-is-open") ? content.scrollHeight + 'px' : null;
- });
-
- });
- }());
- }
-
- function replaceAllDomainToTheSame() {
-
-
- const arr = [...document.querySelectorAll("a")];
- const domains = [
- "spring-plus.net",
- "summer-plus.net",
- "soul-plus.net",
- "south-plus.net",
- "north-plus.net",
- "snow-plus.net",
- "level-plus.net",
- "white-plus.net",
- "imoutolove.me",
- "south-plus.org",
- ];
- const checker = value => domains.some(element => value.href.includes(element));
-
- arr.filter(checker).filter(ele => !ele.href.includes(window.location.hostname)).forEach(ele => {
- console.log("替换链接:", ele);
- let newURL = new URL(ele.href);
- newURL.hostname = window.location.hostname;
- ele.href = newURL.href;
- });
-
-
- }
-
- function MutationObserverProcess() {
- function callback(mutationList, observer) {
- mutationList.forEach((mutation) => {
- mutation.addedNodes.forEach(ele => {
-
- if (ele.tagName === "IMG") {
- if (ele.classList.contains("spp-mutation-processed")) return
-
- function hide(confirmSelector, handler) {
- const postContainer = ele.closest(confirmSelector);
- if (!postContainer) return
- handler(ele);
- ele.classList.add("spp-mutation-processed");
- }
-
- if (document.location.href.includes("/read.php")) {
- ele.setAttribute("loading", "lazy");
- if (GMK.getValue("hideUserAvatar")) hide(".user-pic", hideAvatar)
- if (GMK.getValue("hidePostImage")) hide(".t5.t2 .r_one", hideImg)
- }
- }
- if (document.location.href.includes("/read.php") && GMK.getValue("linkToReplyAndQuote")) {
- if (ele.title === "复制此楼地址") {
- ele.insertAdjacentHTML("beforebegin", `<a name="SPP-${ele.innerText}" id="SPP-${ele.innerText}"></a>`);
- }
- }
- });
- });
-
-
- }
-
- let observerOptions = {
- childList: true, // 观察目标子节点的变化,是否有添加或者删除
- attributes: true, // 观察属性变动
- subtree: true // 观察后代节点,默认为 false
- }
-
- let observer = new MutationObserver(callback);
- observer.observe(document.documentElement, observerOptions);
- }
-
- async function mppTask() {
- let taskInterval = 5000;
- await (async function () {
-
- // 先查询页数没到最后一页的
- let markedList = Object.entries(MppManager.getMarkList()).filter(e => {
- return e[1]['maxPage'] - e[1]['page'] > 0
- });
- // 如果都到最后一页了,就按上次查询时间距今最远的来
- if (!markedList.length) {
- markedList = Object.entries(MppManager.getMarkList())
- .sort((f, s) => {
- return f[1]['lastFetchTime'] - s[1]['lastFetchTime']
- });
- }
- console.log(markedList);
- if (!markedList.length) return;
- if (MppManager.isAllChecked()) taskInterval = 10 * 1000;
- let [_tid, threadStatus] = markedList[0];
- let maxPage = threadStatus['maxPage'] || 1;
- let currentPage = threadStatus["page"] || 1;
- const dummy = await getPage(`/read.php?tid=${_tid}&page=${currentPage}`, true);
- const m = dummy.innerHTML.match(/var totalpage = parseInt\('(\d+)'\)/);
- if (m) maxPage = parseInt(m[1]);
- const allPosts = [...dummy.querySelectorAll(".t5.t2")];
-
- function getOfferState(dummy) {
- const ele = dummy.querySelector(".tips .s3");
- if (!ele) {
- console.log("没找到悬赏状态", ele, dummy);
- return;
- }
- const state = ele.textContent;
- if (state.includes("剩余时间:已结束")) {
- return "悬赏超时";
- } else if (state.includes("悬赏结束")) {
- return `<a class="mpp-sell" href='/read.php?tid=${_tid}' target="_blank" style="color: #73a5ff">有答案了</a>`;
- } else if (state.includes("悬赏中")) {
- return `剩余${state.match(/(\d+)小时/)[1]}小时`;
- }
- }
-
- if (currentPage === 1) {
- threadStatus["offerState"] = getOfferState(dummy);
- allPosts.shift();
- }
- // 在第一页获取一下帖子的状态,看看到底有没有结贴
- if (threadStatus["allPagesChecked"]) {
- await sleep(5000); // 否则会遇到提示刷新小于1秒;
- const page1dummy = await getPage(`/read.php?tid=${_tid}&page=1`, true);
- threadStatus["offerState"] = getOfferState(page1dummy);
- }
- threadStatus["sell"] = threadStatus["sell"] || [];
- threadStatus["hyperlink"] = threadStatus["hyperlink"] || [];
- threadStatus["magnetOrMiaochuan"] = threadStatus["magnetOrMiaochuan"] || [];
- threadStatus['title'] = dummy.querySelector('.crumbs-item.current strong>a').textContent;
- threadStatus['lastFetchTime'] = getTimeStamp();
- threadStatus['maxPage'] = maxPage;
- threadStatus["page"] += currentPage < maxPage ? 1 : 0;
- const getPid = (post) => {
- return post.previousSibling.getAttribute("name");
- }
- allPosts.forEach(post => {
-
- let u = `/read.php?tid=${_tid}&page=${currentPage}#${getPid(post)}`;
- if (post.querySelector(".quote.jumbotron")) {
- if (!threadStatus["sell"].includes(u)) threadStatus["sell"].push(u)
- } else if (post.querySelector(".tpc_content a")) {
- if (!threadStatus["hyperlink"].includes(u)) threadStatus["hyperlink"].push(u);
- } else if (post.querySelector(".tpc_content").textContent.match(/^[0-9a-fA-F]{20,}/mg)) {
- if (!threadStatus["magnetOrMiaochuan"].includes(u)) threadStatus["magnetOrMiaochuan"].push(u);
- }
- });
-
-
- threadStatus["allPagesChecked"] = currentPage === maxPage;
- if (MppManager.isThreadExist(_tid)) MppManager.setThreadStatus(_tid, threadStatus);
- console.log(threadStatus);
-
- })();
- if (sessionStorage.getItem("Soul++:MppTaskID") === 'start') setTimeout(mppTask, taskInterval);
-
- }
-
- function linkToReplyAndQuote(target = document) {
- if (window.location.hash.includes("#SPP-")) {
- const ele = document.querySelector(window.location.hash);
- if (ele) ele.scrollIntoView();
- }
-
- let allPosts = [...target.querySelectorAll(".t5.t2")];
- allPosts.forEach(ele => {
- const quote = ele.querySelector("h6.quote2+div");
- if (quote) {
- const floor = parseInt(quote.firstChild.textContent.match(/引用第(\d+)楼/)[1]);
- const page = Math.ceil(floor / 30);
- const text = quote.firstChild.textContent.replace(/引用(第\d+楼)(.+)/, `引用<a style="color: dodgerblue" href="/read.php?tid=${tid}&page=${page}#SPP-B${floor}F">$1</a>$2`);
- quote.removeChild(quote.firstChild);
- quote.insertAdjacentHTML("afterbegin", text);
-
- }
- const reply = ele.querySelector(".h1.fl>.fl");
- if (reply) {
- const m = reply.firstChild.textContent.match(/回 (\d+)楼/);
- if(!m) return
- const floor = parseInt(m[1]);
- const page = Math.ceil(floor / 30);
- const text = reply.innerText.replace(/回 (\d+)楼(.+)/, `回 <a style="color: dodgerblue" href="/read.php?tid=${tid}&page=${page}#SPP-B${floor}F">$1楼</a>$2`);
- reply.innerText = "";
- reply.insertAdjacentHTML("afterbegin", text);
-
- }
- });
- }
-
- function hoistingResourcePost(target = document) {
- if (document.location.href.includes("#")) return;
- let allPosts = [...target.querySelectorAll(".t5.t2")];
-
- // 是否拿出顶楼
- const insertPosition = page === 1 ? allPosts.shift() : target.querySelector("input[name=tid]");
- const resourcePosts = allPosts.filter(post =>
- post.querySelector(".quote.jumbotron")
- || post.querySelector(".tpc_content a")
- || post.querySelector(".tpc_content").textContent.match(/^[0-9a-fA-F]{20,}/mg)
- ).reverse();
- resourcePosts.forEach(ele => insertPosition.after(ele));
-
- }
-
- function AddIntersectionObserver(callback, element) {
- const obs = new window.IntersectionObserver(callback, {
- root: null,
- threshold: 0.5,
- })
- obs.observe(element);
- }
-
- //##############################################################
- // 执行入口
- //##############################################################
- (function () {
-
- GMK.addStyle(`<style>
- .spp-last-viewed-thread{
- background: #deeeff;
- }
- .spp-viewed-thread{
- color: #bbbbbb;
- }
- .spp-hide{
- display: none;
- }
-
-
-
- .spp-menu{
- position: fixed;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- background: white;
- z-index: 2000000;
- }
- .spp-menu-mask{
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background: black;
- opacity: 0.5;
- user-select: none;
- z-index: 1000000;
- }
- .spp-menu-container{
- background: #eeeeee;
- display:grid;
- grid-template-areas:
- "title"
- "main"
- "op";
- grid-template-rows: 28px auto 40px;
- grid-gap: 10px;
- min-height: 80vh;
- max-height: 80vh;
- width: 600px;
- }
- .spp-menu-title{
- grid-area: title;
- background: url(images/colorImagination/bg_topnav.gif) repeat-x #000000;
- border-left: black;
- border-right: black;
- text-align: center;
- font-weight: bold;
- height: 100%;
- color: white;
- padding-top: 5px;
- margin: 0;
- }
-
- .spp-menu-main{
- grid-area: main;
- height: 70vh;
- overflow-y: scroll;
- }
-
- /*.spp-menu-op-zone{*/
- /* grid-area: op;*/
- /* display: grid;*/
- /* grid-template-columns: 50% 50%;*/
- /*}*/
-
- .spp-hide{
- display: none;
- }
-
- button.spp-accordion{
- width: 100%;
- border: none;
- outline: none;
- background-color: whitesmoke;
- text-align: left;
- padding: 10px 10px;
- font-size: 14px;
- font-weight: bold;
- color: #444;
- cursor: pointer;
- transition: background-color 0.2s linear;
- }
-
- button.spp-accordion:after{
- content:'+';
- font-size: 14px;
- float: right;
- }
-
- button.spp-accordion.spp-accordion-is-open:after{
- content: '-';
- }
-
- button.spp-accordion:hover, button.spp-accordion.spp-accordion-is-open{
- background-color: #ddd;
- }
-
- .spp-accordion-content{
- background: #eeeeee;
- border-left: 1px solid whitesmoke;
- border-right: 1px solid whitesmoke;
- padding: 0 20px;
- margin-bottom: 3px;
- max-height: 0;
- overflow: hidden;
- /*transition: all 0.2s ease-in-out;*/
- font-size: 14px;
- }
-
- .spp-accordion-content.spp-accordion-is-open{
- max-height: fit-content;
- /*transition: all 0.2s ease-in-out;*/
- }
-
- .spp-sticky{
- position: sticky;
- top: 0;
- }
-
- .spp-menu-accordion-op{
- display: grid;
- grid-template-columns: repeat(5,1fr);
- justify-content: end;
- align-content: center;
- }
- .spp-menu-accordion-op a{
- padding: 5px;
- margin-left: 20px;
- font-size: 12px;
- cursor: pointer;
- }
-
- .spp-menu-checkbox{
- margin: 10px;
- }
- .spp-menu-checkbox input[type="checkbox"]{
- margin-bottom: 5px;
- }
- /*.spp-menu-op-zone{*/
-
- /* display: flex;*/
- /* justify-content: space-around;*/
- /* align-content: center;*/
- /*}*/
-
- .spp-menu-op-zone button{
- display: block;
- width: 100%;
- height: 100%;
- background: black;
- color: white;
- border: 1px solid black;
- font-size: 16px;
- font-family: 宋体,"sans-serif";
- font-weight: bold;
- cursor: pointer;
-
- }
-
- #spp-menu-close{
- background:linear-gradient(to bottom, #3a3a3a,#000000);
- }
-
- .spp-menu-description{
- padding-left: 20px;
- font-size: 12px;
- }
-
- .spp-danger-content{
- padding: 0;
- }
-
- .spp-btn-danger{
- display: block;
- background: crimson;
- color: whitesmoke;
- width: 100%;
- height: 40px;
- border: none;
- outline: none;
- cursor: pointer;
- }
- .spp-menu-sub-item{
- padding-left: 20px;
- }
- .spp-loading-animation{
- width:150px;
- margin:50px auto;
- text-align: center;
- }
- .spp-loading-animation >div{
- width: 18px;
- height: 18px;
- border-radius: 100%;
- display:inline-block;
- background-color: #af0909;
- -webkit-animation: dot 1.4s infinite ease-in-out;
- animation: dot 1.4s infinite ease-in-out;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- }
- .spp-loading-animation .dot1{
- -webkit-animation-delay: -0.30s;
- animation-delay: -0.30s;
- }
- .spp-loading-animation .dot2{
- -webkit-animation-delay: -0.15s;
- animation-delay: -0.15s;
- }
- @-webkit-keyframes dot {
- 0%, 80%, 100% {-webkit-transform: scale(0.0) }
- 40% { -webkit-transform: scale(1.0) }
- }
- @keyframes dot {
- 0%, 80%, 100% {-webkit-transform: scale(0.0) }
- 40% { -webkit-transform: scale(1.0) }
- }
- </style>`.replace(/<\/?style>/gm, ""));
- GMK.addStyle(GMK.getResourceText("TOASTIFY_CSS"));
-
- console.log(`=======================================
- Soul++ 已经启动
- =======================================`);
- // 给所有图片增加懒加载,以及处理图片隐藏
- MutationObserverProcess();
-
- // toast("Soul++ 已启动,可以在论坛导航栏进行设置", ToastType.WARNING, 5000);
- // toast("Soul++ 已启动,可以在论坛导航栏进行设置", ToastType.INFO, 5000);
- // toast("Soul++ 已启动,可以在论坛导航栏进行设置", ToastType.SUCCESS, 5000);
- // toast("Soul++ 已启动,可以在论坛导航栏进行设置", ToastType.DANGER, 5000);
-
- document.addEventListener("readystatechange", evt => {
- if (!(document.readyState === "interactive")) return;
- createSettingMenu();
- backToTop();
-
- if (document.location.href.includes("/read.php")) {
- postAddAnchorAttribute(document, page, tid);
- if (GMK.getValue("hoistingResourcePost")) {
- hoistingResourcePost();
- }
- if (GMK.getValue("linkToReplyAndQuote")) {
- linkToReplyAndQuote();
- }
- }
- if (document.location.href.includes("/thread.php")) {
- threadAddAnchorAttribute(document, page, fid);
- if (GMK.getValue("hideForumRules")) {
- document.cookie = "deploy=%09thread%09%0A;"
- document.querySelector("#cate_thread").style.display = "none";
- } else {
- document.cookie = "deploy=;"
- document.querySelector("#cate_thread").style.display = null;
- }
- }
-
- if (GMK.getValue("buyRefresh_free") && document.location.href.includes("/read.php")) {
- buyRefresh_free();
- }
- if (GMK.getValue("dynamicLoadingThreads") && (document.location.href.includes("/thread.php"))) {
- dynamicLoadingNextPage(PageType.THREADS_PAGE);
- }
- if (GMK.getValue("dynamicLoadingPicWall") && document.location.href.includes("/thread_new.php")) {
- dynamicLoadingNextPage(PageType.PIC_WALL_PAGE);
- }
- if (GMK.getValue("dynamicLoadingPosts") && document.location.href.includes("/read.php")) {
- dynamicLoadingNextPage(PageType.POSTS_PAGE);
- }
- if (GMK.getValue("dynamicLoadingSearchResult") && document.location.href.includes("/search.php")) {
- dynamicLoadingNextPage(PageType.SEARCH_RESULT);
- }
- if (GMK.getValue("blockAdforumSearchResult") && document.location.href.includes("/search.php")) {
- blockAdforumSearchResult();
- }
- if (GMK.getValue("automaticTaskCollection")) {
- automaticTaskCollection();
- }
- if (GMK.getValue("highlightViewedThread")) {
- highlightViewedThread();
- }
- if (GMK.getValue("replaceAllDomainToTheSame")) {
- replaceAllDomainToTheSame();
- }
- if (GMK.getValue("markPlusPlus")) {
- mark();
- }
-
- });
-
-
- })();
-
-
-