斗鱼特殊时期弹幕恢复

100%AI编写,没弹幕看牛魔直播

< Feedback on 斗鱼特殊时期弹幕恢复

Review: Good - script works

§
Posted: 2026-06-03

添加透明度


(function() {
'use strict';

console.log("=== 斗鱼特殊时期弹幕恢复引擎(透明度可调版)已启动 ===");

let myDanmuLayer = null;
let rulerNode = null;

// ==========================================
// === 核心参数配置区 (你可以随意修改这里) ===
// ==========================================
const DANMU_OPACITY = 0.6; // 🟢 弹幕透明度:取值范围 0.1 到 1.0 (1.0为完全不透明,0.5为半透明)
const MAX_TRACKS = 20; // 满幅支持 20 条轨道
const TRACK_HEIGHT = 36; // 每条轨道间距 36px
const TRACK_COOL_DOWN_MS = 2500; // 每条轨道发车后的潮汐冷静期(毫秒)
// ==========================================


let trackAvailableTime = Array(MAX_TRACKS).fill(0);

function initDanmuLayer() {
const playerContainer = document.getElementById('__video_container') || document.getElementById('js-web-stream');
if (!playerContainer) return false;

if (document.getElementById('gemini-rescue-danmu-layer')) {
document.getElementById('gemini-rescue-danmu-layer').remove();
}
myDanmuLayer = document.createElement('div');
myDanmuLayer.id = 'gemini-rescue-danmu-layer';
myDanmuLayer.style.position = 'absolute';
myDanmuLayer.style.inset = '0';
myDanmuLayer.style.overflow = 'hidden';
myDanmuLayer.style.pointerEvents = 'none';
myDanmuLayer.style.zIndex = '1000';
playerContainer.style.position = 'relative';
playerContainer.appendChild(myDanmuLayer);

if (document.getElementById('gemini-danmu-ruler')) {
document.getElementById('gemini-danmu-ruler').remove();
}
rulerNode = document.createElement('div');
rulerNode.id = 'gemini-danmu-ruler';
rulerNode.style.position = 'absolute';
rulerNode.style.visibility = 'hidden';
rulerNode.style.whiteSpace = 'nowrap';
rulerNode.style.fontSize = '24px';
rulerNode.style.fontWeight = 'bold';
document.body.appendChild(rulerNode);

trackAvailableTime.fill(0);
return true;
}

function startObserve() {
const barrageList = document.getElementById('js-barrage-list');
if (!barrageList) {
setTimeout(startObserve, 1000);
return;
}

if (!initDanmuLayer()) {
setTimeout(startObserve, 1000);
return;
}

const observer = new MutationObserver((mutations) => {
if (document.hidden) return;

mutations.forEach((mutation) => {
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
const contentEl = node.querySelector('.Barrage-content');
if (contentEl) {
const text = contentEl.innerText.trim();
createFloatingDanmu(text);
}
}
});
}
});
});

observer.observe(barrageList, { childList: true });
}

function createFloatingDanmu(text) {
if (!myDanmuLayer || !rulerNode || !text) return;

rulerNode.innerText = text;
const preciseWidth = rulerNode.offsetWidth;

const item = document.createElement('div');
item.innerText = text;
item.style.position = 'absolute';
item.style.color = '#ffffff';
item.style.fontSize = '24px';
item.style.fontWeight = 'bold';

// 🟢 应用透明度设置
item.style.opacity = DANMU_OPACITY;

item.style.textShadow = '1px 0px 0px #000, -1px 0px 0px #000, 0px 1px 0px #000, 0px -1px 0px #000, 1px 1px 0px #000, -1px -1px 0px #000, 1px -1px 0px #000, -1px 1px 0px #000';
item.style.whiteSpace = 'nowrap';
item.style.willChange = 'transform'; // 提示浏览器开启GPU加速

const containerWidth = myDanmuLayer.clientWidth;
const containerHeight = myDanmuLayer.clientHeight;

const now = performance.now();
let chosenTrack = -1;

for (let i = 0; i < MAX_TRACKS; i++) {
if (trackAvailableTime[i] <= now) {
chosenTrack = i;
break;
}
}

if (chosenTrack === -1) {
let minAvailableTime = Infinity;
for (let i = 0; i < MAX_TRACKS; i++) {
if (trackAvailableTime[i] < minAvailableTime) {
minAvailableTime = trackAvailableTime[i];
chosenTrack = i;
}
}
if (minAvailableTime > now + 1200) return;
}

const topPosition = 40 + (chosenTrack * TRACK_HEIGHT);
if (topPosition > containerHeight - 75) return;

item.style.top = topPosition + 'px';

// 🟢 优化:起点设为0,通过 transform 位移,GPU渲染更丝滑不卡顿
item.style.left = '0px';
let currentLeft = containerWidth;
item.style.transform = `translateX(${currentLeft}px)`;

myDanmuLayer.appendChild(item);

let lastTime = performance.now();

const speedFactor = 1.0 + (Math.random() * 0.2);
const speedPerMs = 0.10 * speedFactor;

const timeToClearRightEdge = (preciseWidth + 70) / speedPerMs;
const finalLockTime = Math.max(timeToClearRightEdge, TRACK_COOL_DOWN_MS);
trackAvailableTime[chosenTrack] = Math.max(trackAvailableTime[chosenTrack], now) + finalLockTime;

function walk(timeStamp) {
if (!myDanmuLayer || !item.parentElement) return;

let delta = timeStamp - lastTime;
lastTime = timeStamp;

if (delta > 100) delta = 16.7;

currentLeft -= speedPerMs * delta;
// 🟢 优化:使用 transform 替代原来的 style.left
item.style.transform = `translateX(${currentLeft}px)`;

if (currentLeft > -item.clientWidth - 50) {
requestAnimationFrame(walk);
} else {
item.remove();
}
}
requestAnimationFrame(walk);
}

document.addEventListener('visibilitychange', () => {
if (!document.hidden && myDanmuLayer) {
myDanmuLayer.innerHTML = '';
trackAvailableTime.fill(0);
}
});

let lastUrl = location.href;
setInterval(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
initDanmuLayer();
}
}, 2000);

setTimeout(startObserve, 2000);
})();

Post reply

Sign in to post a reply.