bilispace

good

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         bilispace
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  good
// @match        *://space.bilibili.com/*
// @run-at       document-start
// @grant        none
// ==/UserScript==
 
(function() {
    'use strict';
    
    const originalFetch = window.fetch;
    const userCardCache = new Map();
    const requestCounter = new Map();
    function safeGet(obj, path, defaultValue = undefined) {
        return path.split('.').reduce((current, key) => {
            return (current && current[key] !== undefined) ? current[key] : defaultValue;
        }, obj);
    }
 
    async function fetchUserCard(mid) {
        // 检查缓存
        if (userCardCache.has(mid)) {
            console.log(`[SpaceTweaks] 使用缓存数据 mid: ${mid}`);
            return userCardCache.get(mid);
        }
 
        const now = Date.now();
        const userRequests = requestCounter.get(mid) || [];
        const recentRequests = userRequests.filter(time => now - time < 60000);
        
        if (recentRequests.length >= 3) {
            console.warn(`[SpaceTweaks] 用户 ${mid} 请求过于频繁,已限制`);
            return null;
        }
        
        try {
            console.log(`[SpaceTweaks] 获取用户卡片信息 mid: ${mid}`);
            
            const cardResponse = await originalFetch(`https://api.bilibili.com/x/web-interface/card?mid=${mid}`);
            
            if (!cardResponse.ok) {
                console.error(`[SpaceTweaks] 卡片接口请求失败: ${cardResponse.status}`);
                return null;
            }
            
            const cardData = await cardResponse.json();
            
            if (cardData.code !== 0) {
                console.warn(`[SpaceTweaks] 卡片接口返回错误: code=${cardData.code}, message=${cardData.message}`);
                return null;
            }
            if (!cardData.data?.card) {
                console.warn('[SpaceTweaks] 卡片数据结构异常');
                return null;
            }
            
            recentRequests.push(now);
            requestCounter.set(mid, recentRequests);
       
            const cacheData = {
                data: cardData.data.card,
                expiry: now + 300000
            };
            userCardCache.set(mid, cacheData);
            setTimeout(() => {
                userCardCache.delete(mid);
            }, 300000);
            
            return cacheData;
            
        } catch (error) {
            console.error(`[SpaceTweaks] 获取用户卡片时发生错误:`, error);
            return null;
        }
    }
    
    function createSafeResponse(cardData, mid) {
        const card = cardData.data;
        
        const official = {
            type: safeGet(card, 'Official.type', -1),
            desc: safeGet(card, 'Official.desc', ''),
            title: safeGet(card, 'Official.title', '')
        };
        
        return {
            code: 0,
            message: "0",
            ttl: 1,
            data: {
                attestation: {
                    type: official.type,
                    desc: official.desc,
                    splice_info: {
                        title: official.title
                    },
                    common_info: {
                        title: official.title
                    }
                },
                birthday: '01-01',
                certificate_show: 0,
                coins: 0,
                contract: {
                    is_display: false,
                    is_follow_display: false
                },
                elec: {
                    show_info: {
                        show: false
                    }
                },
                face: safeGet(card, 'face', 'https://i0.hdslb.com/bfs/face/member/noface.jpg'),
                face_nft: safeGet(card, 'face_nft', 0),
                face_nft_type: safeGet(card, 'face_nft_type', 0),
                fans_badge: true,
                fans_medal: {
                    show: false
                },
                gaia_data: null,
                gaia_res_type: 0,
                is_followed: false,
                is_risk: false,
                is_senior_member: false,
                level: safeGet(card, 'level_info.current_level', 0),
                mid: parseInt(mid, 10),
                name: safeGet(card, 'name', '未知用户'),
                offical: official, 
                sex: safeGet(card, 'sex', '保密'),
                sign: safeGet(card, 'sign', ''),
                tags: [],
                top_photo_v2: {
                    l_img: safeGet(card, 'l_img', '')
                },
                _spacetweaks_processed: true,
                _spacetweaks_timestamp: Date.now()
            }
        };
    }
    
    window.fetch = async function(...args) {
        const response = await originalFetch.apply(this, args);
 
        if (!args[0] || !args[0].includes('x/space/wbi/acc/info')) {
            return response;
        }
        
        try {
            const clone = response.clone();
            let json;
            
            try {
                json = await clone.json();
            } catch (parseError) {
                console.error('[SpaceTweaks] JSON解析失败:', parseError);
                return response;
            }
 
            if (json.code !== -404) {
                return response;
            }
 
            let mid;
            try {
                const fullUrl = args[0].startsWith('http') ? args[0] : `https://api.bilibili.com${args[0]}`;
                mid = (new URL(fullUrl)).searchParams.get('mid');
                
                if (!mid || !/^\d+$/.test(mid)) {
                    console.warn('[SpaceTweaks] 无效的mid参数:', mid);
                    return response;
                }
            } catch (urlError) {
                console.error('[SpaceTweaks] URL解析失败:', urlError);
                return response;
            }
            
            console.log(`[SpaceTweaks] 检测到用户不存在或被封禁 mid: ${mid}, 尝试获取基本信息`);
 
            const cardData = await fetchUserCard(mid);
            if (!cardData) {
                console.log('[SpaceTweaks] 无法获取用户信息,返回原响应');
                return response;
            }
 
            if (Date.now() > cardData.expiry) {
                console.log('[SpaceTweaks] 缓存已过期,返回原响应');
                return response;
            }
            
            // 构造新的响应
            const newJson = createSafeResponse(cardData, mid);
            
            const newResponse = new Response(JSON.stringify(newJson), {
                status: response.status,
                statusText: response.statusText,
                headers: response.headers
            });
            
            console.log(`[SpaceTweaks] 成功为用户 ${mid} 构造响应`);
            return newResponse;
            
        } catch (error) {
            console.error('[SpaceTweaks] 处理响应时发生错误:', error);
            return response;
        }
    };
    
    setInterval(() => {
        const now = Date.now();
        for (const [mid, data] of userCardCache.entries()) {
            if (now > data.expiry) {
                userCardCache.delete(mid);
            }
        }
 
        for (const [mid, requests] of requestCounter.entries()) {
            const recent = requests.filter(time => now - time < 60000);
            if (recent.length === 0) {
                requestCounter.delete(mid);
            } else {
                requestCounter.set(mid, recent);
            }
        }
    }, 60000);
    
    console.log('[SpaceTweaks ');
})();