// ==UserScript==
// @name 快捷弹幕
// @namespace http://tampermonkey.net/
// @version 0.2.1
// @description B站直播间发送快捷弹幕
// @author mianju
// @include /https?:\/\/live\.bilibili\.com\/(blanc\/)?\d+\??.*/
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js
// @grant none
// ==/UserScript==
(function () {
function main() {
initLib()
initCss()
waitForLoaded(() => {
initUi()
})
}
function initLib() {
let scriptElement = document.createElement('script')
scriptElement.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js'
document.head.appendChild(scriptElement)
let linkElement = document.createElement('link')
linkElement.rel = 'stylesheet'
linkElement.href = 'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
document.head.appendChild(linkElement)
scriptElement = document.createElement('script')
scriptElement.src = 'https://unpkg.com/element-ui/lib/index.js'
document.head.appendChild(scriptElement)
}
function initCss() {
let css = `
.el-select .el-input {
width: 80px;
}
.input-with-select .el-input-group__prepend {
background-color: #fff;
}
`
let styleElement = document.createElement('style')
styleElement.innerText = css
document.head.appendChild(styleElement)
}
function waitForLoaded(callback, timeout = 10 * 1000) {
let startTime = new Date()
function poll() {
if (isLoaded()) {
callback()
return
}
if (new Date() - startTime > timeout) {
return
}
setTimeout(poll, 1000)
}
poll()
}
function isLoaded() {
if (window.ELEMENT === undefined) {
return false
}
if (document.querySelector('#control-panel-ctnr-box') === null) {
return false
}
return true
}
function initUi() {
var father = document.getElementsByClassName('icon-left-part')[0];
let quickDanmukuElement = document.createElement('div');
father.appendChild(quickDanmukuElement);
new Vue({
el: quickDanmukuElement,
template: `
<span>
<template style="width: 200px" >
<el-select v-model="value" placeholder="选择" @change="sendDanmuku" style="width: 80px;height: 24px" size="mini">
<el-option-group
v-for="group in options"
:key="group.label"
:label="group.label">
<el-option
v-for="danmuku in group.danmukus"
:key="danmuku.label"
:label="danmuku.label"
:value="danmuku.label">
</el-option>
</el-option-group>
</el-select>
<el-button icon="el-icon-message" size="mini" circle @click="sendDanmuku(value)"></el-button>
<el-popover
placement="bottom"
title="快捷弹幕设置"
width="300px"
trigger="click"
>
<span class="demonstration">添加</span><br>
<el-input placeholder="请输入内容" v-model="danmuku4add" class="input-with-select" maxlength="20">
<el-select v-model="select" slot="prepend" placeholder="请选择">
<el-option label="当前" value="cur"></el-option>
<el-option label="所有" value="all"></el-option>
</el-select>
<el-button slot="append" icon="el-icon-check" @click="addDanmuku"></el-button>
</el-input>
<div class="block">
<span class="demonstration">删除</span><br>
<el-cascader
v-model="danmukus4del"
:options="options"
:props="{ expandTrigger: 'hover','children': 'danmukus','multiple': 'true','emitPath':'false' }"
></el-cascader>
<el-button type="danger" icon="el-icon-delete" @click="delDanmukus"></el-button>
</div>
<el-button slot="reference" icon="el-icon-setting" size="mini" circle></el-button>
</el-popover>
</template>
</span>
`,
data: {
options: [
{
label: '所有直播间',
value: 'all',
danmukus: []
},
{
label: '当前直播间',
value: 'cur',
danmukus: []
}
],
value: '',
danmuku4add: '',
select: 'cur',
danmukus4del: [],
roomId: 0,
allRoomDanmukus: [],
curRoomDanmukus: [],
key4all: 'allRoomDanmukus',
key4cur: ''
},
methods: {
"delDanmukus": function () {
function del(val,danmukus) {
let index = danmukus.indexOf(val);
danmukus.splice(index,1);
};
for (let i=0;i<this.danmukus4del.length;i++){
let danmuku = this.danmukus4del[i];
if (danmuku[0] == "cur") {
del(danmuku[1],this.curRoomDanmukus);
} else {
del(danmuku[1],this.allRoomDanmukus);
}
}
localStorage.setItem(this.key4cur,JSON.stringify(this.curRoomDanmukus));
localStorage.setItem(this.key4all,JSON.stringify(this.allRoomDanmukus));
this.danmukus4del = [];
this.$message.success("删除成功");
this.handleDanmukus();
},
"getRoomId": function () {
if (window.__NEPTUNE_IS_MY_WAIFU__) {
this.roomId = window.__NEPTUNE_IS_MY_WAIFU__.roomInfoRes.data.room_info.room_id;
} else {
let url = document.URL;
var re = /\/\d+/.exec(url);
this.roomId = re[0].substr(1);
}
},
"getDanmukus": function (key) {
if (localStorage.getItem(key)){
return JSON.parse(localStorage.getItem(key));
}
return [];
},
"handleDanmukus": function () {
function handle(danmukus4opt,danmukus4room){
danmukus4opt.splice(0);
for (let i=0;i<danmukus4room.length;i++) {
danmukus4opt.push({label:danmukus4room[i],value:danmukus4room[i]});
}
}
handle(this.options[0].danmukus,this.allRoomDanmukus);
handle(this.options[1].danmukus,this.curRoomDanmukus);
},
"addDanmuku": function () {
function add(key,danmukus,danmuku){
danmukus.push(danmuku);
localStorage.setItem(key,JSON.stringify(danmukus));
};
if (this.select == "cur") {
add(this.key4cur,this.curRoomDanmukus,this.danmuku4add);
} else {
add(this.key4all,this.allRoomDanmukus,this.danmuku4add);
}
this.danmuku4add = '';
this.$message.success("添加成功");
this.handleDanmukus();
},
"sendDanmuku": function (danmuku4send) {
var jct = getCookie('bili_jct');
var date = new Date();
var data = new FormData();
data.append('bubble',0);
data.append('color',16777215);
data.append('fontsize',25);
data.append('mode',1);
data.append('msg',danmuku4send);
data.append('rnd',parseInt(date.getTime()/1000));
data.append('roomid',this.roomId);
data.append('csrf',jct);
data.append('csrf_token',jct);
let apiClient = axios.create({
baseURL: 'https://api.live.bilibili.com',
withCredentials: true
});
apiClient.post('/msg/send',data).then((res)=>{
if (res.data.msg == 'f'){
this.$message.error('发送失败 - 弹幕被屏蔽: ' + danmuku4send);
}
else if (res.data.code ==0) {
this.$message.success('发送成功 - ' + danmuku4send);
} else {
this.$message.error('发送失败 - ' + res.data.message);
}
}).catch(()=>{
this.$message.error('发送失败 - ' + danmuku4send);
});
}
} ,
created: function () {
this.getRoomId();
this.key4cur = this.roomId + '-danmukus';
this.curRoomDanmukus = this.getDanmukus(this.key4cur);
this.allRoomDanmukus = this.getDanmukus(this.key4all);
this.handleDanmukus();
}
});
}
function getCookie(cname){
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name)==0) { return c.substring(name.length,c.length); }
}
return "";
}
main()
})();