Advertisement
Guest User

code

a guest
Jan 27th, 2025
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.01 KB | None | 0 0
  1. // ==UserScript==
  2. // @name ED-Puzzle Hack
  3. // @namespace https://github.com/longkidkoolstar
  4. // @description An Ed-Puzzle Hack with a LOT of Features!!!!!!!
  5. // @author longkidkoolstar
  6. // @version 0.2.1
  7. // @icon https://th.bing.com/th/id/OIP.3LKllA9fA7DTJ4Kb92LbowHaHa?rs=1&pid=ImgDetMain
  8. // @match *://edpuzzle.com/lti/*
  9. // @match *://edpuzzle.com/assignments/*
  10. // @match *://edpuzzle.com/media/*
  11. // @match *://youtube.com/embed*
  12. // @match *://youtube-nocookie.com/embed*
  13. // @grant none
  14. // @license GPL
  15. // @downloadURL https://update.greasyfork.org/scripts/486265/ED-Puzzle%20Hack.user.js
  16. // @updateURL https://update.greasyfork.org/scripts/486265/ED-Puzzle%20Hack.meta.js
  17. // ==/UserScript==
  18.  
  19. /*
  20. This program is free software: you can redistribute it and/or modify
  21. it under the terms of the GNU General Public License as published by
  22. the Free Software Foundation, either version 3 of the License, or
  23. (at your option) any later version.
  24.  
  25. This program is distributed in the hope that it will be useful,
  26. but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28. GNU General Public License for more details.
  29.  
  30. You should have received a copy of the GNU General Public License
  31. along with this program. If not, see <https://www.gnu.org/licenses/>.
  32. */
  33.  
  34. //Copyright (C) [2024] [longkidkoolstar]
  35. // This script is based on the original code from the edpuzzle-answers project by ading2210
  36. // See: https://github.com/ading2210/edpuzzle-answers
  37.  
  38.  
  39.  
  40. var popup = null;
  41. var base_url;
  42. if (typeof document.dev_env != "undefined") {
  43. base_url = document.dev_env;
  44. }
  45. else {
  46. //get resources off of github to not inflate the jsdelivr stats
  47. base_url = "https://raw.githubusercontent.com/ading2210/edpuzzle-answers/main";
  48. }
  49.  
  50. function http_get(url, callback, headers=[], method="GET", content=null) {
  51. var request = new XMLHttpRequest();
  52. request.addEventListener("load", callback);
  53. request.open(method, url, true);
  54.  
  55. if (window.__EDPUZZLE_DATA__ && window.__EDPUZZLE_DATA__.token) {
  56. headers.push(["authorization", window.__EDPUZZLE_DATA__.token]);
  57. }
  58. for (const header of headers) {
  59. request.setRequestHeader(header[0], header[1]);
  60. }
  61.  
  62. request.send(content);
  63. }
  64. function createActivationButton() {
  65. // Create a button element
  66. var activationButton = document.createElement("button");
  67.  
  68. // Set the button text
  69. activationButton.textContent = "Activate Edpuzzle Script";
  70.  
  71. // Add a click event listener to the button
  72. activationButton.addEventListener("click", function () {
  73. // Call the init function to activate the Edpuzzle script
  74. init();
  75. });
  76.  
  77. // Create a style for the button
  78. var buttonStyle = `
  79. background-color: #00ADEF;
  80. color: #FFFFFF;
  81. padding: 10px 20px;
  82. font-size: 16px;
  83. border: none;
  84. cursor: pointer;
  85. transition: opacity 0.3s ease-in-out; /* Add a smooth transition effect */
  86.  
  87. `;
  88.  
  89. // Apply the style to the button
  90. activationButton.style.cssText = buttonStyle;
  91.  
  92. // Add a hover effect
  93. activationButton.addEventListener("mouseover", function () {
  94. activationButton.style.opacity = 0.8; // Adjust the opacity as needed
  95. });
  96.  
  97. // Restore the original opacity on mouseout
  98. activationButton.addEventListener("mouseout", function () {
  99. activationButton.style.opacity = 1;
  100. });
  101.  
  102. // Append the button to the body of the document
  103. document.body.appendChild(activationButton);
  104. }
  105.  
  106.  
  107. // Call the function to create the activation button
  108. createActivationButton();
  109.  
  110.  
  111. function init() {
  112. if (window.location.hostname == "edpuzzle.hs.vc") {
  113. alert("To use this, drag this button into your bookmarks bar. Then, run it when you're on an Edpuzzle assignment.");
  114. }
  115. else if ((/https{0,1}:\/\/edpuzzle.com\/assignments\/[a-f0-9]{1,30}\/watch/).test(window.location.href)) {
  116. getAssignment();
  117. }
  118. else if (window.canvasReadyState) {
  119. handleCanvasURL();
  120. }
  121. else if (window.schoologyMoreLess) {
  122. handleSchoologyURL();
  123. }
  124. else {
  125. alert("Please run this script on an Edpuzzle assignment. For reference, the URL should look like this:\nhttps://edpuzzle.com/assignments/{ASSIGNMENT_ID}/watch");
  126. }
  127. }
  128.  
  129. function handleCanvasURL() {
  130. let location_split = window.location.href.split("/");
  131. let url = `/api/v1/courses/${location_split[4]}/assignments/${location_split[6]}`;
  132. http_get(url, function(){
  133. let data = JSON.parse(this.responseText);
  134. let url2 = data.url;
  135.  
  136. http_get(url2, function() {
  137. let data = JSON.parse(this.responseText);
  138. let url3 = data.url;
  139.  
  140. alert(`Please re-run this script in the newly opened tab. If nothing happens, then allow popups on Canvas and try again.`);
  141. open(url3);
  142. });
  143. });
  144. }
  145.  
  146. function handleSchoologyURL() {
  147. let assignment_id = window.location.href.split("/")[4];
  148. let url = `/external_tool/${assignment_id}/launch/iframe`;
  149. http_get(url, function() {
  150. alert(`Please re-run this script in the newly opened tab. If nothing happens, then allow popups on Schoology and try again.`);
  151.  
  152. //strip js tags from response and add to dom
  153. let html = this.responseText.replace(/<script[\s\S]+?<\/script>/, "");
  154. let div = document.createElement("div");
  155. div.innerHTML = html;
  156. let form = div.querySelector("form");
  157.  
  158. let input = document.createElement("input")
  159. input.setAttribute("type", "hidden");
  160. input.setAttribute("name", "ext_submit");
  161. input.setAttribute("value", "Submit");
  162. form.append(input);
  163. document.body.append(div);
  164.  
  165. //submit form in new tab
  166. form.setAttribute("target", "_blank");
  167. form.submit();
  168. div.remove();
  169. });
  170. }
  171.  
  172. function getAssignment(callback) {
  173. var assignment_id = window.location.href.split("/")[4];
  174. if (typeof assignment_id == "undefined") {
  175. alert("Error: Could not infer the assignment ID. Are you on the correct URL?");
  176. return;
  177. }
  178. var url1 = "https://edpuzzle.com/api/v3/assignments/"+assignment_id;
  179.  
  180. http_get(url1, function(){
  181. var assignment = JSON.parse(this.responseText);
  182. if ((""+this.status)[0] == "2") {
  183. openPopup(assignment);
  184. }
  185. else {
  186. alert(`Error: Status code ${this.status} recieved when attempting to fetch the assignment data.`)
  187. }
  188. });
  189. }
  190.  
  191. function openPopup(assignment) {
  192. var media = assignment.medias[0];
  193. var teacher_assignment = assignment.teacherAssignments[0];
  194. var assigned_date = new Date(teacher_assignment.preferences.startDate);
  195. var date = new Date(media.createdAt);
  196. thumbnail = media.thumbnailURL;
  197. if (thumbnail.startsWith("/")) {
  198. thumbnail = "https://"+window.location.hostname+thumbnail;
  199. }
  200.  
  201. var deadline_text;
  202. if (teacher_assignment.preferences.dueDate == "") {
  203. deadline_text = "no due date"
  204. }
  205. else {
  206. deadline_text = "due on "+(new Date(teacher_assignment.preferences.dueDate)).toDateString();
  207. }
  208.  
  209. var base_html = `
  210. <!DOCTYPE html>
  211. <head>
  212. <style>
  213. * {font-family: Arial}
  214. </style>
  215. <script>
  216. var base_url = "${base_url}";
  217. function http_get(url, callback) {
  218. var request = new XMLHttpRequest();
  219. request.addEventListener("load", callback);
  220. request.open("GET", url, true);
  221. request.send();
  222. }
  223. function get_tag(tag, url) {
  224. console.log("Loading "+url);
  225. http_get(url, function(){
  226. if ((""+this.status)[0] == "2") {
  227. var element = document.createElement(tag);
  228. element.innerHTML = this.responseText;
  229. document.getElementsByTagName("head")[0].appendChild(element);
  230. }
  231. else {
  232. console.error("Could not fetch "+url);
  233. }
  234. });
  235. }
  236. get_tag("style", base_url+"/app/popup.css");
  237. get_tag("script", base_url+"/app/popup.js");
  238. get_tag("script", base_url+"/app/videooptions.js");
  239. get_tag("script", base_url+"/app/videospeed.js");
  240. </script>
  241. <title>Answers for: ${media.title}</title>
  242. </head>
  243. <div id="header_div">
  244. <div>
  245. <img src="${thumbnail}" height="108px">
  246. </div>
  247. <div id="title_div">
  248. <p style="font-size: 16px"><b>${media.title}</b></h2>
  249. <p style="font-size: 12px">Uploaded by ${media.user.name} on ${date.toDateString()}</p>
  250. <p style="font-size: 12px">Assigned on ${assigned_date.toDateString()}, ${deadline_text}</p>
  251. <p style="font-size: 12px">Correct choices are <u>underlined</u>.</p>
  252. <input id="skipper" type="button" value="Skip Video" onclick="skip_video();" disabled/>
  253. <input id="answers_button" type="button" value="Answer Questions" onclick="answer_questions();" disabled/>
  254. <div id="speed_container" hidden>
  255. <label style="font-size: 12px" for="speed_dropdown">Video speed:</label>
  256. <select name="speed_dropdown" id="speed_dropdown" onchange="video_speed()">
  257. <option value="0.25">0.25</option>
  258. <option value="0.5">0.5</option>
  259. <option value="0.75">0.75</option>
  260. <option value="1" selected>Normal</option>
  261. <option value="1.25">1.25</option>
  262. <option value="1.5">1.5</option>
  263. <option value="1.75">1.75</option>
  264. <option value="2">2</option>
  265. <option value="-1">Custom</option>
  266. </select>
  267. <label id="custom_speed_label" style="font-size: 12px" for="custom_speed"></label>
  268. <input type="range" id="custom_speed" name="custom_speed" value="1" min="0.1" max="16" step="0.1" oninput="video_speed()" hidden>
  269. </div>
  270. <div id="options_container">
  271. <label for="pause_on_focus" style="font-size: 12px">Don't pause on unfocus: </label>
  272. <input type="checkbox" id="pause_on_focus" name="pause_on_focus" onchange="toggle_unfocus();">
  273. </div>
  274. </div>
  275. </div>
  276. <hr>
  277. <div id="content">
  278. <p style="font-size: 12px" id="loading_text"></p>
  279. </div>
  280. <hr>
  281. `;
  282. popup = window.open("about:blank", "", "width=600, height=400");
  283. popup.document.write(base_html);
  284.  
  285. popup.document.assignment = assignment;
  286. popup.document.dev_env = document.dev_env;
  287. popup.document.edpuzzle_data = window.__EDPUZZLE_DATA__;
  288.  
  289. getMedia(assignment);
  290. }
  291.  
  292. function getMedia(assignment) {
  293. var text = popup.document.getElementById("loading_text");
  294. text.innerHTML = `Fetching assignments...`;
  295.  
  296. var media_id = assignment.teacherAssignments[0].contentId;
  297. var url2 = `https://edpuzzle.com/api/v3/media/${media_id}`;
  298.  
  299. fetch(url2, {credentials: "omit"})
  300. .then(response => {
  301. if (!response.ok) {
  302. var text = popup.document.getElementById("loading_text");
  303. var content = popup.document.getElementById("content");
  304. popup.document.questions = questions;
  305. text.remove();
  306. content.innerHTML += `Error: Status code ${response.status} received when attempting to fetch the answers.`;
  307. }
  308. else return response.json();
  309. })
  310. .then(media => {
  311. parseQuestions(media.questions);
  312. })
  313. }
  314.  
  315. function parseQuestions(questions) {
  316. var text = popup.document.getElementById("loading_text");
  317. var content = popup.document.getElementById("content");
  318. popup.document.questions = questions;
  319. text.remove();
  320.  
  321. if (questions == null) {
  322. content.innerHTML += `<p style="font-size: 12px">Error: Could not get the media for this assignment. </p>`;
  323. return;
  324. }
  325.  
  326. var question;
  327. var counter = 0;
  328. var counter2 = 0;
  329. for (let i=0; i<questions.length; i++) {
  330. for (let j=0; j<questions.length-i-1; j++) {
  331. if (questions[j].time > questions[j+1].time){
  332. let question_old = questions[j];
  333. questions[j] = questions[j + 1];
  334. questions[j+1] = question_old;
  335. }
  336. }
  337. }
  338.  
  339. for (let i=0; i<questions.length; i++) {
  340. question = questions[i];
  341. let choices_lines = [];
  342.  
  343. if (typeof question.choices != "undefined") {
  344. let min = Math.floor(question.time/60).toString();
  345. let secs = Math.floor(question.time%60).toString();
  346. if (secs.length == 1) {
  347. secs = "0"+secs;
  348. }
  349. let timestamp = min+":"+secs;
  350. let question_content;
  351. if (question.body[0].text != "") {
  352. question_content = `<p>${question.body[0].text}</p>`;
  353. }
  354. else {
  355. question_content = question.body[0].html;
  356. }
  357.  
  358. let answer_exists = false;
  359. for (let j=0; j<question.choices.length; j++) {
  360. let choice = question.choices[j];
  361. if (typeof choice.body != "undefined") {
  362. counter++;
  363. let item_html;
  364. if (choice.body[0].text != "") {
  365. item_html = `<p>${choice.body[0].text}</p>`;
  366. }
  367. else {
  368. item_html = `${choice.body[0].html}`;
  369. }
  370. if (choice.isCorrect == true) {
  371. choices_lines.push(`<li class="choice choice-correct">${item_html}</li>`);
  372. answer_exists = true;
  373. }
  374. else {
  375. choices_lines.push(`<li class="choice">${item_html}</li>`);
  376. }
  377. }
  378. }
  379. if (!answer_exists) continue;
  380.  
  381. let choices_html = choices_lines.join("\n");
  382. let table = ``
  383. if (counter2 != 0) {
  384. table += `<hr>`;
  385. }
  386. table += `
  387. <table>
  388. <tr class="header no_vertical_margin">
  389. <td class="timestamp_div no_vertical_margin">
  390. <p>[${timestamp}]</p>
  391. </td>
  392. <td class="question">
  393. ${question_content}
  394. </td>
  395. </tr>
  396. <tr>
  397. <td></td>
  398. <td>
  399. <ul style="margin-top: 6px; margin-bottom: 0px; padding-left: 18px;">
  400. ${choices_html}
  401. </ul>
  402. </td>
  403. </tr>
  404. </table>
  405. `;
  406.  
  407. content.innerHTML += table;
  408. counter2++;
  409. }
  410. }
  411. popup.document.getElementById("skipper").disabled = false;
  412. if (counter == 0 || counter2 == 0) {
  413. content.innerHTML += `<p style="font-size: 12px">No valid multiple choice questions were found.</p>`;
  414. }
  415. else {
  416. popup.document.getElementById("answers_button").disabled = false;
  417. }
  418. popup.questions = questions;
  419. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement