Greasy Fork

Greasy Fork is available in English.

TypeMonkey视频&音频解析器

高效抓取网页内的视频和音频资源,提供复制和下载功能

这些是此脚本的所有版本。 只显示代码变更过的版本。

  • v2.6 2025-06-05

    这是我用AI软件写的一个脚本,不嫌弃的大家可以用一用,修复了一些已知bug。

  • v2.5 2025-06-05

    TypeMonkey视频&音频解析器


    TypeMonkey视频&音频解析器

    支持抖音无水印下载、网页音视频解析及流媒体捕获的TypeMonkey专用脚本


    抖音无水印
    视频音频解析
    流媒体支持
    悬浮球UI
    一键下载

    安装方法

    1. 安装TypeMonkey扩展(Chrome/Firefox/Edge)
    2. 点击TypeMonkey图标打开仪表盘
    3. 创建新脚本并粘贴下方代码
    4. 保存脚本并确保已启用
    5. 访问含有视频/音频的页面使用
    复制脚本代码

    主要功能


    抖音无水印

    去除抖音/快手等短视频平台的水印


    视频解析

    提取网页视频源包括M3U8/MPD流


    音频提取

    识别并下载网页中的音频资源


    智能识别

    自动检测视频音频源无需手动查找

    TypeMonkey脚本代码

    将以下代码完整复制到TypeMonkey的新脚本中:

    // ==UserScript==
    // @name         TypeMonkey视频&音频解析器
    // @namespace    https://github.com/yourname
    // @version      2.5
    // @description  高级视频&音频解析器,支持抖音无水印和流媒体格式
    // @author       YourName
    // @match        *://*/*
    // @grant        GM_xmlhttpRequest
    // @grant        GM_download
    // @grant        GM_notification
    // @grant        GM_setClipboard
    // @grant        GM_addStyle
    // @grant        GM_getValue
    // @grant        GM_setValue
    // @connect      *
    // @run-at       document-idle
    // ==/UserScript==
    
    (function() {
        'use strict';
        
        // 抖音无水印解析API
        const DOUYIN_API = "https://api.douyin.wtf/api?url=";
        
        // 全局变量
        let floatBall = null;
        let panel = null;
        let lastPosition = {
            x: GM_getValue('lastPositionX', 20),
            y: GM_getValue('lastPositionY', 20)
        };
        let isExpanded = false;
        let sourcesCount = 0;
    
        // 添加全局样式
        GM_addStyle(`
            #videoParserFloatBall {
                position: fixed;
                width: 50px;
                height: 50px;
                background: linear-gradient(145deg, #4a76c6, #3a66b6);
                border-radius: 50%;
                cursor: pointer;
                z-index: 99999;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-size: 24px;
                box-shadow: 0 6px 15px rgba(0,0,0,0.3);
                transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
                user-select: none;
            }
            
            #videoParserFloatBall.badge::after {
                content: '';
                position: absolute;
                top: -5px;
                right: -5px;
                width: 15px;
                height: 15px;
                background: #ff4757;
                border-radius: 50%;
                border: 2px solid white;
            }
            
            #videoParserPanel {
                position: fixed;
                z-index: 99998;
                background: #2d3a4b;
                color: #ecf0f1;
                padding: 0;
                border-radius: 15px;
                box-shadow: 0 12px 30px rgba(0,0,0,0.4);
                width: 95%;
                max-width: 420px;
                max-height: 85vh;
                overflow: hidden;
                font-family: system-ui, -apple-system, sans-serif;
                display: flex;
                flex-direction: column;
                display: none;
                transform-origin: top center;
                font-size: 14px;
                border: 1px solid #3a4a60;
            }
            
            #videoParserPanel .header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 15px;
                background: #1e2a38;
                color: white;
                cursor: move;
                border-bottom: 1px solid #3a4a60;
                user-select: none;
            }
            
            #videoParserPanel .header h3 {
                margin: 0;
                font-size: 16px;
                font-weight: 600;
                color: #3498db;
            }
            
            #videoParserPanel .header .buttons {
                display: flex;
                gap: 10px;
            }
            
            #videoParserPanel .header button {
                width: 30px;
                height: 30px;
                background: #3a4a60;
                color: white;
                border: none;
                border-radius: 6px;
                cursor: pointer;
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 18px;
                transition: background 0.3s;
            }
            
            #videoParserPanel .header button:hover {
                background: #4a5a70;
            }
            
            #videoParserPanel .header .close:hover {
                background: #ff4757;
            }
            
            #panelContent {
                overflow-y: auto;
                padding: 15px;
                max-height: calc(85vh - 60px);
                background: #1e2a38;
                font-size: 14px;
            }
            
            .source-item {
                margin: 15px 0;
                padding: 15px;
                background: #2d3a4b;
                border-radius: 10px;
                box-shadow: 0 4px 10px rgba(0,0,0,0.2);
                border: 1px solid #3a4a60;
            }
            
            .source-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 12px;
            }
            
            .source-info {
                font-weight: bold;
                display: flex;
                align-items: center;
                gap: 10px;
            }
            
            .source-url {
                word-break: break-all;
                font-size: 13px;
                color: #bdc3c7;
                padding: 12px;
                background: #1a2432;
                border-radius: 8px;
                max-height: 80px;
                overflow-y: auto;
                margin-bottom: 15px;
                border: 1px solid #2d3a4b;
            }
            
            .btn-group {
                display: flex;
                gap: 10px;
                flex-wrap: wrap;
            }
            
            .btn-group button {
                padding: 8px 15px;
                color: white;
                border: none;
                border-radius: 8px;
                cursor: pointer;
                flex: 1;
                font-size: 13px;
                min-width: 100px;
                font-weight: 600;
                transition: all 0.3s;
            }
            
            .btn-group button:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 8px rgba(0,0,0,0.2);
            }
            
            .copy-btn {
                background: linear-gradient(145deg, #2ecc71, #27ae60);
            }
            
            .douyin-btn {
                background: linear-gradient(145deg, #e74c3c, #c0392b);
            }
            
            .download-btn {
                background: linear-gradient(145deg, #9b59b6, #8e44ad);
            }
            
            .audio-btn {
                background: linear-gradient(145deg, #f39c12, #d35400);
            }
            
            .empty-msg {
                text-align: center;
                padding: 40px 20px;
                color: #7f8c8d;
            }
            
            .empty-msg p {
                margin: 10px 0;
            }
            
            @media (max-width: 500px) {
                #videoParserPanel {
                    width: 98%;
                    max-width: none;
                    left: 1% !important;
                    right: 1% !important;
                    transform: none !important;
                    max-width: unset;
                }
                
                .btn-group button {
                    min-width: 45%;
                }
            }
        `);
    
        // 创建球形悬浮按钮
        function createFloatBall() {
            if (floatBall) return;
            
            floatBall = document.createElement('div');
            floatBall.id = 'videoParserFloatBall';
            floatBall.textContent = '🎥';
            floatBall.title = '视频&音频解析器';
            
            // 定位
            floatBall.style.left = `${lastPosition.x}px`;
            floatBall.style.top = `${lastPosition.y}px`;
            
            // 添加拖拽功能
            let isDragging = false;
            let offsetX, offsetY;
            
            floatBall.addEventListener('mousedown', startDrag);
            document.addEventListener('mousemove', drag);
            document.addEventListener('mouseup', stopDrag);
            
            function startDrag(e) {
                isDragging = true;
                offsetX = e.clientX - floatBall.getBoundingClientRect().left;
                offsetY = e.clientY - floatBall.getBoundingClientRect().top;
                floatBall.style.cursor = 'grabbing';
                floatBall.style.boxShadow = '0 10px 25px rgba(0,0,0,0.4)';
            }
            
            function drag(e) {
                if (!isDragging) return;
                floatBall.style.left = `${e.clientX - offsetX}px`;
                floatBall.style.top = `${e.clientY - offsetY}px`;
                lastPosition = { 
                    x: e.clientX - offsetX,
                    y: e.clientY - offsetY
                };
                GM_setValue('lastPositionX', lastPosition.x);
                GM_setValue('lastPositionY', lastPosition.y);
            }
            
            function stopDrag() {
                isDragging = false;
                floatBall.style.cursor = 'pointer';
                floatBall.style.boxShadow = '0 6px 15px rgba(0,0,0,0.3)';
            }
            
            // 点击展开面板
            floatBall.addEventListener('click', async () => {
                if (isExpanded) {
                    collapsePanel();
                } else {
                    const sources = await findVideoSources();
                    showResults(sources);
                }
            });
            
            document.body.appendChild(floatBall);
        }
    
        // 展开面板
        function expandPanel() {
            if (!panel) return;
            
            isExpanded = true;
            floatBall.style.display = 'none';
            
            // 设置面板初始位置
            const rect = floatBall.getBoundingClientRect();
            panel.style.left = `${rect.left}px`;
            panel.style.top = `${rect.top}px`;
            panel.style.display = 'flex';
            panel.style.transform = 'scale(0.5) translateY(-30px)';
            panel.style.opacity = '0';
            
            // 动画效果
            setTimeout(() => {
                panel.style.transition = 'all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55)';
                panel.style.transform = 'scale(1) translateY(0)';
                panel.style.opacity = '1';
            }, 10);
        }
    
        // 收起面板
        function collapsePanel() {
            if (!panel || !floatBall) return;
            
            isExpanded = false;
            
            // 动画效果
            panel.style.transition = 'all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55)';
            panel.style.transform = 'scale(0.5) translateY(-30px)';
            panel.style.opacity = '0';
            
            setTimeout(() => {
                panel.style.display = 'none';
                floatBall.style.display = 'flex';
                floatBall.style.left = `${lastPosition.x}px`;
                floatBall.style.top = `${lastPosition.y}px`;
            }, 400);
        }
    
        // 主解析函数
        async function findVideoSources() {
            const sources = [];
            const now = Date.now();
            const uniqueSources = new Set();
    
            // 1. 解析标准视频元素
            document.querySelectorAll('video').forEach(video => {
                if (video.src) addUniqueSource(sources, uniqueSources, 'video', video.src);
                video.querySelectorAll('source').forEach(s => {
                    if (s.src) addUniqueSource(sources, uniqueSources, 'source', s.src);
                });
            });
            
            // 2. 解析音频元素
            document.querySelectorAll('audio').forEach(audio => {
                if (audio.src) addUniqueSource(sources, uniqueSources, 'audio', audio.src);
                audio.querySelectorAll('source').forEach(s => {
                    if (s.src) addUniqueSource(sources, uniqueSources, 'audio-source', s.src);
                });
            });
    
            // 3. 解析iframe嵌入视频
            const iframePromises = [];
            document.querySelectorAll('iframe').forEach(iframe => {
                const src = iframe.src || iframe.dataset.src;
                if (!src) return;
                
                // 抖音特殊处理
                if (src.includes("douyin.com") || src.includes("iesdouyin.com")) {
                    iframePromises.push(
                        parseDouyin(src).then(url => {
                            if (url) addUniqueSource(sources, uniqueSources, 'douyin', url);
                        })
                    );
                } 
                else if (/youtube|vimeo|bilibili/.test(src)) {
                    addUniqueSource(sources, uniqueSources, 'iframe', src);
                }
            });
    
            // 等待所有抖音解析完成
            await Promise.all(iframePromises);
    
            // 更新计数
            sourcesCount = sources.length;
            if (sourcesCount > 0 && !isExpanded) {
                floatBall.classList.add('badge');
            }
    
            return sources;
        }
    
        // 添加唯一来源
        function addUniqueSource(sources, uniqueSet, type, url) {
            if (!url || uniqueSet.has(url)) return;
            uniqueSet.add(url);
            sources.push(createSource(type, url));
        }
    
        // 创建来源对象
        function createSource(type, url) {
            return {
                type: type,
                url: url,
                timestamp: Date.now(),
                isStream: /\.(m3u8|mpd)(\?|$)/i.test(url),
                isAudio: /audio|audio-source/.test(type)
            };
        }
    
        // 抖音无水印解析
        function parseDouyin(url) {
            return new Promise(resolve => {
                GM_xmlhttpRequest({
                    method: "GET",
                    url: `${DOUYIN_API}${encodeURIComponent(url)}`,
                    timeout: 8000,
                    onload: function(response) {
                        try {
                            const data = JSON.parse(response.responseText);
                            resolve(data.nwm_video_url || null);
                        } catch (e) {
                            resolve(null);
                        }
                    },
                    onerror: function() {
                        resolve(null);
                    },
                    ontimeout: function() {
                        resolve(null);
                    }
                });
            });
        }
    
        // 显示结果面板
        function showResults(sources) {
            if (panel) panel.remove();
            
            panel = document.createElement('div');
            panel.id = 'videoParserPanel';
            
            // 标题栏
            const header = document.createElement('div');
            header.className = 'header';
            
            const title = document.createElement('h3');
            title.textContent = sources.length > 0 ? 
                `🎥 发现 ${sources.length} 个媒体源` : 
                `⚠️ 未检测到媒体源`;
    
            const buttonContainer = document.createElement('div');
            buttonContainer.className = 'buttons';
    
            // 刷新按钮
            const refreshBtn = document.createElement('button');
            refreshBtn.textContent = '↻';
            refreshBtn.title = '重新扫描';
    
            // 收起按钮
            const minimizeBtn = document.createElement('button');
            minimizeBtn.textContent = '−';
            minimizeBtn.title = '收起/展开';
            
            // 关闭按钮
            const closeBtn = document.createElement('button');
            closeBtn.textContent = '×';
            closeBtn.title = '关闭';
            closeBtn.className = 'close';
            
            buttonContainer.appendChild(refreshBtn);
            buttonContainer.appendChild(minimizeBtn);
            buttonContainer.appendChild(closeBtn);
            
            header.appendChild(title);
            header.appendChild(buttonContainer);
    
            // 内容区域
            const content = document.createElement('div');
            content.id = 'panelContent';
            
            if (sources.length > 0) {
                const list = document.createElement('div');
                
                sources.forEach((src, i) => {
                    const item = document.createElement('div');
                    item.className = 'source-item';
                    
                    const headerRow = document.createElement('div');
                    headerRow.className = 'source-header';
                    
                    const sourceInfo = document.createElement('div');
                    sourceInfo.className = 'source-info';
                    
                    const sourceType = document.createElement('span');
                    let typeText = src.type.toUpperCase();
                    if (src.isAudio) {
                        sourceType.style.color = '#f39c12';
                        typeText = '音频资源';
                    } else if (src.type === 'douyin') {
                        sourceType.style.color = '#e74c3c';
                    } else if (src.type === 'stream') {
                        sourceType.style.color = '#9b59b6';
                    } else {
                        sourceType.style.color = '#3498db';
                    }
                    sourceType.textContent = `[${typeText}]`;
                    
                    const sourceIndex = document.createElement('span');
                    sourceIndex.textContent = `#${i+1}`;
                    
                    sourceInfo.appendChild(sourceIndex);
                    sourceInfo.appendChild(sourceType);
                    
                    const urlText = document.createElement('div');
                    urlText.className = 'source-url';
                    urlText.textContent = src.url;
                    
                    const btnGroup = document.createElement('div');
                    btnGroup.className = 'btn-group';
                    
                    // 复制按钮
                    const copyBtn = document.createElement('button');
                    copyBtn.textContent = '复制链接';
                    copyBtn.className = 'copy-btn';
                    copyBtn.dataset.url = src.url;
                    
                    // 下载按钮
                    let downloadBtn = null;
                    if (src.isAudio) {
                        downloadBtn = document.createElement('button');
                        downloadBtn.textContent = '下载音频';
                        downloadBtn.className = 'audio-btn';
                        downloadBtn.dataset.download = src.url;
                    } else if (src.type === 'douyin') {
                        downloadBtn = document.createElement('button');
                        downloadBtn.textContent = '无水印下载';
                        downloadBtn.className = 'douyin-btn';
                        downloadBtn.dataset.download = src.url;
                    } else if (!src.isStream) {
                        downloadBtn = document.createElement('button');
                        downloadBtn.textContent = '下载视频';
                        downloadBtn.className = 'download-btn';
                        downloadBtn.dataset.download = src.url;
                    }
                    
                    btnGroup.appendChild(copyBtn);
                    if (downloadBtn) btnGroup.appendChild(downloadBtn);
                    
                    item.appendChild(headerRow);
                    item.appendChild(urlText);
                    item.appendChild(btnGroup);
                    headerRow.appendChild(sourceInfo);
                    list.appendChild(item);
                });
                
                content.appendChild(list);
            } else {
                const emptyMsg = document.createElement('div');
                emptyMsg.className = 'empty-msg';
                emptyMsg.innerHTML = `
                    

    📹

    未找到视频或音频资源

    尝试播放媒体后重新扫描

    `; content.appendChild(emptyMsg); } // 组装面板 panel.appendChild(header); panel.appendChild(content); document.body.appendChild(panel); // 添加事件监听器 function setupEventListeners() { // 复制功能 content.querySelectorAll('.copy-btn').forEach(btn => { btn.addEventListener('click', () => { GM_setClipboard(btn.dataset.url); GM_notification({ title: '复制成功', text: '链接已复制到剪贴板', timeout: 2000 }); }); }); // 下载功能 content.querySelectorAll('.download-btn, .audio-btn, .douyin-btn').forEach(btn => { btn.addEventListener('click', () => { const url = btn.dataset.download; const isAudio = btn.classList.contains('audio-btn'); let fileExtension = 'mp4'; if (isAudio) { fileExtension = url.includes('.m4a') ? 'm4a' : url.includes('.aac') ? 'aac' : url.includes('.wav') ? 'wav' : 'mp3'; } const filename = `${isAudio ? 'audio' : 'video'}_${Date.now()}.${fileExtension}`; GM_download({ url: url, name: filename }); }); }); // 刷新功能 refreshBtn.addEventListener('click', async () => { refreshBtn.textContent = '...'; refreshBtn.disabled = true; const newSources = await findVideoSources(); showResults(newSources); }); // 收起功能 minimizeBtn.addEventListener('click', collapsePanel); // 关闭功能 closeBtn.addEventListener('click', () => { if (panel) panel.remove(); if (floatBall) floatBall.remove(); panel = null; floatBall = null; }); // 拖动功能 let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', stopDrag); function startDrag(e) { if (e.target.tagName === 'BUTTON') return; isDragging = true; offsetX = e.clientX - panel.getBoundingClientRect().left; offsetY = e.clientY - panel.getBoundingClientRect().top; panel.style.cursor = 'grabbing'; } function drag(e) { if (!isDragging) return; panel.style.left = `${e.clientX - offsetX}px`; panel.style.top = `${e.clientY - offsetY}px`; } function stopDrag() { isDragging = false; panel.style.cursor = 'default'; } } setupEventListeners(); expandPanel(); } // 主执行函数 function init() { createFloatBall(); // 初始扫描 setTimeout(async () => { await findVideoSources(); }, 5000); } // 等待页面加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();

    功能演示

    🎥

    使用说明


    基本操作

    视频加载完成后点击悬浮球解析


    拖拽功能

    可自由拖动悬浮球和解析面板


    重新扫描

    当有新视频加载时可刷新扫描


    安全使用

    不会收集用户数据,仅解析页面媒体

    © 2023 TypeMonkey视频&音频解析器 | 专为TypeMonkey平台设计

    免责声明:本脚本仅供学习交流使用,请勿用于非法用途




  • v2.5 2025-06-05