Randomus.ru

Predictable number generation for Randomus.ru (https://randomus.ru)

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Randomus.ru
// @version      0.4
// @match        *://randomus.ru/*
// @run-at       document-start
// @description  Predictable number generation for Randomus.ru (https://randomus.ru)
// @author       Kaimi
// @homepage     https://kaimi.io/
// @license      GPLv3
// @namespace https://greasyfork.org/users/228137
// ==/UserScript==

// Initialize or retrieve persisted desired_numbers array
let storedNumbers = localStorage.getItem("desired_numbers");
let desired_numbers = storedNumbers ? JSON.parse(storedNumbers) : [62, 2, 39, 52, 335, 264];

var debug = false;
const selector = "p.subtitle.is-7.mb-3";

var num_from;
var num_to;
var button;
var file_path = undefined;

// Ensure the menu item is added after page load
window.addEventListener("load", () => {
    addMenuItem();

    num_from = document.getElementById('num_from').value;
    num_to = document.getElementById('num_to').value;
    button = document.getElementsByTagName('button')[0];

    onPageLoad();
}, false);

// Function to insert new menu item in the navbar (both desktop and mobile)
function addMenuItem() {
    // Check for desktop version (.navbar-dropdown)
    var dropdown = document.querySelector('.navbar-dropdown');
    
    if (dropdown) {
        // Desktop version found, add item to the dropdown
        insertMenuItem(dropdown);
    } else {
        // Check for mobile version (.navbar-menu and .navbar-burger)
        var burgerMenu = document.querySelector('.navbar-burger');
        var mobileMenu = document.querySelector('.navbar-menu');

        if (burgerMenu && mobileMenu) {
            // Ensure mobile menu is visible before adding menu item
            burgerMenu.addEventListener('click', () => {
                setTimeout(() => {
                    insertMenuItem(mobileMenu);
                }, 500); // Small delay to allow the menu to fully load
            });
        } else {
            console.error('Neither desktop nor mobile menu found.');
        }
    }
}

// Function to create and insert the new menu item
function insertMenuItem(parentElement) {
    // Create the new menu item
    const newMenuItem = document.createElement('a');
    newMenuItem.classList.add('navbar-item');
    newMenuItem.innerHTML = `
        <span class="icon">
            <svg class="svg-inline--fa fa-pencil-alt" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="pencil-alt" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" data-fa-i2svg="">
                <path fill="currentColor" d="M497.9 142.1l-46.1-46.1c-12.5-12.5-32.8-12.5-45.3 0l-56 56 91.4 91.4 56-56c12.5-12.6 12.5-32.8 0-45.3zm-124 124L130.6 510.3c-3.6 3.6-8.2 6.4-13.3 8.1L9.4 511.9c-10.9 3.6-22.3-7.7-18.7-18.7l7.4-107.9c1.6-5.1 4.4-9.7 8.1-13.3L245.9 138l91.4 91.4-63.7 63.7 71.9 71.9z"></path>
            </svg>
        </span> Edit Desired Numbers`;

    // Add click event to prompt for editing desired_numbers
    newMenuItem.addEventListener('click', () => {
        const input = prompt("Enter the desired numbers (comma-separated):", desired_numbers.join(", "));
        if (input !== null) {
            desired_numbers = input.split(',').map(Number).filter(n => !isNaN(n));
            localStorage.setItem("desired_numbers", JSON.stringify(desired_numbers));
            alert("Desired numbers updated!");
        }
    });

    // Append the new item to the parent element
    parentElement.appendChild(newMenuItem);
}

async function onPageLoad() {
    // Replace first-pass image
    var resultImg = document.getElementById('result_main_image');

    if (resultImg && desired_numbers.length > 0) {
        show_loader("Генерируем результаты");
        resultImg.src = '';

        // Actual image
        await replaceImage();
        hide_loader();
    }
}

async function replaceImage() {
    if (debug) {
        logVariable({ desired_numbers });
        logVariable({ num_from });
        logVariable({ num_to });
    }

    var resultImg = document.getElementById('result_main_image');

    if (resultImg) {
        // If there's an existing blob URL, revoke it
        if (resultImg.src.startsWith('blob:')) {
            URL.revokeObjectURL(resultImg.src);
        }

        var number = desired_numbers.shift();
        localStorage.setItem("desired_numbers", JSON.stringify(desired_numbers));

        var imageSrc = await processImages(number, num_from, num_to);
        resultImg.src = imageSrc;

        // Add event listener to clean up the blob URL when the image is no longer needed
        resultImg.onload = () => {
            resultImg.classList.remove('fade');
            // Optional: if you want to revoke immediately after load
            // URL.revokeObjectURL(imageSrc);
        };

        appendTimestampToElement(file_path, selector);
    }
}

async function fetchHtml(url) {
    const response = await fetch(url);
    const text = await response.text();
    const parser = new DOMParser();
    return parser.parseFromString(text, 'text/html');
}

function extractImagePath(doc) {
    const aTag = doc.querySelector('a[download]') || {};
    return aTag.href || null;
}

function loadImage(url) {
    if (debug) {
        logVariable({ url });
    }

    return new Promise((resolve, reject) => {
        const img = new Image();
        img.crossOrigin = 'Anonymous';
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.src = url;
    });
}

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function processImages(want, from, to) {
    // Construct URLs for fetching the images
    const firstUrl = '/quick?from=' + want + '&to=' + want + '&count=1';
    const secondUrl = '/quick?from=' + from + '&to=' + to + '&count=1';

    // Optionally log URLs for debugging
    if (debug) {
        logVariable({ firstUrl });
        logVariable({ secondUrl });
    }

    // Some delay because of the server
    await delay(1000);


    // Fetch and load the first image
    let doc = await fetchHtml(firstUrl);
    let imagePath = extractImagePath(doc);
    const firstImage = await loadImage(imagePath);

    file_path = imagePath;

    // Fetch and load the second image
    doc = await fetchHtml(secondUrl);
    imagePath = extractImagePath(doc);
    const secondImage = await loadImage(imagePath);

    // Create a canvas element and get the drawing context
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Set canvas dimensions
    const width = firstImage.width;
    const height = firstImage.height;
    canvas.width = width;
    canvas.height = height;

    // Draw the first image from height 0 to 400
    ctx.drawImage(firstImage, 0, 0, width, 400, 0, 0, width, 400);

    // Draw the second image from height 400 to 500
    ctx.drawImage(secondImage, 0, 400, width, 100, 0, 400, width, 100);

    // Draw the first image from height 500 to the rest of the canvas
    ctx.drawImage(firstImage, 0, 500, width, height - 500, 0, 500, width, height - 500);

    // Return the resulting image as a data URL
    return new Promise((resolve, reject) => {
        canvas.toBlob((blob) => {
            if (!blob) {
                reject(new Error('Failed to create blob'));
                return;
            }
            const url = URL.createObjectURL(blob);
            resolve(url);
        }, 'image/png');
    });
}

function appendTimestampToElement(filePath, selector) {
    const timestamp = parseTimestamp(filePath);
    if (!timestamp) return;

    const targetElement = document.querySelector(selector);
    if (!targetElement) {
        console.error("Target element not found.");
        return;
    }

    const textNode = Array.from(targetElement.childNodes).find(node => node.nodeType === Node.TEXT_NODE && node.textContent.includes('в'));
    if (!textNode) {
        console.error("Text node containing date not found.");
        return;
    }

    textNode.textContent = timestamp;
}

function parseTimestamp(filePath) {
    const timestampMatch = filePath.match(/quickw_(\d+)_/);
    if (!timestampMatch) {
        console.error("Timestamp not found in the given string.");
        return null;
    }

    const timestamp = parseInt(timestampMatch[1], 10) * 1000;
    const date = new Date(timestamp);

    const optionsDate = {
        day: '2-digit',
        month: '2-digit',
        year: 'numeric'
    };

    const optionsTime = {
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
    };

    const formattedDate = date.toLocaleDateString('ru-RU', optionsDate);
    const formattedTime = date.toLocaleTimeString('ru-RU', optionsTime);

    return `${formattedDate} в ${formattedTime}`;
}

function logVariable(varObj) {
    const timestamp = new Date().toISOString();
    const varName = Object.keys(varObj)[0];
    const varValue = varObj[varName];
    const varType = typeof varValue;

    console.log(`[${timestamp}] ${varName} (${varType}):`, varValue);
}