Contexto Hack

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

当前为 2024-06-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Contexto Hack
  3. // @namespace your-namespace-here
  4. // @version 3.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. (function() {
  15. 'use strict';
  16. // Function to change the world list mode
  17. function changeWorldListMode() {
  18. const htmlElement = document.querySelector("html");
  19. const worldListElement = document.querySelector('.info-bar');
  20. if (htmlElement && worldListElement) {
  21. const isDarkMode = htmlElement.getAttribute('data-theme') === 'dark';
  22. // Adjust the background color for a slightly darker effect
  23. const darkModeBackgroundColor = 'rgb(15, 24, 32)';
  24. const lightModeBackgroundColor = 'white';
  25. worldListElement.style.backgroundColor = isDarkMode ? darkModeBackgroundColor : lightModeBackgroundColor;
  26. worldListElement.style.color = isDarkMode ? 'white' : 'black';
  27. // Adjust the saved words GUI mode for a slightly darker effect
  28. const savedWordsGUI = document.querySelector('#saved-words-list');
  29. if (savedWordsGUI) {
  30. savedWordsGUI.style.backgroundColor = isDarkMode ? darkModeBackgroundColor : lightModeBackgroundColor;
  31. savedWordsGUI.style.color = isDarkMode ? 'white' : 'black';
  32. }
  33. }
  34. }
  35. // Function to check if a string contains the number 1 by itself
  36. function containsOne(str) {
  37. return /^\D*1\D*$/.test(str);
  38. }
  39. // Retrieve saved words and game numbers from JSONBin.io
  40. let savedWords = {};
  41. let gameNumbers = {};
  42. // JSONStorage.net configurations
  43. const userId = 'd206ce58-9543-48db-a5e4-997cfc745ef3';
  44. const apiKey = 'e8dccf1d-81f7-4ecc-b99d-dc7401df192d';
  45.  
  46. // Function to fetch saved words from JSONStorage.net
  47. function fetchSavedWords() {
  48. // Check if saved words exist in the Tampermonkey storage
  49. const savedWordsData = GM_getValue('savedWordsData');
  50. if (savedWordsData) {
  51. savedWords = savedWordsData.savedWords;
  52. gameNumbers = savedWordsData.gameNumbers;
  53. console.log('Loaded saved words from Tampermonkey storage');
  54. updateSavedWordsGUI();
  55. }
  56.  
  57. // Fetch saved words from JSONStorage.net
  58. GM_xmlhttpRequest({
  59. method: 'GET',
  60. url: `https://api.jsonstorage.net/v1/json/${userId}/7d74d2ca-952e-4812-8a5c-76ec64d66a28?apiKey=${apiKey}`,
  61. headers: {
  62. 'Content-Type': 'application/json',
  63. },
  64. onload: function (response) {
  65. if (response.status === 200) {
  66. const responseData = JSON.parse(response.responseText);
  67. if (responseData.savedWords) {
  68. savedWords = responseData.savedWords;
  69. }
  70. if (responseData.gameNumbers) {
  71. gameNumbers = responseData.gameNumbers;
  72. }
  73. console.log('Read saved words successfully');
  74. updateSavedWordsGUI();
  75.  
  76. // Save fetched words to Tampermonkey storage
  77. const savedWordsData = {
  78. savedWords: savedWords,
  79. gameNumbers: gameNumbers,
  80. };
  81. GM_setValue('savedWordsData', savedWordsData);
  82. console.log('Saved fetched words to Tampermonkey storage');
  83.  
  84. // Call the searchForWordsAndGameNumbers function if it doesn't have the word for the current game number
  85. if (!Object.values(gameNumbers).includes(currentGameNumber)) {
  86. searchForWordsAndGameNumbers();
  87. }
  88. }
  89. },
  90. });
  91. }
  92.  
  93. // Function to save words and game numbers to JSONStorage.net
  94. function saveWordsToJSONStorage() {
  95. GM_xmlhttpRequest({
  96. method: 'PUT',
  97. url: `https://api.jsonstorage.net/v1/json/${userId}/7d74d2ca-952e-4812-8a5c-76ec64d66a28?apiKey=${apiKey}`,
  98. headers: {
  99. 'Content-Type': 'application/json',
  100. },
  101. data: JSON.stringify({
  102. savedWords: savedWords,
  103. gameNumbers: gameNumbers,
  104. }),
  105. onload: function (response) {
  106. if (response.status === 200) {
  107. console.log('Words and game numbers saved successfully');
  108. }
  109. },
  110. });
  111. }
  112.  
  113. // Function to search for words and game numbers to save on the page
  114. let currentGameNumber = '';
  115.  
  116. function searchForWordsAndGameNumbers() {
  117. // Find the game number element on the page
  118. const gameNumberElement = document.querySelector('.info-bar span:nth-child(2)');
  119. currentGameNumber = gameNumberElement ? gameNumberElement.textContent.trim().replace('#', '') : '';
  120.  
  121. if (currentGameNumber && !Object.values(gameNumbers).includes(currentGameNumber)) {
  122. // Find all the div elements with class "row" on the page
  123. const rows = document.querySelectorAll('.row');
  124. for (let i = 0; i < rows.length; i++) {
  125. const row = rows[i];
  126. // Find all the span elements within the row
  127. const spans = row.querySelectorAll('span');
  128. let hasOne = false;
  129. let word = '';
  130. for (let j = 0; j < spans.length; j++) {
  131. const span = spans[j];
  132. if (containsOne(span.innerHTML)) {
  133. hasOne = true;
  134. } else {
  135. word = span.innerHTML;
  136. }
  137. }
  138. // Save the word and game number to the objects if the word has the number 1 by itself and it's not already saved
  139. // Save the updated objects to JSONStorage.net only if a new word is saved
  140. if (hasOne && word && !savedWords.hasOwnProperty(word)) {
  141. savedWords[word] = true;
  142. gameNumbers[word] = currentGameNumber; // Save the current game number instead of searching for it again
  143. // Log the game number for the saved word
  144. console.log(`Game number for ${word}: ${currentGameNumber}`);
  145.  
  146. // Save the updated objects to JSONStorage.net
  147. saveWordsToJSONStorage();
  148. }
  149. }
  150. }
  151.  
  152. // Update the GUI with the saved words and game numbers
  153. updateSavedWordsGUI();
  154. }
  155.  
  156. // Function to reveal the word for the current game number
  157. function revealWordForCurrentGameNumber() {
  158. currentGameNumber = ''; // Clear the current game number
  159.  
  160. // Find the game number element on the page
  161. const gameNumberElement = document.querySelector('.info-bar span:nth-child(2)');
  162. currentGameNumber = gameNumberElement ? gameNumberElement.textContent.trim().replace('#', '') : '';
  163.  
  164. // Find the saved word for the current game number
  165. const savedWordsForCurrentGameNumber = Object.keys(savedWords).filter((word) => {
  166. return gameNumbers[word] === currentGameNumber;
  167. });
  168.  
  169. // Display the saved word in an alert box
  170. if (savedWordsForCurrentGameNumber.length > 0) {
  171. alert(`The word for game number ${currentGameNumber} is: ${savedWordsForCurrentGameNumber[0]}`);
  172. } else {
  173. alert(`No saved words for game number ${currentGameNumber}. Trying to find the word in the library...`);
  174. fetchSavedWords();
  175. }
  176. }
  177.  
  178. // rest of code ..
  179. const buttoncss = `
  180. .theme-button {
  181. background-color: #29a19c; /* Contexto primary color - Change this to the actual primary color */
  182. color: #ffffff; /* White text to contrast with the primary color */
  183. border: none;
  184. padding: 5px 13px; /* Reduce padding to make the button smaller */
  185. font-size: 11px; /* Reduce font size to make the button smaller */
  186. border-radius: 3px; /* Adjust border radius for less rounded corners */
  187. cursor: pointer;
  188. margin: 5px;
  189. /* Add any additional styles or adjustments you want */
  190. }
  191. .theme-button:hover {
  192. background-color: #45c0b5; /* Lighter shade on hover - Change this to the actual hover color */
  193. }
  194. `;
  195. // Add the CSS styles to the page
  196. const buttonstyle = document.createElement('style');
  197. buttonstyle.innerHTML = buttoncss;
  198. document.head.appendChild(buttonstyle);
  199. // Create a button to show the saved words GUI
  200. const showSavedWordsButton = document.createElement('button');
  201. showSavedWordsButton.textContent = 'Saved Words';
  202. showSavedWordsButton.classList.add('theme-button'); // Add a custom class for styling
  203. showSavedWordsButton.addEventListener('click', () => {
  204. savedWordsGUI.classList.add('open');
  205. });
  206. document.body.appendChild(showSavedWordsButton);
  207. // Create a button to reveal the word for the current game number
  208. const revealButton = document.createElement('button');
  209. revealButton.textContent = 'Reveal Word';
  210. revealButton.classList.add('theme-button'); // Add a custom class for styling
  211. revealButton.addEventListener('click', revealWordForCurrentGameNumber);
  212. document.body.appendChild(revealButton);
  213. // Create a div element to hold the saved words GUI
  214. const savedWordsGUI = document.createElement('div');
  215. savedWordsGUI.id = 'saved-words-list';
  216. document.body.appendChild(savedWordsGUI);
  217. // Create a button to minimize the saved words GUI
  218. const minimizeSavedWordsButton = document.createElement('button');
  219. minimizeSavedWordsButton.innerHTML = '<img src="https://th.bing.com/th/id/R.6a6eda3ee63c80ebc02dc830b395324e?rik=t2E%2fYYP3IGbSsQ&pid=ImgRaw&r=0" alt="Close">';
  220. minimizeSavedWordsButton.addEventListener('click', () => {
  221. savedWordsGUI.classList.remove('open');
  222. });
  223. savedWordsGUI.appendChild(minimizeSavedWordsButton);
  224. // Create a list element to display the saved words
  225. const savedWordsList = document.createElement('ul');
  226. savedWordsGUI.appendChild(savedWordsList);
  227. // Function to update the saved words GUI with the saved words and game numbers
  228. function updateSavedWordsGUI() {
  229. // Clear the current saved words list
  230. savedWordsList.innerHTML = '';
  231. // Get all saved words sorted by game number
  232. const savedWordsSorted = Object.keys(gameNumbers).sort((a, b) => {
  233. return gameNumbers[a] - gameNumbers[b];
  234. });
  235. // Add each saved word to the list
  236. for (let i = 0; i < savedWordsSorted.length; i++) {
  237. const word = savedWordsSorted[i];
  238. const gameNumber = gameNumbers[word];
  239. const listItem = document.createElement('li');
  240. listItem.textContent = `${word} (Game ${gameNumber})`;
  241. savedWordsList.appendChild(listItem);
  242. }
  243. }
  244. // Update the saved words GUI with the saved words and game numbers
  245. updateSavedWordsGUI();
  246. // Function to clear the saved words and game numbers from JSONBin.io
  247. function clearSavedWords() {
  248. savedWords = {};
  249. gameNumbers = {};
  250. //saveWordsToJSONBin();
  251. updateSavedWordsGUI();
  252. alert('Saved words cleared');
  253. }
  254. // Create a button to clear the saved words and game numbers
  255. const clearSavedWordsButton = document.createElement('button');
  256. clearSavedWordsButton.textContent = 'Clear Saved Words';
  257. clearSavedWordsButton.addEventListener('click', clearSavedWords);
  258. savedWordsGUI.appendChild(clearSavedWordsButton);
  259. // Function to export the saved words and game numbers as JSON
  260. function exportSavedWords() {
  261. const savedWordsData = {
  262. savedWords: savedWords,
  263. gameNumbers: gameNumbers
  264. };
  265. const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(savedWordsData));
  266. const downloadAnchorNode = document.createElement('a');
  267. downloadAnchorNode.setAttribute('href', dataStr);
  268. downloadAnchorNode.setAttribute('download', 'contexto_saved_words.json');
  269. document.body.appendChild(downloadAnchorNode); // required for firefox
  270. downloadAnchorNode.click();
  271. downloadAnchorNode.remove();
  272. }
  273. // Create a button to export the saved words and game numbers
  274. const exportSavedWordsButton = document.createElement('button');
  275. exportSavedWordsButton.textContent = 'Export Saved Words';
  276. exportSavedWordsButton.addEventListener('click', exportSavedWords);
  277. savedWordsGUI.appendChild(exportSavedWordsButton);
  278. // Function to import saved words and game numbers from JSON
  279. function importSavedWords() {
  280. const fileInput = document.createElement('input');
  281. fileInput.type = 'file';
  282. fileInput.accept = '.json';
  283. fileInput.addEventListener('change', () => {
  284. const file = fileInput.files[0];
  285. const reader = new FileReader();
  286. reader.onload = (e) => {
  287. try {
  288. const savedWordsData = JSON.parse(e.target.result);
  289. savedWords = savedWordsData.savedWords;
  290. gameNumbers = savedWordsData.gameNumbers;
  291. saveWordsToJSONBin();
  292. updateSavedWordsGUI();
  293. alert('Saved words imported');
  294. } catch (err) {
  295. alert('Error importing saved words');
  296. }
  297. };
  298. reader.readAsText(file);
  299. });
  300. fileInput.click();
  301. }
  302. // Create a button to import saved words and game numbers
  303. const importSavedWordsButton = document.createElement('button');
  304. importSavedWordsButton.textContent = 'Import Saved Words';
  305. importSavedWordsButton.addEventListener('click', importSavedWords);
  306. savedWordsGUI.appendChild(importSavedWordsButton);
  307. // Define CSS styles for the saved words GUI
  308. const css = `
  309. #saved-words-list {
  310. position: fixed;
  311. bottom: 0;
  312. right: 0;
  313. background-color: white;
  314. border: 2px solid black;
  315. border-radius: 5px 0 0 0;
  316. padding: 10px;
  317. max-height: 300px;
  318. overflow-y: auto;
  319. display: none;
  320. }
  321. #saved-words-list.open {
  322. display: block;
  323. }
  324. #saved-words-list button {
  325. margin: 5px;
  326. padding: 0;
  327. background: none;
  328. border: none;
  329. cursor: pointer;
  330. }
  331. #saved-words-list img {
  332. width: 20px;
  333. height: 20px;
  334. }
  335. `;
  336. // Add the CSS styles to the page
  337. const style = document.createElement('style');
  338. style.innerHTML = css;
  339. document.head.appendChild(style);
  340. // Fetch saved words and game numbers from JSONBin.io on page load
  341. fetchSavedWords();
  342. // Search for words and game numbers to save on page load and every 5 seconds
  343. searchForWordsAndGameNumbers();
  344. setInterval(searchForWordsAndGameNumbers, 17000);//17 seconds
  345. // Change the world list mode on page load and whenever the data-theme changes
  346. changeWorldListMode();
  347. const htmlElement = document.querySelector("html");
  348. const observer = new MutationObserver(changeWorldListMode);
  349. observer.observe(htmlElement, { attributes: true, attributeFilter: ['data-theme'] });
  350. })();