您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shadow blocks user (only blocks on responses and timeline of yourself)
// ==UserScript== // @name Plurk shadow block // @name:zh-TW 噗浪隱形黑名單 // @description Shadow blocks user (only blocks on responses and timeline of yourself) // @description:zh-TW 隱形封鎖使用者(只是會在回應和在河道上看不到被封鎖者的發文、轉噗,其他正常) // @version 0.4.0 // @license MIT // @namespace https://github.com/stdai1016 // @match https://www.plurk.com/* // @exclude https://www.plurk.com/_* // @require https://code.jquery.com/jquery-3.5.1.min.js // @require https://gf.qytechs.cn/scripts/432792-plurk-lib/code/plurk_lib.js?version=972862 // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // ==/UserScript== /* jshint esversion: 6 */ /* global $, plurklib */ (function () { 'use strict'; const LANG = { DEFAULT: { resp_btn_hide: 'Hide blocked responses', resp_btn_show: 'Show blocked responses', set_alert: 'Incorrect format of nick name!', set_append: 'Append', set_empty: 'There is no one in your blocklist.', set_note: 'A blocked user will not be shown on responses and your timeline,' + ' but is still able to see your profile, follow you,' + ' respond to your plurks or befriend you.', set_remove: 'Remove', set_replurk: 'Block replurks', set_response: 'Block responses', set_tab: 'Shadow Block' }, 'zh-hant': { resp_btn_hide: '隱藏被封鎖的回應', resp_btn_show: '顯示被封鎖的回應', set_alert: '帳號格式不正確', set_append: '新增', set_empty: '沒有任何人在黑名單中', set_note: '在回應區和自己的河道上看不到被封鎖者的發文、轉噗;' + '但對方仍可瀏覽您的個人檔案,關注、回應您的訊息,或加您為朋友。', set_remove: '移除', set_replurk: '封鎖轉噗', set_response: '封鎖回應', set_tab: '隱形黑名單' } }; let lang = LANG.DEFAULT; const curLang = document.documentElement.getAttribute('lang') || ''; if (curLang.toLowerCase() in LANG) lang = LANG[curLang.toLowerCase()]; if (typeof plurklib === 'undefined') { console.error('plurklib load failed!'); return; } const pageUserId = plurklib.getPageUserData()?.id; const currUserId = plurklib.getUserData()?.id; /* ======= storage ======= */ /** Struct in GM storage: * { * `u${currUserId}`: { * `b${blockedUserId}`: { * id: blockedUserId, * nick_name: <string>, // for readability * replurk: <bool>, // block his replurks * response: <bool>, // block his responses * date: <UTC_datetime_string> * } * } * } */ function valueGetSet (val = null) { if (val != null) GM_setValue(`u${currUserId}`, val); return GM_getValue(`u${currUserId}`); } let _blockedUsers = valueGetSet(); if (typeof _blockedUsers !== 'object') _blockedUsers = valueGetSet({}); const blockedList = { get: id => _blockedUsers[`b${id}`], add: user => { _blockedUsers[`b${user.id}`] = { id: user.id, nick_name: user.nick_name, replurk: user.replurk ?? true, response: user.response ?? true, date: user.date ?? (new Date()).toUTCString() }; valueGetSet(_blockedUsers); }, remove: id => { delete _blockedUsers[`b${id}`]; valueGetSet(_blockedUsers); }, contains: user => { switch (typeof user) { case 'string': for (const u in _blockedUsers) { if (_blockedUsers[u].nick_name === user) return true; } break; case 'number': return !!_blockedUsers[`b${user}`]; case 'object': return !!_blockedUsers[`b${user?.id}`]; } return false; }, forEach: callbackfn => { for (const i in _blockedUsers) { callbackfn(_blockedUsers[i], i, _blockedUsers); } }, get length () { return Object.keys(_blockedUsers).length; } }; /* ============== */ GM_addStyle( '.hide {display:none}' + '.item_holder .user_item.user_shadow_blocked_users_item .user_info {' + ' width: calc(100% - 190px);}' + '.friend_man.not_block {background-color:#999;}' + '.friend_man.not_block:hover {background-color:#207298}' + '.resp-hidden-show {background:#f5f5f9;color:#afb8cc;' + ' font-weight:normal;vertical-align:top;transform:scale(0.9);opacity:0;}' + '.resp-hidden-show.show {opacity:1}' + '.resp-hidden-show:not(.show) .onshow {display:none}' + '.resp-hidden-show.show .onhide {display:none}' + '.response-status:hover .resp-hidden-show {opacity:1}' + '.resp-hidden-show:hover {background:#afb8cc;color:#fff}' ); if (window.location.pathname === '/Friends/') { $('<li><a void="">' + lang.set_tab + '</a></li>').on('click', function () { window.history.pushState('', document.title, '/Friends/'); $('#pop-window-tabs>ul>li').removeClass('current'); this.classList.add('current'); const $content = $('#pop-window-inner-content .content_inner').empty(); $content.append( '<div class="note">' + lang.set_note + '</div>', '<div class="dashboard">' + ' <div class="search_box"><input>' + ' <button>' + lang.set_append + '</button></div>' + ' <div class="empty">' + lang.set_empty + '</div>' + '</div>'); const $holder = $('<div class="item_holder"></div>').appendTo($content); if (blockedList.length) { $content.find('.dashboard .empty').addClass('hide'); } blockedList.forEach(u => { plurklib.fetchUserInfo(u.id).then(info => { makeBlockedUserItem(info, $holder); }).catch(e => { console.info(`Cannot get info of "${u.nick_name}" (${e.message})`); makeBlockedUserItem(u, $holder); }); }); $content.find('.search_box>button').on('click', function () { const m = this.parentElement.children[0].value.match(/^[A-Za-z]\w+$/); if (m) { this.parentElement.children[0].value = ''; $content.find('.dashboard .empty').addClass('hide'); plurklib.fetchUserInfo(m[0]).then(info => { blockedList.add(info); makeBlockedUserItem(info, $holder); }).catch(e => { window.alert(`Unknown user "${m[0]}"`); }); } else { window.alert(lang.set_alert); } }); }).appendTo('#pop-window-tabs>ul'); } else if (pageUserId === currUserId || window.location.pathname.match(/^\/p\/[0-9a-z]+$/)) { makeButton($('#plurk_responses>.response_box')); makeButton($('#form_holder>.response_box')); makeButton($('#cbox_response>.response_box')); const po = new plurklib.PlurkObserver(prs => prs.forEach(pr => { pr.plurks.forEach(plurk => { if (blockedList.contains(plurk.owner_id)) { if (plurk.isResponse) { plurk.target.classList.add('shadow-block'); const btn = pr.target.parentElement.querySelector('.resp-hidden-show'); btn?.classList.remove('hide'); if (blockedList.get(plurk.owner_id).response) { plurk.target.classList.add('hide'); console.debug(`block #m${plurk.id}`); } else { btn?.classList.add('show'); } } else { plurk.target.classList.add('shadow-block', 'hide'); console.debug(`block #p${plurk.id}`); } } else if (blockedList.get(plurk.replurker_id)?.replurk) { plurk.target.classList.add('shadow-block', 'hide'); console.debug(`block #p${plurk.id}`); } }); })); po.observe({ plurk: true }); } function makeButton ($responseBox) { if (!$responseBox.length) return; const $formBtn = $( '<div><span class="onshow">' + lang.resp_btn_hide + '</span>' + '<span class="onhide">' + lang.resp_btn_show + '</span></div>' ); $formBtn.on('click', function () { $formBtn.toggleClass('show'); const $blocks = $responseBox.children('.list').children('.shadow-block'); if ($formBtn.hasClass('show')) $blocks.removeClass('hide'); else $blocks.addClass('hide'); }).addClass(['resp-hidden-show', 'button', 'small-button', 'hide']) .insertAfter($responseBox.find('.response-only-owner')); (new MutationObserver(mrs => mrs.forEach(mr => { if (!mr.target.querySelector('.handle-remove')) { $('<div class="handle-remove hide"></div>').prependTo(mr.target); } mr.removedNodes.forEach(node => { if (node.classList.contains('handle-remove')) { $formBtn.removeClass('show').addClass('hide').text(lang.resp_btn_show); } }); }))).observe($responseBox.find('.list').first()[0], { childList: true }); } function makeBlockedUserItem (info, holder) { const user = blockedList.get(info.id); if (info.nick_name && info.nick_name !== user.nick_name) { user.nick_name = info.nick_name; blockedList.add(user); } blockedList.add(user); const $u = $('<div class="user_item user_shadow_blocked_users_item"></div>'); const img = info.has_profile_image ? `https://avatars.plurk.com/${info.id}-medium${info.avatar ?? ''}.gif` : 'https://www.plurk.com/static/default_medium.jpg'; $u.append([ '<a class="user_avatar" target="_blank">', ` <img class="profile_pic" src="${img}"></img>`, '</a>', '<div class="user_info">', ' <a class="user_link" target="_blank"', ` style="color:#000">${info.display_name}</a>`, ` <span class="nick_name">@${info.nick_name}</span>`, ' <div class="more_info"><br></div>', '</div>', '<div class="user_action">', ` <a void="" data-switch="replurk" title="${lang.set_replurk}"`, ' class="friend_man icon_only pif-replurk', ` ${user.replurk ? 'has_block' : 'not_block'}"></a>`, ` <a void="" data-switch="response" title="${lang.set_response}"`, ' class="friend_man icon_only pif-message', ` ${user.response ? 'has_block' : 'not_block'}"></a>`, ` <a void="" data-remove="1" title="${lang.set_remove}"`, ' class="friend_man icon_only pif-user-blocked has_block"></a>', '</div>' ].join('')); $u.find('a:not(.icon_only)').attr('href', '/' + info.nick_name); $u.find('a.icon_only').on('click', function () { if (this.dataset.switch) { user[this.dataset.switch] = !user[this.dataset.switch]; if (user[this.dataset.switch]) { this.classList.add('has_block'); this.classList.remove('not_block'); } else { this.classList.remove('has_block'); this.classList.add('not_block'); } blockedList.add(user); } if (this.dataset.remove) { blockedList.remove(user.id); $u.remove(); } }); $u.appendTo(holder); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址