Greasy Fork is available in English.
b站主页面视频推荐挂载脚本,可以下载b站视频(最新版包括互动视频,番剧)呦~~~
// ==UserScript== // @name MyBilibili // @namespace http://tampermonkey.net/ // @version 0.4.3 // @description b站主页面视频推荐挂载脚本,可以下载b站视频(最新版包括互动视频,番剧)呦~~~ // @author N-cat // @match https://api.bilibili.com/x/web-interface/dynamic/region?ps=*&rid=* // @match *://www.bilibili.com/ // @match *://www.bilibili.com/video/* // @match *://www.bilibili.com/bangumi/play/* // @icon https://www.bilibili.com/favicon.ico?v=1 // @grant GM_xmlhttpRequest // @grant GM_download // @connect * // ==/UserScript== (function() { 'use strict'; // api及参数说明来自 https://zhuanlan.zhihu.com/p/210779665 const style = `<style> .add-main{ margin:auto; width:1100px; z-index:999999; } .add-div{ width: 206px; height: 206px; display:inline-block; padding:7px 7px 7px 7px; box-sizing:content-box; position:relative; z-index:999999; } .add-a{ color: #212121; margin: 10px 0 8px; height: 40px; text-decoration: none; width: 206px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; font-size: 14px; line-height: 20px; overflow: hidden; text-overflow: ellipsis; transition: color .3s; z-index:999999; } .add-a:hover{ color: #00a1d6; transition: color .3s; z-index:999999; } .add-img{ width: 206px; height: 116px; border-radius: 2px; z-index:999999; } .add-author{ color:#999; text-decoration: none; transition: color .3s; font-size: 12px; z-index:999999; } .add-author:hover{ color: #00a1d6; transition: color .3s; z-index:999999; } .re{ position:fixed; right:80px; bottom:80px; background-color:#00a1d6; color:white; height:50px; width:50px; border-radius: 10px; font-size:15px; border:solid 3px #FA5A57; cursor:pointer; outline: none; z-index:999999; } .top{ position:fixed; right:80px; bottom:150px; background-color:#00a1d6; color:white; height:50px; width:50px; border-radius: 10px; font-size:15px; border:solid 3px #FA5A57; cursor:pointer; outline: none; z-index:999999; } .add-bds{ position: absolute; height: 22px; width: 206px; top: 101px; color: white; font-size: 14px; background-color: rgba(0,0,0,.6); // text-align: center; border-radius: 2px; z-index:999999; } .jindu{ position:fixed; right:80px; bottom:40px; background-color:#00a1d6; width: 80px; color:white; border-radius: 10px; height: 20px; border:solid 3px #FA5A57; outline: none; cursor:default; text-align: center; font-size: 10px; z-index:999999; } </style>`; var ps = 50; // 页数 var rid = 1; // 类型(1:综合) // var cookie = document.cookie; // console.log(cookie) var data // api删除原数据 var pre = document.getElementsByTagName('pre') if(pre.length != 0){ pre[0].remove(); } // 主站隐藏原数据(旧) var olddiv = document.getElementsByClassName('b-wrap'); for(let i in olddiv){ if(i > 1){ olddiv[i].style.display = "none"; } } olddiv = document.getElementsByClassName('international-footer'); if(olddiv.length != 0){ olddiv[0].style.display = "none"; } // 主站隐藏原数据(新) var newdiv = document.getElementsByClassName('bili-layout'); if(newdiv.length != 0){ newdiv[0].style.display = "none"; } // 请求推荐api function getvideo(){ GM_xmlhttpRequest({ url:"https://api.bilibili.com/x/web-interface/dynamic/region?ps=" + ps + "&rid=" + rid, // url:"https://api.bilibili.com/x/web-interface/popular?ps=50&pn=10", method:"get", // cookie:cookie, onload:function(xhr){ data = JSON.parse(xhr.response) console.log(data.data.archives) // 添加元素 let div = document.createElement("div"); div.classList.add('add-main'); for(let i of data.data.archives){ //div.innerHTML += '<div class="add-div">' //div.innerHTML += '<a href="https://www.bilibili.com/video/' + i.bvid + '" target="_blank"><img class="add-img" src="' + i.pic + '" /></a><br>' //div.innerHTML += '<a class="add-a" href="https://www.bilibili.com/video/' + i.bvid + '" target="_blank">' + i.title + '</a></div>'; // 视频总div let id = document.createElement("div"); div.appendChild(id); id.classList.add('add-div'); // 图片链接 let a1 = document.createElement("a"); id.appendChild(a1); a1.innerHTML = '<img class="add-img" src="' + i.pic + '" />' a1.setAttribute('href',"https://www.bilibili.com/video/" + i.bvid ); a1.setAttribute('target',"_blank"); // 文字链接 let a2 = document.createElement("a"); id.appendChild(a2); a2.classList.add('add-a'); a2.setAttribute('href',"https://www.bilibili.com/video/" + i.bvid ); a2.setAttribute('target',"_blank"); // 文字 let txt = document.createTextNode(i.title); a2.appendChild(txt); // 作者 let a3 = document.createElement("a"); id.appendChild(a3); a3.classList.add('add-author'); a3.setAttribute('href',"https://space.bilibili.com/" + i.owner.mid ); a3.setAttribute('target',"_blank"); let author = document.createTextNode(i.owner.name); a3.appendChild(author); // 播放量,点赞,时常 let bds = document.createElement("div"); bds.classList.add('add-bds'); let b = i.stat.view; if(i.stat.view >= 10000){ b = (i.stat.view/10000).toFixed(1) + '万' } let d = i.stat.like; if(i.stat.like >= 10000){ d = (i.stat.like/10000).toFixed(1) + '万' } let s = i.duration; if(i.duration >= 3600){ let mm = parseInt((i.duration%3600)/60); if(mm < 10){ mm = '0' + mm; } let ss = i.duration%60; if(ss < 10){ ss = '0' + ss; } s = parseInt(i.duration/3600) + ':' + mm + ':' + ss; } else if(i.duration <= 3600 && i.duration >= 60){ let mm = parseInt(i.duration/60); if(mm < 10){ mm = '0' + mm; } let ss = i.duration%60; if(ss < 10){ ss = '0' + ss; } s = mm + ':' + ss; } else { let ss = i.duration%60; if(ss < 10){ ss = '0' + ss; } s = '00:' + ss } bds.innerHTML = '<span style="padding-left:10px;float:left;line-height:22px"> ▶ ' + b + ' ❤ ' + d + '</span><span style="padding-right:10px;float:right;line-height:22px">' + s + '</span>'; id.appendChild(bds); } div.innerHTML += style; // 设置添加位置 var header = document.getElementsByClassName('bili-layout'); if(header.length != 0){ header[0].parentNode.insertBefore(div, header[0]); // 新 } else { document.body.append(div); // 旧 } } }) } function getQueryVariable(variable){ var query = window.location.search.substring(1); var vars = query.split("&"); for (var i=0;i<vars.length;i++) { var pair = vars[i].split("="); if(pair[0] == variable){return pair[1];} } return(false); } // 进度条 let jindu = document.createElement("input"); jindu.classList.add('jindu'); jindu.setAttribute("value", "下载进度条"); jindu.setAttribute("readonly", "true"); document.body.append(jindu); // 请求事件监听(每0.5s输出一次) var ms= 500; var lastClick = Date.now() - ms; function downloadProgress(event, type) { // 如果lengthComputable属性的值是false,那么意味着总字节数是未知并且total的值为零 if ((event.lengthComputable && Date.now() - lastClick >= ms) || event.loaded == event.total) { let progress = event.loaded / event.total * 100; jindu.setAttribute("value", `${type}下载${progress.toFixed(0)}%`); console.log(`${type}下载${progress.toFixed(0)}%`); // 更新时间 lastClick = Date.now(); } } getvideo(); var url = window.location.href; var btn = document.createElement("input"); // 创建blob下载 function downloadVideo(data, filename, type, page){ try { // 文件流可以自定义文件名 var blob = new Blob([data], { type: `${type}/mp4` }); var url = window.URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = `${filename}-P${page}-${type}.mp4`; a.style.display = 'none'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); // 释放 URL console.log(`下载成功: ${filename}-P${page}-${type}.mp4`); } catch (error) { console.error("下载失败: ", error); } } // 下载视频或音频 function download(url, name, type, page){ GM_xmlhttpRequest({ url: url, method: "GET", responseType: 'blob', // cookie:document.cookie, headers: { 'Referer': 'https://www.bilibili.com', // 根据实际情况设置 // 'Cookie':document.cookie, }, onload: function(xhr) { console.log("下载完成"); console.log(xhr.response) downloadVideo(xhr.response, name, type, page); }, onerror: function(error) { console.error("下载失败", error); }, onprogress: function(progress) { downloadProgress(progress, type); } }); } // 获下载链接 function getUrl(name, bv, cid, mod, page) { var url = 'https://api.bilibili.com/x/player/playurl?bvid='+bv+'&cid='+cid+'&qn=120'; console.log(url); if(mod == 3 || mod == 2){ url += '&fnval=4048'; } GM_xmlhttpRequest({ url:url, method:"get", // cookie:cookie, onload:function(xhr){ data = JSON.parse(xhr.response) console.log(data); var con = confirm('确认后视频开始下载,请耐心等待...\n下载视频及音频:'+name+'-P'+page); if(con == true){ if(mod == 3 || mod == 2){ var videourl = data.data.dash.video[0].baseUrl; console.log(videourl); download(videourl, name, "video", page); var audiourl = data.data.dash.audio[0].baseUrl; console.log(audiourl); download(audiourl, name, "audio", page); } else { var allurl = data.data.durl[0].url; download(allurl, name, "all", page); } } // 复制视频音频合并软件链接到剪切板 const input = document.createElement('input'); document.body.appendChild(input); input.setAttribute('value', "https://gitee.com/z2322739526/mybilibili/blob/master/%E5%90%88%E5%B9%B6%E8%A7%86%E9%A2%91%E9%9F%B3%E9%A2%91.exe"); input.select(); // 选取文本域的内容 if (document.execCommand('copy')) { document.execCommand('copy'); console.log('复制成功'); } document.body.removeChild(input); } }); } if(url.split('/')[3] == 'video' || url.split('/')[3] == "bangumi"){ // 下载按钮 btn.setAttribute("type", "button"); btn.setAttribute("value", "下载"); btn.classList.add('re'); document.body.append(btn); var page = 1; var bv = ""; btn.onclick = function(){ var page = 1; var bv = ""; // 番剧类型获取bv if(url.includes('www.bilibili.com/bangumi/play')){ const parentElement = document.querySelector('.mediainfo_mediaRight__SDOq4'); const divElement = parentElement.getElementsByTagName('div')[1]; // 第二个div(索引1) const spanElement = divElement.getElementsByTagName('span')[3]; // 第四个span(索引3) bv = spanElement.textContent; } else { bv = url.split('/')[4].split('?')[0]; if(getQueryVariable('p')){ page = getQueryVariable('p'); } } console.log('bvid:' + bv); GM_xmlhttpRequest({ url:'https://api.bilibili.com/x/web-interface/view/detail?bvid='+bv, method:"get", // cookie:cookie, onload:function(xhr){ data = JSON.parse(xhr.response); console.log(data); console.log(data.data.View); var name = data.data.View.title; var cid = data.data.View.pages[page-1].cid; // cid = 268123629 // test var aid = data.data.View.aid; var part = data.data.View.pages[page-1].part; console.log('aid:' + aid); console.log('cid:' + cid); // 判断是否是互动视频 // https://api.bilibili.com/x/player/wbi/v2?bvid=BV1DK411u7QX&cid=267642140 // https://api.bilibili.com/x/stein/nodeinfo?bvid=BV1DK411u7QX&graph_version=397257 GM_xmlhttpRequest({ url:'https://api.bilibili.com/x/player/wbi/v2?bvid='+bv+'&cid='+cid, method:"get", // cookie:cookie, onload:function(xhr){ data = JSON.parse(xhr.response) console.log(data); var graph_version = 0; if('interaction' in data.data){ console.log('互动视频graph_version:' + data.data.interaction.graph_version); graph_version = data.data.interaction.graph_version; } else { console.log('未检测到interaction字段,该视频非互动视频'); } var mod = 1; // 默认1直接完整视频,2视频音频分别下载,3互动视频 if(graph_version != 0){ // 互动视频 GM_xmlhttpRequest({ url:'https://api.bilibili.com/x/stein/nodeinfo?bvid='+bv+'&graph_version='+graph_version, method:"get", // cookie:cookie, onload:function(xhr){ data = JSON.parse(xhr.response) console.log(data); var story_list = data.data.story_list; var outlist = {} var outtext = "检测到该视频为互动视频,视频音频合并软件链接将在确认后复制到剪切板,请输入下载视频名称对应id:\n" for(let i of story_list){ outlist[i.cursor] = [i.title, i.cid]; // outtext += 'id:' + i.cursor + '-' + i.title + ','; outtext += `${i.title}(id=${i.cursor});` } var id = 0; // 默认为0 id = prompt(outtext); cid = outlist[id][1]; name += "-" + outlist[id][0]; console.log('互动视频cid:' + cid); mod = 3; getUrl(name, bv, cid, mod, page); } }); } else { // 非互动视频 mod = prompt("请选择下载模式id:\nid:1-直接下载视频,画质较低(默认)\nid:2-分别下载视频音频,画质较高(视频音频合并软件链接将在确认后复制到剪切板)") getUrl(name, bv, cid, mod, page); } } }); } }); } }else{ // 刷新按钮 btn.setAttribute("type", "button"); btn.setAttribute("value", "刷新"); btn.classList.add('re'); document.body.append(btn); btn.onclick = function(){ document.body.scrollTop = document.documentElement.scrollTop = 0; var dd = document.getElementsByClassName('add-main'); for(let j of dd){ j.style.display = "none"; } getvideo(); // 请求后刷新也会请求一次,这里待优化 } } // 顶部按钮 var top = document.createElement("input"); top.setAttribute("type", "button"); top.setAttribute("value", "顶部"); top.classList.add('top'); document.body.append(top); top.onclick = function(){ document.body.scrollTop = document.documentElement.scrollTop = 0; } // 下拉刷新 let timeout = null; window.onscroll = function() { const scrollH = document.documentElement.scrollHeight;// 文档的完整高度 const scrollT = document.documentElement.scrollTop || document.body.scrollTop; // 当前滚动条的垂直偏移 const screenH = window.screen.height; // 屏幕可视高度 if ((scrollH - scrollT - screenH) < 500) { // 只是一个相对值,可以让页面再接近底面的时候就开始请求 timeout && clearTimeout(timeout); // 判断timeout是否在执行 timeout = setTimeout(() => { console.log('下拉刷新') getvideo(); }, 3000); // api在3s内请求返回重复内容 } }; })();