Sleazy Fork is available in English.

头歌复制助手 Educoder Copy Helper

📝解除头歌复制粘贴限制,解除头哥复制缩短限制,海角社区,支持考试;✨与《头歌助手 EduCoder Helper》搭配使用解锁“一键复制”、“一键全部文件复制”、“导出全部文件”等功能。🧹大小仅1.82KB,极小尺寸,无需任何权限,无需任何配置,安装即用。💛安全开源可读,无论是编译前后的代码均保持开源和易读性,防止窃取其他信息

  1. // ==UserScript==
  2. // @name 头歌复制助手 Educoder Copy Helper
  3. // @namespace https://github.com/lcandy2/user.js/tree/main/websites/educoder.net/educoder-copy-helper
  4. // @version 2.8
  5. // @author 甜檸Cirtron (lcandy2)
  6. // @description 📝解除头歌复制粘贴限制,解除头哥复制缩短限制,海角社区,支持考试;✨与《头歌助手 EduCoder Helper》搭配使用解锁“一键复制”、“一键全部文件复制”、“导出全部文件”等功能。🧹大小仅1.82KB,极小尺寸,无需任何权限,无需任何配置,安装即用。💛安全开源可读,无论是编译前后的代码均保持开源和易读性,防止窃取其他信息
  7. // @license AGPL-3.0-or-later
  8. // @copyright lcandy2 All Rights Reserved
  9. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAABsUlEQVR4nO2ZzUrDQBCAA3kM23NfJKuC4FW6vYjZV/DiK7SaeCxYKiRQE5qNB7EPUoT6A3op9GBFi5eeIhsMjNbW2s2apMwHc2t35tud3RxG0xTQ6IRlyw26thtMRFgu55ZzWdGKQKMTlm2Hj22XR1/C4eNTJyhpeceKdz4u+ur43N8QRdtOcP0p4Wt5x47bhkdwt+NTcXlkucFbJkVt7u2XCTW7RpVNCGVREjNtAuLopLmT/P/Qau4u+i0Ba4ocBmXhVu2gklrxBmVjmGQZgXr7YiokRPH1tj9dVoAkItR8EbmlBcTO/5TgN4G/BJmzPqFM/s7Atrm5fYggaQlA+oN72E7ydwbuyHfOeE+6+BbvzawLcyoVeByOpCRavBc9DUfZCaiCoAAAT2AFCLbQki2ke+9SkfkJoMAc8A5A8BldAYLPKABfIS/H3wFVEBRQdAdydwJ60QVUQVAAgN8BD78Dcqz1JdaL/ozqRRdQBUEBAJ5A1i1kgAGHGD6opj+4AwLmq7wAZeGCEZDiMD1pATEtFAO3fy++yp63a6yU4piV+WJmpbpwI85heqkVjyBrzgdOSyKlYdgYdgAAAABJRU5ErkJggg==
  10. // @homepage https://greasyfork.org/scripts/495490
  11. // @homepageURL https://greasyfork.org/scripts/495490
  12. // @source https://github.com/lcandy2/user.js/tree/main/websites/educoder.net/educoder-copy-helper
  13. // @match *://*/*
  14. // @grant none
  15. // @run-at document-start
  16. // ==/UserScript==
  17.  
  18. (function () {
  19. 'use strict';
  20.  
  21. async function saveTaskJson(request, response) {
  22. try {
  23. const signature = request.headers.get("X-EDU-Signature");
  24. if (signature) {
  25. window.xEduSignature = signature;
  26. }
  27. const timestamp = request.headers.get("X-EDU-Timestamp");
  28. if (timestamp) {
  29. window.xEduTimestamp = timestamp;
  30. }
  31. const type = request.headers.get("X-EDU-Type");
  32. if (type) {
  33. window.xEduType = type;
  34. }
  35. } catch (e) {
  36. console.error("[educoder-copy-helper] Error reading request headers:", e);
  37. }
  38. const res = response.clone();
  39. if (request.url.includes("/api/tasks") || request.url.includes("json?homework_common_id")) {
  40. try {
  41. const json = await res.json();
  42. console.debug(`[educoder-copy-helper] [RESPONSE] ${request.url.toString()}`, json);
  43. if (json && json.challenge && json.challenge.path) {
  44. const path = json.challenge.path;
  45. window.taskChallengePath = path;
  46. }
  47. } catch (e) {
  48. console.error("[educoder-copy-helper] Error reading response body:", e);
  49. }
  50. }
  51. if (request.url.includes("watch_video_histories.json")) {
  52. try {
  53. const reqJson = await request.json();
  54. const resJson = await res.json();
  55. console.debug(`[educoder-copy-helper] [REQUEST] ${request.url.toString()}`, reqJson);
  56. console.debug(`[educoder-copy-helper] [RESPONSE] ${request.url.toString()}`, resJson);
  57. if (reqJson && reqJson.video_id) {
  58. window.videoId = reqJson.video_id;
  59. }
  60. if (resJson && resJson.log_id) {
  61. window.videoLogId = resJson.log_id;
  62. }
  63. } catch (e) {
  64. console.error("[educoder-copy-helper] Error reading response body:", e);
  65. }
  66. }
  67. if (request.url.includes("rep_content.json")) {
  68. try {
  69. const url = new URL(request.url);
  70. const pathSegments = url.pathname.split("/");
  71. const taskId = pathSegments[pathSegments.length - 2];
  72. console.debug(`[educoder-copy-helper] [RESPONSE] ${request.url.toString()}`, taskId);
  73. if (taskId) {
  74. window.taskId = taskId;
  75. }
  76. } catch (e) {
  77. console.error("[educoder-copy-helper] Error reading response body:", e);
  78. }
  79. }
  80. }
  81. async function modifyTaskCopy(request, response) {
  82. let res = response.clone();
  83. res = await modifyTask(request, res);
  84. res = await modifyExercise(request, res);
  85. return res;
  86. }
  87. const modifyTask = async (request, response) => {
  88. if (request.url.includes("/api/tasks") || request.url.includes("json?homework_common_id")) {
  89. const res = response.clone();
  90. try {
  91. const json = await res.json();
  92. if (json) {
  93. if (json.shixun) {
  94. !json.shixun.forbid_copy && (json.shixun.name = `${json.shixun.name} (已允许复制粘贴)`);
  95. json.shixun.can_copy = true;
  96. json.shixun.vip = true;
  97. json.shixun.forbid_copy = false;
  98. json.shixun.copy_for_exercise = true;
  99. json.shixun.active_copy = true;
  100. json.shixun.copy_for_exercise_save = true;
  101. json.shixun.allow_file_upload = true;
  102. json.shixun.open_local_evaluate = true;
  103. json.shixun.open_self_run = true;
  104. json.shixun.code_edit_permission = true;
  105. }
  106. if (json.challenge) {
  107. json.challenge.diasble_copy = false;
  108. }
  109. if (OTHER_MODIFY)
  110. ;
  111. }
  112. return new Response(JSON.stringify(json), {
  113. status: response.status,
  114. statusText: response.statusText,
  115. headers: response.headers
  116. });
  117. } catch (e) {
  118. console.error("Error reading response body:", e);
  119. return response;
  120. }
  121. }
  122. return response;
  123. };
  124. const modifyExercise = async (request, response) => {
  125. const modifyExerciseSetting = (json) => {
  126. json.is_random = false;
  127. json.screen_open = false;
  128. json.screen_num = 0;
  129. json.screen_sec = 0;
  130. json.ip_limit = "no";
  131. json.ip_bind = false;
  132. json.ip_bind_type = false;
  133. json.question_random = false;
  134. json.choice_random = false;
  135. json.check_camera = false;
  136. json.open_phone_video_recording = false;
  137. json.forbid_screen = false;
  138. json.use_white_list = false;
  139. json.net_limit = false;
  140. json.net_limit_list = null;
  141. json.only_on_client = false;
  142. json.open_camera = false;
  143. json.is_locked = false;
  144. json.identity_verify = false;
  145. json.open_appraise = true;
  146. json.score_open = 0;
  147. json.answer_open = true;
  148. json.open_score = 0;
  149. json.open_total_score = 0;
  150. json.screen_shot_open = false;
  151. };
  152. if (request.url.includes("/api/exercises") && request.url.includes("get_exercise_user_info.json")) {
  153. const res = response.clone();
  154. try {
  155. const json = await res.json();
  156. if (json) {
  157. if (json.data) {
  158. modifyExerciseSetting(json.data);
  159. }
  160. }
  161. return new Response(JSON.stringify(json), {
  162. status: response.status,
  163. statusText: response.statusText,
  164. headers: response.headers
  165. });
  166. } catch (e) {
  167. console.error("Error reading response body:", e);
  168. return response;
  169. }
  170. }
  171. if (request.url.includes("/api/exercises") && (request.url.includes("start.json") || request.url.includes("exercise_setting.json"))) {
  172. const res = response.clone();
  173. try {
  174. const json = await res.json();
  175. if (json) {
  176. if (json.exercise) {
  177. modifyExerciseSetting(json.exercise);
  178. }
  179. }
  180. return new Response(JSON.stringify(json), {
  181. status: response.status,
  182. statusText: response.statusText,
  183. headers: response.headers
  184. });
  185. } catch (e) {
  186. console.error("Error reading response body:", e);
  187. return response;
  188. }
  189. }
  190. return response;
  191. };
  192. function hookFetch() {
  193. const nativeFetch = window.fetch;
  194. const hookedFetch = async (...args) => {
  195. const request = new Request(...args);
  196. const response = await nativeFetch(...args);
  197. const clonedResponse = response.clone();
  198. await saveTaskJson(request, clonedResponse);
  199. const modifiedResponse = await modifyTaskCopy(request, clonedResponse);
  200. return modifiedResponse;
  201. };
  202. window.fetch = hookedFetch;
  203. }
  204. const OTHER_MODIFY = false;
  205. hookFetch();
  206. window.educoderCopyHelper = "2.8";
  207.  
  208. })();