bilispace

good

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==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 ');
})();