Nexus One Click Download

Скачивание с нексуса в 1 клик

// ==UserScript==
// @name        Nexus One Click Download
// @description:ru-RU Скачивание с нексуса в 1 клик
// @description:en-EN Nexus One Click Download
// @namespace   Violentmonkey Scripts
// @match       https://www.nexusmods.com/*/mods/*
// @grant       GM.xmlHttpRequest
// @version     1.1
// @license     MIT
// @description Скачивание с нексуса в 1 клик
// ==/UserScript==

(async function () {
    const lang = navigator.language.startsWith('ru') ? 'ru' : 'en';
    const messages = {
        ru: { error: 'ОШИБКА', loading: 'ЗАГРУЗКА...', wait: 'ОЖИДАНИЕ...', success: 'УСПЕШНО', alert: 'Ошибка при загрузке:\n' },
        en: { error: 'ERROR', loading: 'LOADING...', wait: 'WAITING...', success: 'SUCCESS', alert: 'Error occurred while downloading:\n' }
    };

    const ajax = async ({ url, method = 'GET', data = null, headers = {} }) => {
        try {
            const res = await fetch(url, { method, body: data, headers: { ...headers, 'X-Requested-With': 'XMLHttpRequest' } });
            if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
            return await res.text();
        } catch (e) {
            console.error(e);
            throw e;
        }
    };

    const setButtonState = (btn, state) => {
        btn.style.backgroundColor = { error: 'red', loading: 'black', wait: 'yellow', success: 'green' }[state];
        btn.innerText = messages[lang][state];
    };

    const handleClick = async (e) => {
        const href = e.currentTarget.href || window.location.href;
        const params = new URL(href).searchParams;

        if (!params.get('file_id')) return;

        e.preventDefault();
        const btn = e.currentTarget;
        setButtonState(btn, 'wait');

        try {
            const gameId = document.getElementById('section')?.dataset.gameId || window.current_game_id;
            const fileId = params.get('file_id') || params.get('id');
            const nmmParam = params.get('nmm');
            if (!fileId || !gameId) throw new Error('Missing parameters');

            let downloadUrl;
            if (!nmmParam) {
                const resText = await ajax({
                    url: '/Core/Libs/Common/Managers/Downloads?GenerateDownloadUrl',
                    method: 'POST',
                    data: `fid=${fileId}&game_id=${gameId}`,
                    headers: { Origin: href, Referer: href, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }
                });
                downloadUrl = JSON.parse(resText)?.url;
            } else {
                const resText = await ajax({ url: href, headers: { Origin: href, Referer: document.location.href } });
                downloadUrl = new DOMParser().parseFromString(resText, 'text/html').querySelector('#slowDownloadButton')?.dataset.downloadUrl;
            }

            if (downloadUrl) {
                setButtonState(btn, 'loading');
                setTimeout(() => (window.location.href = downloadUrl), 1000);
                setButtonState(btn, 'success');
            } else throw new Error('Download URL not found');
        } catch (err) {
            setButtonState(btn, 'error');
            alert(messages[lang].alert + err.message);
        }
    };

    const addListenersToButtons = () => {
        document.querySelectorAll('a.btn:not([data-listener])').forEach((btn) => {
            btn.addEventListener('click', handleClick);
            btn.setAttribute('data-listener', true);
        });
    };

    new MutationObserver(() => addListenersToButtons()).observe(document.body, { childList: true, subtree: true });
    addListenersToButtons();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址