B站视频下载-油猴脚本

简介:调用B站API下载B站网页视频-可下载普通视频、分集视频、合集视频、番剧。

分享一个2022年5月写的脚本,当时下载b站视频一直用的是别人的油猴脚本,诚然那个脚本很强,还能下载字幕、音频等等(不过这些功能我都用不上),但是有个缺点就是文件命名不是视频标题(记得是一串数字字母组合,不好分辨不同的视频),下载完成后要自己手动修改,不太方便,于是就写了这个脚本。最近下载视频的时候发现分集视频页面元素发生了一点点小变化,导致脚本失效了,现在修复好了顺便分享出来。

效果图(普通视频点击下载后直接下载,没有分集选择框):

可以取消下载,下载好的文件命名就是视频标题。

调用的API下载的是1080p的flv格式的视频。

代码:

// ==UserScript==
// @name         B站视频下载
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  try to take over the world!
// @author       harglo
// @include      *://www.bilibili.com*
// @include      *://*.bilibili.com/video/*
// @include      *://*.bilibili.com/bangumi/play/*
// @require      https://unpkg.com/axios@0.27.2/dist/axios.min.js
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    setTimeout(function () {
        let xmlHTTP = new XMLHttpRequest();
        let xmlHttpAbort=false;
        function myDownloadTip(number,text,width,height){
            let tip=$('<div id="downloadVideoTip"><span id="downloadVideoTipText">'+text+'</span><button id="cancelDownload" style="float: right;margin-top: 7px;margin-right: 20px;height: 35px;line-height: 35px;">取消下载</button></div>');
            let tip_style="z-index:9999;position: fixed;top:20px;left: calc(50% - "+width/2+"px);width: "+width+"px;height: "+height+"px;border-radius: 5px;text-align: center;line-height: 50px;font-size: 16px;";
            number===1?tip.get(0).style.cssText=tip_style+"background-color: #dff0d8;color: #3c763d;":tip.get(0).style.cssText=tip_style+"background-color: #f2dede;color: #a94442;";
            $('body').append(tip);
            document.getElementById('cancelDownload').onclick=function () {
                this.style.display="none";
                xmlHttpAbort=true;
                xmlHTTP.abort();
                $('#downloadVideoTipText').text("已取消下载");
                $('#downloadVideoTip').fadeTo(3000,0);
                setTimeout(function () {
                    $('#downloadVideoTip').remove();
                },3100);
            };
        }
        function byteUnitConversion(size) {
            if (!size)
                return "";
            let num = 1024.00; //byte
            if (size < num)
                return size + "B";
            if (size < Math.pow(num, 2))
                return (size / num).toFixed(2) + "KB"; //kb
            if (size < Math.pow(num, 3))
                return (size / Math.pow(num, 2)).toFixed(2) + "MB"; //M
            if (size < Math.pow(num, 4))
                return (size / Math.pow(num, 3)).toFixed(2) + "G"; //G
            return (size / Math.pow(num, 4)).toFixed(2) + "T"; //T
        }
        function myDownloadFunction(fileUrl,fileName) {
            myDownloadTip(1,"正在下载",550,50);
            let blob;
            xmlHTTP.open('GET', fileUrl, true);
            xmlHTTP.responseType = 'arraybuffer';
            xmlHTTP.onload = function(e) {
                blob = new Blob([this.response]);
            };
            xmlHTTP.onprogress = function(pr) {
                //document.getElementById('downloadVideo').textContent="正在下载:"+Number(pr.loaded/pr.total*100).toFixed(2)+"%";
                $('#downloadVideoTipText').text("正在下载:"+byteUnitConversion(pr.loaded)+"/"+byteUnitConversion(pr.total)+"  进度: "+Number(pr.loaded/pr.total*100).toFixed(2)+"%");
                if(Number(pr.loaded/pr.total*100).toFixed(2)==100){
                    $('#downloadVideoTipText').text("下载完成");
                    $('#downloadVideoTip').fadeTo(3000,0);
                    setTimeout(function () {
                        $('#downloadVideoTip').remove();
                    },3100);
                }
            };
            let fileName2 = fileName;
            xmlHTTP.onloadend = function(e){
                if(!xmlHttpAbort){

                    console.log("fileName="+fileName2);
                    let tempEl = document.createElement("a");
                    document.body.appendChild(tempEl);
                    tempEl.style = "display: none";
                    let downUrl = window.URL.createObjectURL(blob);
                    tempEl.href = downUrl;
                    tempEl.download = fileName2;
                    tempEl.click();
                    window.URL.revokeObjectURL(downUrl);
                }
            };
            xmlHTTP.send();
        }
        //上面↑是方法
        //批量下载的弹出框
        let body = document.body;
        let toastDiv = document.createElement("div");
        toastDiv.setAttribute("id","myToastDiv");
        toastDiv.style.cssText="display:none;z-index:9999;position:fixed;bottom:8px;left:8px;background-color:#f4f4f4;border: skyblue 2px solid;";
        let toastDivChild1 = document.createElement("div");
        toastDivChild1.style.cssText="margin:8px";
        toastDivChild1.textContent="下载视频";
        toastDiv.appendChild(toastDivChild1);
        let htmlSpanElement = document.createElement("span");
        htmlSpanElement.textContent="X";
        htmlSpanElement.style.cssText="float:right;cursor:pointer;";
        htmlSpanElement.onclick=function(){
            $('#myToastDiv').animate({width: 'toggle'}, 460);
        };
        toastDivChild1.appendChild(htmlSpanElement);
        let toastDivChild2 = document.createElement("div");
        toastDiv.appendChild(toastDivChild2);
        toastDivChild2.style.cssText="border: skyblue 2px solid;margin:8px;max-height:200px;max-width:400px;overflow-y:auto;display:flex;flex-direction:row;flex-wrap:wrap;background-color:#f4f4f4";
        body.appendChild(toastDiv);
        //弹出框↑
        let href = location.href;
        axios.defaults.withCredentials=true;
        if(href.includes(".bilibili.com/video")){
            let bvid,cid,url;
            if(document.getElementById('multi_page')){
                console.log("分集视频");//bvid是一样的,cid不同
                let href1 = document.getElementsByClassName('watched on')[0].firstElementChild.href;
                bvid = href1.match(/(?=BV).*?(?=(\?|\/|$))/)[0];
                console.log(bvid);
                let myInterval=setInterval(function () {
                    console.log(document.getElementsByClassName('bpx-player-ctrl-eplist-menu')[0]);
                    if(document.getElementsByClassName('bpx-player-ctrl-eplist-menu')[0]){
                        clearInterval(myInterval);
                        let li1 = document.getElementsByClassName('bpx-player-ctrl-eplist-menu')[0].getElementsByTagName('li');
                        console.log(li1.length);
                        for (let i = 0; i < li1.length; i++) {
                            cid=li1[i].getAttribute("data-cid");
                            let title=li1[i].textContent;
                            console.log(cid);
                            console.log(title);
                            let htmlButtonElement = document.createElement("button");
                            htmlButtonElement.style.cssText="cursor:pointer;margin:5px;border: skyblue 2px solid;border-radius:10px;background-color:white;";
                            htmlButtonElement.textContent=title+".flv";
                            htmlButtonElement.onmouseover=function(){
                                this.style.backgroundColor="skyblue"
                            };
                            htmlButtonElement.onmouseout=function(){
                                this.style.backgroundColor="white";
                            };
                            htmlButtonElement.onclick=function(){
                                url="https://api.bilibili.com/x/player/playurl?bvid="+bvid+"&cid="+cid+"&qn=80&fnval=0&fnver=0&fourk=0";
                                console.log("url="+url);
                                axios.get(url).then((resp)=>{
                                    console.log(resp.data.data.durl[0].url);
                                    myDownloadFunction(resp.data.data.durl[0].url,title+".flv");
                                });
                            };
                            toastDivChild2.appendChild(htmlButtonElement);
                        }
                        let span = document.createElement('span');
                        span.title="下载视频";
                        span.innerHTML='<i class="van-icon-videodetails_share" style="transform: rotate(90deg)"></i>下载';
                        document.getElementsByClassName('collect')[0].after(span);
                        span.onclick=function () {
                            $('#myToastDiv').animate({width: 'toggle'}, 460);
                        }
                    }
                },300);
            }else if(document.getElementsByClassName('base-video-sections')[0]){
                console.log("合集视频");
                $.get(window.location.href,function(res){
                    let regExpMatchArray = res.match(/"aid":\d+,"cid":\d+,"title":(.*?),/g);
                    let resultArray=[...new Set(regExpMatchArray)];
                    console.log(resultArray);
                    for (let i = 0; i < resultArray.length; i++) {
                        let aid = resultArray[i].match(/(?<="aid":)(.*?)(?=,)/)[0];
                        let cid = resultArray[i].match(/(?<="cid":)(.*?)(?=,)/)[0];
                        let title = resultArray[i].match(/(?<="title":)(.*?)(?=,)/)[0];
                        console.log(aid+"-"+cid+"-"+title);
                        let htmlButtonElement = document.createElement("button");
                        htmlButtonElement.style.cssText="cursor:pointer;margin:5px;border: skyblue 2px solid;border-radius:10px;background-color:white;";
                        htmlButtonElement.textContent=title+".flv";
                        htmlButtonElement.onmouseover=function(){
                            this.style.backgroundColor="skyblue"
                        };
                        htmlButtonElement.onmouseout=function(){
                            this.style.backgroundColor="white";
                        };
                        htmlButtonElement.onclick=function(){
                            url="https://api.bilibili.com/x/player/playurl?avid="+aid+"&cid="+cid+"&qn=80&fnval=0&fnver=0&fourk=0";
                            console.log("url="+url);
                            axios.get(url).then((resp)=>{
                                console.log(resp.data.data.durl[0].url);
                                myDownloadFunction(resp.data.data.durl[0].url,title+".flv");
                            });
                        };
                        toastDivChild2.appendChild(htmlButtonElement);
                    }
                    let span = document.createElement('span');
                    span.title="下载视频";
                    span.innerHTML='<i class="van-icon-videodetails_share" style="transform: rotate(90deg)"></i>下载';
                    document.getElementsByClassName('collect')[0].after(span);
                    span.onclick=function () {
                        $('#myToastDiv').animate({width: 'toggle'}, 460);
                    }
                });
            }else{
                console.log("普通视频");
                let span = document.createElement('span');
                span.title="下载视频";
                span.innerHTML='<i class="van-icon-videodetails_share" style="transform: rotate(90deg)"></i>下载';
                document.getElementsByClassName('collect')[0].after(span);
                span.onclick=function () {
                    bvid = location.href.match(/(?=BV).*?(?=(\?|\/|$))/)[0];
                    axios.all([
                        axios.get("https://api.bilibili.com/x/player/pagelist?bvid="+bvid).then(resp=>{
                            console.log(resp.data);
                            console.log(resp.data.data[0].cid);
                            cid=resp.data.data[0].cid;
                            url="https://api.bilibili.com/x/player/playurl?bvid="+bvid+"&cid="+cid+"&qn=80&fnval=0&fnver=0&fourk=0";
                        })
                    ]).then(()=>{
                        console.log("url="+url);
                        axios.get(url).then((resp)=>{
                            console.log(resp.data.data.durl[0].url);
                            console.log(document.getElementsByClassName('tit')[0].textContent+".flv");
                            //window.open(resp.data.data.durl[0].url+"&attname="+document.getElementsByClassName('tit')[0].textContent+".flv");
                            myDownloadFunction(resp.data.data.durl[0].url,document.getElementsByClassName('tit')[0].textContent+".flv");
                        })
                    })
                }
            }
        }else if(href.includes(".bilibili.com/bangumi/play/")){
            console.log("番剧");
            //弹出框
            //弹出框↑
            let ep_id=document.getElementsByClassName('ep-item cursor visited')[0].firstElementChild.href.match(/(?<=ep).*?(?=\/)/)[0];
            axios.get("https://api.bilibili.com/pgc/view/web/season?ep_id="+ep_id).then((resp)=>{
                console.log(resp.data.result.episodes);
                for (let i = 0; i < resp.data.result.episodes.length; i++) {
                    let epid=resp.data.result.episodes[i].link.match(/(?<=ep).*?(?=$)/)[0];
                    console.log(epid);
                    let title=resp.data.result.episodes[i].share_copy;
                    console.log(title);
                    let htmlButtonElement = document.createElement("button");
                    htmlButtonElement.style.cssText="cursor:pointer;margin:5px;border: skyblue 2px solid;border-radius:10px;background-color:white;";
                    htmlButtonElement.textContent=title+".flv";
                    htmlButtonElement.onmouseover=function(){
                        this.style.backgroundColor="skyblue"
                    };
                    htmlButtonElement.onmouseout=function(){
                        this.style.backgroundColor="white";
                    };
                    htmlButtonElement.onclick=function(){
                        let requestUrl="https://api.bilibili.com/pgc/player/web/playurl?ep_id="+epid+"&qn=80&fnval=0&fnver=0&fourk=0";
                        console.log("url="+requestUrl);
                        axios.get(requestUrl).then((resp)=>{
                            console.log(resp.data.result.durl[0].url);
                            myDownloadFunction(resp.data.result.durl[0].url,title+".flv");
                        });
                    };
                    toastDivChild2.appendChild(htmlButtonElement);
                }
                let div = document.createElement('div');
                div.title="下载视频";
                div.setAttribute("class","share-info");
                div.innerHTML='<i class="iconfont icon-share" style="transform: rotate(90deg)"></i><span>下载</span>';
                document.getElementsByClassName('coin-info')[0].after(div);
                div.onclick=function () {
                    // myTip(1,"请在右侧点击下载",350,50);
                    $('#myToastDiv').animate({width: 'toggle'}, 460);
                }
            });
        }
    },5000);
})();
posted @ 2023-02-06 15:40  harglo  阅读(1591)  评论(0编辑  收藏  举报