您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
增强 Greasy Fork,在标题旁显示脚本图标,为编辑器(评论和描述)添加 Markdown 格式工具栏,可在代码页面直接下载 .user.js 文件,并改进页面设计。
// ==UserScript== // @name Better Greasy Fork // @name:pt-BR Greasy Fork Aprimorado // @name:zh-CN 更好的 Greasy Fork // @name:zh-TW 更好的 Greasy Fork // @name:en Better Greasy Fork // @name:es Greasy Fork Mejorado // @name:ja 改良版 Greasy Fork // @name:ko 향상된 Greasy Fork // @name:de Verbesserter Greasy Fork // @name:fr Greasy Fork Amélioré // @namespace https://github.com/0H4S // @version 1.0 // @description Enhances Greasy Fork by displaying the script icon next to the title, adding a Markdown formatting toolbar to the editor (for comments and descriptions), allowing the script to be downloaded as a .user.js file directly from the code page, and improving the overall page design. // @description:pt-BR Aprimora o Greasy Fork exibindo o ícone do script ao lado do título, adiciona uma barra de formatação Markdown ao editor (para comentários e descrições), permite baixar o script como um arquivo .user.js diretamente na página de código e traz outras melhorias ao design da página. // @description:zh-CN 增强 Greasy Fork,在标题旁显示脚本图标,为编辑器(评论和描述)添加 Markdown 格式工具栏,可在代码页面直接下载 .user.js 文件,并改进页面设计。 // @description:zh-TW 增強 Greasy Fork,在標題旁顯示腳本圖示,為編輯器(評論與描述)新增 Markdown 格式工具列,可在程式碼頁面直接下載 .user.js 檔案,並改進頁面設計。 // @description:en Enhances Greasy Fork by displaying the script icon next to the title, adding a Markdown formatting toolbar to the editor (for comments and descriptions), allowing the script to be downloaded as a .user.js file directly from the code page, and improving the overall page design. // @description:es Mejora Greasy Fork mostrando el icono del script junto al título, añade una barra de formato Markdown al editor (para comentarios y descripciones), permite descargar el script como archivo .user.js directamente desde la página de código y mejora el diseño general de la página. // @description:ja Greasy Fork を強化し、タイトルの横にスクリプトアイコンを表示、エディター(コメントと説明)に Markdown 書式ツールバーを追加し、コードページから直接 .user.js ファイルとしてスクリプトをダウンロードできるようにし、ページ全体のデザインを改善します。 // @description:ko Greasy Fork를 개선하여 제목 옆에 스크립트 아이콘을 표시하고, 편집기(댓글 및 설명)에 Markdown 서식 도구 모음을 추가하며, 코드 페이지에서 .user.js 파일로 직접 스크립트를 다운로드할 수 있게 하고, 페이지 디자인 전반을 개선합니다. // @description:de Verbessert Greasy Fork, indem das Skriptsymbol neben dem Titel angezeigt wird, fügt dem Editor (für Kommentare und Beschreibungen) eine Markdown-Formatierungsleiste hinzu, ermöglicht das direkte Herunterladen des Skripts als .user.js-Datei von der Code-Seite und verbessert das gesamte Seitendesign. // @description:fr Améliore Greasy Fork en affichant l’icône du script à côté du titre, ajoute une barre de mise en forme Markdown à l’éditeur (pour les commentaires et descriptions), permet de télécharger le script au format .user.js directement depuis la page du code, et améliore le design général de la page. // @author OHAS // @license CC-BY-NC-ND-4.0 // @copyright 2025 OHAS. All Rights Reserved. (https://gist.github.com/0H4S/ae2fa82957a089576367e364cbf02438) // @icon https://gist.githubusercontent.com/0H4S/0f1517e84b8f0aaa2d1f26e853096f62/raw/BGF_icon.svg // @match https://greasyfork.org/* // @require https://update.greasyfork.org/scripts/549920/Script%20Notifier.js // @connect update.greasyfork.org // @connect gist.githubusercontent.com // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @compatible chrome // @compatible firefox // @compatible edge // @run-at document-idle // ==/UserScript== (function () { 'use strict'; if (window.top !== window.self) { return; } const SCRIPT_CONFIG = { notificationsUrl: 'https://gist.githubusercontent.com/0H4S/1eee8eb439b554860274686143eda3f9/raw/better_greasy_fork.notifications.json', scriptVersion: '1.0', }; const notifier = new ScriptNotifier(SCRIPT_CONFIG); notifier.run(); // ================ // SESSÃO ÍCONES // ================ const CACHE_KEY = 'Icons'; let iconCache; const processedKeys = new Set(); async function saveCache() { await GM_setValue(CACHE_KEY, iconCache); } function normalizeScriptPath(pathname) { let withoutLocale = pathname.replace(/^\/[a-z]{2}(?:-[A-Z]{2})?\//, '/'); const match = withoutLocale.match(/^\/scripts\/\d+-.+?(?=\/|$)/); return match ? match[0] : null; } function extractScriptIdFromNormalizedPath(normalized) { const match = normalized.match(/\/scripts\/(\d+)-/); return match ? match[1] : null; } function createIconElement(src, isHeader = false) { const img = document.createElement('img'); img.src = src; img.alt = ''; if (isHeader) { img.style.cssText = ` width: 80px; height: 80px; margin-right: 10px; vertical-align: middle; border-radius: 4px; object-fit: contain; pointer-events: none; `; } else { img.style.cssText = ` width: 40px; height: 40px; margin-right: 8px; vertical-align: middle; border-radius: 3px; object-fit: contain; pointer-events: none; `; } img.loading = 'lazy'; return img; } function extractIconFromContent(content) { if (typeof content !== 'string') return null; const match = content.match(/\/\/\s*@icon\s+(.+)/i); return match ? match[1].trim() : null; } function isValidIconUrl(url) { return url && (url.startsWith('http') || url.startsWith('')); } async function processScript(normalizedPath, targetElement, isHeader = false) { if (processedKeys.has(normalizedPath)) { const cached = iconCache[normalizedPath]; if (cached && isValidIconUrl(cached.iconUrl)) { targetElement.prepend(createIconElement(cached.iconUrl, isHeader)); } return; } processedKeys.add(normalizedPath); const cached = iconCache[normalizedPath]; const now = Date.now(); if (cached && now - cached.ts < 30 * 24 * 60 * 60 * 1000 && isValidIconUrl(cached.iconUrl)) { targetElement.prepend(createIconElement(cached.iconUrl, isHeader)); return; } const scriptId = extractScriptIdFromNormalizedPath(normalizedPath); if (!scriptId) { iconCache[normalizedPath] = { iconUrl: null, ts: now }; await saveCache(); return; } const scriptUrl = `https://update.greasyfork.org/scripts/${scriptId}.js`; GM_xmlhttpRequest({ method: 'GET', url: scriptUrl, timeout: 6000, onload: async function (res) { if (typeof res.responseText !== 'string') { iconCache[normalizedPath] = { iconUrl: null, ts: now }; await saveCache(); return; } const iconUrl = extractIconFromContent(res.responseText); if (isValidIconUrl(iconUrl)) { iconCache[normalizedPath] = { iconUrl, ts: now }; await saveCache(); targetElement.prepend(createIconElement(iconUrl, isHeader)); } else { iconCache[normalizedPath] = { iconUrl: null, ts: now }; await saveCache(); } }, onerror: async function () { iconCache[normalizedPath] = { iconUrl: null, ts: now }; await saveCache(); } }); } function handleScriptLink(linkEl) { if (linkEl._handled) return; linkEl._handled = true; const href = linkEl.getAttribute('href'); if (!href || !href.startsWith('/')) return; try { const url = new URL(href, window.location.origin); const normalized = normalizeScriptPath(url.pathname); if (!normalized) return; setTimeout(() => processScript(normalized, linkEl, false), 0); } catch (e) {} } function handleMainHeaderH2() { const headers = document.querySelectorAll('header'); for (const header of headers) { const h2 = header.querySelector('h2'); const desc = header.querySelector('p.script-description'); if (h2 && desc && !h2._handled) { h2._handled = true; const normalized = normalizeScriptPath(window.location.pathname); if (!normalized) return; setTimeout(() => processScript(normalized, h2, true), 0); break; } } } function processIconElements() { document.querySelectorAll('a.script-link:not([data-icon-processed])') .forEach(el => { el.setAttribute('data-icon-processed', '1'); handleScriptLink(el); }); handleMainHeaderH2(); } // ================ // SESSÃO GLOBAL // ================ const translations = { 'en': { langName: 'English', languageSettings: '🌐 Language', close: 'Close', titles: 'Headings', title_placeholder: 'Heading', bold: 'Bold', bold_placeholder: 'bold text', italic: 'Italic', italic_placeholder: 'italic text', underline: 'Underline', underline_placeholder: 'underlined text', strikethrough: 'Strikethrough', strikethrough_placeholder: 'strikethrough text', unordered_list: 'Unordered List', list_item_placeholder: 'Item', ordered_list: 'Ordered List', quote: 'Quote', quote_placeholder: 'Quote', inline_code: 'Inline Code', inline_code_placeholder: 'code', code_block: 'Code Block', code_block_placeholder: 'code here', horizontal_line: 'Horizontal Line', link: 'Link', prompt_insert_url: 'Enter the URL:', link_text_placeholder: 'link text', image: 'Image', prompt_insert_image_url: 'Enter the image URL (https):', table: 'Table', prompt_columns: 'Number of columns:', prompt_rows: 'Number of rows:', table_header_placeholder: 'Header', table_cell_placeholder: 'Cell', video: 'Video (YouTube/Bilibili)', prompt_insert_video_url: 'Enter the video URL (YouTube or Bilibili):', alert_invalid_video_url: 'Invalid or unsupported video URL.', subscript: 'Subscript', subscript_placeholder: 'sub', superscript: 'Superscript', superscript_placeholder: 'sup', highlight: 'Highlight', highlight_placeholder: 'highlighted', keyboard: 'Keyboard', keyboard_placeholder: 'Ctrl+C', abbreviation: 'Abbreviation', prompt_abbreviation_meaning: 'What does the abbreviation stand for?', abbreviation_placeholder: 'HTML', text_color: 'Text Color', colored_text_placeholder: 'colored text', background_color: 'Background Color', colored_background_placeholder: 'colored background', download: 'Download', notFound: 'Code not found!', scriptIdNotFound: 'Could not identify the script ID.', downloading: 'Downloading...', downloadError: 'An error occurred while downloading the script.', downloadTimeout: 'The script download timed out.' }, 'pt-BR': { langName: 'Português (BR)', languageSettings: '🌐 Idioma', close: 'Fechar', titles: 'Títulos', title_placeholder: 'Título', bold: 'Negrito', bold_placeholder: 'negrito', italic: 'Itálico', italic_placeholder: 'itálico', underline: 'Sublinhado', underline_placeholder: 'sublinhado', strikethrough: 'Riscado', strikethrough_placeholder: 'riscado', unordered_list: 'Lista não ordenada', list_item_placeholder: 'Item', ordered_list: 'Lista ordenada', quote: 'Citação', quote_placeholder: 'Citação', inline_code: 'Código Inline', inline_code_placeholder: 'código', code_block: 'Bloco de Código', code_block_placeholder: 'código aqui', horizontal_line: 'Linha Horizontal', link: 'Link', prompt_insert_url: 'Insira a URL:', link_text_placeholder: 'texto do link', image: 'Imagem', prompt_insert_image_url: 'Insira a URL da imagem (https):', table: 'Tabela', prompt_columns: 'Número de colunas:', prompt_rows: 'Número de linhas:', table_header_placeholder: 'Cabeçalho', table_cell_placeholder: 'Célula', video: 'Vídeo (YouTube/Bilibili)', prompt_insert_video_url: 'Insira a URL do vídeo (YouTube ou Bilibili):', alert_invalid_video_url: 'URL de vídeo inválida ou não suportada.', subscript: 'Subscrito', subscript_placeholder: 'sub', superscript: 'Sobrescrito', superscript_placeholder: 'sup', highlight: 'Marcação', highlight_placeholder: 'marcado', keyboard: 'Teclado', keyboard_placeholder: 'Ctrl+C', abbreviation: 'Abreviação', prompt_abbreviation_meaning: 'Qual o significado da abreviação?', abbreviation_placeholder: 'HTML', text_color: 'Cor do Texto', colored_text_placeholder: 'texto colorido', background_color: 'Cor de Fundo', colored_background_placeholder: 'fundo colorido', download: 'Baixar', notFound: 'Código não encontrado!', scriptIdNotFound: 'Não foi possível identificar o ID do script.', downloading: 'Baixando...', downloadError: 'Ocorreu um erro ao baixar o script.', downloadTimeout: 'O tempo para baixar o script esgotou.' }, 'es': { langName: 'Español', languageSettings: '🌐 Idioma', close: 'Cerrar', titles: 'Títulos', title_placeholder: 'Título', bold: 'Negrita', bold_placeholder: 'texto en negrita', italic: 'Cursiva', italic_placeholder: 'texto en cursiva', underline: 'Subrayado', underline_placeholder: 'texto subrayado', strikethrough: 'Tachado', strikethrough_placeholder: 'texto tachado', unordered_list: 'Lista sin ordenar', list_item_placeholder: 'Elemento', ordered_list: 'Lista ordenada', quote: 'Cita', quote_placeholder: 'Cita', inline_code: 'Código en línea', inline_code_placeholder: 'código', code_block: 'Bloque de código', code_block_placeholder: 'código aquí', horizontal_line: 'Línea horizontal', link: 'Enlace', prompt_insert_url: 'Introduzca la URL:', link_text_placeholder: 'texto del enlace', image: 'Imagen', prompt_insert_image_url: 'Introduzca la URL de la imagen (https):', table: 'Tabla', prompt_columns: 'Número de columnas:', prompt_rows: 'Número de filas:', table_header_placeholder: 'Encabezado', table_cell_placeholder: 'Celda', video: 'Video (YouTube/Bilibili)', prompt_insert_video_url: 'Introduzca la URL del video (YouTube o Bilibili):', alert_invalid_video_url: 'URL de video no válida o no compatible.', subscript: 'Subíndice', subscript_placeholder: 'sub', superscript: 'Superíndice', superscript_placeholder: 'sup', highlight: 'Resaltado', highlight_placeholder: 'resaltado', keyboard: 'Teclado', keyboard_placeholder: 'Ctrl+C', abbreviation: 'Abreviatura', prompt_abbreviation_meaning: '¿Qué significa la abreviatura?', abbreviation_placeholder: 'HTML', text_color: 'Color del texto', colored_text_placeholder: 'texto coloreado', background_color: 'Color de fondo', colored_background_placeholder: 'fondo coloreado', download: 'Descargar', notFound: '¡Código no encontrado!', scriptIdNotFound: 'No se pudo identificar el ID del script.', downloading: 'Descargando...', downloadError: 'Ocurrió un error al descargar el script.', downloadTimeout: 'Se agotó el tiempo de espera para la descarga del script.' }, 'zh-CN': { langName: '简体中文', languageSettings: '🌐 语言', close: '关闭', titles: '标题', title_placeholder: '标题', bold: '粗体', bold_placeholder: '粗体文本', italic: '斜体', italic_placeholder: '斜体文本', underline: '下划线', underline_placeholder: '下划线文本', strikethrough: '删除线', strikethrough_placeholder: '删除线文本', unordered_list: '无序列表', list_item_placeholder: '项目', ordered_list: '有序列表', quote: '引用', quote_placeholder: '引用', inline_code: '行内代码', inline_code_placeholder: '代码', code_block: '代码块', code_block_placeholder: '在此处编写代码', horizontal_line: '水平线', link: '链接', prompt_insert_url: '请输入网址:', link_text_placeholder: '链接文本', image: '图片', prompt_insert_image_url: '请输入图片网址 (https):', table: '表格', prompt_columns: '列数:', prompt_rows: '行数:', table_header_placeholder: '标题', table_cell_placeholder: '单元格', video: '视频 (YouTube/Bilibili)', prompt_insert_video_url: '请输入视频网址 (YouTube or Bilibili):', alert_invalid_video_url: '无效或不支持的视频网址。', subscript: '下标', subscript_placeholder: '下标', superscript: '上标', superscript_placeholder: '上标', highlight: '标记', highlight_placeholder: '标记', keyboard: '键盘', keyboard_placeholder: 'Ctrl+C', abbreviation: '缩写', prompt_abbreviation_meaning: '缩写的含义是什么?', abbreviation_placeholder: 'HTML', text_color: '文字颜色', colored_text_placeholder: '彩色文本', background_color: '背景颜色', colored_background_placeholder: '彩色背景', download: '下载', notFound: '未找到代码!', scriptIdNotFound: '无法识别脚本 ID。', downloading: '下载中...', downloadError: '下载脚本时发生错误。', downloadTimeout: '脚本下载超时。' } }; let currentLang = 'en'; let languageModal = null; const LANG_STORAGE_KEY = 'UserScriptLang'; function getTranslation(key) { return translations[currentLang] ?.[key] || translations.en[key]; } async function determineLanguage() { const savedLang = await GM_getValue(LANG_STORAGE_KEY); if (savedLang && translations[savedLang]) { currentLang = savedLang; return; } const browserLang = (navigator.language || navigator.userLanguage).toLowerCase(); if (browserLang.startsWith('pt')) currentLang = 'pt-BR'; else if (browserLang.startsWith('es')) currentLang = 'es'; else if (browserLang.startsWith('zh')) currentLang = 'zh-CN'; else currentLang = 'en'; } function registerLanguageMenu() { GM_registerMenuCommand(getTranslation('languageSettings'), () => { showModal(languageModal); }); } const icons = { h: `<svg viewBox="0 0 16 16"><path d="M3.75 2a.75.75 0 0 1 .75.75V7h7V2.75a.75.75 0 0 1 1.5 0v10.5a.75.75 0 0 1-1.5 0V8.5h-7v4.75a.75.75 0 0 1-1.5 0V2.75A.75.75 0 0 1 3.75 2Z"></path></svg>`, bold: `<svg viewBox="0 0 16 16"><path d="M4 2h4.5a3.5 3.5 0 0 1 2.85 5.53A3.5 3.5 0 0 1 9.5 14H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Zm1 7v3h4.5a1.5 1.5 0 0 0 0-3Zm3.5-2a1.5 1.5 0 0 0 0-3H5v3Z"></path></svg>`, italic: `<svg viewBox="0 0 16 16"><path d="M6 2.75A.75.75 0 0 1 6.75 2h6.5a.75.75 0 0 1 0 1.5h-2.505l-3.858 9H9.25a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.505l3.858-9H6.75A.75.75 0 0 1 6 2.75Z"></path></svg>`, underline: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M11 1h2v6.5c0 2.485-2.239 4.5-5 4.5S3 9.985 3 7.5V1h2v6.5c0 .628.285 1.23.802 1.695C6.379 9.714 7.159 10 8 10s1.621-.286 2.198-.805C10.715 8.729 11 8.127 11 7.5V1zM3 13h10v2H3z"/></svg>`, strikethrough: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor" d="M952 474H569.9c-10-2-20.5-4-31.6-6c-15.9-2.9-22.2-4.1-30.8-5.8c-51.3-10-82.2-20-106.8-34.2c-35.1-20.5-52.2-48.3-52.2-85.1c0-37 15.2-67.7 44-89c28.4-21 68.8-32.1 116.8-32.1c54.8 0 97.1 14.4 125.8 42.8c14.6 14.4 25.3 32.1 31.8 52.6c1.3 4.1 2.8 10 4.3 17.8c.9 4.8 5.2 8.2 9.9 8.2h72.8c5.6 0 10.1-4.6 10.1-10.1v-1c-.7-6.8-1.3-12.1-2-16c-7.3-43.5-28-81.7-59.7-110.3c-44.4-40.5-109.7-61.8-188.7-61.8c-72.3 0-137.4 18.1-183.3 50.9c-25.6 18.4-45.4 41.2-58.6 67.7c-13.5 27.1-20.3 58.4-20.3 92.9c0 29.5 5.7 54.5 17.3 76.5c8.3 15.7 19.6 29.5 34.1 42H72c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h433.2c2.1.4 3.9.8 5.9 1.2c30.9 6.2 49.5 10.4 66.6 15.2c23 6.5 40.6 13.3 55.2 21.5c35.8 20.2 53.3 49.2 53.3 89c0 35.3-15.5 66.8-43.6 88.8c-30.5 23.9-75.6 36.4-130.5 36.4c-43.7 0-80.7-8.5-110.2-25c-29.1-16.3-49.1-39.8-59.7-69.5c-.8-2.2-1.7-5.2-2.7-9c-1.2-4.4-5.3-7.5-9.7-7.5h-79.7c-5.6 0-10.1 4.6-10.1 10.1v1c.2 2.3.4 4.2.6 5.7c6.5 48.8 30.3 88.8 70.7 118.8c47.1 34.8 113.4 53.2 191.8 53.2c84.2 0 154.8-19.8 204.2-57.3c25-18.9 44.2-42.2 57.1-69c13-27.1 19.7-57.9 19.7-91.5c0-31.8-5.8-58.4-17.8-81.4c-5.8-11.2-13.1-21.5-21.8-30.8H952c4.4 0 8-3.6 8-8v-60a8 8 0 0 0-8-7.9z"/></svg>`, link: `<svg viewBox="0 0 16 16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .75.75 0 0 1 1.06-1.06 2 2 0 0 0 2.83 0l2.5-2.5a2 2 0 0 0-2.83-2.83l-1.25 1.25a.75.75 0 0 1-1.06-1.06Zm-4.69 9.64a2 2 0 0 0 2.83 0l1.25-1.25a.75.75 0 0 1 1.06 1.06l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .75.75 0 0 1-1.06 1.06 2 2 0 0 0-2.83 0l-2.5 2.5a2 2 0 0 0 0 2.83Z"></path></svg>`, quote: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 304 384"><path fill="currentColor" d="m21 299l43-86H0V85h128v128l-43 86H21zm171 0l43-86h-64V85h128v128l-43 86h-64z"/></svg>`, code: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m.586 12l4.95-4.95L6.95 8.464L3.414 12l3.536 3.536l-1.414 1.414L.586 12Zm8.201 8.728l4.486-17.94l1.94.485l-4.485 17.94l-1.94-.485Zm8.263-5.192L20.586 12L17.05 8.464l1.415-1.414l4.95 4.95l-4.95 4.95l-1.415-1.414Z"/></svg>`, code_block: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path id="oouiCode0" fill="currentColor" d="M1 10.08V8.92h1.15c1.15 0 1.15 0 1.15-1.15V5a7.42 7.42 0 0 1 .09-1.3a2 2 0 0 1 .3-.7a1.84 1.84 0 0 1 .93-.68A6.44 6.44 0 0 1 6.74 2h1.18v1.15h-.86A1.32 1.32 0 0 0 6 3.62a1.71 1.71 0 0 0-.36 1.23V7a3.22 3.22 0 0 1-.28 1.72a2 2 0 0 1-1.26.77a2.15 2.15 0 0 1 1.26.79A3.26 3.26 0 0 1 5.62 12v3.15A1.67 1.67 0 0 0 6 16.37a1.31 1.31 0 0 0 1.08.47h.87V18H6.74a6.3 6.3 0 0 1-2.12-.29a1.82 1.82 0 0 1-.93-.71a1.94 1.94 0 0 1-.3-.72A7.46 7.46 0 0 1 3.31 15v-3.77c0-1.15 0-1.15-1.15-1.15zm18 0V8.92h-1.15c-1.15 0-1.15 0-1.15-1.15V5a7.42 7.42 0 0 0-.08-1.32a2 2 0 0 0-.3-.73a1.84 1.84 0 0 0-.93-.68A6.44 6.44 0 0 0 13.26 2h-1.18v1.15h.87a1.32 1.32 0 0 1 1.05.47a1.71 1.71 0 0 1 .36 1.23V7a3.22 3.22 0 0 0 .28 1.72a2 2 0 0 0 1.26.77a2.15 2.15 0 0 0-1.26.79a3.26 3.26 0 0 0-.26 1.72v3.15a1.67 1.67 0 0 1-.38 1.22a1.31 1.31 0 0 1-1.08.47h-.87V18h1.19a6.3 6.3 0 0 0 2.12-.29a1.82 1.82 0 0 0 .93-.68a1.94 1.94 0 0 0 .3-.72a7.46 7.46 0 0 0 .1-1.31v-3.77c0-1.15 0-1.15 1.15-1.15z"/><use href="#oouiCode0" transform="matrix(-1 0 0 1 20 0)"/></svg>`, ul: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1025 1024"><path fill="currentColor" d="M960.356 1024h-512q-27 0-45.5-19t-18.5-45V832q0-26 18.5-45t45.5-19h512q26 0 45 19t19 45v128q0 27-19 45.5t-45 18.5zm0-384h-512q-27 0-45.5-18.5t-18.5-45.5V448q0-27 18.5-45.5t45.5-18.5h512q26 0 45 18.5t19 45.5v128q0 27-19 45.5t-45 18.5zm0-384h-512q-27 0-45.5-19t-18.5-45V64q0-27 18.5-45.5t45.5-18.5h512q26 0 45 18.5t19 45.5v128q0 26-19 45t-45 19zm-768 768h-128q-26 0-45-19t-19-45V832q0-26 19-45t45-19h128q26 0 45 19t19 45v128q0 27-18.5 45.5t-45.5 18.5zm0-384h-128q-26 0-45-18.5t-19-45.5V448q0-27 19-45.5t45-18.5h128q26 0 45 18.5t19 45.5v128q0 27-18.5 45.5t-45.5 18.5zm0-384h-128q-26 0-45-19t-19-45V64q0-27 19-45.5t45-18.5h128q26 0 45 18.5t19 45.5v128q0 26-18.5 45t-45.5 19z"/></svg>`, ol: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M3.684 1.01c.193.045.33.21.33.402v3.294a.42.42 0 0 1-.428.412a.42.42 0 0 1-.428-.412V2.58a3.11 3.11 0 0 1-.664.435a.436.436 0 0 1-.574-.184a.405.405 0 0 1 .192-.552c.353-.17.629-.432.82-.661a2.884 2.884 0 0 0 .27-.388a.44.44 0 0 1 .482-.22Zm-1.53 6.046a.401.401 0 0 1 0-.582l.002-.001V6.47l.004-.002l.008-.008a1.12 1.12 0 0 1 .103-.084a2.2 2.2 0 0 1 1.313-.435h.007c.32.004.668.084.947.283c.295.21.485.536.485.951c0 .452-.207.767-.488.992c-.214.173-.49.303-.714.409c-.036.016-.07.033-.103.049c-.267.128-.468.24-.61.39a.763.763 0 0 0-.147.22h1.635a.42.42 0 0 1 .427.411a.42.42 0 0 1-.428.412H2.457a.42.42 0 0 1-.428-.412c0-.51.17-.893.446-1.184c.259-.275.592-.445.86-.574c.043-.02.085-.04.124-.06c.231-.11.4-.19.529-.293c.12-.097.18-.193.18-.36c0-.148-.057-.23-.14-.289a.816.816 0 0 0-.448-.122a1.32 1.32 0 0 0-.818.289l-.005.005a.44.44 0 0 1-.602-.003Zm.94 5.885a.42.42 0 0 1 .427-.412c.294 0 .456-.08.537-.15a.303.303 0 0 0 .11-.246c-.006-.16-.158-.427-.647-.427c-.352 0-.535.084-.618.137a.349.349 0 0 0-.076.062l-.003.004a.435.435 0 0 0 .01-.018v.001l-.002.002l-.002.004l-.003.006l-.005.008l.002-.003a.436.436 0 0 1-.563.165a.405.405 0 0 1-.191-.552v-.002l.002-.003l.003-.006l.008-.013a.71.71 0 0 1 .087-.12c.058-.067.142-.146.259-.22c.238-.153.59-.276 1.092-.276c.88 0 1.477.556 1.502 1.22c.012.303-.1.606-.339.84c.238.232.351.535.34.838c-.026.664-.622 1.22-1.503 1.22c-.502 0-.854-.122-1.092-.275a1.19 1.19 0 0 1-.326-.308a.71.71 0 0 1-.02-.033l-.008-.013l-.003-.005l-.001-.003v-.001l-.001-.001a.405.405 0 0 1 .19-.553a.436.436 0 0 1 .564.165l.003.004c.01.01.033.035.076.063c.083.053.266.137.618.137c.489 0 .641-.268.648-.428a.303.303 0 0 0-.11-.245c-.082-.072-.244-.151-.538-.151a.42.42 0 0 1-.427-.412ZM7.75 3a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5Zm0 4a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5Zm0 4a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5Z"/></svg>`, image: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 42 42"><path fill="currentColor" d="M.5 7.5v27c0 2.52.51 3 3 3h34c2.471 0 3-.46 3-3v-27c0-2.46-.471-3-3-3h-34c-2.48 0-3 .43-3 3zm35.29 23H5.23c3.34-4.87 9.279-12.99 10.789-12.99c1.461 0 6.42 6.561 8.661 8.87c0 0 2.881-3.851 4.391-3.851c1.538 0 6.669 7.931 6.719 7.971zm-8.979-17c0-2.04 1.649-3.689 3.689-3.689s3.689 1.649 3.689 3.689s-1.649 3.689-3.689 3.689s-3.689-1.649-3.689-3.689z"/></svg>`, video: `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1024 768"><path fill="currentColor" d="M928 736q-222 32-416 32q-86 0-190-8t-165-16l-61-8q-27-5-47.5-37.5t-30-78.5t-14-86T0 461V307Q0 52 96 32Q318 0 512 0q86 0 190 8t165 16l61 8q29 4 49.5 36.5T1007 148t13 86t4 73v154q0 36-3 73t-12 85t-30 80t-51 37zM693 359L431 199q-11-10-29-5.5T384 208v352q0 11 18 15t29-6l262-160q11-10 11-25t-11-25z"/></svg>`, subscript: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M32 64C14.3 64 0 78.3 0 96s14.3 32 32 32h15.3l89.6 128l-89.6 128H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h32c10.4 0 20.2-5.1 26.2-13.6L176 311.8l85.8 122.6c6 8.6 15.8 13.6 26.2 13.6h32c17.7 0 32-14.3 32-32s-14.3-32-32-32h-15.3l-89.6-128l89.6-128H320c17.7 0 32-14.3 32-32s-14.3-32-32-32h-32c-10.4 0-20.2 5.1-26.2 13.6L176 200.2L90.2 77.6C84.2 69.1 74.4 64 64 64H32zm448 256c0-11.1-5.7-21.4-15.2-27.2s-21.2-6.4-31.1-1.4l-32 16c-15.8 7.9-22.2 27.1-14.3 42.9C393 361.5 404.3 368 416 368v80c-17.7 0-32 14.3-32 32s14.3 32 32 32h64c17.7 0 32-14.3 32-32s-14.3-32-32-32V320z"/></svg>`, superscript: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M480 32c0-11.1-5.7-21.4-15.2-27.2s-21.2-6.4-31.1-1.4l-32 16c-15.8 7.9-22.2 27.1-14.3 42.9C393 73.5 404.3 80 416 80v80c-17.7 0-32 14.3-32 32s14.3 32 32 32h64c17.7 0 32-14.3 32-32s-14.3-32-32-32V32zM32 64C14.3 64 0 78.3 0 96s14.3 32 32 32h15.3l89.6 128l-89.6 128H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h32c10.4 0 20.2-5.1 26.2-13.6L176 311.8l85.8 122.6c6 8.6 15.8 13.6 26.2 13.6h32c17.7 0 32-14.3 32-32s-14.3-32-32-32h-15.3l-89.6-128l89.6-128H320c17.7 0 32-14.3 32-32s-14.3-32-32-32h-32c-10.4 0-20.2 5.1-26.2 13.6L176 200.2L90.2 77.6C84.2 69.1 74.4 64 64 64H32z"/></svg>`, highlight: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill="currentColor" d="M16.5 3v4a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5V3h13Zm-10 7.5v7l6.447-3.106a1 1 0 0 0 .553-.894v-3h-7Z"/></svg>`, abbreviation: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><path fill="currentColor" d="M20 424.229h20V279.771H20c-11.046 0-20-8.954-20-20V212c0-11.046 8.954-20 20-20h112c11.046 0 20 8.954 20 20v212.229h20c11.046 0 20 8.954 20 20V492c0 11.046-8.954 20-20 20H20c-11.046 0-20-8.954-20-20v-47.771c0-11.046 8.954-20 20-20zM96 0C56.235 0 24 32.235 24 72s32.235 72 72 72s72-32.235 72-72S135.764 0 96 0z"/></svg>`, keyboard: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M3 4h10a1.5 1.5 0 0 1 1.5 1.5v5A1.5 1.5 0 0 1 13 12H3a1.5 1.5 0 0 1-1.5-1.5v-5A1.5 1.5 0 0 1 3 4M0 5.5a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3zm6.25 3.25a.75.75 0 0 0 0 1.5h3.5a.75.75 0 0 0 0-1.5zM4.5 6.5a1 1 0 1 1-2 0a1 1 0 0 1 2 0m2 1a1 1 0 1 0 0-2a1 1 0 0 0 0 2m4-1a1 1 0 1 1-2 0a1 1 0 0 1 2 0m2 1a1 1 0 1 0 0-2a1 1 0 0 0 0 2m-8 2a1 1 0 1 1-2 0a1 1 0 0 1 2 0m8 1a1 1 0 1 0 0-2a1 1 0 0 0 0 2" clip-rule="evenodd"/></svg>`, text_color: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><path fill="currentColor" d="M12 1v2a1 1 0 0 1-2 0V2H7v8h1a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1V2H2v1a1 1 0 1 1-2 0V1a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1Z"/></svg>`, background_color: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M4 20q-.825 0-1.413-.588T2 18V6q0-.825.588-1.413T4 4h16q.825 0 1.413.588T22 6v12q0 .825-.588 1.413T20 20H4Zm2-3h12q.425 0 .713-.288T19 16q0-.425-.288-.713T18 15H6q-.425 0-.713.288T5 16q0 .425.288.713T6 17Zm0-4h12q.425 0 .713-.288T19 12q0-.425-.288-.713T18 11H6q-.425 0-.713.288T5 12q0 .425.288.713T6 13Zm0-4h8q.425 0 .713-.288T15 8q0-.425-.288-.713T14 7H6q-.425 0-.713.288T5 8q0 .425.288.713T6 9Z"/></svg>`, table: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill="currentColor" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 4h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>`, hr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M2 7.75A.75.75 0 0 1 2.75 7h10.5a.75.75 0 0 1 0 1.5H2.75A.75.75 0 0 1 2 7.75Z"/></svg>`, }; GM_addStyle(` .txt-editor-container.dark-theme { background-color: #0d1117; border: 1px solid #3d444d; } .dark-theme .txt-editor-toolbar { background-color: #151b23f2; border-bottom: 1px solid #3d444d; } .dark-theme .txt-editor-toolbar-button, .dark-theme .txt-editor-toolbar-select { color: #9198a1; } .dark-theme .txt-editor-toolbar-button:hover, .dark-theme .txt-editor-toolbar-select:hover { background-color: #212830; color: #fcf0f0ff; } .dark-theme .txt-editor-toolbar-button[data-tooltip]:hover::after { background-color: #212830; color: #fcf0f7ff; } .dark-theme textarea { background-color: #0d1117; color: #f0f6fc; border-top: 1px solid #3d444d; } .dark-theme .txt-editor-toolbar-divider { border-left: 1px solid #3d444d; } .dark-theme .txt-editor-toolbar-select { background-color: #151b23; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="%239198a1" viewBox="0 0 16 16"><path d="M4.427 7.427a.25.25 0 0 0-.354.354l4 4a.25.25 0 0 0 .354 0l4-4a.25.25 0 0 0-.354-.354L8.25 11.22l-3.823-3.793Z"></path></svg>'); } .dark-theme .txt-editor-toolbar-select option { background: #0d1117; color: #f0f6fc; } .dark-theme .txt-color-picker-input { border: 1px solid #3d444d; background-color: #0d1117; } .txt-editor-container.light-theme { background-color: #ffffff; border: 1px solid #d0d7de; } .light-theme .txt-editor-toolbar { background-color: #f6f8fa; border-bottom: 1px solid #d0d7de; } .light-theme .txt-editor-toolbar-button, .light-theme .txt-editor-toolbar-select { color: #57606a; } .light-theme .txt-editor-toolbar-button:hover, .light-theme .txt-editor-toolbar-select:hover { background-color: #ebecf0; color: #24292f; } .light-theme .txt-editor-toolbar-button[data-tooltip]:hover::after { background-color: #24292f; color: #ffffff; } .light-theme textarea { background-color: #ffffff; color: #24292f; border-top: 1px solid #d0d7de; } .light-theme .txt-editor-toolbar-divider { border-left: 1px solid #d0d7de; } .light-theme .txt-editor-toolbar-select { background-color: #f6f8fa; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="%2357606a" viewBox="0 0 16 16"><path d="M4.427 7.427a.25.25 0 0 0-.354.354l4 4a.25.25 0 0 0 .354 0l4-4a.25.25 0 0 0-.354-.354L8.25 11.22l-3.823-3.793Z"></path></svg>'); } .light-theme .txt-editor-toolbar-select option { background: #ffffff; color: #24292f; } .light-theme .txt-color-picker-input { border: 1px solid #d0d7de; background-color: #ffffff; } .txt-editor-container { border-radius: 6px; margin: 10px 0; } .txt-editor-container textarea { border: 0; border-radius: 0 0 6px 6px; width: 100% !important; min-height: 180px; padding: 10px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; resize: vertical; } .txt-editor-toolbar { display: flex; flex-wrap: wrap; align-items: center; padding: 8px 5px; } .txt-editor-toolbar-button, .txt-editor-toolbar-select { background: none; border: none; cursor: pointer; padding: 6px; margin: 0 2px; border-radius: 6px; position: relative; } .txt-editor-toolbar-button svg { width: 16px; height: 16px; fill: currentColor; vertical-align: middle; } .txt-editor-toolbar-button[data-tooltip]:hover::after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); padding: 4px 8px; border-radius: 4px; font-size: 12px; white-space: nowrap; z-index: 10; margin-bottom: 5px; } .txt-editor-toolbar-divider { margin: 4px 8px; height: 16px; } .txt-editor-toolbar-select { -webkit-appearance: none; appearance: none; padding-right: 20px; background-repeat: no-repeat; background-position: right 6px center; } .txt-color-picker-container { display: flex; align-items: center; } .txt-color-picker-input { border-radius: 4px; width: 24px; height: 24px; padding: 1px; cursor: pointer; } .lang-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: none; z-index: 2147483647; justify-content: center; align-items: center; backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); } .lang-modal-box { padding: 24px; border-radius: 16px; width: min(90vw, 320px); text-align: center; transform: scale(0.95); opacity: 0; transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease-out; } .lang-modal-box.dark-theme { background-color: rgba(30, 30, 32, 0.85); border: 1px solid #333; box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); } .lang-modal-box.light-theme { background-color: rgba(255, 255, 255, 0.8); border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1); } .lang-modal-buttons { display: flex; flex-direction: column; gap: 12px; } .lang-modal-buttons button { padding: 14px; border-radius: 10px; font-weight: 500; cursor: pointer; transition: all 0.2s ease-in-out; text-align: center; font-size: 1rem; } .lang-modal-box.dark-theme .lang-modal-buttons button { background-color: #2a2d31; color: #e0e0e0; border: 1px solid #444; } .lang-modal-box.light-theme .lang-modal-buttons button { background-color: #f0f2f5; color: #333; border: 1px solid #ddd; } .lang-modal-box.dark-theme .lang-modal-buttons button:hover { border-color: #58a6ff; background-color: #313438; } .lang-modal-box.light-theme .lang-modal-buttons button:hover { border-color: #0969da; background-color: #e6e8eb; } .script-description-blockquote { margin: 15px 0 !important; padding: 12px 15px; border-radius: 6px; transition: background-color 0.2s, border-color 0.2s, color 0.2s; background-color: #e0e0e0ff; border-left: 4px solid #670000; color: #131313ff; } .script-description-blockquote * { font-weight: 600 !important; color: inherit !important; } @media (prefers-color-scheme: dark) { .script-description-blockquote { background-color: #1c2128; border-left: 4px solid #e95757; color: #ffffffff; } } .good-rating-count, .ok-rating-count, .bad-rating-count { font-weight: bold; display: inline-flex; align-items: center; font-size: 1.15em; padding: 2px 3px; border-radius: 5px; transition: background-color 0.2s ease; } .good-rating-count { color: #1f883d; } .ok-rating-count { color: #6e7781; } .bad-rating-count { color: #cf222e; } .good-rating-count:hover { background-color: rgba(31, 136, 61, 0.1); } .ok-rating-count:hover { background-color: rgba(110, 119, 129, 0.1); } .bad-rating-count:hover { background-color: rgba(207, 34, 46, 0.1); } .good-rating-count::before { content: '👍'; margin-right: 3px; } .ok-rating-count::before { content: '🤔'; margin-right: 3px; } .bad-rating-count::before { content: '👎'; margin-right: 3px; } @media (prefers-color-scheme: dark) { .ok-rating-count { color: #ccbf1c; } .good-rating-count:hover { background-color: rgba(46, 160, 67, 0.15); } .ok-rating-count:hover { background-color: rgba(139, 148, 158, 0.15); } .bad-rating-count:hover { background-color: rgba(248, 81, 73, 0.15); } } .script-list-ratings { align-self: center; } .script-list-ratings + dd { align-self: center; white-space: nowrap; } .bgs-info-separator { height: 3px; border: none; background-color: #b1b8c0; margin: 1.5em 0; } @media (prefers-color-scheme: dark) { .bgs-info-separator { background-color: #4e5761; } } `); function showModal(modal) { if (!modal) return; modal.style.display = 'flex'; setTimeout(() => { const box = modal.querySelector('.lang-modal-box'); box.style.opacity = '1'; box.style.transform = 'scale(1)'; }, 10); } function hideModal(modal) { if (!modal) return; const box = modal.querySelector('.lang-modal-box'); box.style.opacity = '0'; box.style.transform = 'scale(0.95)'; setTimeout(() => { modal.style.display = 'none'; }, 200); } function createLanguageModal() { const overlay = document.createElement('div'); overlay.className = 'lang-modal-overlay'; overlay.addEventListener('click', (e) => { if (e.target === overlay) { hideModal(overlay); } }); const box = document.createElement('div'); box.className = 'lang-modal-box'; const buttonsContainer = document.createElement('div'); buttonsContainer.className = 'lang-modal-buttons'; Object.keys(translations).forEach(langKey => { const btn = document.createElement('button'); btn.textContent = translations[langKey].langName; btn.onclick = async () => { await GM_setValue(LANG_STORAGE_KEY, langKey); window.location.reload(); }; buttonsContainer.appendChild(btn); }); box.appendChild(buttonsContainer); overlay.appendChild(box); const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); function applyTheme(isDark) { box.classList.toggle('dark-theme', isDark); box.classList.toggle('light-theme', !isDark); } applyTheme(mediaQuery.matches); mediaQuery.addEventListener('change', e => applyTheme(e.matches)); return overlay; } // ================ // SESSÃO ESTILIZAR // ================ function isScriptPage() { const path = window.location.pathname; return /^\/([a-z]{2}(-[A-Z]{2})?\/)?scripts\/\d+-[^/]+$/.test(path); } function addAdditionalInfoSeparator() { const additionalInfo = document.getElementById('additional-info'); if (additionalInfo && !additionalInfo.previousElementSibling?.matches('hr.bgs-info-separator')) { const hr = document.createElement('hr'); hr.className = 'bgs-info-separator'; additionalInfo.before(hr); } } function highlightScriptDescription() { const descriptionElements = document.querySelectorAll('#script-description, .script-description.description'); descriptionElements.forEach(element => { if (element && element.parentElement.tagName !== 'BLOCKQUOTE') { const blockquoteWrapper = document.createElement('blockquote'); blockquoteWrapper.className = 'script-description-blockquote'; element.parentNode.insertBefore(blockquoteWrapper, element); blockquoteWrapper.appendChild(element); } }); } // ================ // SESSÃO EDITOR MD // ================ function insertText(textarea, prefix, suffix = '', placeholder = '') { const start = textarea.selectionStart; const end = textarea.selectionEnd; const selected = textarea.value.substring(start, end); const text = selected || placeholder; textarea.setRangeText(prefix + text + suffix, start, end, selected ? 'end' : 'select'); textarea.focus(); } function createToolbarButton(def) { const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'txt-editor-toolbar-button'; btn.dataset.tooltip = def.title; btn.innerHTML = def.icon || def.label; btn.addEventListener('click', e => { e.preventDefault(); def.action(); }); return btn; } function createTextStyleEditor(textarea) { if (textarea.dataset.editorApplied) return; textarea.dataset.editorApplied = 'true'; const container = document.createElement('div'); container.className = 'txt-editor-container'; const toolbar = document.createElement('div'); toolbar.className = 'txt-editor-toolbar'; const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); function applyTheme(isDark) { container.classList.toggle('dark-theme', isDark); container.classList.toggle('light-theme', !isDark); } applyTheme(mediaQuery.matches); mediaQuery.addEventListener('change', e => applyTheme(e.matches)); const tools = [ { type: 'select', title: getTranslation('titles'), options: { 'H1': '# ', 'H2': '## ', 'H3': '### ', 'H4': '#### ', 'H5': '##### ', 'H6': '###### ' }, action: (val) => insertText(textarea, val, '', getTranslation('title_placeholder')) }, { type: 'divider' }, { title: getTranslation('bold'), icon: icons.bold, action: () => insertText(textarea, '**', '**', getTranslation('bold_placeholder')) }, { title: getTranslation('italic'), icon: icons.italic, action: () => insertText(textarea, '*', '*', getTranslation('italic_placeholder')) }, { title: getTranslation('underline'), icon: icons.underline, action: () => insertText(textarea, '<u>', '</u>', getTranslation('underline_placeholder')) }, { title: getTranslation('strikethrough'), icon: icons.strikethrough, action: () => insertText(textarea, '~~', '~~', getTranslation('strikethrough_placeholder')) }, { type: 'divider' }, { title: getTranslation('unordered_list'), icon: icons.ul, action: () => { const start = textarea.selectionStart, end = textarea.selectionEnd, selection = textarea.value.substring(start, end); textarea.setRangeText(selection ? selection.split('\n').map(line => line.trim() === '' ? '' : '- ' + line).join('\n') : '\n- ' + getTranslation('list_item_placeholder'), start, end, 'select'); textarea.focus(); } }, { title: getTranslation('ordered_list'), icon: icons.ol, action: () => { const start = textarea.selectionStart, end = textarea.selectionEnd, selection = textarea.value.substring(start, end); if (selection) { let counter = 1; textarea.setRangeText(selection.split('\n').map(line => line.trim() === '' ? '' : (counter++) + '. ' + line).join('\n'), start, end, 'select'); } else insertText(textarea, '\n1. ', '', getTranslation('list_item_placeholder')); textarea.focus(); } }, { type: 'divider' }, { title: getTranslation('quote'), icon: icons.quote, action: () => insertText(textarea, '\n> ', '', getTranslation('quote_placeholder')) }, { title: getTranslation('inline_code'), icon: icons.code, action: () => insertText(textarea, '`', '`', getTranslation('inline_code_placeholder')) }, { title: getTranslation('code_block'), label: icons.code_block, action: () => insertText(textarea, '\n```\n', '\n```\n', getTranslation('code_block_placeholder')) }, { title: getTranslation('horizontal_line'), icon: icons.hr, action: () => insertText(textarea, '\n---\n') }, { type: 'divider' }, { title: getTranslation('link'), icon: icons.link, action: () => { const url = prompt(getTranslation('prompt_insert_url'), "https://"); if (url) insertText(textarea, '[', `](${url})`, getTranslation('link_text_placeholder')); } }, { title: getTranslation('image'), icon: icons.image, action: () => { const url = prompt(getTranslation('prompt_insert_image_url'), "https://"); if (url) insertText(textarea, ``); } }, { title: getTranslation('table'), icon: icons.table, action: () => { const cols = parseInt(prompt(getTranslation('prompt_columns'), "3"), 10) || 3; const rows = parseInt(prompt(getTranslation('prompt_rows'), "2"), 10) || 2; let table = '\n| ' + Array(cols).fill(getTranslation('table_header_placeholder')).join(' | ') + ' |\n'; table += '| ' + Array(cols).fill('---').join(' | ') + ' |\n'; for (let i = 0; i < rows; i++) { table += '| ' + Array(cols).fill(getTranslation('table_cell_placeholder')).join(' | ') + ' |\n'; } insertText(textarea, table); } }, { title: getTranslation('video'), icon: icons.video, action: () => { const url = prompt(getTranslation('prompt_insert_video_url')); if (!url) return; let src = ''; if (url.includes('youtube.com/watch?v=')) src = `https://www.youtube.com/embed/${new URL(url).searchParams.get('v')}`; else if (url.includes('youtu.be/')) src = `https://www.youtube.com/embed/${new URL(url).pathname.substring(1)}`; else if (url.includes('bilibili.com/video/')) src = `https://player.bilibili.com/player.html?bvid=${new URL(url).pathname.split('/')[2]}`; if (src) insertText(textarea, `<iframe src="${src}" allowfullscreen></iframe>`); else alert(getTranslation('alert_invalid_video_url')); } }, { type: 'divider' }, { title: getTranslation('subscript'), label: icons.subscript, action: () => insertText(textarea, '<sub>', '</sub>', getTranslation('subscript_placeholder')) }, { title: getTranslation('superscript'), label: icons.superscript, action: () => insertText(textarea, '<sup>', '</sup>', getTranslation('superscript_placeholder')) }, { title: getTranslation('highlight'), label: icons.highlight, action: () => insertText(textarea, '<mark>', '</mark>', getTranslation('highlight_placeholder')) }, { title: getTranslation('keyboard'), label: icons.keyboard, action: () => insertText(textarea, '<kbd>', '</kbd>', getTranslation('keyboard_placeholder')) }, { title: getTranslation('abbreviation'), label: icons.abbreviation, action: () => { const title = prompt(getTranslation('prompt_abbreviation_meaning')); if (title) insertText(textarea, `<abbr title="${title}">`, `</abbr>`, getTranslation('abbreviation_placeholder')); } }, { type: 'color-picker' } ]; tools.forEach(tool => { if (tool.type === 'divider') { const div = document.createElement('div'); div.className = 'txt-editor-toolbar-divider'; toolbar.appendChild(div); } else if (tool.type === 'select') { const container = document.createElement('span'); container.className = 'txt-editor-toolbar-button'; container.dataset.tooltip = tool.title; container.style.position = 'relative'; container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.justifyContent = 'center'; container.innerHTML = icons.h; const select = document.createElement('select'); select.className = 'txt-editor-toolbar-select'; select.style.cssText = ` -webkit-appearance: none; appearance: none; background: transparent; border: none; color: transparent; position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: pointer; `; const placeholderOpt = document.createElement('option'); placeholderOpt.value = ''; placeholderOpt.textContent = ''; placeholderOpt.disabled = true; placeholderOpt.selected = true; placeholderOpt.style.display = 'none'; select.appendChild(placeholderOpt); Object.keys(tool.options).forEach(key => { const opt = document.createElement('option'); opt.value = tool.options[key]; opt.textContent = key; select.appendChild(opt); }); select.addEventListener('change', () => { if (select.value) tool.action(select.value); select.selectedIndex = 0; }); container.appendChild(select); toolbar.appendChild(container); } else if (tool.type === 'color-picker') { const colorContainer = document.createElement('div'); colorContainer.className = 'txt-color-picker-container'; const input = document.createElement('input'); input.type = 'color'; input.className = 'txt-color-picker-input'; input.value = "#58a6ff"; const colorBtn = createToolbarButton({ title: getTranslation('text_color'), label: icons.text_color, action: () => insertText(textarea, `<span style="color: ${input.value};">`, '</span>', getTranslation('colored_text_placeholder')) }); const bgBtn = createToolbarButton({ title: getTranslation('background_color'), label: icons.background_color, action: () => insertText(textarea, `<span style="background-color: ${input.value};">`, '</span>', getTranslation('colored_background_placeholder')) }); colorContainer.append(input, colorBtn, bgBtn); toolbar.appendChild(colorContainer); } else { toolbar.appendChild(createToolbarButton(tool)); } }); textarea.parentNode.insertBefore(container, textarea); container.append(toolbar, textarea); } function applyToAllTextareas() { const textareas = document.querySelectorAll('textarea:not(#script_version_code):not([data-editor-applied])'); textareas.forEach(createTextStyleEditor); } function enableSourceEditorCheckbox() { const enableCheckbox = () => { const checkbox = document.getElementById('enable-source-editor-code'); if (checkbox && !checkbox.checked) { checkbox.checked = true; const event = new Event('change', { bubbles: true }); checkbox.dispatchEvent(event); } }; enableCheckbox(); const observer = new MutationObserver((mutationsList, observer) => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { const checkbox = document.getElementById('enable-source-editor-code'); if (checkbox) { enableCheckbox(); observer.disconnect(); break; } } } }); observer.observe(document.body, { childList: true, subtree: true }); } function isMarkdownPage() { const path = window.location.pathname; const markdownSegments = [ '/new', '/edit', '/feedback', '/discussions' ]; if (path.includes('/sets/')) { return false; } return markdownSegments.some(segment => path.includes(segment)); } // ================ // SESSÃO DOWNLOAD // ================ function isCodePage() { return /^\/([a-z]{2}(-[A-Z]{2})?\/)?scripts\/\d+-.+\/code/.test(window.location.pathname); } function initializeDownloadButton() { 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 = getTranslation('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', () => { const normalizedPath = normalizeScriptPath(window.location.pathname); const scriptId = extractScriptIdFromNormalizedPath(normalizedPath); if (!scriptId) { alert(getTranslation('scriptIdNotFound')); return; } const scriptUrl = `https://update.greasyfork.org/scripts/${scriptId}.js`; btn.disabled = true; btn.textContent = getTranslation('downloading'); GM_xmlhttpRequest({ method: 'GET', url: scriptUrl, onload: function (res) { const code = res.responseText; if (!code) { alert(getTranslation('notFound')); return; } const nameMatch = code.match(/\/\/\s*@name\s+(.+)/i); const fileName = nameMatch ? `${nameMatch[1].trim()}.user.js` : 'script.user.js'; const blob = new Blob([code], { type: 'application/javascript;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }, onerror: function (res) { alert(getTranslation('downloadError')); }, ontimeout: function () { alert(getTranslation('downloadTimeout')); }, onloadend: function () { btn.disabled = false; btn.textContent = getTranslation('download'); } }); }); toolbar.appendChild(btn); const spacer = document.createElement('div'); spacer.style.height = '12px'; toolbar.appendChild(spacer); }); } // ================ // SESSÃO INICIALIZAR // ================ async function start() { iconCache = await GM_getValue(CACHE_KEY, {}); await determineLanguage(); languageModal = createLanguageModal(); document.body.appendChild(languageModal); registerLanguageMenu(); if (isMarkdownPage()) { applyToAllTextareas(); enableSourceEditorCheckbox(); } if (isCodePage()){ initializeDownloadButton(); } processIconElements(); highlightScriptDescription(); if (isScriptPage()) { addAdditionalInfoSeparator(); } const observer = new MutationObserver(() => { processIconElements(); highlightScriptDescription(); if (isScriptPage()) { addAdditionalInfoSeparator(); } if (isMarkdownPage()) { applyToAllTextareas(); } }); observer.observe(document.body, { childList: true, subtree: true }); } start(); })();