您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Unlock kiitconnect for free
// ==UserScript== // @name KIIT-Connect Unlocker // @namespace https://github.com/rohitaryal/kiitconnect-unlocker // @version 3.0 // @description Unlock kiitconnect for free // @author rohitaryal // @match https://www.kiitconnect.com/academic/* // @icon https://www.google.com/s2/favicons?sz=64&domain=kiitconnect.com // @grant none // @license MIT // ==/UserScript== const debugMode = true; const driveFile = "https://drive.google.com/file/d/"; const driveFolder = "https://drive.google.com/drive/folders/"; const youtubePlaylist = "https://www.kiitconnect.com/player?playlistId="; const pyqsRegex = /academic\/PYQS\/Content\/PYQS\-(cse|csse|csce|it)\-[1-7]/; const notesRegex = /academic\/PYQS\/Content\/Notes\-(cse|csse|csce|it)\-[1-7]/; class Utils { constructor() { } /* * Get all script that doesn't have src attribute */ static getScripts() { let scriptElements = document.querySelectorAll("script:not([src])"); return [...scriptElements]; } /* * Copy item to clipboard */ static copy(text) { document.body.focus(); navigator.clipboard.writeText(text); } /* * Logger for debug mode */ static log(text) { if (debugMode) { console.log(text) } } /* * Clone node and remove its junk and replace with new one */ static replaceNode(node) { if (!node) { throw new Error("Invalid node provided to clone"); } const newNode = node.cloneNode(true); node.replaceWith(newNode); return newNode; } /* * Re-Serialize the json in our own way (For PYQS) */ static parsePYQ(data) { if (typeof data !== 'object') { throw new Error(`Expected 'object' but obtained '${typeof data}' while parsing`); } // Skeleton for subjects pyq, syllabus + some extra detail holder let pyqDetails = { semester: data.semeseter, // Yes, thats the actual spelling branch: data.stream, subjects: [], }; pyqDetails.subjects = data.data.semesters[0].subjects.map((subject) => { // Skeleton for subject detail holder let subDetails = { subjectName: subject.name, subjectCode: subject.SUBCODE, folder: driveFolder + subject.folderId, // Makes an accessable drive folder link subjectSyllabus: driveFile + subject.syllabus, // Makes an accessable drive file link playlist: [], papers: [], }; // Parse individual playlist subDetails.playlist = subject.youtubePlaylist.map((playlist) => { return { id: playlist.id, title: playlist.title, videoCount: playlist.noOfVides, videoLink: `${youtubePlaylist}id&playlist=${playlist.title}` }; }); // Parse individual pyqs subDetails.papers = subject.pyqs.map((paper) => { return { name: paper.name, year: Number(paper.year) || 0, solution: driveFile + paper.solution, // Makes an accessable file link question: driveFile + paper.Question, // Same } }); // Sort papers based on years subDetails.papers = subDetails.papers.sort((a, b) => a.year - b.year); return subDetails; }); return pyqDetails; } /* * Re-Serialize the json in our own way (For Notes) */ static parseNotes(data) { } /* * Parse script content (For PYQS) */ static parseFromScriptPYQ(scriptContent) { // Pre-process and beautufy scriptContent = scriptContent.replaceAll(`\\"`, `"`); scriptContent = scriptContent.replaceAll(`\\n`, ``); const parsableContent = scriptContent.slice( scriptContent.indexOf(`self.__next_f.push([1,"1e:`) + 26, // <-- 26 is the length of this scriptContent.lastIndexOf(`"])`) // string itself. ); const jsonContent = JSON.parse(parsableContent)[3].children[3]; return this.parsePYQ(jsonContent); } /* * Parse script content (For Notes) */ static parseFromScriptNotes(scriptContent) { } /* * Replace pyq table + headings with from our own serialized form */ static rewritePYQPage(subjectArray) { if (typeof subjectArray !== 'object') { throw new Error(`Expected 'object' but obtained '${typeof subjectArray}' while rewriting`); } // After successful injection head will contain this classlist // which is an indicator to stop further injection if(document.head.classList.contains("injected")) { return; } Utils.log("Re-writing the pyq page.") const parentContainer = [...document.querySelector("main div div").childNodes].slice(1); for (let i = 0; i < parentContainer.length; i++) { let totalRows = parentContainer[i].querySelectorAll("table tbody").length; // Get count of rows for (let j = 0; j < subjectArray.length; j++) { let totalPapers = subjectArray[j].papers.length; if (totalRows === totalPapers) { let temp = subjectArray[j]; subjectArray[j] = subjectArray[i]; subjectArray[i] = temp; break; } } } for (let i = 0; i < subjectArray.length; i++) { const subject = subjectArray[i]; const parent = parentContainer[i]; const [titleDiv, tableContainer] = parent.childNodes; const syllabusButton = titleDiv.querySelector("a"); syllabusButton.href = subject.subjectSyllabus; // New button with folder link const folderButton = syllabusButton.cloneNode(true); folderButton.innerText = "Open Folder"; folderButton.href = subject.folder; // Modify title (middle one is TEXT_NODE) const title = titleDiv.childNodes[1]; title.textContent = subject.subjectName; // Modify the table const tableRows = tableContainer.querySelectorAll("table tbody"); for (let j = 0; j < tableRows.length; j++) { const row = tableRows[j]; const paper = subject.papers[j]; const td = row.querySelectorAll("td:not(.hidden)"); // Year of paper td[0].textContent = paper.year; // Link to question paper let paperAnchor = td[1].querySelector("a"); paperAnchor = this.replaceNode(paperAnchor); paperAnchor.textContent = paper.name; paperAnchor.href = paper.question; paperAnchor.classList.add("text-cyan-500"); paperAnchor.classList.remove("text-yellow-500", "cursor-not-allowed"); // Link to solution paper let solutionAnchor = td[2].querySelector("a"); // Since solution is the last element if(!solutionAnchor) continue; solutionAnchor = this.replaceNode(solutionAnchor); if (solutionAnchor.classList.contains("text-gray-400")) { solutionAnchor.textContent = "Not Available"; } else { solutionAnchor.classList.add("text-cyan-500"); solutionAnchor.classList.remove("text-yellow-500", "cursor-not-allowed"); solutionAnchor.href = paper.solution } } } // Mark as succrssful injection document.head.classList.add("injected"); } } (function () { 'use strict'; // Last script will always contain the paper's JSON let scriptContent = Utils.getScripts().at(-1).textContent; if (!!location.pathname.match(pyqsRegex)) { // Means we are in 'pyqs' page const parsedContent = Utils.parseFromScriptPYQ(scriptContent); window.addEventListener('load', function () { Utils.log("DOMContent has been loaded"); this.setInterval(function () { try { Utils.rewritePYQPage(parsedContent.subjects); } catch(e) { console.log(e) } }, 2000) }); } else if (!!location.pathname.match(notesRegex)) { // Means we are in 'notes' page } })();