Greasy Fork

来自缓存

Greasy Fork is available in English.

有道答疑助手

Automatically expand all problem lists and fetch problem titles

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         有道答疑助手
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  Automatically expand all problem lists and fetch problem titles
// @author       You
// @match        https://oj.youdao.com/course/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 定义请求间隔时间(毫秒为单位),例如5秒
    const REQUEST_INTERVAL = 5000;  // 每5秒为一个题目发送一次请求


    // 自动展开所有题目单元
    function expandAllUnits() {
        const svgElements = document.querySelectorAll('[class^="_courseId__unit_main__"]');

        svgElements.forEach(svg => {
            let style = svg.getAttribute('style');
            if (style && style.includes('display:none')) {
                svg.setAttribute('style', style.replace('display:none', 'display:block'));
            } else {
                svg.setAttribute('style', 'display:block');
            }
        });
    }

    // 页面加载完成后执行展开操作
    window.addEventListener('load', () => {
        // 定义 localStorage 存储键名
        const STORAGE_KEY = 'problem_titles_cache';

        // 获取 localStorage 中的缓存题目信息
        let cachedTitles = JSON.parse(localStorage.getItem(STORAGE_KEY)) || {};

        console.log('Initial cached titles:', cachedTitles);

        console.log('Page loaded, expanding all units...');
        expandAllUnits();

        // 获取页面上所有 <li> 元素
        const listItems = document.querySelectorAll('[class^="CourseStep_step_tags_item__"]');

        // 处理没有缓存的 problemId 数组
        const problemsToFetch = [];

        // 遍历每个 <li> 元素,优先显示缓存中的数据
        listItems.forEach((li) => {
            const aTag = li.querySelector('a');
            const href = aTag.getAttribute('href');

            // 从 href 中提取 courseId、lessonId、lessonProblemType 和 problemId
            const courseAndLessonPart = href.split('#')[0].split('/');
            const problemPart = href.split('#/1/')[1];

            const courseId = courseAndLessonPart[2];  // 提取 courseId
            const lessonId = courseAndLessonPart[3];  // 提取 lessonId
            const lessonProblemType = courseAndLessonPart[4];  // 提取 lessonProblemType
            const problemId = problemPart;  // 提取 problemId

            // 如果本地缓存中有对应的 problemId 数据,立即显示标题
            if (cachedTitles[problemId]) {
                console.log(`Using cached title for problemId ${problemId}: ${cachedTitles[problemId]}`);
                const titleSpan = document.createElement('span');
                titleSpan.textContent = ` - ${cachedTitles[problemId]}`;
                li.appendChild(titleSpan);
            } else {
                // 如果没有缓存,将问题的相关信息添加到待请求的数组中
                problemsToFetch.push({ li, courseId, lessonId, lessonProblemType, problemId });
            }
        });

        // 对于没有缓存的题目,按顺序发送请求,并延时
        problemsToFetch.forEach((problem, index) => {
            setTimeout(() => {
                console.log(`Fetching title for problemId: ${problem.problemId}`);

                // 发送请求获取题目信息
                const requestBody = {
                    courseId: problem.courseId,
                    problemId: problem.problemId,
                    lessonId: problem.lessonId,
                    lessonProblemType: problem.lessonProblemType
                };

                // 输出发送请求的参数
                console.log(`Request parameters for problemId ${problem.problemId}:`, requestBody);

                fetch('https://icodecontest-online-api.youdao.com/api/course/lesson/problem/detail', {
                    method: 'POST',
                    headers: {
                        'accept': 'application/json, text/plain, */*',
                        'content-type': 'application/json;charset=UTF-8',
                    },
                    body: JSON.stringify(requestBody),
                    credentials: 'include',
                })
                .then(response => response.json())
                .then(data => {
                    console.log(`Received response for problemId ${problem.problemId}:`, data);

                    if (data.code === 0) {
                        const title = data.data.title;

                        // 保存到本地缓存
                        cachedTitles[problem.problemId] = title;
                        localStorage.setItem(STORAGE_KEY, JSON.stringify(cachedTitles));

                        console.log(`Title for problemId ${problem.problemId} saved to cache: ${title}`);

                        // 在 <li> 标签中附加题目标题
                        const titleSpan = document.createElement('span');
                        titleSpan.textContent = ` - ${title}`;
                        problem.li.appendChild(titleSpan);
                    } else {
                        console.error(`Failed to fetch title for problemId ${problem.problemId}:`, data.msg);
                    }
                })
                .catch(error => {
                    console.error('Error fetching problem details:', error);
                });
            }, REQUEST_INTERVAL * index);  // 延时发送请求,每个请求的延迟时间由索引决定
        });
    });
})();