Contexto Hack

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

目前為 2023-10-25 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Contexto Hack
// @namespace    your-namespace-here
// @version      2.4.2
// @author       longkidkoolstar
// @description  This is a Contexto Hack that Gives you the word of the day for everyday.
// @icon         https://styles.redditmedia.com/t5_72ajpm/styles/communityIcon_2y8kmvv8z6wa1.png?width=256&v=enabled&s=497ae2191ac283aadfc5da5941539fcc5a575e1b
// @match        https://contexto.me/*
// @license      CC BY-NC-ND 4.0
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';



// Function to change the world list mode
function changeWorldListMode() {
    const htmlElement = document.querySelector("html");
    const worldListElement = document.querySelector('.info-bar');

    if (htmlElement && worldListElement) {
        const isDarkMode = htmlElement.getAttribute('data-theme') === 'dark';

        // Adjust the background color for a slightly darker effect
        const darkModeBackgroundColor = 'rgb(15, 24, 32)';
        const lightModeBackgroundColor = 'white';
        worldListElement.style.backgroundColor = isDarkMode ? darkModeBackgroundColor : lightModeBackgroundColor;
        worldListElement.style.color = isDarkMode ? 'white' : 'black';

        // Adjust the saved words GUI mode for a slightly darker effect
        const savedWordsGUI = document.querySelector('#saved-words-list');
        if (savedWordsGUI) {
            savedWordsGUI.style.backgroundColor = isDarkMode ? darkModeBackgroundColor : lightModeBackgroundColor;
            savedWordsGUI.style.color = isDarkMode ? 'white' : 'black';
        }
    }
}


    // JSONBin.io configurations
    const binId = '65394ea554105e766fc701f3';
    const accessKey = '$2a$10$clc2YpzfET69uHWru0RKY.wZv2v1MkRqxJmV1GvhMTV0ANpN.wb4a';

    // Function to check if a string contains the number 1 by itself
    function containsOne(str) {
        return /^\D*1\D*$/.test(str);
    }

    // Retrieve saved words and game numbers from JSONBin.io
    let savedWords = {};
    let gameNumbers = {};

    function fetchSavedWords() {
        // Check if saved words exist in the Tampermonkey storage
        const savedWordsData = GM_getValue('savedWordsData');
        if (savedWordsData) {
            savedWords = savedWordsData.savedWords;
            gameNumbers = savedWordsData.gameNumbers;
            console.log('Loaded saved words from Tampermonkey storage');
            updateSavedWordsGUI();
        }

        // Fetch saved words from JSONBin.io
        GM_xmlhttpRequest({
            method: 'GET',
            url: `https://api.jsonbin.io/v3/b/${binId}/latest`,
            headers: {
                'Content-Type': 'application/json',
                'X-Bin-Access-Token': accessKey,
                'X-Access-Key': accessKey,
            },
            onload: function (response) {
                if (response.status === 200) {
                    const responseData = JSON.parse(response.responseText);
                    if (responseData.record) {
                        const recordData = responseData.record;
                        if (recordData.savedWords) {
                            savedWords = recordData.savedWords;
                        }
                        if (recordData.gameNumbers) {
                            gameNumbers = recordData.gameNumbers;
                        }
                    }
                    console.log('Read saved words successfully');
                    updateSavedWordsGUI();

                    // Save fetched words to Tampermonkey storage
                    const savedWordsData = {
                        savedWords: savedWords,
                        gameNumbers: gameNumbers,
                    };
                    GM_setValue('savedWordsData', savedWordsData);
                    console.log('Saved fetched words to Tampermonkey storage');

                    // Call the searchForWordsAndGameNumbers function if it doesn't have the word for the current game number
                    if (!Object.values(gameNumbers).includes(currentGameNumber)) {
                        searchForWordsAndGameNumbers();
                    }
                }
            },
        });
    }



    // Function to save words and game numbers to JSONBin.io
    function saveWordsToJSONBin() {
        GM_xmlhttpRequest({
            method: 'GET',
            url: `https://api.jsonbin.io/v3/b/${binId}`,
            headers: {
                'Content-Type': 'application/json',
                'X-Bin-Access-Token': accessKey,
                'X-Access-Key': accessKey
            },
            onload: function(response) {
                if (response.status === 200) {
                    const responseData = JSON.parse(response.responseText);
                    const existingData = responseData.record;

                    // Merge existing data with new data
                    const mergedData = {
                        savedWords: { ...existingData.savedWords, ...savedWords },
                        gameNumbers: { ...existingData.gameNumbers, ...gameNumbers }
                    };

                    GM_xmlhttpRequest({
                        method: 'PUT',
                        url: `https://api.jsonbin.io/v3/b/${binId}`,
                        headers: {
                            'Content-Type': 'application/json',
                            'X-Bin-Access-Token': accessKey,
                            'X-Access-Key': accessKey
                        },
                        data: JSON.stringify(mergedData),
                        onload: function(response) {
                            if (response.status === 200) {
                                console.log('Words and game numbers saved successfully');
                            }
                        }
                    });
                }
            }
        });
    }


    // Function to search for words and game numbers to save on the page
    let currentGameNumber = '';

    function searchForWordsAndGameNumbers() {
        // Find the game number element on the page
        const gameNumberElement = document.querySelector('.info-bar span:nth-child(2)');
        currentGameNumber = gameNumberElement ? gameNumberElement.textContent.trim().replace('#', '') : '';


        if (currentGameNumber && !Object.values(gameNumbers).includes(currentGameNumber)) {
            // Find all the div elements with class "row" on the page
            const rows = document.querySelectorAll('.row');
            for (let i = 0; i < rows.length; i++) {
                const row = rows[i];
                // Find all the span elements within the row
                const spans = row.querySelectorAll('span');
                let hasOne = false;
                let word = '';
                for (let j = 0; j < spans.length; j++) {
                    const span = spans[j];
                    if (containsOne(span.innerHTML)) {
                        hasOne = true;
                    } else {
                        word = span.innerHTML;
                    }
                }
                // Save the word and game number to the objects if the word has the number 1 by itself and it's not already saved
                // Save the updated objects to JSONBin.io only if a new word is saved
                if (hasOne && word && !savedWords.hasOwnProperty(word)) {
                    savedWords[word] = true;
                    gameNumbers[word] = currentGameNumber; // Save the current game number instead of searching for it again
                    // Log the game number for the saved word
                    console.log(`Game number for ${word}: ${currentGameNumber}`);

                    // Save the updated objects to JSONBin.io
                    saveWordsToJSONBin();
                }

            }
        }


        // Update the GUI with the saved words and game numbers
        updateSavedWordsGUI();
    }


    // Function to reveal the word for the current game number
    function revealWordForCurrentGameNumber() {
        currentGameNumber = ''; // Clear the current game number

        // Find the game number element on the page
        const gameNumberElement = document.querySelector('.info-bar span:nth-child(2)');
        currentGameNumber = gameNumberElement ? gameNumberElement.textContent.trim().replace('#', '') : '';

        // Find the saved word for the current game number
        const savedWordsForCurrentGameNumber = Object.keys(savedWords).filter((word) => {
            return gameNumbers[word] === currentGameNumber;
        });

        // Display the saved word in an alert box
        if (savedWordsForCurrentGameNumber.length > 0) {
            alert(`The word for game number ${currentGameNumber} is: ${savedWordsForCurrentGameNumber[0]}`);
        } else {
            alert(`No saved words for game number ${currentGameNumber}. Trying to find the word in the library...`);
            fetchSavedWords();
        }
    }


