Contexto Hack

This is a Contexto Hack that Gives you the word of the day for everyday.

目前为 2023-07-05 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Contexto Hack
  3. // @namespace your-namespace-here
  4. // @version 2.0
  5. // @author longkidkoolstar
  6. // @description This is a Contexto Hack that Gives you the word of the day for everyday.
  7. // @icon https://styles.redditmedia.com/t5_72ajpm/styles/communityIcon_2y8kmvv8z6wa1.png?width=256&v=enabled&s=497ae2191ac283aadfc5da5941539fcc5a575e1b
  8. // @match https://contexto.me/*
  9. // @license CC BY-NC-ND 4.0
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_xmlhttpRequest
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // JSONBin.io configurations
  19. const binId = '649efcdbb89b1e2299b7c40c';
  20. const accessKey = '$2b$10$7aFXF1Powlysz7vBu8xY2u9QOHeJUxwtcE4d2cW2/AFg6AhZP4XR2';
  21.  
  22. // Function to check if a string contains the number 1 by itself
  23. function containsOne(str) {
  24. return /^\D*1\D*$/.test(str);
  25. }
  26.  
  27. // Retrieve saved words and game numbers from JSONBin.io
  28. let savedWords = {};
  29. let gameNumbers = {};
  30.  
  31. function fetchSavedWords() {
  32. setInterval(() => {
  33. GM_xmlhttpRequest({
  34. method: 'GET',
  35. url: `https://api.jsonbin.io/v3/b/${binId}/latest`,
  36. headers: {
  37. 'Content-Type': 'application/json',
  38. 'X-Bin-Access-Token': accessKey,
  39. 'X-Access-Key': accessKey
  40. },
  41. onload: function(response) {
  42. if (response.status === 200) {
  43. const responseData = JSON.parse(response.responseText);
  44. if (responseData.record) {
  45. const recordData = responseData.record;
  46. if (recordData.savedWords) {
  47. savedWords = recordData.savedWords;
  48. }
  49. if (recordData.gameNumbers) {
  50. gameNumbers = recordData.gameNumbers;
  51. }
  52. }
  53. console.log('Read saved words successfully');
  54. updateSavedWordsGUI();
  55. }
  56. }
  57. });
  58. }, 20000); // Fetch every 1000 milliseconds (20 second)
  59. }
  60.  
  61.  
  62.  
  63. // Function to save words and game numbers to JSONBin.io
  64. // Function to save words and game numbers to JSONBin.io
  65. function saveWordsToJSONBin() {
  66. GM_xmlhttpRequest({
  67. method: 'GET',
  68. url: `https://api.jsonbin.io/v3/b/${binId}`,
  69. headers: {
  70. 'Content-Type': 'application/json',
  71. 'X-Bin-Access-Token': accessKey,
  72. 'X-Access-Key': accessKey
  73. },
  74. onload: function(response) {
  75. if (response.status === 200) {
  76. const responseData = JSON.parse(response.responseText);
  77. const existingData = responseData.record;
  78.  
  79. // Merge existing data with new data
  80. const mergedData = {
  81. savedWords: { ...existingData.savedWords, ...savedWords },
  82. gameNumbers: { ...existingData.gameNumbers, ...gameNumbers }
  83. };
  84.  
  85. GM_xmlhttpRequest({
  86. method: 'PUT',
  87. url: `https://api.jsonbin.io/v3/b/${binId}`,
  88. headers: {
  89. 'Content-Type': 'application/json',
  90. 'X-Bin-Access-Token': accessKey,
  91. 'X-Access-Key': accessKey
  92. },
  93. data: JSON.stringify(mergedData),
  94. onload: function(response) {
  95. if (response.status === 200) {
  96. console.log('Words and game numbers saved successfully');
  97. }
  98. }
  99. });
  100. }
  101. }
  102. });
  103. }
  104.  
  105.  
  106. // Function to search for words and game numbers to save on the page
  107. let currentGameNumber = '';
  108.  
  109. function searchForWordsAndGameNumbers() {
  110. // Find the game number element on the page
  111. const gameNumberElement = document.querySelector('.info-bar span:nth-child(2)');
  112. currentGameNumber = gameNumberElement ? gameNumberElement.textContent.trim().replace('#', '') : '';
  113.  
  114. // Find all the div elements with class "row" on the page
  115. const rows = document.querySelectorAll('.row');
  116. for (let i = 0; i < rows.length; i++) {
  117. const row = rows[i];
  118. // Find all the span elements within the row
  119. const spans = row.querySelectorAll('span');
  120. let hasOne = false;
  121. let word = '';
  122. for (let j = 0; j < spans.length; j++) {
  123. const span = spans[j];
  124. if (containsOne(span.innerHTML)) {
  125. hasOne = true;
  126. } else {
  127. word = span.innerHTML;
  128. }
  129. }
  130. // Save the word and game number to the objects if the word has the number 1 by itself and it's not already saved
  131. if (hasOne && word && !savedWords[word]) {
  132. savedWords[word] = true;
  133. gameNumbers[word] = currentGameNumber; // Save the current game number instead of searching for it again
  134. // Log the game number for the saved word
  135. console.log(`Game number for ${word}: ${currentGameNumber}`);
  136. }
  137. }
  138.  
  139. // Save the updated objects to JSONBin.io
  140. saveWordsToJSONBin();
  141.  
  142. // Update the GUI with the saved words and game numbers
  143. updateSavedWordsGUI();
  144. }
  145.  
  146. // Function to reveal the word for the current game number
  147. function revealWordForCurrentGameNumber() {
  148. // Find the saved word for the current game number
  149. const savedWordsForCurrentGameNumber = Object.keys(savedWords).filter((word) => {
  150. return gameNumbers[word] === currentGameNumber;
  151. });
  152.  
  153. // Display the saved word in an alert box
  154. if (savedWordsForCurrentGameNumber.length > 0) {
  155. alert(`The word for game number ${currentGameNumber} is: ${savedWordsForCurrentGameNumber[0]}`);
  156. } else {
  157. alert(`No saved words for game number ${currentGameNumber}`);
  158. }
  159. }
  160.  
  161. // Create a button to reveal the word for the current game number
  162. const revealButton = document.createElement('button');
  163. revealButton.textContent = 'Reveal Word';
  164. revealButton.addEventListener('click', revealWordForCurrentGameNumber);
  165. document.body.appendChild(revealButton);
  166.  
  167. // Create a div element to hold the saved words GUI
  168. const savedWordsGUI = document.createElement('div');
  169. savedWordsGUI.id = 'saved-words-list';
  170. document.body.appendChild(savedWordsGUI);
  171.  
  172. // Create a button to show the saved words GUI
  173. const showSavedWordsButton = document.createElement('button');
  174. showSavedWordsButton.textContent = 'Saved Words';
  175. showSavedWordsButton.addEventListener('click', () => {
  176. savedWordsGUI.classList.add('open');
  177. });
  178. document.body.appendChild(showSavedWordsButton);
  179.  
  180. // Create a button to minimize the saved words GUI
  181. const minimizeSavedWordsButton = document.createElement('button');
  182. minimizeSavedWordsButton.innerHTML = '<img src="https://th.bing.com/th/id/R.6a6eda3ee63c80ebc02dc830b395324e?rik=t2E%2fYYP3IGbSsQ&pid=ImgRaw&r=0" alt="Close">';
  183. minimizeSavedWordsButton.addEventListener('click', () => {
  184. savedWordsGUI.classList.remove('open');
  185. });
  186. savedWordsGUI.appendChild(minimizeSavedWordsButton);
  187.  
  188.  
  189. // Create a list element to display the saved words
  190. const savedWordsList = document.createElement('ul');
  191. savedWordsGUI.appendChild(savedWordsList);
  192.  
  193. // Function to update the saved words GUI with the saved words and game numbers
  194. function updateSavedWordsGUI() {
  195. // Clear the current saved words list
  196. savedWordsList.innerHTML = '';
  197.  
  198. // Get all saved words sorted by game number
  199. const savedWordsSorted = Object.keys(gameNumbers).sort((a, b) => {
  200. return gameNumbers[a] - gameNumbers[b];
  201. });
  202.  
  203. // Add each saved word to the list
  204. for (let i = 0; i < savedWordsSorted.length; i++) {
  205. const word = savedWordsSorted[i];
  206. const gameNumber = gameNumbers[word];
  207. const listItem = document.createElement('li');
  208. listItem.textContent = `${word} (Game ${gameNumber})`;
  209. savedWordsList.appendChild(listItem);
  210. }
  211. }
  212.  
  213. // Update the saved words GUI with the saved words and game numbers
  214. updateSavedWordsGUI();
  215.  
  216. // Function to clear the saved words and game numbers from JSONBin.io
  217. function clearSavedWords() {
  218. savedWords = {};
  219. gameNumbers = {};
  220. saveWordsToJSONBin();
  221. updateSavedWordsGUI();
  222. alert('Saved words cleared');
  223. }
  224.  
  225. // Create a button to clear the saved words and game numbers
  226. const clearSavedWordsButton = document.createElement('button');
  227. clearSavedWordsButton.textContent = 'Clear Saved Words';
  228. clearSavedWordsButton.addEventListener('click', clearSavedWords);
  229. savedWordsGUI.appendChild(clearSavedWordsButton);
  230.  
  231. // Function to export the saved words and game numbers as JSON
  232. function exportSavedWords() {
  233. const savedWordsData = {
  234. savedWords: savedWords,
  235. gameNumbers: gameNumbers
  236. };
  237. const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(savedWordsData));
  238. const downloadAnchorNode = document.createElement('a');
  239. downloadAnchorNode.setAttribute('href', dataStr);
  240. downloadAnchorNode.setAttribute('download', 'contexto_saved_words.json');
  241. document.body.appendChild(downloadAnchorNode); // required for firefox
  242. downloadAnchorNode.click();
  243. downloadAnchorNode.remove();
  244. }
  245.  
  246. // Create a button to export the saved words and game numbers
  247. const exportSavedWordsButton = document.createElement('button');
  248. exportSavedWordsButton.textContent = 'Export Saved Words';
  249. exportSavedWordsButton.addEventListener('click', exportSavedWords);
  250. savedWordsGUI.appendChild(exportSavedWordsButton);
  251.  
  252. // Function to import saved words and game numbers from JSON
  253. function importSavedWords() {
  254. const fileInput = document.createElement('input');
  255. fileInput.type = 'file';
  256. fileInput.accept = '.json';
  257. fileInput.addEventListener('change', () => {
  258. const file = fileInput.files[0];
  259. const reader = new FileReader();
  260. reader.onload = (e) => {
  261. try {
  262. const savedWordsData = JSON.parse(e.target.result);
  263. savedWords = savedWordsData.savedWords;
  264. gameNumbers = savedWordsData.gameNumbers;
  265. saveWordsToJSONBin();
  266. updateSavedWordsGUI();
  267. alert('Saved words imported');
  268. } catch (err) {
  269. alert('Error importing saved words');
  270. }
  271. };
  272. reader.readAsText(file);
  273. });
  274. fileInput.click();
  275. }
  276.  
  277. // Create a button to import saved words and game numbers
  278. const importSavedWordsButton = document.createElement('button');
  279. importSavedWordsButton.textContent = 'Import Saved Words';
  280. importSavedWordsButton.addEventListener('click', importSavedWords);
  281. savedWordsGUI.appendChild(importSavedWordsButton);
  282.  
  283. // Define CSS styles for the saved words GUI
  284. const css = `
  285. #saved-words-list {
  286. position: fixed;
  287. bottom: 0;
  288. right: 0;
  289. background-color: white;
  290. border: 2px solid black;
  291. border-radius: 5px 0 0 0;
  292. padding: 10px;
  293. max-height: 300px;
  294. overflow-y: auto;
  295. display: none;
  296. }
  297. #saved-words-list.open {
  298. display: block;
  299. }
  300. #saved-words-list button {
  301. margin: 5px;
  302. padding: 0;
  303. background: none;
  304. border: none;
  305. cursor: pointer;
  306. }
  307. #saved-words-list img {
  308. width: 20px;
  309. height: 20px;
  310. }
  311. `;
  312.  
  313. // Add the CSS styles to the page
  314. const style = document.createElement('style');
  315. style.innerHTML = css;
  316. document.head.appendChild(style);
  317.  
  318. // Fetch saved words and game numbers from JSONBin.io on page load
  319. fetchSavedWords();
  320.  
  321. // Search for words and game numbers to save on page load and every 5 seconds
  322. searchForWordsAndGameNumbers();
  323. setInterval(searchForWordsAndGameNumbers, 17000);//15 seconds
  324. })();