// ==UserScript== // @name Hostloc根据关键字和用户名屏蔽帖子 // @namespace https://hostloc.com/ // @version 0.2.7 // @description 根据关键字和用户名屏蔽帖子,根据用户名屏蔽签名 // @author kiwi // @homepage https://github.com/FlyxFly/hostloc-block-post-and-signature // @match https://hostloc.com/forum-* // @match https://hostloc.com/thread-* // @match https://hostloc.com/forum.php?mod=viewthread&tid=* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @require https://unpkg.com/sweetalert/dist/sweetalert.min.js // @downloadURL https://update.greasyfork.icu/scripts/435442/Hostloc%E6%A0%B9%E6%8D%AE%E5%85%B3%E9%94%AE%E5%AD%97%E5%92%8C%E7%94%A8%E6%88%B7%E5%90%8D%E5%B1%8F%E8%94%BD%E5%B8%96%E5%AD%90.user.js // @updateURL https://update.greasyfork.icu/scripts/435442/Hostloc%E6%A0%B9%E6%8D%AE%E5%85%B3%E9%94%AE%E5%AD%97%E5%92%8C%E7%94%A8%E6%88%B7%E5%90%8D%E5%B1%8F%E8%94%BD%E5%B8%96%E5%AD%90.meta.js // ==/UserScript== (function() { 'use strict'; const now = function(){ return new Date().getTime(); } // 移除数组中的空元素 if(!Array.prototype.trim){ Array.prototype.trim = function removeEmptyElements () { return this.filter((x)=>{ return x; }) } } // 查询数组是否存在某个值,忽略大小写 if(!Array.prototype.contains){ Array.prototype.contains = function checkIfInArray (target) { for(let i=0;i jsonData.data.hasOwnProperty(key))) { this.saveToLocal(); return; } // 如果有 pantry 数据,则检查 pantry 数据是否过期,如果过期则从云端获取数据 if(jsonData.data.pantry.APIKey && jsonData.data.pantry.basket){ this.config.pantry = jsonData.data.pantry; if((now() - jsonData.timestamp) > 12*3600*1000){ return this.modifyCloudData('get'); } } for (let x in this.dataKeys) { const key = this.dataKeys[x]; this.config[key]=jsonData.data[key]; } } async modifyCloudData(action){ // 如果云端数据没有配置APIKey和basket,则保存到本地并提示用户 if(!this.config.pantry.APIKey || !this.config.pantry.basket){ this.saveToLocal(); swal({ text:'已保存到本地浏览器,清理浏览器缓存可能会导致数据丢失', icon:'info', button: '我知道了' }); return false; } // 操作云端数据 const url = `https://getpantry.cloud/apiv1/pantry/${this.config.pantry.APIKey}/basket/${this.config.pantry.basket}`; switch(action){ case 'get': swal({ title:'正在获取云端数据', text:'每天第一次打开需要同步数据,请稍后...', icon:'info', button:false }); fetch(url,{ method:'GET', headers: { 'Content-Type': 'application/json' }, }) .then((response)=>{ return response.text() }) .then((text)=>{ if(text.includes('pantry with id')){ throw new Error('Pantry Key 不存在,请检查'); } if(text.includes('does not exist')){ throw new Error('Baskey 不存在,请检查'); } const data = JSON.parse(text); // 检查云端数据是否有对应键值,如果有就加载到本对象中 if(data.pantry && data.blockedKeyword && data.blockedSignatureUser && data.blockedUser){ this.config = data; swal({ text:'云端数据加载成功', icon:'success', button:'好的' }); }else{ swal({ text:'云端数据格式不正确,初始化数据', icon:'info', button: '我知道了' }) } // 如果云端数据结构不正确,则直接保存本对象自带的初始化数据 this.saveToLocal(); this.restoreFromLocal(); this.startBlockProcess(); console.log('Got data from cloud.',data); }).catch((e)=>{ swal({ title:'云端数据加载失败', text:e.message, icon:'error', button:'好的' }) }) break; case 'save': swal({ text:'正在保存数据到云端,请稍后', icon:'info', button: false }); fetch(url, { method:'POST', headers: { 'Content-Type': 'application/json' }, body:JSON.stringify(this.config) }).then((res)=>{ swal({ text:'数据保存到云端成功,可以跳转到其他页面了', icon:'success', button:'好的' }); console.log('Save data to cloud',res); }).catch((e)=>{ swal({ title:'保存失败', text:e.message, icon:'error', button:'好的' }); }) break; default: return false; } } hideFromList(){ const blockedKeyword = this.config.blockedKeyword; const blockedUser = this.config.blockedUser; document.querySelectorAll('#threadlisttableid tbody').forEach((item,index)=>{ if(item.id.includes('normalthread')){ const title=item.querySelector('a.s.xst').innerText; for (let i = blockedKeyword.length - 1; i >= 0; i--) { if(title.toUpperCase().includes(blockedKeyword[i].toUpperCase())){ // item.querySelector('a.s.xst').innerText='已屏蔽'; item.style.display='none'; break; } } const nameA=item.querySelectorAll('td.by')[0].querySelector('a'); if(nameA){ const userName=nameA.innerText.trim().toUpperCase(); if(blockedUser.contains(userName)){ // item.querySelector('a.s.xst').innerText='已屏蔽'; item.style.display='none'; } } } }) } hideReplyAndSignature(){ const blockedSignatureUser = this.config.blockedSignatureUser; const blockedKeyword = this.config.blockedKeyword; const contentStorage = this.contentStorage; const blockedUser = this.config.blockedUser; document.querySelectorAll('#postlist>div').forEach((post)=>{ if(!post.id.includes('post_')){ return false; } const userLink=post.querySelector('a.xw1'); if(userLink){ const userName=userLink.innerText.trim(); // 根据用户名屏蔽发帖 if(userName && blockedUser.includes(userName)){ post.style.display='none'; return false; } // 根据用户名屏蔽签名 if(blockedSignatureUser.includes(userName) && post.querySelector('div.sign')){ const signature=post.querySelector('div.sign'); const contentText=signature.innerText; const contentHTML=signature.innerHTML; const storageKey=post.id+'signature'; contentStorage[storageKey]=contentHTML; signature.innerHTML=`已屏蔽,鼠标移到此处查看内容,点击还原内容`; } } const tds=post.querySelectorAll('td'); tds.forEach((td)=>{ // 查找帖子内容容器: td.postmessage_{thread_id} if(td.id.includes('postmessage_')){ const content=td.innerText; for (let i = blockedKeyword.length - 1; i >= 0; i--) { // 根据关键字屏蔽发帖内容 if(content.toUpperCase().includes(blockedKeyword[i].toUpperCase())){ const contentHTML=td.innerHTML; const contentText=td.innerText; contentStorage[post.id]=contentHTML; td.innerHTML=`已屏蔽,鼠标移到此处查看内容,点击还原内容`; break; } } } }) }) } addSettingButton(){ const p = document.querySelectorAll('#um p')[1]; p.appendChild(htmlToElement(`|`)); p.appendChild(htmlToElement(`屏蔽名单设置`)); } addSettingPanel(){ const div = document.createElement('div'); div.id='hostloc-blocker-panel-wrapper'; div.innerHTML = ` Document `; document.body.appendChild(div); } addPanelEvents(){ const panel = document.querySelector('#hostloc-blocker-panel'); const saveButton = panel.querySelector('.save'); const inputPantryAPIKey = panel.querySelector('[name="pantry-api-key"]'); const inputBasketName = panel.querySelector('[name="pantry-basket-name"]'); const textareaBlockedUser = panel.querySelector('textarea[name="blocked-user"]'); const textareaBlockedSignatureUser = panel.querySelector('textarea[name="blocked-signature-user"]'); const textareaBlockedKeyword = panel.querySelector('textarea[name="blocked-keyword"]'); const openPanelLink = document.querySelector('#show-block-panel'); panel.addEventListener('click',(event)=>{ event.stopPropagation(); }) document.body.addEventListener('click',()=>{ panel.classList.remove('is-active'); }) openPanelLink.addEventListener('click',(event)=>{ event.stopPropagation(); textareaBlockedKeyword.value = this.config.blockedKeyword.join('\n'); textareaBlockedSignatureUser.value = this.config.blockedSignatureUser.join('\n'); textareaBlockedUser.value = this.config.blockedUser.join('\n'); inputPantryAPIKey.value = this.config.pantry.APIKey; inputBasketName.value = this.config.pantry.basket; panel.classList.add('is-active'); }); saveButton.addEventListener('click',()=>{ this.config.pantry.APIKey = inputPantryAPIKey.value; this.config.pantry.basket = inputBasketName.value; // 如果仅输入了apikey 则表示从云端拉取数据,将覆盖本地数据 if(!textareaBlockedKeyword.value && !textareaBlockedSignatureUser.value && !textareaBlockedUser.value){ this.modifyCloudData('get'); return; }else{ // 将api key 和数据保存到本地 this.config.blockedKeyword = textareaBlockedKeyword.value.split('\n').trim(); this.config.blockedSignatureUser = textareaBlockedSignatureUser.value.split('\n').trim(); this.config.blockedUser = textareaBlockedUser.value.split('\n').trim(); // 保存到本地 this.saveToLocal(); // 启动屏蔽流程 this.startBlockProcess(); // 将数据保存到云端 this.modifyCloudData('save'); } panel.classList.remove('is-active'); }) } startBlockProcess(){ if(location.href.includes('forum')){ this.hideFromList(); } if(location.href.includes('thread')){ this.hideReplyAndSignature(); } //监听点击事件,恢复被屏蔽的签名和帖子 if(location.href.includes('thread')){ document.querySelector('#postlist').addEventListener('click',(e)=>{ const item=e.target; if(item.className.includes('hidden-by-script')){ item.innerHTML=this.contentStorage[item.dataset.restoreKey]; item.title=''; item.style=''; } }) } } init(){ this.addSettingPanel(); this.addSettingButton(); this.addPanelEvents(); this.restoreFromLocal(); this.startBlockProcess(); } } const app=new HostLocBlocker(); app.init(); })();