Download JS

Downloads the available code from Greasy Fork's code page in .js format

// ==UserScript==
// @name         Download JS
// @name:pt-BR   Download JS
// @name:en      Download JS
// @name:es      Download JS
// @name:zh      Download JS
// @name:fr      Download JS
// @name:de      Download JS
// @name:it      Download JS
// @name:ja      Download JS
// @name:ko      Download JS
// @name:ru      Download JS
// @name:hi      Download JS
// @name:ar      Download JS
// @name:nl      Download JS
// @name:pl      Download JS
// @name:tr      Download JS
// @namespace    DownloadJS_OHAS
// @version      1.1.2
// @description  Downloads the available code from Greasy Fork's code page in .js format
// @description:pt-BR Baixa o código disponível na página de códigos do Greasy Fork em formato .js
// @description:en  Downloads the available code from Greasy Fork's code page in .js format
// @description:es Descarga el código disponible en la página de códigos de Greasy Fork en formato .js
// @description:zh 从 Greasy Fork 的代码页面下载可用代码,格式为 .js
// @description:fr Télécharge le code disponible sur la page de code de Greasy Fork au format .js
// @description:de  Lädt den verfügbaren Code von der Greasy Fork-Code-Seite im .js-Format herunter
// @description:it  Scarica il codice disponibile dalla pagina del codice di Greasy Fork in formato .js
// @description:ja  Greasy Fork のコードページから利用可能なコードを .js 形式でダウンロードします
// @description:ko  Greasy Fork의 코드 페이지에서 사용 가능한 코드를 .js 형식으로 다운로드합니다
// @description:ru  Загружает доступный код со страницы кода Greasy Fork в формате .js
// @description:hi  Greasy Fork के कोड पेज से उपलब्ध कोड को .js प्रारूप में डाउनलोड करता है
// @description:ar  يقوم بتنزيل الكود المتاح من صفحة كود Greasy Fork بتنسيق .js
// @description:nl  Downloadt de beschikbare code van de Greasy Fork-codepagina in .js-formaat
// @description:pl  Pobiera dostępny kod ze strony kodu Greasy Fork w formacie .js
// @description:tr  Greasy Fork'un kod sayfasından mevcut kodu .js formatında indirir
// @author       OHAS
// @license      MIT
// @icon         https://cdn-icons-png.flaticon.com/512/10009/10009249.png
// @match        https://greasyfork.org/*/scripts/*/code*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
  'use strict';
  const translations = {
    en: { download: 'Download', notFound: 'Code not found!' },
    'pt-BR': { download: 'Baixar', notFound: 'Código não encontrado!' },
    es: { download: 'Descargar', notFound: '¡Código no encontrado!' },
    zh: { download: '下载', notFound: '未找到代码!' },
    fr: { download: 'Télécharger', notFound: 'Code non trouvé !' },
    de: { download: 'Herunterladen', notFound: 'Code nicht gefunden!' },
    it: { download: 'Scarica', notFound: 'Codice non trovato!' },
    ja: { download: 'ダウンロード', notFound: 'コードが見つかりません!' },
    ko: { download: '다운로드', notFound: '코드를 찾을 수 없습니다!' },
    ru: { download: 'Скачать', notFound: 'Код не найден!' },
    hi: { download: 'डाउनलोड', notFound: 'कोड नहीं मिला!' },
    ar: { download: 'تحميل', notFound: 'لم يتم العثور على الكود!' },
    nl: { download: 'Downloaden', notFound: 'Code niet gevonden!' },
    pl: { download: 'Pobierz', notFound: 'Nie znaleziono kodu!' },
    tr: { download: 'İndir', notFound: 'Kod bulunamadı!' },
  };
  const lang = navigator.language;
  const primaryLang = lang.split('-')[0];
  const i18n = translations[lang] || translations[primaryLang] || translations.en;
  const waitFor = (sel) =>
    new Promise((resolve) => {
      const el = document.querySelector(sel);
      if (el) return resolve(el);
      const obs = new MutationObserver(() => {
        const el = document.querySelector(sel);
        if (el) {
          obs.disconnect();
          resolve(el);
        }
      });
      obs.observe(document, { childList: true, subtree: true });
    });
  waitFor('label[for="wrap-lines"]').then((label) => {
    const wrapLinesCheckbox = document.getElementById('wrap-lines');
    if (wrapLinesCheckbox) {
      wrapLinesCheckbox.checked = false;
    }
    const toolbar = label.parentElement;
    const btn = document.createElement('button');
    btn.className = 'btn';
    btn.textContent = i18n.download;
    btn.style.marginLeft = '12px';
    btn.style.backgroundColor = '#005200';
    btn.style.color = 'white';
    btn.style.border = 'none';
    btn.style.padding = '6px 16px';
    btn.style.borderRadius = '4px';
    btn.style.cursor = 'pointer';
    btn.addEventListener('mouseenter', () => {
      btn.style.backgroundColor = '#1e971e';
    });
    btn.addEventListener('mouseleave', () => {
      btn.style.backgroundColor = '#005200';
    });
    btn.addEventListener('click', () => {
      let code = '';
      const liLines = document.querySelectorAll('pre.prettyprint.lang-js li');
      if (liLines.length) {
        code = [...liLines].map((li) => li.textContent).join('\n');
      }
      if (!code) {
        const preBlock = document.querySelector('#script-content > div.code-container > pre');
        if (preBlock) {
          code = preBlock.textContent;
        }
      }
      if (!code) {
        alert(i18n.notFound);
        return;
      }
      const nameMatch = code.match(/\/\/\s*@name\s+(.+)/i);
      const fileName = nameMatch ? `${nameMatch[1].trim()}.js` : 'script.js';
      const blob = new Blob([code], { type: 'application/javascript' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = fileName;
      a.style.display = 'none';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    });
    toolbar.appendChild(btn);
  });
})();