您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
计算Bilibili视频剩余时长。
当前为
// ==UserScript== // @name Bilibili视频剩余时长计算器 // @namespace http://tampermonkey // @version 1.1 // @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`; } } })();