Linux Do 个人活动信息查询

获取你Linux do 行为信息

// ==UserScript==
// @name         Linux Do 个人活动信息查询
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  获取你Linux do 行为信息
// @author       Unique、King-Huiwen-of-Qin
// @match        https://linux.do/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let username = '';
    let hideTimeout;
    let isQuerying = false;

    // Constants for local storage keys
    const STORAGE_KEY_COUNTS = 'timings_counts';
    const STORAGE_KEY_DATE = 'timings_date';
    const STORAGE_KEY_TOPIC = 'topic_count';

    // Utility function to check if a timestamp is from today
    function isToday(timestamp) {
        const now = new Date();
        const date = new Date(timestamp);
        return date.toDateString() === now.toDateString();
    }

    // Utility function to check if a timestamp is older than today
    function isOlderThanToday(timestamp) {
        const now = new Date();
        const date = new Date(timestamp);
        return date < new Date(now.getFullYear(), now.getMonth(), now.getDate());
    }

    // Utility function to delay execution
    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // Function to fetch user actions with pagination and count today's actions
    async function countTodaysActions(username, filter, uniqueTopicIds = false) {
        let offset = 0;
        let actionCount = 0;
        let uniqueTopicCount = 0;
        let hasMoreData = true;
        let queryData = true;
        const topicIds = new Set();
        let firstAction = '';

        while (hasMoreData) {
            const url = `https://linux.do/user_actions.json?offset=${offset}&limit=500&username=${username}&filter=${filter}`;
            try {
                const response = await fetch(url);
                const data = await response.json();
                const userActions = data.user_actions;

                // Check if there's no more data
                if (userActions.length === 0) {
                    hasMoreData = false;
                    break;
                }
                firstAction = userActions[0];
                // Filter today's actions and update the count
                const todaysActions = userActions.filter(action => isToday(action.created_at));
                actionCount += todaysActions.length;

                if (uniqueTopicIds) {
                    todaysActions.forEach(action => {
                        if (!topicIds.has(action.topic_id)) {
                            topicIds.add(action.topic_id);
                            uniqueTopicCount++;
                        }
                    });
                }

                // Check if the earliest action is older than today to stop further requests
                const oldestAction = userActions[userActions.length - 1];
                if (isOlderThanToday(oldestAction.created_at)) {
                    hasMoreData = false;
                    break;
                }

                // Increment the offset for the next batch
                offset += 500;

                // Delay before the next request
                await delay(600);
            } catch (error) {
                console.error(`Error fetching user actions with filter ${filter}:`, error);
                hasMoreData = false;
                queryData =false;
                break;
            }
        }
        return {actionCount, uniqueTopicCount,firstAction,queryData};
    }

    // Function to fetch reactions received with pagination and count today's reactions
    async function countTodaysReactionsReceived(username) {
        let beforeReactionUserId = null;
        let reactionCount = 0;
        let hasMoreData = true;

        while (hasMoreData) {
            let url = `https://linux.do/discourse-reactions/posts/reactions-received.json?username=${username}`;
            if (beforeReactionUserId) {
                url += `&before_reaction_user_id=${beforeReactionUserId}`;
            }
            try {
                const response = await fetch(url);
                const data = await response.json();
                const reactionsReceived = data;

                // Check if there's no more data
                if (reactionsReceived.length === 0) {
                    hasMoreData = false;
                    break;
                }

                // Filter today's reactions and update the count
                const todaysReactions = reactionsReceived.filter(reaction => isToday(reaction.created_at));
                reactionCount += todaysReactions.length;

                // Check if the earliest reaction is older than today to stop further requests
                const oldestReaction = reactionsReceived[reactionsReceived.length - 1];
                if (isOlderThanToday(oldestReaction.created_at)) {
                    hasMoreData = false;
                    break;
                }

                // Update beforeReactionUserId for the next batch
                beforeReactionUserId = oldestReaction.user_id;

                // Delay before the next request
                await delay(400);
            } catch (error) {
                console.error('Error fetching reactions received:', error);
                hasMoreData = false;
                break;
            }
        }

        return reactionCount;
    }


    async function getTotalUsers() {
        const response = await fetch('https://linux.do/about.json');
        const data = await response.json();
        return data.about.stats.users_count;
    }

    async function getUsersPerPage() {
        const response = await fetch('https://linux.do/leaderboard/1.json?page=0&period=all');
        const data = await response.json();
        return data.users.length;
    }

    async function getPageData(page) {
        const response = await fetch(`https://linux.do/leaderboard/1.json?page=${page}&period=all`);
        return await response.json();
    }

    async function findUserPosition(targetName, gamificationScore) {
        const totalUsers = await getTotalUsers();
        const usersPerPage = await getUsersPerPage();
        const totalPages = Math.ceil(totalUsers / usersPerPage);
        let left = 0;
        let right = totalPages - 1;
        let position = "未查询到";

         // Helper function to normalize the first character case
    const normalizeFirstChar = (name) => {
        return name.charAt(0).toLowerCase() + name.slice(1);
    };

    const normalizedTargetName = normalizeFirstChar(targetName);

        while (left <= right) {
            const mid = Math.floor((left + right) / 2);
            const data = await getPageData(mid);

            if (data.users.length === 0) {
                console.log('User not found.');
                break;
            }

            const firstUserTotalScore = data.users[0].total_score;
            const lastUserTotalScore = data.users[data.users.length - 1].total_score;

            if (gamificationScore > firstUserTotalScore) {
                right = mid - 1;
            } else if (gamificationScore < lastUserTotalScore) {
                left = mid + 1;
            } else {
                // Linear search on the current page
                for (let i = 0; i < data.users.length; i++) {
                    if (normalizeFirstChar(data.users[i].username) === normalizedTargetName) {
                        position = data.users[i].position;
                        console.log(`User: ${data.users[i].username}, Position: ${position}`);
                        return position;
                    }
                }

                // Continue searching previous pages for the same score
                let tempPage = mid - 1;
                while (tempPage >= 0) {
                    const tempData = await getPageData(tempPage);
                    for (let i = tempData.users.length - 1; i >= 0; i--) {
                        if (tempData.users[i].total_score !== gamificationScore) {
                            tempPage = -1;
                            break;
                        }
                        if (tempData.users[i].username === targetName) {
                            position = tempData.users[i].position;
                            console.log(`User: ${tempData.users[i].username}, Position: ${position}`);
                            return position;
                        }
                    }
                    tempPage--;
                }

                // Continue searching next pages for the same score
                tempPage = mid + 1;
                while (tempPage < totalPages) {
                    const tempData = await getPageData(tempPage);
                    for (let i = 0; i < tempData.users.length; i++) {
                        if (tempData.users[i].total_score !== gamificationScore) {
                            tempPage = totalPages;
                            break;
                        }
                        if (tempData.users[i].username === targetName) {
                            position = tempData.users[i].position;
                            console.log(`User: ${tempData.users[i].username}, Position: ${position}`);
                            return position;
                        }
                    }
                    tempPage++;
                }
                break;
            }

            // Add delay of 0.1 seconds to prevent too many requests in a short time
            await new Promise(resolve => setTimeout(resolve, 100));
        }

        return position;
    }



    // Function to fetch reactions given with pagination and count today's reactions given
    async function countTodaysReactionsGiven(username) {
        let beforeReactionUserId = null;
        let reactionCount = 0;
        let hasMoreData = true;

        while (hasMoreData) {
            let url = `https://linux.do/discourse-reactions/posts/reactions.json?username=${username}`;
            if (beforeReactionUserId) {
                url += `&before_reaction_user_id=${beforeReactionUserId}`;
            }
            try {
                const response = await fetch(url);
                const data = await response.json();
                const reactionsGiven = data;

                // Check if there's no more data
                if (reactionsGiven.length === 0) {
                    hasMoreData = false;
                    break;
                }

                // Filter today's reactions and update the count
                const todaysReactions = reactionsGiven.filter(reaction => isToday(reaction.created_at));
                reactionCount += todaysReactions.length;

                // Check if the earliest reaction is older than today to stop further requests
                const oldestReaction = reactionsGiven[reactionsGiven.length - 1];
                if (isOlderThanToday(oldestReaction.created_at)) {
                    hasMoreData = false;
                    break;
                }

                // Update beforeReactionUserId for the next batch
                beforeReactionUserId = oldestReaction.user_id;

                // Delay before the next request
                await delay(400);
            } catch (error) {
                console.error('Error fetching reactions given:', error);
                hasMoreData = false;
                break;
            }
        }

        return reactionCount;
    }

    async function checkUserOnline(username) {
        try {
            const csrfToken = getCsrfToken();
            const url = `https://linux.do/u/${username}/card.json`;
            // 构建请求头
            const headers = new Headers();
            // 添加需要的请求头,例如认证信息等
            headers.append('Accept', 'application/json, text/javascript, */*; q=0.01');
            headers.append('Discourse-Logged-In', 'true');
            headers.append('Discourse-Present', 'true');
            headers.append('Referer', 'https://linux.do');
            headers.append('Sec-Ch-Ua', '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"');
            headers.append('Sec-Ch-Ua-Mobile', '?0');
            headers.append('Sec-Ch-Ua-Platform', '"Windows"');
            headers.append('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36');
            headers.append('X-Csrf-Token', csrfToken);
            headers.append('X-Requested-With', 'XMLHttpRequest');

            // 发送请求
            const response = await fetch(url, {
                method: 'GET',
                headers: headers,
            });

            const userData = await response.json();
            const lastSeenTime = new Date(userData.user.last_seen_at);
            const currentTime = new Date();
            const timeDifference = currentTime - lastSeenTime;
            const minutesDifference = timeDifference / (1000 * 60);

            // 用户在线状态
            const isOnline = minutesDifference <= 5;

            // 用户点数
            const gamificationScore = userData.user.gamification_score;

            return {
                isOnline,
                gamificationScore
            };
        } catch (error) {
            console.error("Error checking user online status:", error);
            return {
                isOnline: false,
                gamificationScore: null
            };
        }
    }


    // Function to get the CSRF token
    function getCsrfToken() {
        const csrfTokenMeta = document.querySelector('meta[name="csrf-token"]');
        return csrfTokenMeta ? csrfTokenMeta.content : '';
    }

    // Function to fetch the username
    const getUsername = async () => {
        if (username === '') {
            // Construct headers with CSRF token
            const headers = new Headers();
            headers.append('X-Csrf-Token', getCsrfToken());
            // Make the request with CSRF token
            const response = await fetch('https://linux.do/my/summary.json', {
                method: 'GET',
                headers: headers
            });
            const newURL = response.url;
            const urlObj = new URL(newURL);
            const pathParts = urlObj.pathname.split('/');
            username = pathParts[2];
        }
    };

    // Function to count today's likes given, replies made (in distinct topics), likes received, reactions received, and reactions given and display the result
    async function countAllTodaysActions(queryUsername) {
        isQuerying = true; // Set querying flag
        button.innerText = '.......';
        button.disabled = true; // Disable the button


        const user = queryUsername || username;
        const likesGiven = await countTodaysActions(user, 1); // Assuming filter 1 is for likes given
        await delay(300);
        const repliesMadeData = await countTodaysActions(user, 5, true); // Assuming filter 5 is for replies made, unique topics
        await delay(300);
        let message;
        if(!likesGiven.queryData) {
           message = `👻这个佬友什么也没有留下~`
        }else {
          message = `
        ❤️ 送出爱心: ${likesGiven.actionCount}<br>
        💬 回复帖子: ${repliesMadeData.actionCount}<br>
        🗂️ 回复话题: ${repliesMadeData.uniqueTopicCount}
        `;
            if (queryUsername) {
                const { isOnline, gamificationScore } = await checkUserOnline(queryUsername);
                await delay(100);
                const position = await findUserPosition(queryUsername, gamificationScore);

                message += `
            <br>📟 佬友状态: ${isOnline ? '在线🙉' : '离线🙈'}
            <br>🏅 冲浪排名: ${position}
            <br>🏄 最后冲浪: <a href="https://linux.do/t/topic/${repliesMadeData.firstAction.topic_id}/${repliesMadeData.firstAction.post_number}">${repliesMadeData.firstAction.title}</a>
            `
                ;
            }
            if (!queryUsername) {
                const likesReceived = await countTodaysActions(user, 2); // Assuming filter 2 is for likes received
                await delay(300);
                const reactionsReceived = await countTodaysReactionsReceived(user); // For reactions received
                await delay(300);
                const reactionsGiven = await countTodaysReactionsGiven(user); // For reactions given

                // Load the stored data
                const timingsCount = parseInt(localStorage.getItem(STORAGE_KEY_COUNTS), 10) || 0;
                const timingsTotalTime = parseInt(localStorage.getItem('timeSpent'), 10) || 0;
                let storedTopics = (() => { try { return JSON.parse(localStorage.getItem(STORAGE_KEY_TOPIC)) || []; } catch(e) { return []; }})();


                // 将总时间转换为小时、分钟和秒
                const hours = Math.floor(timingsTotalTime / 3600);
                const minutes = Math.floor((timingsTotalTime % 3600) / 60);
                const seconds = timingsTotalTime % 3600 % 60;

                message += `
            <br>🥰 收到爱心: ${likesReceived.actionCount}<br>
            🤩 收到回应: ${reactionsReceived}<br>
            👏 给出回应: ${reactionsGiven}<br>
            📖 阅读话题: ${storedTopics.length}<br>
            ⏱️ 阅读帖子: ${timingsCount}<br>
            🕒 停留时间: ${hours}时${minutes}分${seconds}秒
            `;
            }

        }
        resultContainer.innerHTML = message; // Set the message
        resultContainer.style.display = 'block'; // Ensure the result container is visible
        isQuerying = false; // Reset querying flag
        button.innerText = '';
        button.disabled = false; // Re-enable the button
        createBeforeElement(button);

    }

    // Add input field for querying other users and result container
    const inputContainer = document.createElement('div');
    inputContainer.style.position = 'fixed';
    inputContainer.style.bottom = '-300px';
    inputContainer.style.left = '10px';
    inputContainer.style.transition = 'bottom 0.3s ease-in-out';
    inputContainer.style.backgroundColor = '#e8e8e8';
    inputContainer.style.padding = '15px';
    inputContainer.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)';
    inputContainer.style.borderRadius = '10px';
    inputContainer.style.fontFamily = 'Arial, sans-serif';
    inputContainer.style.fontSize = '14px';
    inputContainer.style.color = '#333';



    // 创建输入框
    const input = document.createElement('input');
    input.type = 'text';
    input.placeholder = '输入用户名';
    input.style.width = '160px';
    input.style.height = '40px';
    input.style.lineHeight = '28px';
    input.style.padding = '0 1rem';
    input.style.paddingLeft = '10px';
    input.style.marginRight = '10px';
    input.style.border = '2px solid transparent';
    input.style.borderRadius = '8px';
    input.style.outline = 'none';
    input.style.backgroundColor = '#f3f3f4';
    input.style.color = '#0d0c22';
    input.style.transition = '.3s ease';

    // 设置 placeholder 的样式
    const style = document.createElement('style');
    style.innerHTML = `
  .input::placeholder {
    color: #9e9ea7;
  }
  .input:focus, .input:hover {
    outline: none;
    border-color: rgba(93,24,220,0.4) !important;
    background-color: #fff;
    box-shadow: 0 0 0 4px rgb(93 24 220 / 10%) !important;
  }
`;
    document.head.appendChild(style);

    // 为输入框添加类以应用样式
    input.classList.add('input');
    inputContainer.appendChild(input);
    //document.body.appendChild(inputContainer);


    // Create and add pseudo-element effect method
    function createBeforeElement(button) {
        const buttonContent = document.createElement('span');
        buttonContent.innerText = '查询';
        buttonContent.style.position = 'relative';
        buttonContent.style.zIndex = '1';
        button.appendChild(buttonContent);
        const beforeElement = document.createElement('span');
        beforeElement.setAttribute('id', 'myBeforeElement');
        beforeElement.style.position = 'absolute';
        beforeElement.style.top = '0';
        beforeElement.style.left = '0';
        beforeElement.style.transform = 'scaleX(0)';
        beforeElement.style.transformOrigin = '0 50%';
        beforeElement.style.width = '100%';
        beforeElement.style.height = '100%';
        beforeElement.style.borderRadius = 'inherit';
        beforeElement.style.background = 'linear-gradient(82.3deg, rgba(150, 93, 233, 1) 10.8%, rgba(99, 88, 238, 1) 94.3%)';
        beforeElement.style.transition = 'all 0.475s';
        beforeElement.style.zIndex = '0';
        button.style.position = 'relative'; // 确保按钮具有相对定位
        button.insertBefore(beforeElement, button.firstChild);

        return beforeElement;
    }

    // Create button and add styles
    const button = document.createElement('button');
    button.style.position = 'relative';
    button.style.overflow = 'hidden';
    button.style.height = '38px';
    button.style.padding = '0 2rem';
    button.style.borderRadius = '0.5rem';
    button.style.background = '#3d3a4e';
    button.style.backgroundSize = '400%';
    button.style.color = '#fff';
    button.style.border = 'none';
    button.style.cursor = 'pointer';
    button.style.zIndex = '1';


    // Create the pseudo-element once and store it
    const beforeElement = createBeforeElement(button);

    // Function to handle hover effect
    function handleHoverEffect(isHovered) {
        const beforeElement = document.getElementById('myBeforeElement'); // 通过 ID 获取 beforeElement
        if (beforeElement) {
            beforeElement.style.transform = isHovered ? 'scaleX(1)' : 'scaleX(0)';
        }
    }

    // Add hover effect
    button.addEventListener('mouseover', () => handleHoverEffect(true));
    button.addEventListener('mouseout', () => handleHoverEffect(false));

    // Button click event
    button.onclick = async () => {
        const queryUsername = input.value.trim();
        await countAllTodaysActions(queryUsername);
        hideContainer(); // Hide the container
    };

    inputContainer.appendChild(button);

    const resultContainer = document.createElement('div');
    resultContainer.style.marginTop = '20px';
    resultContainer.style.padding = '20px';
    resultContainer.style.width = '217px';
    //resultContainer.style.border = '1px solid #ccc';
    resultContainer.style.borderRadius = '15px';
    resultContainer.style.backgroundColor = '#efefef';
    resultContainer.style.boxShadow = '8px 8px 5px #bebebe, -8px -8px 5px #ffffff';
    resultContainer.style.display = 'none';
    inputContainer.appendChild(resultContainer);

    const closeButton = document.createElement('button');
    closeButton.innerText = '清除';
    closeButton.style.display = 'block';
    closeButton.style.width = '257px'
    closeButton.style.marginTop = '20px';
    closeButton.style.padding = '10px 40px';
    closeButton.style.borderRadius = '6px';
    closeButton.style.cursor = 'pointer';
    closeButton.style.border = '0';
    closeButton.style.backgroundColor = '#ffffff';
    closeButton.style.boxShadow = 'rgb(0 0 0 / 5%) 0 0 8px';
    closeButton.style.letterSpacing = '1.5px';
    closeButton.style.textTransform = 'uppercase';
    closeButton.style.fontSize = '15px';
    closeButton.style.transition = 'all 0.5s ease';
    closeButton.style.color = '#000'; // 添加字体颜色以便在背景色为白色时可见

    // 添加hover效果
    closeButton.onmouseover = () => {
        closeButton.style.letterSpacing = '3px';
        closeButton.style.backgroundColor = 'hsl(261deg 80% 48%)';
        closeButton.style.color = 'hsl(0, 0%, 100%)';
        closeButton.style.boxShadow = 'rgb(93 24 220) 0px 7px 29px 0px';
    };

    // 恢复到默认效果
    closeButton.onmouseout = () => {
        closeButton.style.letterSpacing = '1.5px';
        closeButton.style.backgroundColor = 'white';
        closeButton.style.color = '#000';
        closeButton.style.boxShadow = 'rgb(0 0 0 / 5%) 0 0 8px';
    };

    // 添加active效果
    closeButton.onmousedown = () => {
        closeButton.style.transform = 'translateY(10px)';
        closeButton.style.transition = '100ms';
        closeButton.style.boxShadow = 'rgb(93 24 220) 0px 0px 0px 0px';
    };

    closeButton.onmouseup = () => {
        closeButton.style.transform = 'translateY(0)';
        closeButton.style.transition = 'all 0.5s ease';
    };

    closeButton.onclick = () => {
        resultContainer.style.display = 'none';
        input.value = ''; // Clear the input field
        hideContainer(); // Hide the container
    };

    inputContainer.appendChild(closeButton);


    document.body.appendChild(inputContainer);

    // Function to show the container
    const showContainer = () => {
        clearTimeout(hideTimeout);
        inputContainer.style.bottom = '10px';
    };

    // Function to hide the container
    const hideContainer = () => {
        if (!isQuerying && !inputContainer.matches(':hover')) {
            hideTimeout = setTimeout(() => {
                inputContainer.style.bottom = '-500px';
            }, 2000);
        }
    };

    // Event listener for mouse movement
    document.addEventListener('mousemove', (e) => {
        if (e.clientY > window.innerHeight - 50 && e.clientX < 50) {
            showContainer();
            hideTimeout = setTimeout(() => {
                hideContainer();
            }, 2000); // 2秒后隐藏容器
        }
    });

    // Event listener for mouse over and out
    inputContainer.addEventListener('mouseover', () => {
        clearTimeout(hideTimeout);
    });

    inputContainer.addEventListener('mouseout', () => {
        hideTimeout = setTimeout(() => {
            hideContainer();
        }, 2000);
    });

    // Fetch the username on script load
    getUsername();

    // Check if the stored date is today
    async function resetLocalStorageIfNeeded() {
        const storedDate = localStorage.getItem(STORAGE_KEY_DATE);
        const now = new Date();

        if (!storedDate || isOlderThanToday(new Date(storedDate))) {
            // Reset the counts and times if the stored date is not today
            localStorage.setItem(STORAGE_KEY_COUNTS, '0');
            localStorage.setItem(STORAGE_KEY_TOPIC, JSON.stringify([])); // Ensure to stringify arrays
            localStorage.setItem(STORAGE_KEY_DATE, now.toISOString());
            localStorage.setItem('timeSpent', '0'); // Assuming timeSpent is a number, convert to string
            return true; // Return true if reset was performed
        }else{
            return false;
        }
    }

    // Function to handle and monitor timings request
    function handleTimingsRequest(count, topicId) {
        const now = new Date();
        const todayStr = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;

        // Load the stored data
        let storedCounts = parseInt(localStorage.getItem(STORAGE_KEY_COUNTS), 10) || 0;
        const storedDate = localStorage.getItem(STORAGE_KEY_DATE) || '';
        let storedTopics = (() => { try { return JSON.parse(localStorage.getItem(STORAGE_KEY_TOPIC)) || []; } catch(e) { return []; }})();

        // Check if the stored date is today
        if (storedDate !== todayStr) {
            // If not, reset the stored data
            storedCounts = 0;
            storedTopics = [];
        }

        if (!storedTopics.includes(topicId)) {
            storedTopics.push(topicId);
        }
        // Update the stored data with the new values
        storedCounts += count;

        // Store the updated data
        localStorage.setItem(STORAGE_KEY_COUNTS, storedCounts);
        localStorage.setItem(STORAGE_KEY_DATE, todayStr);
        localStorage.setItem(STORAGE_KEY_TOPIC, JSON.stringify(storedTopics));
        // Display the stored data
        console.log(`Today's timings count: ${storedCounts}`);
    }


    (function() {
        // Save the original XMLHttpRequest open and send methods
        const originalXHROpen = XMLHttpRequest.prototype.open;
        const originalXHRSend = XMLHttpRequest.prototype.send;

        // Overwrite the open method
        XMLHttpRequest.prototype.open = function(...args) {
            const url = args[1];
            this._url = url;
            if (url === '/topics/timings') {
                // Record start time for the request
                const xhr = this;
                const startTime = performance.now();

                // Listen for request completion
                xhr.addEventListener('readystatechange', function() {
                    if (xhr.readyState === XMLHttpRequest.DONE) {
                        const endTime = performance.now();
                        const duration = endTime - startTime;
                    }
                });
            }

            // Call the original open method
            return originalXHROpen.apply(this, args);
        };

        // Overwrite the send method
        XMLHttpRequest.prototype.send = function(body) {
            // Process the request body if it's the correct URL
            if (this._url === '/topics/timings') {
                processRequestBody(body);
            }

            // Call the original send method
            return originalXHRSend.call(this, body);
        };

        // Process request body to extract timing data
        function processRequestBody(body) {
            if (typeof body === 'string') {
                try {
                    const params = new URLSearchParams(body);
                    let timings = 0;
                    let topicTime = 0;
                    let topicId = 0;
                    let topicCount = 0;

                    for (const [key, value] of params.entries()) {
                        if (key.startsWith('timings[')) {
                            timings += parseInt(value);
                            topicCount+=1;
                        }
                        if (key.startsWith('topic_time')) {
                            topicTime = parseInt(value);
                        }
                        if (key.startsWith('topic_id')) {
                            topicId = parseInt(value);
                        }
                    }
                    const count = topicCount;
                    handleTimingsRequest(count,topicId);

                } catch (error) {
                    console.error('Error processing form data:', error);
                }
            } else {
                console.error('Unknown request body type:', body);
            }
        }
    })();

    let timer;
    let timeSpent = parseInt(localStorage.getItem('timeSpent')) || 0;

    function updateLocalStorage() {
        localStorage.setItem('timeSpent', timeSpent);
    }

    function startTimer() {
        timer = setInterval(async () => {
            const istoday = await resetLocalStorageIfNeeded(); // Await the async function

            if (!istoday) {
                timeSpent += 1;
            } else {
                console.log("时间到了,开始更新");
                timeSpent = 0;
            }
            updateLocalStorage(); // Assuming this function saves timeSpent to localStorage
        }, 1000);
    }

    function stopTimer() {
        clearInterval(timer);
    }

    document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'visible') {
            startTimer();
        } else {
            stopTimer();
        }
    });

    window.addEventListener('load', () => {
        startTimer();
    });

    window.addEventListener('beforeunload', () => {
        stopTimer();
        updateLocalStorage();
    });
})();