// ==UserScript== // @name YouTube 视频下载助手|多种清晰度HD🔥|Video&Audio 📥 // @name:en YouTube Video Downloader | HD Quality Options | Video&Audio 📥 // @name:ja YouTube動画ダウンローダー|HD高画質|ビデオ&オーディオ 📥 // @name:es Descargador de YouTube | Alta Calidad HD | Video y Audio 📥 // @name:pt Baixador de YouTube | Qualidade HD | Vídeo e Áudio 📥 // @namespace http://tampermonkey.net/ // @version 0.1 // @description YouTube视频下载神器,支持1080P/2K高清视频下载,支持字幕下载,支持视频/音频分离下载,支持短视频下载,完全免费无广告 // @description:en Download YouTube videos in HD(1080P/2K), subtitles support, video/audio separate download, shorts download, completely free & no ads // @description:ja YouTubeビデオをHD(1080P/2K)でダウンロード、字幕対応、ビデオ/オーディオ分離ダウンロード、ショート動画対応、完全無料&広告なし // @description:es Descarga videos de YouTube en HD(1080P/2K), soporte de subtítulos, descarga separada de video/audio, descarga de shorts, completamente gratis y sin anuncios // @description:pt Baixe vídeos do YouTube em HD(1080P/2K), suporte a legendas, download separado de vídeo/áudio, download de shorts, totalmente gratuito e sem anúncios // @author YouhouLab // @license MIT // @match https://www.youtube.com/watch* // @match https://www.youtube.com/shorts/* // @match https://m.youtube.com/watch* // @match https://m.youtube.com/shorts/* // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @connect www.y2mate.com // @run-at document-end // @homepage https://github.com/youhou-project // @supportURL https://github.com/youhou-project/issues // @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // @compatible chrome // @compatible firefox // @compatible opera // @compatible edge // @compatible safari // @keywords youtube, download, video, audio, subtitle, shorts, hd, 1080p, 2k, free, no ads, y2mate // @downloadURL none // ==/UserScript== (function() { 'use strict'; const i18n = { 'zh': { downloadText: '免费下载', error: { addNormalButton: '添加普通下载按钮时出错:', addShortsButton: '添加Shorts下载按钮时出错:' } }, 'en': { downloadText: 'Free Download', error: { addNormalButton: 'Error adding normal download button:', addShortsButton: 'Error adding Shorts download button:' } }, 'ja': { downloadText: '無料ダウンロード', error: { addNormalButton: '通常ダウンロードボタンの追加エラー:', addShortsButton: 'Shortsダウンロードボタンの追加エラー:' } }, 'es': { downloadText: 'Descarga Gratis', error: { addNormalButton: 'Error al agregar botón de descarga normal:', addShortsButton: 'Error al agregar botón de descarga Shorts:' } }, 'pt': { downloadText: 'Download Grátis', error: { addNormalButton: 'Erro ao adicionar botão de download normal:', addShortsButton: 'Erro ao adicionar botão de download Shorts:' } } }; function getCurrentLanguage() { const lang = navigator.language.split('-')[0]; return i18n[lang] ? lang : 'en'; } const currentLang = getCurrentLanguage(); const texts = i18n[currentLang]; function getVideoId() { const url = window.location.href; if (url.includes('/shorts/')) { return url.split('/shorts/')[1].split('?')[0]; } return new URLSearchParams(window.location.search).get('v'); } function addNormalDownloadButton() { try { if (document.getElementById('download-btn')) return; const buttonContainer = document.querySelector('#top-level-buttons-computed'); if (!buttonContainer) { return; } const downloadBtn = document.createElement('button'); downloadBtn.id = 'download-btn'; downloadBtn.className = 'yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m'; downloadBtn.style.marginLeft = '8px'; const btnContent = document.createElement('div'); btnContent.className = 'cbox'; btnContent.style.display = 'flex'; btnContent.style.alignItems = 'center'; const icon = document.createElement('span'); icon.className = 'material-icons'; icon.style.marginRight = '6px'; const text = document.createElement('span'); text.textContent = texts.downloadText; btnContent.appendChild(icon); btnContent.appendChild(text); downloadBtn.appendChild(btnContent); downloadBtn.addEventListener('click', function() { const videoId = getVideoId(); if (videoId) { window.open(`https://www.y2mate.com/youtube/${videoId}`, '_blank'); } }); buttonContainer.appendChild(downloadBtn); } catch (error) { console.error(texts.error.addNormalButton, error); } } function addShortsDownloadButton() { try { if (document.getElementById('shorts-download-btn')) return; const likeButton = document.querySelector('#like-button'); if (!likeButton) { return; } const buttonContainer = likeButton.parentElement; if (!buttonContainer) { return; } const downloadBtn = document.createElement('button'); downloadBtn.id = 'shorts-download-btn'; downloadBtn.className = 'yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m'; downloadBtn.style.cssText = ` height: 36px; padding: 0 16px; margin: 8px 0; background: transparent; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #fff; `; const btnContent = document.createElement('div'); btnContent.style.display = 'flex'; btnContent.style.alignItems = 'center'; btnContent.style.gap = '6px'; const icon = document.createElement('span'); icon.className = 'material-icons'; icon.style.fontSize = '20px'; icon.textContent = 'download'; const text = document.createElement('span'); text.textContent = texts.downloadText; text.style.fontSize = '14px'; btnContent.appendChild(icon); btnContent.appendChild(text); downloadBtn.appendChild(btnContent); downloadBtn.addEventListener('click', function() { const videoId = getVideoId(); if (videoId) { window.open(`https://www.y2mate.com/youtube/${videoId}`, '_blank'); } }); buttonContainer.appendChild(downloadBtn); } catch (error) { console.error(texts.error.addShortsButton, error); } } function addDownloadButton() { try { const isShorts = window.location.pathname.includes('/shorts/'); if (isShorts) { addShortsDownloadButton(); } else { addNormalDownloadButton(); } } catch (error) { console.error('Error adding download button:', error); } } function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } const debouncedAddButton = debounce(addDownloadButton, 500); const observer = new MutationObserver((mutations) => { const shouldUpdate = mutations.some(mutation => { return mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0; }); if (shouldUpdate) { debouncedAddButton(); } }); observer.observe(document.body, { childList: true, subtree: true }); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', addDownloadButton); } else { addDownloadButton(); } })();