// ==UserScript==
// @name 弹幕词云
// @namespace http://tampermonkey.net/
// @version 0.11
// @description bilibili弹幕词云
// @author You
// @match https://www.bilibili.com/bangumi/play/*
// @match https://www.bilibili.com/video/*
// @grant none
// @require https://cdn.bootcdn.net/ajax/libs/wordcloud2.js/1.1.2/wordcloud2.min.js
// ==/UserScript==
(function() {
'use strict';
// Your code here...
function geo(){
console.log("开始")
// setInterval(modi,1000);
init();
}
//======变量=======
var canv;
var canvP;//词云div
var hasCi=false;//词云是否显示
let s=[]//弹幕
let sai=[]//词频
let fail=false;
let tez=[0]//[最大值]
let reqParm=[0,1]
let colorTable=['ffff00','ffff33','ffff66','ffff99','ffffcc','ffffff','ffcc00','ffcc33','ffcc66','ffcc99','ffcccc','ffccff','ff9900','ff9933','ff9966','ff9999','ff99cc','ff99ff','ff6600','ff6633','ff6666','ff6699','ff66cc','ff66ff','ff3300','ff3333','ff3366','ff3399','ff33cc','ff33ff','ff0000','ff0033','ff0066','ff0099','ff00cc','ff00ff']
//======函数======
let moveAble=function(dv,clickFun){
var x = 0;
var y = 0;
var l = 0;
var t = 0;
var isDown = false;
var moved=false;
//鼠标按下事件
dv.onmousedown = function(e) {
//获取x坐标和y坐标
x = e.clientX;
y = e.clientY;
//获取左部和顶部的偏移量
l = dv.offsetLeft;
t = dv.offsetTop;
//开关打开
isDown = true;
//设置样式
}
//鼠标移动
window.onmousemove = function(e) {
if (isDown == false) {
return;
}
//获取x和y
var nx = e.clientX;
var ny = e.clientY;
//计算移动后的左偏移量和顶部的偏移量
var nl = nx - (x - l);
var nt = ny - (y - t);
moved=true;
dv.style.left = nl + 'px';
dv.style.top = nt + 'px';
}
//鼠标抬起事件
dv.onmouseup = function() {
if(moved) {
moved=false;
}else if(clickFun){
clickFun();
}
//开关关闭
isDown = false;
}
}
var init=()=>{
var cibtn= document.createElement("div");
var cibtnBg= document.createElement("div");
cibtnBg.style="position:relative;top:-17px;background: linear-gradient(45deg , #e5c0ff, skyblue);border-radius: 4px;filter: blur(15px);width: 54px;height: 30px;"
cibtn.innerText='词云'
cibtn.style='user-select:none;overflow:hidden;position:fixed;top:20px;z-index:999999;left:40px;width: 54px;height: 30px;border-radius: 3px;font-size: 22px;padding: 4px;cursor: pointer;'
cibtn.append(cibtnBg);
moveAble(cibtn,ciw)
document.body.append(cibtn)
var sty=document.createElement("style");
sty.innerHTML=` .blura{
animation: 1s animatea 1 linear;
}
.blura:hover{
animation: 2s animateb 1 linear;
}
@keyframes animatea{
0%{ text-shadow: 0 0 0 white; }
50%{
color: rgba(238, 235, 235, 0.8);
text-shadow: 0 0 30px rgb(216, 227, 243);
}
100%{ text-shadow: 0 0 40px white; }
}
@keyframes animateb{
0%{ text-shadow: 0 0 0px rgba(255,255,255,0); }
50%{
color: rgba(255, 255, 255, 0.925);
text-shadow: 0 0 10px rgb(184, 245, 242);
}
100%{ text-shadow: 0 0 0 white; }
}`
document.head.append(sty)
canv=document.createElement("div");
canvP=document.createElement("div");
canvP.append(canv);
canv.style="height: 700px;width: 1200px;"
canvP.style="height: 700px;width: 1200px;position:fixed;top:50px;left:60px;z-index:999999";
document.body.append(canvP)
canvP.setAttribute("hidden",true);
moveAble(canvP)
}
var modi=()=>{
var dms=$(".b-danmaku");
for(var i=0;i<dms.length;i++){
if(dms[i].innerHTML.indexOf("div")==-1){
var s=dms[i].style.fontSize.replace("px","")
var l=dms[i].innerHTML.length*s+"px"
dms[i].innerHTML=` <div style="overflow: hidden;height: `+dms[i].style.fontSize+`;width: `+l+`">
<div style="position: relative;top: -32px;">`+dms[i].innerHTML+`</div>
<div style="width: 100%;
height: 100%;
background: linear-gradient(45deg , #e5c0ff, skyblue);
border-radius: 4px;
filter: blur(20px);
position: relative;
top: -90px;"></div>
</div>`
}
}
}
//产生词云
function ciw(){
if(hasCi) {
canvP.setAttribute("hidden",true);
hasCi=false;
return;
};
console.log('生成词云');
var list=sai;
if(sai.length==0) analysi();
canvP.removeAttribute("hidden");
WordCloud([canv],
{
list: list,
color: colorw, //'random-light'
backgroundColor: 'rgba(125,100,125,0.8)',
gridSize: 18,
weightFactor: 200/tez[0],
fontFamily: 'Times, serif',
rotateRatio: 0.5,
classes: "blura",
rotationSteps: 2
} );
hasCi=true;
}
let colorw=(wd,weight)=>{
//tez[0]红色 #ff0000
//1=>蓝色 #0000ff
console.log(wd,weight,tez[0])
let v=parseInt((colorTable.length-1)*weight/(tez[0]))
return '#'+colorTable[v];
// let v=parseInt(512*weight/(tez[0]))-1
// return 'rgb('+(v>255?(v-255):125)+','+(v<255?v:510-v)+','+(v<255?255-v:125)+')';
}
let analysi=()=>{
loadParam()
console.log("等待弹幕获取完成")
getOneSeg(1)
// while(!fail){
// console.log("等待弹幕获取完成")
// }
return cia(3);
}
let getOneSeg=(seg)=>{
let regex=/:.(.*?)[�@]/
$.ajax({
url:'https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid='+reqParm[0]+'&pid='+reqParm[1]+'&segment_index='+seg,
data:{},
async:false,
cache:false,
ifModified :true,
type:'GET',
success:function(re, textStatus, xhr){ //成功回调函数
if(xhr.status!=200) {
console.log("失败点:",seg)
fail=true
return;
}
let ss=re.split('\n');
ss.forEach(e=>{
let dm=regex.exec(e);
if(dm&&dm[1])
s.push(dm[1])
})
console.log(s);
sleep(500)
getOneSeg(seg+1)
},
error:function (err){ //失败回调函数
fail=true;
console.log("失败点:",seg)
console.log(err);
}
});
}
function cia(l){
console.log('分析弹幕...')
let wds=[]
s.forEach(e => {
e=e.replace(/[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]/g,"");
ctin(wds,e)
});
wds.forEach(e=>{
if(e[1]>=l) {
if(tez[0]<e[1]) tez[0]=e[1]
sai.push(e)
}
})
console.log("最大次数:",tez[0])
console.log("筛选结果:",sai)
return sai;
}
function ctin(a,b){
var h=true;
for(let i in a){
if(a[i][0].indexOf(b)>-1||xiangsi(a[i][0],b)){
a[i][1]+=1;
h=false;
}
}
if(h){
a.push([b,0])
}
}
let xiangsi=(a,b)=>{
if(xiangsi0(a,b)||xiangsi0(b,a)) return true;
return false;
}
let xiangsi0=(a,b)=>{
let m=a.split('')
let c=0;
m.forEach(e=>{
if(b.indexOf(e)>-1) c++;
})
if(c/m.length>=0.5) return true;
return false;
}
let loadParam=()=>{
reqParm= [window.cid,window.aid]
console.log('找到参数:',reqParm)
}
function sleep(numberMillis) {
var now = new Date();
var exitTime = now.getTime() + numberMillis;
while (true) {
now = new Date();
if (now.getTime() > exitTime)
return;
}
}
geo();
})();