KIITConnect Data Management

Adds a settings menu for downloading data, uploading data, and downloading a file

当前为 2024-11-28 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         KIITConnect Data Management
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  Adds a settings menu for downloading data, uploading data, and downloading a file
// @author       Bibek
// @match        https://www.kiitconnect.com/*
// @grant        none
// @icon         https://www.kiitconnect.com/favicon.ico
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const filenameDivSelector = '.flex.w-full.pt-10.md\\:pt-0.pb-6.text-base.mt-5.md\\:py-10.md\\:my-0.font-bold.md\\:text-2xl.justify-center.items-center span.pl-2';

    // Ensure the filename div is detected
    function ensureFilenameDivLoaded(callback) {
        const retryInterval = 100; // Check every 100ms
        const maxRetries = 50; // Limit retries to avoid infinite loop
        let retries = 0;

        const interval = setInterval(() => {
            const filenameDiv = document.querySelector(filenameDivSelector);
            if (filenameDiv) {
                clearInterval(interval);
                callback(filenameDiv);
            } else if (++retries >= maxRetries) {
                clearInterval(interval);
                console.error('Filename div not found within the retry limit.');
            }
        }, retryInterval);
    }

    // Function to handle PYQS functionality
    function executePYQsCode() {
        // alert("Now looking for PYQs.");
        console.log('Executing PYQS functionality...');
        // Your existing PYQS logic here
        // Function to create and insert the settings icon and menu
        function createSettingsMenu() {
            // Create settings icon
            const settingsIcon = document.createElement('img');
            settingsIcon.src = 'https://cdn-icons-png.flaticon.com/512/2697/2697990.png';
            settingsIcon.alt = 'Settings';
            settingsIcon.style.width = '40px';
            settingsIcon.style.cursor = 'pointer';
            settingsIcon.style.position = 'fixed';
            settingsIcon.style.bottom = '20px';
            settingsIcon.style.right = '20px';
            settingsIcon.style.zIndex = '1000';

            // Create menu container
            const menuContainer = document.createElement('div');
            menuContainer.style.display = 'none';
            menuContainer.style.flexDirection = 'column';
            menuContainer.style.position = 'fixed';
            menuContainer.style.bottom = '70px';
            menuContainer.style.right = '10px';
            menuContainer.style.backgroundColor = '#041d35';
            menuContainer.style.backdropFilter = 'blur(5px)';
            menuContainer.style.padding = '10px';
            menuContainer.style.border = '1px solid #143267';
            menuContainer.style.borderRadius = '50px';
            menuContainer.style.zIndex = '1000';

            // Toggle menu visibility on settings icon click
            settingsIcon.addEventListener('click', () => {
                menuContainer.style.display = menuContainer.style.display === 'none' ? 'flex' : 'none';
            });

            // Create download CSV icon
            const downloadCSVIcon = document.createElement('img');
            downloadCSVIcon.src = 'https://cdn-icons-png.flaticon.com/512/9153/9153957.png';
            downloadCSVIcon.alt = 'Download CSV';
            downloadCSVIcon.style.width = '40px';
            downloadCSVIcon.style.cursor = 'pointer';
            downloadCSVIcon.style.marginBottom = '10px';
            downloadCSVIcon.addEventListener('click', downloadCSVData);

            // Create upload icon (opens Google Form)
            const uploadIcon = document.createElement('img');
            uploadIcon.src = 'https://cdn-icons-png.flaticon.com/512/10152/10152423.png';
            uploadIcon.alt = 'Upload';
            uploadIcon.style.width = '40px';
            uploadIcon.style.cursor = 'pointer';
            uploadIcon.style.marginBottom = '10px';
            uploadIcon.addEventListener('click', () => {
                window.open('https://forms.gle/sb4uEPXWmhCvRcBG6', '_blank');
            });

            // Create download file icon
            const downloadFileIcon = document.createElement('img');
            downloadFileIcon.src = 'https://cdn-icons-png.flaticon.com/512/1091/1091007.png';
            downloadFileIcon.alt = 'Download File';
            downloadFileIcon.style.width = '40px';
            downloadFileIcon.style.cursor = 'pointer';
            downloadFileIcon.addEventListener('click', () => {
                window.open('https://drive.google.com/drive/folders/11FZF-h8tmulA9LgLLV9E4s2LbGD_Rf7iI5BwCl35WdZ-vfbuQzDZcGgP1IwiwkRVJ-rK0uoU?usp=sharing', '_blank');
            });

            // Append icons to menu container
            menuContainer.appendChild(downloadCSVIcon);
            menuContainer.appendChild(uploadIcon);
            menuContainer.appendChild(downloadFileIcon);

            // Append settings icon and menu container to document body
            document.body.appendChild(settingsIcon);
            document.body.appendChild(menuContainer);
        }

        // Function to scrape data and download as CSV
        function downloadCSVData() {
            // Retrieve the filename from the specific div
            const filenameDiv = document.querySelector('.flex.w-full.pt-10.md\\:pt-0.pb-6.text-base.mt-5.md\\:py-10.md\\:my-0.font-bold.md\\:text-2xl.justify-center.items-center span.pl-2');
            const filename = filenameDiv ? filenameDiv.textContent.trim() : 'subject_data';

            // Initialize an array to hold all subjects with their respective rows
            const allSubjectsData = [];

            // Select all subject name elements
            const subjectNameElements = document.querySelectorAll('.py-3.md\\:py-5.relative.rounded-md.text-\\[12px\\].md\\:text-2xl.font-bold.text-center.border.border-slate-500.text-gray-300');

            // Iterate over each subject name element
            subjectNameElements.forEach(subjectElement => {
                // Extract the subject name
                const subjectName = subjectElement.textContent.trim().replace(/^Syllabus\s*/, '');

                // Select the table rows within this subject
                const rows = subjectElement.nextElementSibling.querySelectorAll('tbody.text-white.text-base tr');

                // Iterate over each row within the subject
                rows.forEach(row => {
                    // Extract row data
                    const pyqYear = row.querySelector('td.whitespace-nowrap.px-6.font-bold.py-4.text-slate-300')?.textContent.trim() || '';
                    const pyqType = row.querySelector('td.whitespace-nowrap.px-6.text-gray-400.font-bold.hidden.md\\:block.py-4')?.textContent.trim() || '';

                    const pyqLinkElement = row.querySelector('td.whitespace-nowrap.px-6.py-4 a.font-bold.text-cyan-500');
                    const pyqLink = pyqLinkElement ? pyqLinkElement.href : '';
                    const pyqName = pyqLinkElement ? pyqLinkElement.textContent.trim() : '';

                    // Extract the last 33 characters of the question code from the link
                    // const questionCode = pyqLink ? pyqLink.match(/academic\/view\/([a-zA-Z0-9_-]{33})\?/)[1] : '';
                    const questionCode = pyqLink ? (pyqLink.match(/([a-zA-Z0-9_-]{33})\?/)?.[1] || '') : '';

                    const pyqSolutionLinkElement = row.querySelector('td.whitespace-nowrap.px-6.py-4.font-bold.text-gray-400 a.text-cyan-500');
                    const pyqSolutionLink = pyqSolutionLinkElement ? pyqSolutionLinkElement.href : '';
                    const solutionTextElement = row.querySelector('td.whitespace-nowrap.px-6.py-4.font-bold.text-gray-400 span');
                    const solution = pyqSolutionLinkElement
                    ? pyqSolutionLinkElement.textContent.trim()
                    : (solutionTextElement ? solutionTextElement.textContent.trim() : 'Not Available');

                    // Get the additional solutionStatus text
                    const solutionStatusText = row.querySelector('td.whitespace-nowrap.px-6.py-4.font-bold.text-gray-400')?.textContent.trim() || '';

                    const solutionCode = pyqSolutionLink ? (pyqSolutionLink.match(/([a-zA-Z0-9_-]{33})\?/)?.[1] || '') : ''; //  new line

                    // Add row data to the allSubjectsData array with subject name included
                    allSubjectsData.push({
                        subject: subjectName,
                        year: pyqYear,
                        type: pyqType,
                        pyqName: pyqName,
                        pyqLink: pyqLink,
                        questionCode: questionCode,// Add question code here
                        solutionLink: pyqSolutionLink,
                        solution: solution,
                        solutionStatus: solutionStatusText,
                        solutionCode: solutionCode,
                    });
                });
            });

            // Function to convert JSON to CSV format
            function convertToCSV(data) {
                const headers = [
                    'Subject',
                    'Year',
                    'Type',
                    'PYQ Name',
                    'PYQ Link',
                    'Question Code',
                    'Solution Link',
                    'Solution',
                    'Solution Status',
                    'solutionCode',
                    'Question Link', // New column header
                    'Solution Link' // New column header
                ];

                const rows = data.map(row => [
                    row.subject,
                    row.year,
                    row.type,
                    row.pyqName,
                    row.pyqLink,
                    row.questionCode,
                    row.solutionLink,
                    row.solution,
                    row.solutionStatus,
                    row.solutionCode,

                    // Question Link
                    row.questionCode
                    ? `=HYPERLINK("https://drive.google.com/file/d/${row.questionCode}/edit", "${row.year} ${row.pyqName}")`.replace(/"/g, '""')
                    : 'Not Available',
                    // Solution Link
                    row.solutionCode
                    ? `=HYPERLINK("https://drive.google.com/file/d/${row.solutionCode}/edit", "${row.year} ${row.pyqName} Solution")`.replace(/"/g, '""')
                    : 'Not Available'

                ]);

                // Convert rows to CSV format
                return [headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(','))].join('\n');
            }




            // Convert the data to CSV format
            const csvData = convertToCSV(allSubjectsData);

            // Create a Blob from the CSV data and trigger the download
            const blob = new Blob([csvData], { type: 'text/csv' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `${filename}.csv`;
            a.style.display = 'none';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url); // Clean up the URL object
        }

        // Run the script only on the specified page
        if (window.location.href.startsWith('https://www.kiitconnect.com/')) {
            createSettingsMenu();
        }
    }

    // Function to handle NOTES functionality
    function executeNOTESCode() {
        // alert("Now looking for NOTES.");
        console.log('Executing NOTES functionality...');
        // Your existing NOTES logic here
        // Function to create and insert the settings icon and menu
        function createSettingsMenu() {
            // Create settings icon
            const settingsIcon = document.createElement('img');
            settingsIcon.src = 'https://cdn-icons-png.flaticon.com/512/2697/2697990.png';
            settingsIcon.alt = 'Settings';
            settingsIcon.style.width = '40px';
            settingsIcon.style.cursor = 'pointer';
            settingsIcon.style.position = 'fixed';
            settingsIcon.style.bottom = '20px';
            settingsIcon.style.right = '20px';
            settingsIcon.style.zIndex = '1000';

            // Create menu container
            const menuContainer = document.createElement('div');
            menuContainer.style.display = 'none';
            menuContainer.style.flexDirection = 'column';
            menuContainer.style.position = 'fixed';
            menuContainer.style.bottom = '70px';
            menuContainer.style.right = '10px';
            menuContainer.style.backgroundColor = '#041d35';
            menuContainer.style.backdropFilter = 'blur(5px)';
            menuContainer.style.padding = '10px';
            menuContainer.style.border = '1px solid #143267';
            menuContainer.style.borderRadius = '50px';
            menuContainer.style.zIndex = '1000';

            // Toggle menu visibility on settings icon click
            settingsIcon.addEventListener('click', () => {
                menuContainer.style.display = menuContainer.style.display === 'none' ? 'flex' : 'none';
            });

            // Create download CSV icon
            const downloadCSVIcon = document.createElement('img');
            downloadCSVIcon.src = 'https://cdn-icons-png.flaticon.com/512/9153/9153957.png';
            downloadCSVIcon.alt = 'Download CSV';
            downloadCSVIcon.style.width = '40px';
            downloadCSVIcon.style.cursor = 'pointer';
            downloadCSVIcon.style.marginBottom = '10px';
            downloadCSVIcon.addEventListener('click', downloadCSVData);

            // Create upload icon (opens Google Form)
            const uploadIcon = document.createElement('img');
            uploadIcon.src = 'https://cdn-icons-png.flaticon.com/512/10152/10152423.png';
            uploadIcon.alt = 'Upload';
            uploadIcon.style.width = '40px';
            uploadIcon.style.cursor = 'pointer';
            uploadIcon.style.marginBottom = '10px';
            uploadIcon.addEventListener('click', () => {
                window.open('https://forms.gle/sb4uEPXWmhCvRcBG6', '_blank');
            });

            // Create download file icon
            const downloadFileIcon = document.createElement('img');
            downloadFileIcon.src = 'https://cdn-icons-png.flaticon.com/512/1091/1091007.png';
            downloadFileIcon.alt = 'Download File';
            downloadFileIcon.style.width = '40px';
            downloadFileIcon.style.cursor = 'pointer';
            downloadFileIcon.addEventListener('click', () => {
                window.open('https://drive.google.com/drive/folders/11FZF-h8tmulA9LgLLV9E4s2LbGD_Rf7iI5BwCl35WdZ-vfbuQzDZcGgP1IwiwkRVJ-rK0uoU?usp=sharing', '_blank');
            });

            // Append icons to menu container
            menuContainer.appendChild(downloadCSVIcon);
            menuContainer.appendChild(uploadIcon);
            menuContainer.appendChild(downloadFileIcon);

            // Append settings icon and menu container to document body
            document.body.appendChild(settingsIcon);
            document.body.appendChild(menuContainer);
        }



        function downloadCSVData() {
            // Retrieve the filename from the specific div
            const filenameDiv = document.querySelector('.flex.w-full.pt-10.md\\:pt-0.pb-6.text-base.mt-5.md\\:py-10.md\\:my-0.font-bold.md\\:text-2xl.justify-center.items-center span.pl-2');
            const filename = filenameDiv ? filenameDiv.textContent.trim() : 'data_export';

            // Initialize an array to hold all subjects with their respective rows
            const allSubjectsData = [];

            // Select all subject name elements
            const subjectNameElements = document.querySelectorAll('.py-3.md\\:py-5.relative.rounded-md.text-\\[12px\\].md\\:text-2xl.font-bold.text-center.border.border-slate-500.text-gray-300');

            // Iterate over each subject name element
            subjectNameElements.forEach(subjectElement => {
                // Extract the subject name and remove "Syllabus"
                const subjectName = subjectElement.textContent.trim().replace(/^Syllabus\s*/, '');

                // Select all topics under this subject
                const topics = subjectElement.parentElement.querySelectorAll('.text-cyan-500 h1');
                const topicLinks = subjectElement.parentElement.querySelectorAll('.cursor-pointer.py-3[href]');

                topics.forEach((topicElement, index) => {
                    const topicName = topicElement.textContent.trim();
                    const topicLink = topicLinks[index]?.href || '';
                    const topicCode = topicLink ? (topicLink.match(/([a-zA-Z0-9_-]{33})(?=\?)/)?.[1] || '') : '';

                    // Add topic data to the allSubjectsData array with subject name included
                    allSubjectsData.push({
                        subject: subjectName,
                        topic: topicName,
                        topicLink: topicLink,
                        topicCode: topicCode,
                    });
                });
            });

            // Function to convert JSON to CSV format
            function convertToCSV(data) {
                const headers = ['Subject', 'Topic Name', 'Topic Link', 'Topic Code', 'Note Link'];
                const rows = data.map(row => [
                    row.subject,
                    row.topic,
                    row.topicLink,
                    row.topicCode,
                    `=HYPERLINK("https://drive.google.com/file/d/${row.topicCode}/edit", "${row.topic}")`.replace(/"/g, '""') // Escape double quotes
                ]);

                return [headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(','))].join('\n');
            }

            // Convert the data to CSV format
            const csvData = convertToCSV(allSubjectsData);

            // Create a Blob from the CSV data and trigger the download
            const blob = new Blob([csvData], { type: 'text/csv' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `${filename}.csv`;
            a.style.display = 'none';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url); // Clean up the URL object
        }

        // Run the script only on the specified page
        if (window.location.href.startsWith('https://www.kiitconnect.com/')) {
            createSettingsMenu();
        }
    }

    // Check and execute functionality based on filename div content
    function checkAndExecute(filenameDiv) {
        const textContent = filenameDiv.textContent.trim().toUpperCase();
        console.log('Filename text detected:', textContent);

        if (textContent.includes('PYQS')) {
            executePYQsCode();
        } else if (textContent.includes('NOTES')) {
            executeNOTESCode();
        } else {
            console.warn('Unrecognized filename text:', textContent);
        }
    }

    // Observe changes in the DOM and recheck
    function observeChanges(filenameDiv) {
        const observer = new MutationObserver(() => {
            console.log('Filename text content changed, rechecking...');
            checkAndExecute(filenameDiv);
        });

        observer.observe(filenameDiv, {
            characterData: true,
            subtree: true,
            childList: true
        });

        console.log('MutationObserver is now watching for changes.');
    }

    // Initialize script
    window.addEventListener('load', () => {
        ensureFilenameDivLoaded((filenameDiv) => {
            checkAndExecute(filenameDiv);
            observeChanges(filenameDiv);
        });
    });
})();