const buttoncss = `
    .theme-button {
        background-color: #29a19c; /* Contexto primary color - Change this to the actual primary color */
        color: #ffffff; /* White text to contrast with the primary color */
        border: none;
        padding: 5px 13px; /* Reduce padding to make the button smaller */
        font-size: 11px; /* Reduce font size to make the button smaller */
        border-radius: 3px; /* Adjust border radius for less rounded corners */
        cursor: pointer;
        margin: 5px;
        /* Add any additional styles or adjustments you want */
    }
    .theme-button:hover {
        background-color: #45c0b5; /* Lighter shade on hover - Change this to the actual hover color */
    }
`;

// Add the CSS styles to the page
const buttonstyle = document.createElement('style');
buttonstyle.innerHTML = buttoncss;
    document.head.appendChild(buttonstyle);



// Create a button to show the saved words GUI
const showSavedWordsButton = document.createElement('button');
showSavedWordsButton.textContent = 'Saved Words';
showSavedWordsButton.classList.add('theme-button'); // Add a custom class for styling
showSavedWordsButton.addEventListener('click', () => {
    savedWordsGUI.classList.add('open');
});
document.body.appendChild(showSavedWordsButton);


// Create a button to reveal the word for the current game number
const revealButton = document.createElement('button');
revealButton.textContent = 'Reveal Word';
revealButton.classList.add('theme-button'); // Add a custom class for styling
revealButton.addEventListener('click', revealWordForCurrentGameNumber);
document.body.appendChild(revealButton);

    // Create a div element to hold the saved words GUI
    const savedWordsGUI = document.createElement('div');
    savedWordsGUI.id = 'saved-words-list';
    document.body.appendChild(savedWordsGUI);



    // Create a button to minimize the saved words GUI
    const minimizeSavedWordsButton = document.createElement('button');
    minimizeSavedWordsButton.innerHTML = '<img src="https://th.bing.com/th/id/R.6a6eda3ee63c80ebc02dc830b395324e?rik=t2E%2fYYP3IGbSsQ&pid=ImgRaw&r=0" alt="Close">';
    minimizeSavedWordsButton.addEventListener('click', () => {
        savedWordsGUI.classList.remove('open');
    });
    savedWordsGUI.appendChild(minimizeSavedWordsButton);


    // Create a list element to display the saved words
    const savedWordsList = document.createElement('ul');
    savedWordsGUI.appendChild(savedWordsList);

    // Function to update the saved words GUI with the saved words and game numbers
    function updateSavedWordsGUI() {
        // Clear the current saved words list
        savedWordsList.innerHTML = '';

        // Get all saved words sorted by game number
        const savedWordsSorted = Object.keys(gameNumbers).sort((a, b) => {
            return gameNumbers[a] - gameNumbers[b];
        });

        // Add each saved word to the list
        for (let i = 0; i < savedWordsSorted.length; i++) {
            const word = savedWordsSorted[i];
            const gameNumber = gameNumbers[word];
            const listItem = document.createElement('li');
            listItem.textContent = `${word} (Game ${gameNumber})`;
            savedWordsList.appendChild(listItem);
        }
    }

    // Update the saved words GUI with the saved words and game numbers
    updateSavedWordsGUI();

    // Function to clear the saved words and game numbers from JSONBin.io
    function clearSavedWords() {
        savedWords = {};
        gameNumbers = {};
        //saveWordsToJSONBin();
        updateSavedWordsGUI();
        alert('Saved words cleared');
    }

    // Create a button to clear the saved words and game numbers
    const clearSavedWordsButton = document.createElement('button');
    clearSavedWordsButton.textContent = 'Clear Saved Words';
    clearSavedWordsButton.addEventListener('click', clearSavedWords);
    savedWordsGUI.appendChild(clearSavedWordsButton);

    // Function to export the saved words and game numbers as JSON
    function exportSavedWords() {
        const savedWordsData = {
            savedWords: savedWords,
            gameNumbers: gameNumbers
        };
        const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(savedWordsData));
        const downloadAnchorNode = document.createElement('a');
        downloadAnchorNode.setAttribute('href', dataStr);
        downloadAnchorNode.setAttribute('download', 'contexto_saved_words.json');
        document.body.appendChild(downloadAnchorNode); // required for firefox
        downloadAnchorNode.click();
        downloadAnchorNode.remove();
    }

    // Create a button to export the saved words and game numbers
    const exportSavedWordsButton = document.createElement('button');
    exportSavedWordsButton.textContent = 'Export Saved Words';
    exportSavedWordsButton.addEventListener('click', exportSavedWords);
    savedWordsGUI.appendChild(exportSavedWordsButton);

    // Function to import saved words and game numbers from JSON
    function importSavedWords() {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.json';
        fileInput.addEventListener('change', () => {
            const file = fileInput.files[0];
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const savedWordsData = JSON.parse(e.target.result);
                    savedWords = savedWordsData.savedWords;
                    gameNumbers = savedWordsData.gameNumbers;
                    saveWordsToJSONBin();
                    updateSavedWordsGUI();
                    alert('Saved words imported');
                } catch (err) {
                    alert('Error importing saved words');
                }
            };
            reader.readAsText(file);
        });
        fileInput.click();
    }

    // Create a button to import saved words and game numbers
    const importSavedWordsButton = document.createElement('button');
    importSavedWordsButton.textContent = 'Import Saved Words';
    importSavedWordsButton.addEventListener('click', importSavedWords);
    savedWordsGUI.appendChild(importSavedWordsButton);

    // Define CSS styles for the saved words GUI
    const css = `
        #saved-words-list {
            position: fixed;
            bottom: 0;
            right: 0;
            background-color: white;
            border: 2px solid black;
            border-radius: 5px 0 0 0;
            padding: 10px;
            max-height: 300px;
            overflow-y: auto;
            display: none;
        }
        #saved-words-list.open {
            display: block;
        }
    #saved-words-list button {
        margin: 5px;
        padding: 0;
        background: none;
        border: none;
        cursor: pointer;
    }
    #saved-words-list img {
        width: 20px;
        height: 20px;
    }
`;

    // Add the CSS styles to the page
    const style = document.createElement('style');
    style.innerHTML = css;
    document.head.appendChild(style);

    // Fetch saved words and game numbers from JSONBin.io on page load
    fetchSavedWords();

    // Search for words and game numbers to save on page load and every 5 seconds
    searchForWordsAndGameNumbers();
    setInterval(searchForWordsAndGameNumbers, 17000);//17 seconds
 // Change the world list mode on page load and whenever the data-theme changes
    changeWorldListMode();
    const htmlElement = document.querySelector("html");
    const observer = new MutationObserver(changeWorldListMode);
    observer.observe(htmlElement, { attributes: true, attributeFilter: ['data-theme'] });
})();