KiitConnect Unlocker 🪽

Free as in beer.

目前为 2024-05-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name KiitConnect Unlocker 🪽
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.0
  5. // @license MIT
  6. // @description Free as in beer.
  7. // @author erucix
  8. // @match https://www.kiitconnect.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=kiitconnect.com
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14. // TODO: Make it false in production build or else code won't worlk.
  15.  
  16. let devModeFlag = false;
  17.  
  18. // If you find this flag as true please make it false.
  19.  
  20. // It is only for dev for debugging purpose and won't give you any
  21. // super powers
  22.  
  23. window.onload = function () {
  24. if (devModeFlag) {
  25. console.clear();
  26. console.log("[+] Unlocker Initiated.");
  27. }
  28.  
  29. if (false) {
  30. let script = document.createElement("script");
  31. script.src = "http://127.0.0.1:8080/kiit-connect.js";
  32. document.body.appendChild(script);
  33. } else {
  34. // Removes a node and replaces with its clone and helps in removing all event listeners.
  35. function remove(node) {
  36. node.classList.remove("text-yellow-500", "cursor-not-allowed");
  37. let cursorNotAllowedList = [...node.querySelectorAll(".cursor-not-allowed")];
  38.  
  39. cursorNotAllowedList.forEach(element=>{
  40. element.classList.add("text-cyan-500");
  41. element.classList.remove("text-yellow-500", "cursor-not-allowed");
  42. });
  43.  
  44. if (node.innerText == "Not Available") {
  45. node.classList.add("whitespace-nowrap", "font-bold", "text-gray-400");
  46. } else {
  47. node.classList.add("text-cyan-500");
  48. }
  49.  
  50. var clonedNode = node.cloneNode(true);
  51. node.parentNode.replaceChild(clonedNode, node);
  52. }
  53.  
  54. // Its a single paged application so continuously check for change in URL instead of onload.
  55. setInterval(function () {
  56.  
  57. // Check if the script has already been loaded for given semester.
  58. if (!document.head.classList.contains(location.pathname)) {
  59.  
  60. // Clear all the previous class list.
  61. document.head.classList = "";
  62.  
  63. // Add a class value indicating the script has been loaded for this semester.
  64. document.head.classList.add(location.pathname);
  65.  
  66.  
  67.  
  68. let docRequired; // Type of document required. Can be: notes, pyqs
  69. let branchName; // Name of choosen branch. Can be: cse, csse, csce, it
  70. let semesterId; // Semester representation in number. Can be any between 1 to 6
  71.  
  72. let finalPath = location.pathname;
  73.  
  74. // Assign values only if we have sufficient information in URL.
  75.  
  76. if (finalPath.includes("/academic/PYQS") && finalPath != "/academic/PYQS") {
  77. finalPath = finalPath.substring(finalPath.lastIndexOf("/") + 1);
  78. finalPath = finalPath.split("-");
  79.  
  80. docRequired = location.search.substring(location.search.lastIndexOf("=") + 1);
  81. branchName = finalPath[1].toLowerCase();
  82. semesterId = Number(finalPath[2]);
  83.  
  84. // Fetching original source code so that we could get pdf links
  85. fetch(location.href)
  86. .then(data => data.text())
  87. .then(data => {
  88. // Making some adjustments to successfully parse it as JSON
  89.  
  90. let response = data.substring(data.lastIndexOf("1d:[\\") - 23);
  91. response = response.replace("self.__next_f.push(", "");
  92. response = response.substring(0, response.lastIndexOf(")</script>"));
  93.  
  94. let firstLevelRefined = JSON.parse(response);
  95. let secondLevelRefined = firstLevelRefined[1];
  96. secondLevelRefined = secondLevelRefined.substring(3);
  97.  
  98. let thirdLevelRefined = JSON.parse(secondLevelRefined);
  99.  
  100. let finalRefined = thirdLevelRefined[3].children[3].data.semesters[0].subjects;
  101.  
  102.  
  103. if (docRequired == "pyqs") {
  104. // Sort the list according to year
  105. finalRefined.forEach(element => {
  106. element.pyqs.sort((a, b) => {
  107. return Number(a.year) - Number(b.year);
  108. })
  109. });
  110.  
  111. if (devModeFlag) {
  112. console.log(finalRefined);
  113. }
  114.  
  115. let containerTables = document.querySelectorAll("table");
  116.  
  117. // Used for storing loaded table indexes. SO don't touch the table
  118. // again later.
  119. let storedIndexArray = [];
  120.  
  121. containerTables.forEach((element) => {
  122. let tableRowItems = [...element.querySelectorAll("tr")];
  123.  
  124. // Since the first 'tr' is table header
  125.  
  126. tableRowItems.shift();
  127.  
  128. // Find a table such that the [numbers of paper we have] = [number of rows in table]
  129. // This reduces hassle of creating a new table
  130.  
  131. let index = 0;
  132.  
  133. for (let i = 0; i < finalRefined.length; i++) { // Here we dont touch the loaded table
  134. if (finalRefined[i].pyqs.length == tableRowItems.length && !storedIndexArray.includes(i)) {
  135. index = i;
  136. storedIndexArray.push(i);
  137. break;
  138. }
  139. }
  140.  
  141. let choosenSubject = finalRefined[index].pyqs;
  142.  
  143.  
  144. // Overwrite the 'td' values by our better sorted list
  145. tableRowItems.forEach((item, index1) => {
  146. let tdList = item.querySelectorAll("td");
  147.  
  148. tdList[0].innerText = choosenSubject[index1].year;
  149. tdList[1].innerText = choosenSubject[index1].type;
  150.  
  151. let anchor1 = tdList[2].querySelector("a");
  152. anchor1.innerText = choosenSubject[index1].name;
  153. anchor1.href = "https://drive.google.com/file/d/" + choosenSubject[index1].Question;
  154.  
  155. // Replace the anchor
  156. remove(anchor1);
  157.  
  158. let anchor2 = tdList[3].querySelector("a");
  159.  
  160. if (choosenSubject[index1].solution != null) {
  161. if (anchor2 == null) {
  162. anchor2 = document.createElement("a");
  163. anchor2.target = "_blank";
  164.  
  165. tdList[3].innerText = "";
  166. tdList[3].appendChild(anchor2);
  167. }
  168.  
  169. anchor2.innerText = "Solution";
  170. anchor2.href = "https://drive.google.com/file/d/" + choosenSubject[index1].solution;
  171. } else {
  172. if (anchor2 != null) {
  173. anchor2.innerHTML = "Not Available";
  174. }
  175. }
  176.  
  177. if (anchor2 != null) {
  178. remove(anchor2);
  179. }
  180.  
  181. });
  182. });
  183. } else if (docRequired == "notes") {
  184. let response = data.substring(data.lastIndexOf("1d:[\\") - 23);
  185. response = response.replace("self.__next_f.push(", "");
  186. response = response.substring(0, response.lastIndexOf(")</script>"));
  187.  
  188. let firstLevelRefined = JSON.parse(response);
  189. let secondLevelRefined = firstLevelRefined[1];
  190. secondLevelRefined = secondLevelRefined.substring(3);
  191.  
  192. let thirdLevelRefined = JSON.parse(secondLevelRefined);
  193.  
  194. let finalRefined = thirdLevelRefined[3].children[3].data.semesters[0].subjects;
  195.  
  196. if(devModeFlag){
  197. console.log(finalRefined);
  198. }
  199.  
  200. let subjectNoteContainer = [...document.querySelector("main").querySelector("div").querySelector("div").childNodes];
  201.  
  202. // Since first one is unwanted jargon div.
  203. subjectNoteContainer.shift();
  204.  
  205. // Store manipulated div that should not be re-touched.
  206.  
  207. let storedIndexArray = [];
  208.  
  209. subjectNoteContainer.forEach(element => {
  210. let anchorElementList = element.querySelectorAll("a");
  211. let index = 0;
  212.  
  213. for (let i = 0; i < finalRefined.length; i++){
  214. if(finalRefined[i].notes.length == anchorElementList.length && !storedIndexArray.includes(i)){
  215. index = i;
  216. storedIndexArray.push(i);
  217. break;
  218. }
  219. }
  220.  
  221. let currentSubjectIndex = finalRefined[index].notes;
  222.  
  223. console.log(anchorElementList);
  224.  
  225. [...anchorElementList].forEach((element, index1) => {
  226. element.querySelector("h1").innerText = currentSubjectIndex[index1].name;
  227. element.href = "https://drive.google.com/file/d/" + currentSubjectIndex[index1].Notes;
  228.  
  229. remove(element);
  230. });
  231. });
  232. }
  233. });
  234. }
  235.  
  236. // Remove all get premium buttons from site.
  237. setTimeout(function () {
  238. let premiumButtons = document.querySelectorAll("a[href='/premiuminfo']");
  239. premiumButtons.forEach(item => item.remove());
  240.  
  241. }, 1000);
  242. }
  243. }, 500);
  244. }
  245. }
  246. })();