Nexus One Click Download

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

目前為 2025-03-31 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Nexus One Click Download
  3. // @description Скачивание с нексуса в 1 клик
  4. // @description:en Nexus One Click Download
  5. // @namespace Violentmonkey Scripts
  6. // @match https://www.nexusmods.com/*/mods/*
  7. // @grant GM.xmlHttpRequest
  8. // @version 1.0
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (async function () {
  13. const lang = navigator.language.startsWith('ru') ? 'ru' : 'en';
  14. const messages = {
  15. ru: { error: 'ОШИБКА', loading: 'ЗАГРУЗКА...', wait: 'ОЖИДАНИЕ...', success: 'УСПЕШНО', alert: 'Ошибка при загрузке:\n' },
  16. en: { error: 'ERROR', loading: 'LOADING...', wait: 'WAITING...', success: 'SUCCESS', alert: 'Error occurred while downloading:\n' }
  17. };
  18.  
  19. const ajax = async ({ url, method = 'GET', data = null, headers = {} }) => {
  20. try {
  21. const res = await fetch(url, { method, body: data, headers: { ...headers, 'X-Requested-With': 'XMLHttpRequest' } });
  22. if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
  23. return await res.text();
  24. } catch (e) {
  25. console.error(e);
  26. throw e;
  27. }
  28. };
  29.  
  30. const setButtonState = (btn, state) => {
  31. btn.style.backgroundColor = { error: 'red', loading: 'black', wait: 'yellow', success: 'green' }[state];
  32. btn.innerText = messages[lang][state];
  33. };
  34.  
  35. const handleClick = async (e) => {
  36. const href = e.currentTarget.href || window.location.href;
  37. const params = new URL(href).searchParams;
  38.  
  39. if (!params.get('file_id')) return;
  40.  
  41. e.preventDefault();
  42. const btn = e.currentTarget;
  43. setButtonState(btn, 'wait');
  44.  
  45. try {
  46. const gameId = document.getElementById('section')?.dataset.gameId || window.current_game_id;
  47. const fileId = params.get('file_id') || params.get('id');
  48. const nmmParam = params.get('nmm');
  49. if (!fileId || !gameId) throw new Error('Missing parameters');
  50.  
  51. let downloadUrl;
  52. if (!nmmParam) {
  53. const resText = await ajax({
  54. url: '/Core/Libs/Common/Managers/Downloads?GenerateDownloadUrl',
  55. method: 'POST',
  56. data: `fid=${fileId}&game_id=${gameId}`,
  57. headers: { Origin: href, Referer: href, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }
  58. });
  59. downloadUrl = JSON.parse(resText)?.url;
  60. } else {
  61. const resText = await ajax({ url: href, headers: { Origin: href, Referer: document.location.href } });
  62. downloadUrl = new DOMParser().parseFromString(resText, 'text/html').querySelector('#slowDownloadButton')?.dataset.downloadUrl;
  63. }
  64.  
  65. if (downloadUrl) {
  66. setButtonState(btn, 'loading');
  67. setTimeout(() => (window.location.href = downloadUrl), 1000);
  68. setButtonState(btn, 'success');
  69. } else throw new Error('Download URL not found');
  70. } catch (err) {
  71. setButtonState(btn, 'error');
  72. alert(messages[lang].alert + err.message);
  73. }
  74. };
  75.  
  76. const addListenersToButtons = () => {
  77. document.querySelectorAll('a.btn:not([data-listener])').forEach((btn) => {
  78. btn.addEventListener('click', handleClick);
  79. btn.setAttribute('data-listener', true);
  80. });
  81. };
  82.  
  83. new MutationObserver(() => addListenersToButtons()).observe(document.body, { childList: true, subtree: true });
  84. addListenersToButtons();
  85. })();