js弹幕脚本(基于油猴)
该脚本包含往视频上插入弹幕,发射弹幕,弹幕查询,弹幕暂停,脏话过滤等基础功能。话不多说 ,直接上代码。
仅供参考 ,该代码是我给别人写的定制化的,复制后不可用。
// ==UserScript==
// @name bullet chat
// @namespace http://
// @version 0.0.1a
// @description Display user comments in 'danmaku' style, or in a side comment area
// @require http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js
// @author Hezc
// @match https://
// @grant GM_xmlhttpRequest
// @connect *
// ==/UserScript==
(function ($) {
'use strict';
let _$ = document;
const essentialElements = {
player: _$.getElementById("primaryScreen"),
sideBar: _$.getElementById("eventTabPanes"),
video: _$.getElementById("primaryVideo"),
};
window.datas = [];
let listener;
let danmakuCtl;
let videoFlag;
let textList = ['需要屏蔽的关键字1', '需要屏蔽的关键字2', '需要屏蔽的关键字3', '需要屏蔽的关键字4'];
let timeElapsed = () => essentialElements.video.currentTime;
let domId = 0;
var server = () => (getPageID() === null ? (() => { throw 'Page ID not specified!'; })() : `http://127.0.0.1:8888/${getPageID()}`);
function getPageID() {
var regex = /\?id\=([0-9a-z\-]+)(&start)?/gi;
var result = regex.exec(location.href);
if (result === null) {
console.error("");
} else {
result = result[1];
}
return result;
}
function loadDanmaku() {
GM_xmlhttpRequest({
method: "GET",
url: server(),
headers: { "Content-Type": "application/x-www-form-urlencoded" },
onload: (resp) => {
datas = JSON.parse(resp.responseText);
window.danmakuList = datas.filter(v => v.time > timeElapsed() - 1);
if (danmakuList) {
danmakuList.forEach((item) => {
listener.register(item.time, () => { danmakuCtl.shoot(item.value, item.id); });
});
} else {
console.log("No comment avaliable on this lecture");
}
// 弹幕列表
if (danmakuList.length) {
let html = ''
for (let i in danmakuList) {
html += `<p class="bbp-item" style="line-height: 35px;">${danmakuList[i].value}</p>`
}
let timer01;
timer01 && clearInterval(timer01)
timer01 = setInterval(() => {
if ($('.bulletChatCont-allp')) {
$('.bulletChatCont-allp').html(html)
clearInterval(timer01)
}
}, 33)
}
},
onerror: (e) => {
console.error("Cannot load comment for this page...");
console.error(e);
}
});
}
// 发射弹幕
function sendDanmaku(content) {
GM_xmlhttpRequest({
method: "POST",
url: server() + "/add",
data: "value=" + content + "&time=" + (timeElapsed() + ""),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
onload: (resp) => {
if (resp.responseText.indexOf("Success") != -1){
let item = JSON.parse(JSON.stringify(datas[datas.length - 1]));
datas.push({ id: ++item.id, vid: ++item.vid, time: timeElapsed(), value: content });
listener.register(timeElapsed(), () => { danmakuCtl.shoot(content, item.id); });
}else{
console.warn(resp.responseText);
}
},
onerror: (e) => {
console.log(e);
}
});
}
// 单条弹幕相关
class Barrage {
constructor(videoBox) {
this.videoBox = videoBox;
let rect = this.videoBox.getBoundingClientRect();
this.w = rect.right - rect.left;
this.h = rect.bottom - rect.top;
this.barrageList = [];
}
shoot(value, id) {
let top = this.getTop();
let color = this.getColor();
let offset = this.getOffset();
let reg = new RegExp(textList.join('|'), 'g');
let barrage = {
id: id,
value: value.replace(reg, '***'),
top: top,
left: this.w,
color: color,
offset: offset,
}
this.barrageList.push(barrage);
this.draw()
}
draw() {
// 创建&&移除
if (this.barrageList.length) {
domId++;
let s = this.barrageList[this.barrageList.length - 1];
let html = `<div class="apend-dom-zx apend-dom-${domId}"
style="color:${s.color};
cursor: pointer;
position:absolute;
top:${s.top}px;
animation:mymove 10s;
animation-fill-mode: forwards;
z-index: 999999;
font-size:25px;
font-weight:600;"
data-id="${s.id}">
<span class="bullet-chat-text">${s.value}</span>
<div class="bullet-chat-tips">
<div class="bullet-chat-selss">
<div class="bullet-chat-items bullet-chat-items-fabulous">点赞</div>
<div class="bullet-chat-items bullet-chat-items-reply">回复</div>
<div class="bullet-chat-items bullet-chat-items-forward">转发</div>
<div class="bullet-chat-items bullet-chat-items-copy">复制</div>
</div>
</div>
</div>`;
$('#BulletChatBox').append(html);
$('#primaryScreen').on('webkitAnimationEnd', `.apend-dom-${domId}`, function () {
$(this).remove()
});
}
}
getColor() {
return '#' + Math.floor(Math.random() * 0xffffff).toString(16);
}
getTop() {
return Math.floor(Math.random() * (this.h - 30)) + 30;
}
getOffset() {
return +(Math.random() * 4).toFixed(1) + 1;
}
}
// 弹幕按视频时间进行发射
class PlayerTimeListener {
constructor() {
this.callbackList = new Map();
this.lastCallOn = 0.0;
}
register(time, func) {
this.callbackList.set(time, [func, true]);
}
start() {
window.interval = setInterval(() => {
if (timeElapsed() < this.lastCallOn) {
this.callbackList.forEach((v, k) => {
if (k > timeElapsed()) {
this.callbackList.set(k, [v[0], true]);
}
});
}
this.callbackList.forEach((v, k) => {
if (k < timeElapsed() && v[1]) {
this.callbackList.set(k, [v[0], false]);
v[0]();
}
});
this.lastCallOn = timeElapsed();
}, 500);
}
stop() {
clearInterval(window.interval);
}
}
function main() {
listener = new PlayerTimeListener();
listener.stop();
listener.start();
var videoBox = `<div id="BulletChatBox" style="width:100%;height:100%;position:absolute;top:0;left:0;z-index:999;overflow:hidden"></div>`;
$('#primaryScreen').append(videoBox);
danmakuCtl = new Barrage($('#BulletChatBox').get(0));
danmakuCtl.draw();
loadDanmaku();
}
// init
window.onload = () => {
setTimeout(main, 2000);
!function () {
var timer = setTimeout(() => {
var commentArea = essentialElements.sideBar.appendChild(_$.createElement("DIV"));
commentArea.style.width = commentArea.parentElement.clientWidth + "px";
commentArea.style.height = "10em";
commentArea.style.position = "absolute";
commentArea.style.bottom = 0;
commentArea.style.left = 0;
commentArea.innerHTML = `<textarea id="danmaku-content" style:"width:100%;height:7em;" placeholder="Write your comment here"></textarea>
<div id="danmaku-submit">Send</div>
<div id="danmaku-switch">Close</div>
`;
$('#eventTabPanes').on('click', '#danmaku-submit', function () {
$("#danmaku-content").val().trim() && sendDanmaku($("#danmaku-content").val());
$("#danmaku-content").val('')
$("#danmaku-content").css({ 'border-color': 'rgb(133, 133, 133)' })
$(this).off()
})
// open&close
$('#eventTabPanes').on('click', '#danmaku-switch', function () {
if ($(this).hasClass('switch-flag')) {
$(this).removeClass('switch-flag').text('Close')
$('#BulletChatBox').css({ 'z-index': '999' })
} else {
$(this).addClass('switch-flag').text('Open')
$('#BulletChatBox').css({ 'z-index': '-1' })
}
})
//search
$('#bookmarksTabHeader').after(`<div id="bulletChatCont" class="event-tab-header accented-tab" >
<span class="text">弹幕</span>
</div>`)
$('body').append(`<div class="bulletChatCont-box bulletChatCont-box-none" style="width: 300px;min-height: 400px;max-height: 600px;overflow: auto;background: #fff;border-radius: 8px;position: fixed;top: 20px;left: 150px;padding: 0 20px 20px 20px;box-shadow: 0 0 18px rgba(0, 0, 0, .3);z-index: 9999;">
<div class="bulletChatCont-box-header" style="display: flex;background: #fff;align-items: center;justify-content: center;position: sticky;top: 0px;border-bottom: 1px solid #ccc;padding: 20px 0;">
<input type="text" placeholder="search content" class="bulletChatCont-box-ipt" style="height: 28px;border:1px solid #ccc;padding-left: 5px;outline: none;margin-right: 10px;">
<div class="bulletChatCont-box-btn">search</div>
</div>
<div class="bulletChatCont-allp">
<p class="bbp-item" style="line-height: 35px;">空你几哇</p>
</div>
</div>`)
// 播放状态 - 弹幕
essentialElements.video.addEventListener("playing", function () {
$('.apend-dom-zx').css({ 'animation-play-state': 'running' })
videoFlag = true;
});
essentialElements.video.addEventListener("pause", function () {
$('.apend-dom-zx').css({ 'animation-play-state': 'paused' })
videoFlag = false;
});
// 创建css
var style = document.styleSheets[0];
style.insertRule(`.bulletChatCont-box-none {display:none;}`);
style.insertRule(`.bullet-chat-items {flex-shrink: 0;cursor: pointer;}`);
style.insertRule(`#danmaku-submit,#danmaku-switch,.bulletChatCont-box-btn {cursor: pointer;display: inline-block;padding: 3px 5px;border:1px solid #888;background: #eee;border-radius: 5px;}`);
style.insertRule(`.bullet-chat-tips::before {content: '';width: 0;height: 0px;border: 5px solid transparent;border-bottom: 5px solid rgba(0, 0, 0, .5);position: absolute;top: -10px;left: 50%;transform: translateX(-50%);}`);
style.insertRule(`.bullet-chat-tips::after {content: '';width: 100%;height: 20px;position: absolute;top: -18px;left: 0;}`);
style.insertRule(`.bullet-chat-selss {display: flex;justify-content: space-between;}`);
style.insertRule(`.bullet-chat-tips {width: 180px;padding: 5px 10px;font-size: 16px;background: rgba(0, 0, 0, .5);color: #fff;position: absolute;top: 48px;left: 50%;transform: translateX(-50%);border-radius: 8px;opacity: 0;transition: all .3s;}`);
style.insertRule(`@keyframes mymove{from{transform:translateX(${$('#primaryScreen').width() + 100}px) }to{transform:translateX(-400px)}}`);//写入样式
clearTimeout(timer);
}, 2000);
}()
!function () {
// 移入&&移出
$('#primaryScreen').on('mouseover', '.apend-dom-zx', function () {
let id = $(this).data('id');
$(this).css({ 'animation-play-state': 'paused' });
$(this).find('.bullet-chat-tips').css({ 'opacity': '1', 'top': '35px' })
})
$('#primaryScreen').on('mouseout', '.apend-dom-zx', function () {
if (videoFlag) {
$(this).css({ 'animation-play-state': 'running' })
} else {
$(this).css({ 'animation-play-state': 'paused' })
}
$(this).find('.bullet-chat-tips').css({ 'opacity': '0', 'top': '55px' })
})
//复制
$('#primaryScreen').on('click', '.bullet-chat-items-copy', function () {
copyText($(this).parents('.bullet-chat-tips').siblings('.bullet-chat-text').text())
})
// 转发
$('#primaryScreen').on('click', '.bullet-chat-items-forward', function () {
copyText(window.location.href, function () {
alert('链接已复制到粘贴板!')
});
})
// 点赞
$('#primaryScreen').on('click', '.bullet-chat-items-fabulous', function () {
if ($(this).hasClass('color-red')) {
$(this).removeClass('color-red').css({ 'color': '#fff' });
} else {
$(this).addClass('color-red').css({ 'color': 'red' });
}
})
// 回复
$('#primaryScreen').on('click', '.bullet-chat-items-reply', function () {
$('#danmaku-content').val(`${$(this).parents('.bullet-chat-tips').siblings('.bullet-chat-text').text()} 回复:`)
$('#danmaku-content').css({ 'border': '1px solid red' })
})
//查询
$('#eventTabControl').on('click', '#bulletChatCont', function () {
if ($(this).hasClass('actvxeee')) {
$('.bulletChatCont-box').addClass('bulletChatCont-box-none')
$(this).removeClass('actvxeee')
} else {
$('.bulletChatCont-box').removeClass('bulletChatCont-box-none')
$(this).addClass('actvxeee')
}
})
$(document).on('click', '.bulletChatCont-box-btn', function () {
let t = $('.bulletChatCont-box-ipt').val().trim();
!t && (() => {
if (danmakuList.length) {
let html = '';
for (let i in danmakuList) {
html += `<p class="bbp-item" style="line-height: 35px;">${danmakuList[i].value}</p>`
}
$('.bulletChatCont-allp').html(html)
}
})();
t && (() => {
let arr = window.danmakuList.filter((v, i) => {
let x;
if (v.value.indexOf(t) > -1) {
x = v;
}
return x
})
arr.length && (() => {
let html = '';
for (let i in arr) {
html += `<p class="bbp-item" style="line-height: 35px;">${arr[i].value}</p>`
}
$('.bulletChatCont-allp').html(html)
})();
})();
})
}()
//兼容ios复制
function copyText(text, callback) {
const textString = text.toString();
let input = document.querySelector('#copy-input');
if (!input) {
input = document.createElement('input');
input.id = "copy-input";
input.readOnly = "readOnly";
input.style.position = "absolute";
input.style.left = "-1000px";
input.style.zIndex = "-1000";
document.body.appendChild(input)
}
input.value = textString;
selectText(input, 0, textString.length);
if (document.execCommand('copy')) {
document.execCommand('copy');
} else {
console.log('不兼容');
}
input.blur();
function selectText(textbox, startIndex, stopIndex) {
if (textbox.createTextRange) {//ie
const range = textbox.createTextRange();
range.collapse(true);
range.moveStart('character', startIndex);
range.moveEnd('character', stopIndex - startIndex);
range.select();//不兼容苹果
} else {
textbox.setSelectionRange(startIndex, stopIndex);
textbox.focus();
}
}
callback && callback()
}
};
})($)