// ==UserScript== // @name bilispace# // @namespace http://tampermonkey.net/ // @version 3.0 // @description better // @match *://space.bilibili.com/* // @run-at document-start // @grant none // @require https://scriptcat.org/lib/637/1.4.8/ajaxHooker.js#sha256=dTF50feumqJW36kBpbf6+LguSLAtLr7CEs3oPmyfbiM= // ==/UserScript== (function () { 'use strict'; const CONF = { BLOCKED_STATUS: 128, ERROR_CODES: new Set([-404, -403]), CACHE_TTL: 300_000, ERROR_SELECTORS: [ '.h-forbid', '.h-sign', '.error-text', '.error-container', '.no-permission', '[class*="block"]', '[class*="privacy"]', '[class*="error"]' ], CONTENT_SELECTORS: ['.s-space', '#app', '.wrapper', '.content'], ERROR_KEYWORDS: ['隐私设置'] }; const userCache = new Map(); const utils = { now: () => Date.now(), extractMid: (url) => { try { const u = new URL(url.startsWith('http') ? url : `https://api.bilibili.com${url}`); const m = u.searchParams.get('mid'); return m && /^\d+$/.test(m) ? m : null; } catch { return null; } } }; function getCached(mid) { const entry = userCache.get(mid); if (entry && utils.now() - entry.ts < CONF.CACHE_TTL) return entry.data; return null; } async function fetchCard(mid) { try { const resp = await fetch(`https://api.bilibili.com/x/web-interface/card?mid=${mid}`); const j = await resp.json(); return j?.code === 0 ? j.data?.card : null; } catch { return null; } } function buildCompleteInfo(card, mid) { const c = card || {}; return { code: 0, message: "0", ttl: 1, data: { mid: Number(mid), name: c.name || '用户已注销', sex: c.sex || '保密', face: c.face || 'https://i0.hdslb.com/bfs/face/member/noface.jpg', sign: c.sign || '', rank: c.rank || 10000, level: c.level_info?.current_level || 0, jointime: 0, moral: 0, silence: 0, coins: 0, birthday: c.birthday || '01-01', fans_badge: c.fans_badge || false, fans_medal: c.fans_medal || { show: false, wear: false }, official: c.Official || { type: -1, desc: '', title: '' }, vip: c.vip || { type: 0, status: 0, theme_type: 0 }, pendant: c.pendant || { pid: 0, name: '', image: '', expire: 0 }, nameplate: c.nameplate || { nid: 0, name: '', image: '', image_small: '', level: '', condition: '' }, user_honour_info: { mid: 0, colour: null, tags: [] }, is_followed: false, top_photo: c.space?.l_img || c.space?.s_img || '', theme: {}, sys_notice: {}, live_room: c.live_room || null, is_senior_member: c.is_senior_member || 0, elec: { show_info: { show: false } }, contract: { is_display: false }, certificate_show: false } }; } ajaxHooker.filter([ { url: '/x/space/wbi/acc/relation' }, { url: '/x/space/acc/relation' }, { url: '/x/space/wbi/acc/info' }, { url: '/x/space/acc/info' } ]); ajaxHooker.hook(request => { request.response = async res => { let data; let isJsonObj = res.json !== undefined; if (isJsonObj) { data = res.json; } else if (res.responseText) { try { data = JSON.parse(res.responseText); } catch (e) {} } if (!data) return; if (request.url.includes('/acc/relation')) { if (data?.data?.be_relation?.attribute === CONF.BLOCKED_STATUS) { data.data.be_relation.attribute = 0; if (!data.data.relation) { data.data.relation = { mid: 0, attribute: 0, mtime: 0, tag: null, special: 0 }; } } } if (request.url.includes('/acc/info')) { if (CONF.ERROR_CODES.has(data.code)) { const mid = utils.extractMid(request.url); if (mid) { let cachedInfo = getCached(mid); if (!cachedInfo) { const card = await fetchCard(mid); if (card) { cachedInfo = buildCompleteInfo(card, mid); userCache.set(mid, { data: cachedInfo, ts: utils.now() }); } } if (cachedInfo) { data = cachedInfo; } } } } if (isJsonObj) res.json = data; if (res.responseText !== undefined) res.responseText = JSON.stringify(data); }; }); function cleanupPageOnce() { CONF.ERROR_SELECTORS.forEach(sel => { document.querySelectorAll(sel).forEach(el => { const text = (el.textContent || '').trim(); if (CONF.ERROR_KEYWORDS.some(k => text.includes(k))) { el.style.display = 'none'; } }); }); CONF.CONTENT_SELECTORS.forEach(sel => { const el = document.querySelector(sel); if (el && (getComputedStyle(el).display === 'none' || getComputedStyle(el).visibility === 'hidden')) { el.style.display = ''; el.style.visibility = 'visible'; } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', cleanupPageOnce, { once: true }); } else { cleanupPageOnce(); } if (typeof MutationObserver !== 'undefined') { const observer = new MutationObserver(mutations => { if (mutations.some(m => m.addedNodes?.length > 0)) cleanupPageOnce(); }); const waitBody = setInterval(() => { if (document.body) { clearInterval(waitBody); observer.observe(document.body, { childList: true, subtree: true }); } }, 100); } })();