Greasy Fork is available in English.
加载本地 B站弹幕 JSON文件,在 YouTube 视频上显示
当前为
// ==UserScript==
// @name YouTube 本地B站弹幕播放器
// @namespace https://github.com/ZBpine/bilibili-danmaku-download/
// @version 1.0.1
// @description 加载本地 B站弹幕 JSON文件,在 YouTube 视频上显示
// @author ZBpine
// @match https://www.youtube.com/watch*
// @grant none
// @license MIT
// @run-at document-end
// ==/UserScript==
(async () => {
'use strict';
// 创建按钮
function insertPlayerButton() {
function baseButtonStyle() {
return `
padding: 6px 10px;
background: #555;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
width: 100px;
`;
}
const panel = document.createElement('div');
Object.assign(panel.style, {
position: 'fixed',
left: '-110px',
bottom: '40px',
zIndex: '9999',
transition: 'left 0.3s ease-in-out, opacity 0.3s ease',
opacity: '0.2',
display: 'flex',
flexDirection: 'column',
gap: '8px',
background: '#333',
borderRadius: '0px 20px 20px 0px',
padding: '10px',
width: '110px'
});
panel.addEventListener('mouseenter', () => {
panel.style.left = '0px';
panel.style.opacity = '1';
});
panel.addEventListener('mouseleave', () => {
panel.style.left = '-110px';
panel.style.opacity = '0.2';
});
const loadBtn = document.createElement('button');
loadBtn.textContent = '📂 载入弹幕';
loadBtn.style.cssText = baseButtonStyle();
const toggleBtn = document.createElement('button');
toggleBtn.textContent = '✅ 弹幕开';
toggleBtn.style.cssText = baseButtonStyle();
panel.appendChild(loadBtn);
panel.appendChild(toggleBtn);
document.body.appendChild(panel);
toggleBtn.onclick = () => {
dmPlayer.toggle();
toggleBtn.textContent = dmPlayer.danmakuEnabled ? '✅ 弹幕开' : '❌ 弹幕关';
};
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
loadBtn.onclick = () => fileInput.click();
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
try {
const json = JSON.parse(e.target.result);
// ✅ 当用户载入 json 文件
dmPlayer.init();
dmPlayer.load(json.danmakuData);
const count = json.danmakuData.length;
const title = json.videoData?.title || '(未知标题)';
const readableTime = json.fetchtime ?
new Date(json.fetchtime * 1000).toLocaleString('zh-CN', { hour12: false }) : '(未知)';
dmPlayer.logTag(`🎉 已载入:\n🎬 ${title}\n💬 共 ${count} 条弹幕\n🕒 抓取时间:${readableTime}`);
alert(`🎉 已载入:\n🎬 ${title}\n💬 共 ${count} 条弹幕\n🕒 抓取时间:${readableTime}`);
} catch (err) {
dmPlayer.logTagError('❌ 弹幕 JSON 加载失败', err);
alert('❌ 弹幕 JSON 加载失败:' + err.message);
}
};
reader.readAsText(file);
});
}
const urlOfPlayer = 'https://cdn.jsdelivr.net/gh/ZBpine/bili-danmaku-statistic/docs/BiliDanmakuPlayer.js';
const { BiliDanmakuPlayer } = await import(urlOfPlayer);
const dmPlayer = new BiliDanmakuPlayer();
insertPlayerButton();
})();