Greasy Fork is available in English.
计算Bilibili视频剩余时长。
当前为
// ==UserScript==
// @name Bilibili视频剩余时长计算器
// @namespace http://tampermonkey
// @version 1.0
// @description 计算Bilibili视频剩余时长。
// @author txsxcy
// @match https://www.bilibili.com/video/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// Define CSS style rules
const style = `
.video-info {
overflow: hidden;
text-align: center;
box-sizing: border-box;
height: 100%;
width: 100%;
background-color: rgb(241, 242, 243);
border-radius: 6px;
font-size: 15px;
line-height: 30px;
margin-bottom: 25px;
padding: 10px 10px 0px 10px;
pointer-events: all;
}
.video-info li {
width: 30%;
float: left;
margin-right: 10px;
margin-bottom: 10px;
list-style: none;
}
.video-info ul li:hover {
background-color: rgb(255, 255, 255);
border-radius: 12px;
color: #00aeec;
cursor:pointer
}
.video-info ul li:hover span {
color: #00aeec;
}
.video-info span {
display: block;
width: 100%;
}
.video-info li span:first-child {
color: #222;
font-weight: 700;
}
.video-info li span:last-child {
font-size: 12px;
color: #666;
}
`;
// Create a new style element and append it to the head of the document
const styleEl = document.createElement('style');
styleEl.textContent = style;
document.head.appendChild(styleEl);
})();
(function () {
'use strict';
// 选择要监听的元素
const targetNodes = document.querySelectorAll('.head-left, .html_player_enhance_tips');
// 创建一个 MutationObserver 实例
const observer = new MutationObserver(function (mutationsList) {
// 遍历所有变化记录
for (const mutation of mutationsList) {
// 如果变化是目标节点的innerText发生变化
if (mutation.type === 'childList' && mutation.target.innerText !== mutation.oldValue) {
// 执行函数abc()
abc();
}
}
});
// 配置观察选项
const config = { attributes: false, childList: true, subtree: true, characterDataOldValue: true };
// 开始观察目标节点
for (const targetNode of targetNodes) {
observer.observe(targetNode, config);
}
function abc() {
let currentspeed = parseFloat(document.querySelector(".html_player_enhance_tips").innerText.match(/播放速度:(\d+(\.\d+)?)/)[1]);
let matches = document.querySelector('.cur-page').innerText.match(/\((\d+)\/(\d+)\)/);
let start = parseInt(matches[1]);
let end = parseInt(matches[2]);
let videoData = document.querySelector('#danmukuBox');
let duration = calTime(start, end);
let totalDuration = durationToString(calTime(1, end).total);
let watchedDuration = durationToString(calTime(1, start - 1).total);
let remainingDuration = durationToString(calTime(start, end).total);
let remainingDuration2x = durationToString(Math.floor(duration.total / 2));
let remainingDuration3x = durationToString(Math.floor(duration.total / 3));
let remainingDurationXx = durationToString(Math.floor(duration.total / currentspeed));
// 获取要插入的元素的父元素
let parent = videoData.parentElement;
// 查找是否有类名为 "video-info" 的元素
let info = parent.querySelector(".video-info");
// 如果存在,则删除它
if (info) {
info.remove();
}
const html = ` <div>
<ul>
<li>
<span>总时长</span>
<span>${totalDuration}</span>
</li>
<li>
<span>已看时长</span>
<span>${watchedDuration}</span>
</li>
<li>
<span>剩余时长</span>
<span>${remainingDuration}</span>
</li>
<li>
<span>2x</span>
<span>${remainingDuration2x}</span>
</li>
<li>
<span>3x</span>
<span>${remainingDuration3x}</span>
</li>
<li>
<span>${currentspeed}x</span>
<span>${remainingDurationXx}</span>
</li>
</ul>
</div>`;
videoData.insertAdjacentHTML('afterend', `<div class="video-info">${html}</div>`);
}
window.onpopstate = function (event) {
// 调用 ab 函数
abc();
};
setTimeout(() => abc, 3000);
function calTime(start, end) {
const lis = document.querySelectorAll('.list-box .duration');
const duration = { total: 0, watched: 0, remaining: 0 };
lis.forEach((currentValue, index) => {
if (index >= start - 1 && index <= end - 1) {
const time = currentValue.innerText.replace(/\.\d+/g, ''); // 去除小数点
const timeArr = time.split(':');
let timeSeconds = 0;
if (timeArr.length == 3) {
timeSeconds += Number(timeArr[0]) * 60 * 60;
timeSeconds += Number(timeArr[1]) * 60;
timeSeconds += Number(timeArr[2]);
} else {
timeSeconds += Number(timeArr[0]) * 60;
timeSeconds += Number(timeArr[1]);
}
if (index < end - 1) {
duration.watched += timeSeconds;
} else {
duration.remaining += timeSeconds;
}
duration.total += timeSeconds;
}
});
return duration;
}
function durationToString(duration) {
const h = parseInt(duration / 3600);
const m = parseInt(duration / 60) % 60;
const s = duration % 60;
if (h > 0) {
return `${h}h ${m}min ${s}s`;
} else {
return `${m}min ${s}s`;
}
}
})();