吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8379|回复: 72
上一主题 下一主题
收起左侧

[Java 转载] bilibili音视频下载脚本(油猴)

  [复制链接]
跳转到指定楼层
楼主
52pjmolian 发表于 2025-11-4 08:38 回帖奖励
本帖最后由 52pjmolian 于 2025-11-4 13:54 编辑

搞了一个简易B站音视频下载脚本,结合AI加以优化

附件为txt文件需要修改成.js进行安装

开发思路:解析HTML中音视频m4s地址,直接下载
:下载后音视频是分开的,可以使用FFMPEG合并
参考:ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 output.mp4

直接通过油猴安装即可使用

!!!仅限个人使用!!!

[JavaScript] 纯文本查看 复制代码
// ==UserScript==
// @name         B站视频下载器(稳定版)
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  稳定下载B站音视频,提供本地合并指南
// @AuThor       You
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/bangumi/play/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    console.log('🚀 B站视频下载器启动 - 稳定版');

    class BilibiliDownloader {
        constructor() {
            this.playInfo = null;
            this.init();
        }

        init() {
            this.createDownloadButton();
            this.findPlayInfo();
            this.addGlobalStyles();
        }

        // 添加全局样式
        addGlobalStyles() {
            const style = document.createElement('style');
            style.textContent = `
                .bilibili-downloader-btn {
                    position: fixed !important;
                    bottom: 20px !important;
                    right: 20px !important;
                    background: #00a1d6 !important;
                    color: white !important;
                    border: none !important;
                    border-radius: 20px !important;
                    padding: 10px 15px !important;
                    font-size: 14px !important;
                    font-weight: bold !important;
                    cursor: pointer !important;
                    z-index: 10000 !important;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.3) !important;
                    transition: all 0.3s !important;
                    font-family: Arial, sans-serif !important;
                }

                .bilibili-downloader-btn:hover {
                    transform: scale(1.05) !important;
                    background: #0087b3 !important;
                }

                .bilibili-downloader-panel {
                    position: fixed !important;
                    top: 50% !important;
                    left: 50% !important;
                    transform: translate(-50%, -50%) !important;
                    background: rgba(0,0,0,0.95) !important;
                    color: white !important;
                    border: 2px solid #00a1d6 !important;
                    border-radius: 10px !important;
                    padding: 20px !important;
                    z-index: 10001 !important;
                    width: 500px !important;
                    max-width: 90vw !important;
                    max-height: 80vh !important;
                    overflow-y: auto !important;
                    box-shadow: 0 4px 20px rgba(0,0,0,0.5) !important;
                    font-family: Arial, sans-serif !important;
                }

                .bilibili-downloader-panel h3 {
                    color: #00a1d6 !important;
                    margin: 0 0 15px 0 !important;
                    text-align: center !important;
                }

                .bilibili-downloader-panel .close-btn {
                    position: absolute !important;
                    top: 10px !important;
                    right: 15px !important;
                    background: none !important;
                    border: none !important;
                    color: white !important;
                    font-size: 20px !important;
                    cursor: pointer !important;
                    width: 30px !important;
                    height: 30px !important;
                    border-radius: 50% !important;
                    display: flex !important;
                    align-items: center !important;
                    justify-content: center !important;
                }

                .bilibili-downloader-panel .close-btn:hover {
                    background: rgba(255,255,255,0.1) !important;
                }

                .bilibili-downloader-panel .section {
                    margin-bottom: 20px !important;
                }

                .bilibili-downloader-panel .section-title {
                    color: #ffa500 !important;
                    font-weight: bold !important;
                    margin-bottom: 10px !important;
                    font-size: 14px !important;
                }

                .bilibili-downloader-panel .file-item {
                    background: rgba(255,255,255,0.05) !important;
                    padding: 10px !important;
                    margin-bottom: 8px !important;
                    border-radius: 5px !important;
                    border-left: 3px solid #00a1d6 !important;
                }

                .bilibili-downloader-panel .file-info {
                    display: flex !important;
                    justify-content: space-between !important;
                    align-items: center !important;
                    margin-bottom: 5px !important;
                }

                .bilibili-downloader-panel .quality-badge {
                    background: #ffa500 !important;
                    color: black !important;
                    padding: 2px 6px !important;
                    border-radius: 3px !important;
                    font-size: 10px !important;
                    font-weight: bold !important;
                }

                .bilibili-downloader-panel .download-btn {
                    background: #27ae60 !important;
                    color: white !important;
                    border: none !important;
                    padding: 5px 10px !important;
                    border-radius: 3px !important;
                    cursor: pointer !important;
                    font-size: 12px !important;
                }

                .bilibili-downloader-panel .download-btn:hover {
                    background: #219653 !important;
                }

                .bilibili-downloader-panel .merge-guide {
                    background: rgba(255,255,255,0.1) !important;
                    padding: 15px !important;
                    border-radius: 5px !important;
                    margin-top: 20px !important;
                    font-size: 12px !important;
                }

                .bilibili-downloader-panel .code-block {
                    background: #1a1a1a !important;
                    color: #00ff00 !important;
                    padding: 10px !important;
                    border-radius: 3px !important;
                    font-family: 'Courier New', monospace !important;
                    font-size: 11px !important;
                    margin-top: 8px !important;
                    overflow-x: auto !important;
                }
            `;
            document.head.appendChild(style);
        }

        // 创建下载按钮
        createDownloadButton() {
            const button = document.createElement('button');
            button.className = 'bilibili-downloader-btn';
            button.innerHTML = '📥 下载视频';
            button.title = 'B站视频下载工具';

            button.onclick = () => this.showDownloadPanel();
            document.body.appendChild(button);

            console.log('✅ 下载按钮创建成功');
        }

        // 显示下载面板
        showDownloadPanel() {
            // 移除旧面板
            const oldPanel = document.getElementById('bilibili-downloader-panel');
            if (oldPanel) oldPanel.remove();

            if (!this.playInfo) {
                this.showNotification('❌ 未找到视频数据,请刷新页面重试', 'error');
                return;
            }

            const panel = document.createElement('div');
            panel.id = 'bilibili-downloader-panel';
            panel.className = 'bilibili-downloader-panel';
            panel.innerHTML = this.generatePanelHTML();

            document.body.appendChild(panel);
            this.bindPanelEvents(panel);

            console.log('✅ 下载面板创建成功');
        }

        // 生成面板HTML
        generatePanelHTML() {
            const videos = this.getVideos();
            const audios = this.getAudios();

            return `
                <button class="close-btn">×</button>
                <h3>&#127916; B站视频下载器</h3>

                <div class="section">
                    <div class="section-title">&#127909; 视频流 (${videos.length}个)</div>
                    ${videos.length > 0 ? this.generateFileListHTML(videos, 'video') : '<div style="opacity:0.7;font-size:12px;">暂无视频数据</div>'}
                </div>

                <div class="section">
                    <div class="section-title">&#128266; 音频流 (${audios.length}个)</div>
                    ${audios.length > 0 ? this.generateFileListHTML(audios, 'audio') : '<div style="opacity:0.7;font-size:12px;">暂无音频数据</div>'}
                </div>

                ${videos.length > 0 && audios.length > 0 ? `
                    <div class="merge-guide">
                        <div style="color:#ffa500;font-weight:bold;margin-bottom:8px;">&#128161; 本地合并指南</div>
                        <div style="margin-bottom:8px;">下载后使用FFmpeg合并音视频:</div>
                        <div class="code-block">
                            # Windows CMD<br>
                            ffmpeg -i video.mp4 -i audio.m4a -c copy output.mp4<br><br>
                            # Linux/Mac Terminal<br>
                            ffmpeg -i video.mp4 -i audio.m4a -c copy output.mp4<br><br>
                            # 批量合并脚本<br>
                            for %%i in (*.mp4) do ffmpeg -i "%%i" -i "%%~ni.m4a" -c copy "merged_%%i"
                        </div>
                        <div style="margin-top:8px;font-size:11px;opacity:0.8;">
                            &#128214; <a href="https://ffmpeg.org/download.html" target="_blank" style="color:#00a1d6;">下载FFmpeg</a> 
                        </div>
                    </div>
                ` : ''}

                <div style="text-align:center;margin-top:15px;font-size:11px;opacity:0.7;">
                    &#128170; 稳定可靠 · 无需额外依赖
                </div>
            `;
        }

        // 生成文件列表HTML
        generateFileListHTML(files, type) {
            return files.map((file, index) => {
                const quality = file.id || '未知';
                const codecs = file.codecs || '未知编码';
                const bandwidth = file.bandwidth ? ` (${Math.round(file.bandwidth/1000)}kbps)` : '';
                const url = file.baseUrl || file.base_url || '';

                return `
                    <div class="file-item">
                        <div class="file-info">
                            <div>
                                <span class="quality-badge">${quality}P</span>
                                <span style="font-size:12px;">${codecs}${bandwidth}</span>
                            </div>
                            <button class="download-btn" data-type="${type}" data-index="${index}">
                                下载
                            </button>
                        </div>
                        <div style="font-size:10px;opacity:0.7;word-break:break-all;">
                            ${url.substring(0, 80)}...
                        </div>
                    </div>
                `;
            }).join('');
        }

        // 绑定面板事件
        bindPanelEvents(panel) {
            const downloadButtons = panel.querySelectorAll('.download-btn');
            downloadButtons.forEach(btn => {
                btn.onclick = (e) => {
                    const type = e.target.getAttribute('data-type');
                    const index = parseInt(e.target.getAttribute('data-index'));
                    this.downloadFile(type, index);
                };
            });
        }

        // 下载文件
        downloadFile(type, index) {
            const files = type === 'video' ? this.getVideos() : this.getAudios();
            if (!files || !files[index]) {
                this.showNotification('&#10060; 文件不存在', 'error');
                return;
            }

            const file = files[index];
            const url = file.baseUrl || file.base_url;
            if (!url) {
                this.showNotification('&#10060; 无效的URL', 'error');
                return;
            }

            const extension = type === 'video' ? '.mp4' : '.m4a';
            const filename = this.generateFilename(file, type, index, extension);

            this.startDownload(url, filename);
            this.showNotification(`&#9989; 开始下载: ${filename}`, 'success');
        }

        // 生成文件名
        generateFilename(file, type, index, extension) {
            // 获取视频标题
            let title = 'bilibili_video';
            try {
                const titleElement = document.querySelector('h1.video-title, title');
                if (titleElement) {
                    title = titleElement.textContent
                        .replace(/[<>:"/\\|?*]/g, '_')
                        .substring(0, 30)
                        .trim();
                }
            } catch (e) {
                console.log('获取标题失败,使用默认名称');
            }

            return `${title}_${type}_${file.id || index}${extension}`;
        }

        // 开始下载
        startDownload(url, filename) {
            const link = document.createElement('a');
            link.href = url;
            link.download = filename;
            link.style.display = 'none';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

            console.log(`&#11015;&#65039; 下载: ${filename}`);
        }

        // 查找playinfo数据(增强版)
        findPlayInfo() {
            console.log('&#128269; 开始查找视频数据...');

            let attempts = 0;
            const maxAttempts = 8;

            const search = () => {
                attempts++;
                console.log(`&#128260; 第${attempts}次查找...`);

                // 方法1: 直接检查window对象
                if (window.__playinfo__) {
                    console.log('&#9989; 从window.__playinfo__找到数据');
                    this.playInfo = window.__playinfo__;
                    this.onPlayInfoFound();
                    return;
                }

                // 方法2: 搜索所有script标签
                const scripts = document.querySelectorAll('script');
                console.log(`&#128202; 扫描 ${scripts.length} 个script标签`);

                for (let i = 0; i < scripts.length; i++) {
                    const script = scripts[i];
                    const content = script.textContent || script.innerHTML || '';

                    if (content.includes('window.__playinfo__')) {
                        console.log(`&#9989; 在第${i+1}个script标签中找到目标`);

                        const patterns = [
                            /window\.__playinfo__\s*=\s*({[\s\S]*?})\s*;/,
                            /<script>window\.__playinfo__\s*=\s*({[\s\S]*?})<\/script>/,
                            /window\.__playinfo__\s*=\s*({.*?})(?=window\.__|<\/script>|$)/
                        ];

                        for (let j = 0; j < patterns.length; j++) {
                            const match = content.match(patterns[j]);
                            if (match) {
                                console.log(`&#127919; 使用模式${j+1}匹配成功`);

                                try {
                                    this.playInfo = JSON.parse(match[1]);
                                    console.log('&#9989; JSON解析成功');
                                    this.onPlayInfoFound();
                                    return;
                                } catch (error) {
                                    console.error('&#10060; JSON解析错误,尝试修复...');

                                    // 尝试修复JSON
                                    try {
                                        const fixed = this.fixJson(match[1]);
                                        this.playInfo = JSON.parse(fixed);
                                        console.log('&#128295; 修复后解析成功');
                                        this.onPlayInfoFound();
                                        return;
                                    } catch (e2) {
                                        console.error('&#10060; 修复后仍然解析失败');
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }

                // 如果没找到,准备重试
                if (attempts < maxAttempts) {
                    const delay = attempts * 1000;
                    console.log(`&#9203; 未找到数据,${delay}ms后重试...`);
                    setTimeout(search, delay);
                } else {
                    console.log('&#10060; 达到最大重试次数,停止查找');
                    this.showNotification('&#9888;&#65039; 未找到视频数据,部分视频可能需要登录', 'warning');
                }
            };

            // 延迟启动,确保页面加载完成
            setTimeout(search, 1000);
        }

        // 修复JSON格式
        fixJson(jsonStr) {
            return jsonStr
                .replace(/'/g, '"') // 单引号转双引号
                .replace(/([a-zA-Z_$][a-zA-Z0-9_$]*):/g, '"$1":') // 属性名加引号
                .replace(/,\s*}/g, '}') // 移除尾随逗号
                .replace(/,\s*]/g, ']') // 移除数组尾随逗号
                .replace(/\/\/.*$/gm, '') // 移除单行注释
                .replace(/\/\*[\s\S]*?\*\//g, ''); // 移除多行注释
        }

        // 找到数据后的处理
        onPlayInfoFound() {
            console.log('&#127881; 视频数据加载成功');

            // 更新按钮状态
            const button = document.querySelector('.bilibili-downloader-btn');
            if (button) {
                button.innerHTML = '&#9989; 就绪';
                button.style.background = '#27ae60';
            }

            // 显示成功通知
            this.showNotification('&#9989; 视频数据加载完成,可以下载了', 'success');
        }

        // 获取视频流
        getVideos() {
            if (!this.playInfo || !this.playInfo.data) return [];
            return this.playInfo.data.dash?.video || [];
        }

        // 获取音频流
        getAudios() {
            if (!this.playInfo || !this.playInfo.data) return [];
            return this.playInfo.data.dash?.audio || [];
        }

        // 显示通知
        showNotification(message, type = 'info') {
            const colors = {
                info: '#3498db',
                success: '#27ae60',
                error: '#e74c3c',
                warning: '#f39c12'
            };

            const notification = document.createElement('div');
            notification.innerHTML = message;
            notification.style.cssText = `
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                background: ${colors[type]};
                color: white;
                padding: 10px 20px;
                border-radius: 5px;
                z-index: 10002;
                font-family: Arial, sans-serif;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                max-width: 80vw;
                text-align: center;
            `;

            document.body.appendChild(notification);

            setTimeout(() => {
                if (notification.parentNode) {
                    notification.parentNode.removeChild(notification);
                }
            }, 3000);
        }
    }

    // 启动下载器
    setTimeout(() => {
        console.log('&#127919; 启动B站视频下载器...');
        window.bilibiliDownloader = new BilibiliDownloader();
    }, 1000);

})();

3810239a-fdfd-43b2-ab85-81e8f27072dd.png (376.36 KB, 下载次数: 23)

3810239a-fdfd-43b2-ab85-81e8f27072dd.png

B站视频下载器(稳定版)-3.0.user.txt

19.82 KB, 下载次数: 264, 下载积分: 吾爱币 -1 CB

附件

免费评分

参与人数 13吾爱币 +11 热心值 +13 收起 理由
fate1949 + 1 + 1 热心回复!
cwwloveyu + 1 + 1 我很赞同!
sdlions + 1 + 1 谢谢@Thanks!
wa00000 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
GoldenLumi + 1 + 1 我很赞同!大神厉害,我个人用的bilibili evolved,下载不是很方便,抽空上 ...
ccchpig + 1 我很赞同!
astonlake + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Maniac319 + 1 + 1 谢谢@Thanks!
固相膜 + 1 + 1 感谢分享。窗口无法关闭。需关闭网页。
xlln + 1 + 1 我很赞同!
hwh425 + 1 谢谢@Thanks!
脑子进秋刀鱼 + 1 + 1 我很赞同!
yp17792351859 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 #
wudalang123 发表于 2025-11-12 16:02
sagari 发表于 2025-11-6 11:09
关闭窗口好像关不掉,只能直接关闭网页。

在 bindPanelEvents 方法中,只绑定了下载按钮的点击事件,但没有处理关闭按钮的点击事件。修复方法在 bindPanelEvents 方法中添加关闭按钮的事件处理:
[JavaScript] 纯文本查看 复制代码
// 绑定面板事件
bindPanelEvents(panel) {
    // 绑定关闭按钮事件
    const closeBtn = panel.querySelector('.close-btn');
    if (closeBtn) {
        closeBtn.onclick = () => {
            panel.remove();
            console.log('&#9989; 下载面板已关闭');
        };
    }
    
    // 原有的下载按钮绑定保持不变
    const downloadButtons = panel.querySelectorAll('.download-btn');
    downloadButtons.forEach(btn => {
        btn.onclick = (e) => {
            const type = e.target.getAttribute('data-type');
            const index = parseInt(e.target.getAttribute('data-index'));
            this.downloadFile(type, index);
        };
    });
    
    // 可选:添加ESC键关闭支持
    this.addEscapeHandler(panel);
}

// 添加ESC键关闭功能(可选增强)
addEscapeHandler(panel) {
    const escapeHandler = (e) => {
        if (e.key === 'Escape') {
            panel.remove();
            document.removeEventListener('keydown', escapeHandler);
            console.log('&#9989; 通过ESC键关闭面板');
        }
    };
    document.addEventListener('keydown', escapeHandler);
    
    // 面板移除时清理事件监听
    const observer = new MutationObserver(() => {
        if (!document.body.contains(panel)) {
            document.removeEventListener('keydown', escapeHandler);
            observer.disconnect();
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
}
推荐
sagari 发表于 2025-11-6 11:09
沙发
lhsum 发表于 2025-11-4 12:33
3#
13801402556 发表于 2025-11-4 12:33
谢谢楼主分享
4#
eastmarquis 发表于 2025-11-4 12:49
哇偶,这个很不错哦,
5#
JadeLiao 发表于 2025-11-4 13:12
是不是我哪里操作有问题?插件好像没反应
6#
 楼主| 52pjmolian 发表于 2025-11-4 13:21 |楼主
本帖最后由 52pjmolian 于 2025-11-4 13:25 编辑
JadeLiao 发表于 2025-11-4 13:12
是不是我哪里操作有问题?插件好像没反应

是不是油猴权限没开?油猴详情里有 ‘’有权访问的网站‘’和‘’允许运行用户脚本‘’
附件是txt,需要改成.js再安装
7#
phantom 发表于 2025-11-4 18:28
大佬,这个会自动合并分段吗?
8#
itisif 发表于 2025-11-4 18:29

谢谢大佬分享
9#
脑子进秋刀鱼 发表于 2025-11-4 19:13
不错不错,可以下载充电视频
10#
MPFENG 发表于 2025-11-4 19:14

好东西,感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-1 02:41

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表