老魔已读标记

通用已读标记功能,支持多站点

// ==UserScript==
// @name         老魔已读标记
// @version      1.0.3
// @namespace    https://sleazyfork.org/zh-CN/users/1461640-%E6%98%9F%E5%AE%BF%E8%80%81%E9%AD%94
// @author       星宿老魔
// @description  通用已读标记功能,支持多站点
// @match        *://www.javlibrary.com/cn/publicgroupsearch.php*
// @match        *://www.javlibrary.com/cn/publictopic.php*
// @match        *://www.javlibrary.com/cn/publicgroup.php*
// @match        *://www.google.com/search*udm=48*
// @match        *://images.google.com/search*udm=48*
// @exclude      *://www.google.com/search*site%3A*
// @exclude      *://www.google.com/search*site:*
// @exclude      *://images.google.com/search*site%3A*
// @exclude      *://images.google.com/search*site:*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=javlibrary.com
// @license      MIT
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_openInTab
// @run-at       document-end
// ==/UserScript==

(function(){"use strict";const CONFIG={STORAGE_KEY:"laomo_read_topics",GOOGLE_STORAGE_KEY:"laomo_google_read_urls",STYLES:{READ_TOPIC:{opacity:"0.6",
background:"#f0f0f0",color:"#888"},READ_BADGE:{color:"#666",fontSize:"12px",marginLeft:"8px",fontWeight:"normal"},GOOGLE_READ_LINK:{opacity:"0.5",
filter:"grayscale(50%)"}},SELECTORS:{topicTable:"table.pubgroup",topicRows:"table.pubgroup tbody tr:not(#header)",
topicLinks:'a.topictitle[href*="publictopic.php"]',allTopicLinks:'a[href*="publictopic.php"]',topicTitleCell:"td.left",
googleResultLinks:'a[href*="imgres"], a.ngTNl, a[data-ved]'},REGEX:{topicId:/publictopic\.php\?id=(\d+)/},TEXT:{readBadge:"[已读]"}};class Storage{
static get(t,e=null){try{const i=GM_getValue(t);if(null==i)return e;try{return JSON.parse(i)}catch{return i}}catch(i){return void 0,e}}
static set(t,e){try{const i=JSON.stringify(e);return GM_setValue(t,i),!0}catch(i){return void 0,!1}}static delete(t){try{return GM_deleteValue(t),!0
}catch(e){return void 0,!1}}static listKeys(){try{return GM_listValues()}catch(t){return void 0,[]}}static migrateFromLocalStorage(t,e=!0){try{
const i=localStorage.getItem(t);if(null!==i){try{const e=JSON.parse(i);this.set(t,e)}catch{GM_setValue(t,i)}return e&&localStorage.removeItem(t),!0}
return!1}catch(i){return void 0,!1}}}function t(t){const e=t.match(CONFIG.REGEX.topicId);return e?e[1]:null}function e(){try{
const t=Storage.get(CONFIG.STORAGE_KEY,[])||[];return new Set(t)}catch(t){return void 0,new Set}}function i(t){try{
Storage.set(CONFIG.STORAGE_KEY,Array.from(t))}catch(e){void 0}}function a(t){const a=e();a.add(t),i(a)}function s(t){return e().has(t)}function r(){
try{return Storage.get(CONFIG.GOOGLE_STORAGE_KEY,[])||[]}catch(t){return void 0,[]}}function n(t){try{Storage.set(CONFIG.GOOGLE_STORAGE_KEY,t)
}catch(e){void 0}}function o(t){const e=r();e.includes(t)||(e.push(t),n(e))}function c(t){return r().includes(t)}class ReadMarkManager{constructor(){
this.readTopics=e()}init(){void 0,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{this.handleCurrentPage()
}):this.handleCurrentPage()}handleCurrentPage(){const t=window.location.href
;t.includes("publicgroupsearch.php")||t.includes("publicgroup.php")?(this.setupReadMarks(),
this.bindEvents()):t.includes("publictopic.php")&&this.markCurrentTopicAsRead()}markCurrentTopicAsRead(){const e=t(window.location.href)
;e&&this.markAsRead(e)}setupReadMarks(){void 0;let e=document.querySelectorAll(CONFIG.SELECTORS.topicLinks);if(void 0,0===e.length){
e=document.querySelectorAll(CONFIG.SELECTORS.allTopicLinks);const t=document.querySelectorAll('a[href*="publictopic.php"]');void 0,
document.querySelectorAll("table"),void 0,t.forEach((t,e)=>{e<5,0})}e.forEach(e=>{const i=e;i.target="_blank",i.rel="noopener noreferrer"
;const a=t(i.href);a&&this.isRead(a)&&this.markAsReadVisually(i)})}bindEvents(){let e=null;document.addEventListener("mousedown",t=>{e={
time:Date.now(),x:t.clientX,y:t.clientY,target:t.target}}),document.addEventListener("click",i=>{
const a=i.target.closest(CONFIG.SELECTORS.allTopicLinks);if(a&&0===i.button){const s=t(a.href);s&&this.isValidClick(i,e)&&(this.markAsRead(s),
this.markAsReadVisually(a))}}),document.addEventListener("auxclick",e=>{const i=e.target.closest(CONFIG.SELECTORS.allTopicLinks);if(i&&1===e.button){
const e=t(i.href);e&&(this.markAsRead(e),this.markAsReadVisually(i))}}),document.addEventListener("contextmenu",e=>{
const i=e.target.closest(CONFIG.SELECTORS.allTopicLinks);if(i){const e=t(i.href);e&&setTimeout(()=>{this.markAsRead(e),this.markAsReadVisually(i)
},100)}}),document.addEventListener("click",e=>{const i=e.target.closest(CONFIG.SELECTORS.allTopicLinks);if(i&&(e.ctrlKey||e.metaKey)){
const a=t(i.href);a&&(this.markAsRead(a),this.markAsReadVisually(i),e.ctrlKey)}})}isValidClick(t,e){if(!e)return!0
;const i=Date.now()-e.time,a=Math.sqrt(Math.pow(t.clientX-e.x,2)+Math.pow(t.clientY-e.y,2)),s=window.getSelection()
;return s&&s.toString().length>0?(void 0,!1):!(void 0,i>500||a>5)}markAsRead(t){this.isRead(t)||(this.readTopics.add(t),a(t))}isRead(t){
return this.readTopics.has(t)||s(t)}markAsReadVisually(t){if("true"===t.dataset.readMarked)return;t.dataset.readMarked="true"
;const e=document.createElement("span");e.textContent=CONFIG.TEXT.readBadge,e.style.color=CONFIG.STYLES.READ_BADGE.color,
e.style.fontSize=CONFIG.STYLES.READ_BADGE.fontSize,e.style.marginLeft=CONFIG.STYLES.READ_BADGE.marginLeft,
e.style.fontWeight=CONFIG.STYLES.READ_BADGE.fontWeight,t.appendChild(e);const i=t.closest("tr");i&&(i.style.opacity=CONFIG.STYLES.READ_TOPIC.opacity,
i.style.background=CONFIG.STYLES.READ_TOPIC.background,i.style.color=CONFIG.STYLES.READ_TOPIC.color)}}const l=class{static init(){
this.isInitialized||(this.trackExistingLinks(),this.setupMutationObserver(),this.isInitialized=!0)}static trackExistingLinks(){
const t=document.querySelectorAll(CONFIG.SELECTORS.googleResultLinks);void 0,t.forEach((t,e)=>{e<3,0}),t.forEach(t=>this.processLink(t))}
static setupMutationObserver(){this.observer=new MutationObserver(()=>{this.trackExistingLinks()}),this.observer.observe(document.body,{childList:!0,
subtree:!0})}static processLink(t){if(!t.href||t.dataset.readProcessed)return;t.dataset.readProcessed="1";const e=t.href;void 0,c(e)&&(void 0,
this.applyReadStyle(t));let i=!1;t.addEventListener("contextmenu",()=>{i=!0,setTimeout(()=>{i=!1},0)}),t.addEventListener("click",a=>{
i||0!==a.button||1!==a.detail||a.ctrlKey||a.metaKey||a.shiftKey||a.altKey||(a.preventDefault(),GM_openInTab(e,{active:!1,insert:!0,setParent:!0}),
setTimeout(()=>window.focus(),0),o(e),this.applyReadStyle(t))}),t.addEventListener("auxclick",i=>{1===i.button&&(o(e),this.applyReadStyle(t))})}
static applyReadStyle(t){Object.assign(t.style,CONFIG.STYLES.GOOGLE_READ_LINK)}static cleanup(){this.observer&&(this.observer.disconnect(),
this.observer=null),this.isInitialized=!1}};l.isInitialized=!1,l.observer=null;let d=l;class LaomoReadMarkApp{static main(){void 0,
"loading"===document.readyState?document.addEventListener("DOMContentLoaded",this.initialize.bind(this)):this.initialize()}static initialize(){try{
const t=window.location.href;this.isJavLibraryPage(t)?(void 0,(new ReadMarkManager).init()):this.isGoogleImageSearchPage(t)?(void 0,d.init()):void 0
}catch(t){void 0}}static isJavLibraryPage(t){
return t.includes("javlibrary.com")&&(t.includes("publicgroupsearch.php")||t.includes("publictopic.php")||t.includes("publicgroup.php"))}
static isGoogleImageSearchPage(t){
return(t.includes("google.com/search")||t.includes("images.google.com/search"))&&(t.includes("tbm=isch")||t.includes("udm=48")||t.includes("imgres"))}
static cleanup(){try{d.cleanup()}catch(t){void 0}}}LaomoReadMarkApp.main()})();