// ==UserScript==
// @name b站辅助(时长/集数/倍速/单集循环)
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 辅助使用bilibili(时长/集数/倍速/单集循环)
// @author eleky
// @match https://www.bilibili.com/*
// @require https://cdn.bootcss.com/jquery/3.5.0/jquery.min.js
// @icon https://www.bilibili.com/favicon.ico
// @grant none
// @license MIT
// ==/UserScript==
/*
### 功能
1. 统计视频已看时长、正在观看的这一集的时长、未看时长、总时长,显示到右侧。按“J”键。
2. 统计视频已看集数、正在看的集数、未看集数、总集数,显示到右侧。按“J”键。
3. 视频倍速播放及快捷键,按“,”或“<”速度减0.25,按“。”或“<”速度加0.25。b站自带的倍速调整会失效。
4. 打开视频后默认单集循环。按“J”键。
*/
/*
var jq = document.createElement('script');
jq.src = "https://cdn.bootcss.com/jquery/3.5.0/jquery.min.js";
document.getElementsByTagName('head')[0].appendChild(jq);
*/
let stop;
let speed = 1;
//let speed = 1;
//注册(不可用)按钮监听,
window.onkeydown = function(ev){
document.getElementsByTagName("video")[0].playbackRate = speed;//倍速关键代码,初始化倍速
//ev表示onkeydown事件对象,逗号/小于号是188,句号/大于号是190,回车是13,J是74
if(ev.keyCode===190){
speed += 0.25;
//console.log("speed:" + speed);
show_speed(speed);
document.getElementsByTagName("video")[0].playbackRate = speed;//倍速关键代码
}else if(ev.keyCode===188){
speed -= 0.25;
//console.log("speed:" + speed);
show_speed(speed);
document.getElementsByTagName("video")[0].playbackRate = speed;//倍速关键代码
}else if(ev.keyCode===74){
//主函数,统计集数和时长
main();
//选中洗脑循环
select_repeat();
}
}
function select_repeat() {
//$(".bilibili-player-iconfont .bilibili-player-iconfont-setting").trigger('mouseover');
$(".bilibili-player-video-btn-setting").trigger('mouseover');//使循环播放按钮出现
$(".bilibili-player-video-btn-setting").trigger('mouseout');//使循环播放按钮消失
//let setting = document.querySelector(".bilibili-player-iconfont .bilibili-player-iconfont-setting");
//setting.click();
$(".bilibili-player-video-btn-setting-left-repeat .bui-switch-input").trigger('click');//真实选中洗脑循环
$(".bilibili-player-video-btn-setting-left-repeat .bui-switch-input").attr('checked',true);//只是看起来选中了
}
/*
window.onkeydown = function(ev){
console.log(ev.keyCode);
}
*/
//显示倍速
function show_speed(speed) {
//找到显示位置
let position = document.getElementsByClassName("bilibili-player-video-top")[0];
//获取标签
let tag = document.getElementById("mytag");
let isNull = tag===null;
//没有创建过这个标签就创建
if (isNull){
//创建显示标签
tag = document.createElement("div");
tag.setAttribute("id", "mytag");
tag.style = '\n' +
' width: 50px;\n' +
' height: 28px;\n' +
' background-color: #666666;\n' +
' position: absolute;\n' +
' top: 50%;\n' +
' left: 50%;\n' +
' transform: translate(-50%, -50%);\n' +
' border-radius: 2px;\n' +
' z-index: 99999999;\n' +
' text-align: center;\n' +
' line-height: 28px;\n' +
' font-size: 14px;\n' +
' color: #fff;\n' +
' ';
}
$("#mytag").css("display", "block");
//写入html
tag.innerHTML = "X " + speed ;
//数据添加到面板
if (isNull){
position.after(tag);
}
//定时消失
sleep(1000).then(() => {
$("#mytag").css("display", "none");
})
}
function main() {
let nodeList;
try{
//获取视频列表节点
nodeList = getVideoList();
//console.log("已获取视频列表节点");
}catch (e){
//console.log("没有视频列表,不是视频选集");
show2();//单集视频显示时长
clearInterval(stop);
return;
}
//sleep(10000).then(() => {
//获取当前观看索引
let index = getCurrentLookVideoIndex(nodeList);
//console.log("当前观看索引:"+index);
//全部视频个数
let all_num = nodeList.length;
//console.log("全部视频个数:"+all_num);
//已看视频个数
let looked = index;
//console.log("已看视频个数:"+looked);
//未看视频个数
let number = all_num-index-1;
//console.log("未看视频个数:"+number);
//获取视频全部时间的数组
let allTime = getTimeArray(nodeList,0,nodeList.length);
//console.log("视频全部时间的数组:"+allTime);
//所有时间数组,格式 [h,m]
let all_time_arr = format(allTime);
//console.log("所有时间数组,格式 [h,m,s]:"+all_time_arr);
//获取已观看的视频时间数组
let looked_time = getTimeArray(nodeList,0,index);
//console.log("已观看的视频时间数组:"+ looked_time);
//已看时间数组,格式 [h,m]
let looked_time_arr = format(looked_time);
//console.log("已看时间数组,格式 [h,m,s]:"+ looked_time_arr);
//获取正在观看的视频时间数组
let looking_time = getTimeArray(nodeList,index,index+1);
//console.log("正在观看的视频时间数组:"+ looking_time);
//正在观看时间数组,格式 [h,m]
let looking_time_arr = format(looking_time);
//console.log("正在观看时间数组,格式 [h,m,s]:"+ looking_time_arr);
//获取未观看的视频时间数组
let timeArray = getTimeArray(nodeList,index+1,nodeList.length);
//console.log("未观看的视频时间数组:"+timeArray);
//未看时间数组,格式 [h,m]
let undone_time_arr = format(timeArray);
//console.log("未看时间数组,格式 [h,m,s]:"+undone_time_arr);
//显示到网页
show(looked_time_arr, looking_time_arr, undone_time_arr, all_time_arr, looked, number, all_num);
//console.log("显示到网页:");
//})
}
//单集视频显示时长
function show2() {
//获取总时长
let time_box = document.getElementsByClassName('bilibili-player-video-time-total')[0];
let time_num = time_box.innerHTML;
//console.log("显示到网页:" + time_num);
//找到显示位置
let plain = document.getElementById("danmukuBox");
let data_tag = document.getElementById("data_tag");
let isNull = data_tag===null;
//没有创建过这个标签就创建
if (isNull){
//创建
data_tag = document.createElement("div");
//console.log(data_tag)
//id赋值,用于下次更新查找
data_tag.setAttribute("id", "data_tag");
data_tag.setAttribute("width", "100%");
}
//写入html
data_tag.innerHTML = "<div>总时长:" + time_num + "</div>" ;
//数据添加到面板
if (isNull){
plain.after(data_tag);
}
}
//获取视频索引列表
function getVideoList() {
let list_box = document.getElementsByClassName('list-box')[0];
return list_box.childNodes;
}
//获取到当前观看视频的索引
function getCurrentLookVideoIndex(nodeList) {
let index = null;
for (let i = 0; i < nodeList.length; i++) {
//当前观看的视频
let current = nodeList[i];
//延迟之后获取class值
let class_name = current.className;
//当前观看
if (class_name==='watched on' || class_name==='on'){
//console.log(class_name) //类名
index = i;
//console.log("当前视频索引:"+index)
break;
}
//循环结束时还没有获取到索引(正常不会之前,前面就跳出了)
if (i === nodeList.length - 1){
console.log("error")
}
}
return index;
}
//获取到时间时间字符串
function getTimeArray(nodeList,start_index,end_index) {
let parent_array = [];
for (let i = start_index; i < end_index; i++) {
// nodeList[i]代表列表中的每一个li
let div = nodeList[i].getElementsByClassName("duration");
//每个视频的时长
let duration = div[0].innerHTML;
//console.log(duration); //格式:'09:29'
//添加到数组
let child_array = duration.split(":");
if (child_array.length<3){
//数组首部添加0
child_array.unshift('0');
}
parent_array.push(child_array);
}
return parent_array;
}
//计算时间/格式化
function format(timeArray) {
//console.log("视频列表长度:"+timeArray.length); //如果为0没有数据,就出错了
let h=0,m=0,s=0;
for (let i = 0; i < timeArray.length; i++) {
h += Number(timeArray[i][0]);
m += Number(timeArray[i][1]);
s += Number(timeArray[i][2]);
}
//将秒转换为分钟
let temp1 = s/60;
let m1 = Math.floor(temp1);
m +=m1;
//小于一分钟的转换为秒
let s2 = ('0.'+String(temp1).split('.')[1])*60;
//分钟转换为小时
let temp = m/60;
let h1 = Math.floor(temp);
//小于一小时的转换为分钟
let m2 = ('0.'+String(temp).split('.')[1])*60;
//最终结果
h +=h1;
s =Math.floor(s2);
m =Math.floor(m2);
//分钟出现NaN,原因是因为没有分钟,全是小时,直接赋值
if (isNaN(m)){
m="0";
}
//同理
if (isNaN(s)){
s="0";
}
//console.log("小时:"+h);
//console.log("分钟:"+m);
//console.log("秒:"+s);
return [h,m,s];
}
//在评论上显示
function show(looked_time_arr, looking_time_arr, undone_time_arr, all_time_arr, looked, number, all_num) {
//找到显示面板
let plain = document.getElementById("danmukuBox");
let data_tag = document.getElementById("data_tag");
let isNull = data_tag===null;
//没有创建过这个标签就创建
if (isNull){
//创建
data_tag = document.createElement("table");
//console.log(data_tag)
//id赋值,用于下次更新查找
data_tag.setAttribute("id", "data_tag");
data_tag.setAttribute("class", "multi-page-v1 small-mode");
data_tag.setAttribute("width", "100%");
}
//写入html
data_tag.innerHTML = "<tr><th></th><th>已看</th><th>正在</th><th>未看</th><th>全部</th></tr>" + show_Str();
//数据添加到面板
if (isNull){
plain.after(data_tag);
}
$("#data_tag th,#data_tag td").css("width", "20%");
$("#data_tag th,#data_tag td").css("padding", "5px");
$("#data_tag th,#data_tag td").css("text-align", "center");
function show_Str() {
let looked_time = looked_time_arr.join(':');
let looking_time = looking_time_arr.join(':');
let undone_time = undone_time_arr.join(':');
let all_time = all_time_arr.join(':');
let l1 = "<tr><td>集数</td><td>"+ looked + "</td><td>" + 1 + "</td><td>" + number + "</td><td>" + all_num +"</td></tr>";
let l2 = "<tr><td>时长</td><td>"+ looked_time + "</td><td>" + looking_time + "</td><td>" + undone_time + "</td><td>" + all_time +"</td></tr>";
return l1+l2;
}
}
//跳过充电鸣谢
function pass() {
let jumpButton = '.bilibili-player-electric-panel-jump';
setInterval(() => {
if($(jumpButton).length > 0) {
$(jumpButton).trigger('click')
}
}, 200)
}
//延时函数
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}