// ==UserScript== // @name YOU-GET Download Assistant // @namespace https://you-get.org/ // @version 1.5.0 // @description 一键下载网页视频、音频、图片。支持多平台,自动检测资源链接。 // @author YOU-GET Team // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_setClipboard // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @connect * // @run-at document-idle // @noframes // @license MIT // ==/UserScript== (function() { 'use strict'; // ========== 配置区域 ========== const CONFIG = { // 快捷键配置 hotkey: { showPanel: 'Alt+Y', // 显示/隐藏面板 download: 'Alt+D', // 下载视频 copyUrl: 'Alt+C' // 复制链接 }, // 主题颜色 theme: { primary: '#ff4757', secondary: '#2ed573', background: '#2f3542', text: '#ffffff' }, // 下载器配置 downloader: 'native', // native: 直接下载, blob: Blob下载, proxy: 代理下载 // 自动检测 autoDetect: true, // 面板位置 panelPosition: 'right' // left / right }; // ========== 全局变量 ========== let panelVisible = false; let detectedMedia = []; let panelElement = null; // ========== 工具函数 ========== const utils = { // 格式化文件大小 formatSize(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }, // 获取域名 getDomain() { return window.location.hostname.replace('www.', ''); }, // 生成唯一ID generateId() { return 'yg_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); }, // 延迟执行 sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }, // 检测URL是否为媒体 isMediaUrl(url) { const mediaExtensions = /\.(mp4|webm|m3u8|flv|avi|mov|wmv|mp3|wav|ogg|m4a|aac|jpg|jpeg|png|gif|webp|bmp|svg)(\?.*)?$/i; const mediaMimes = /video|audio|application\/x-mpegURL/i; return mediaExtensions.test(url) || mediaMimes.test(url); }, // 清理URL参数 cleanUrl(url) { try { const urlObj = new URL(url); // 保留重要的查询参数 const keepParams = ['token', 'sign', 'expires', 'auth', 'key', 'policy']; const params = new URLSearchParams(); keepParams.forEach(p => { if (urlObj.searchParams.has(p)) { params.set(p, urlObj.searchParams.get(p)); } }); return urlObj.origin + urlObj.pathname + (params.toString() ? '?' + params.toString() : ''); } catch { return url; } } }; // ========== 媒体检测器 ========== const MediaDetector = { // 视频平台检测规则 platformRules: { 'youtube.com': { extractors: [ () => { const player = document.querySelector('#movie_player video'); if (player && player.src) return { url: player.src, type: 'video', quality: player.videoHeight + 'p' }; }, () => { const ytPlayer = document.getElementById('movie_player'); if (ytPlayer && ytPlayer.getAvailableQualityLevels) { const format = ytPlayer.getAvailableQualityLevels(); if (format.length > 0) return { url: `https://youtube.com/watch?v=${window.location.searchParams.get('v')}`, type: 'hls', quality: format[0] }; } } ] }, 'bilibili.com': { extractors: [ () => { const script = document.querySelector('script#playinfo'); if (script) { try { const data = JSON.parse(script.textContent); if (data.durl) return { url: data.durl[0].url, type: 'video', quality: data.quality + 'p' }; } catch {} } }, () => { const video = document.querySelector('video'); if (video && video.src) return { url: video.src, type: 'video', quality: video.videoHeight + 'p' }; } ] }, 'douyin.com': { extractors: [ () => { const script = document.querySelector('#university-nav + script'); if (script) { try { const match = script.textContent.match(/"playAddr":\s*"([^"]+)"/); if (match) return { url: match[1].replace('playwm', 'play'), type: 'video', quality: 'HD' }; } catch {} } } ] }, 'weibo.com': { extractors: [ () => { const scripts = document.querySelectorAll('script'); for (const script of scripts) { if (script.textContent.includes('video_src')) { const match = script.textContent.match(/"video_src":\s*"([^"]+)"/); if (match) return { url: decodeURIComponent(match[1]), type: 'video', quality: 'SD' }; } } } ] } }, // 通用检测方法 genericDetectors: [ // 检测