Greasy Fork

来自缓存

Greasy Fork is available in English.

TypeMonkey视频&音频解析器

高级视频&音频解析器,支持抖音无水印和流媒体格式

当前为 2025-06-05 提交的版本,查看 最新版本

作者
谷文昌
评分
0 0 0
版本
2.5
创建于
2025-06-05
更新于
2025-06-05
大小
21.9 KB
许可证
暂无
适用于
所有网站

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平台设计

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