快捷弹幕

B站直播间发送快捷弹幕

当前为 2022-01-25 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         快捷弹幕
// @namespace    http://tampermonkey.net/
// @version      0.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: 100px;
        }
        .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: 100px;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-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" size="mini">设置</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: []
            },
            methods: {
                "delDanmukus": function () {
                    for (let i=0;i<this.danmukus4del.length;i++){
                        let danmuku = this.danmukus4del[i];
                        if (danmuku[0] == "cur") {
                            let val = danmuku[1];
                            let index = this.curRoomDanmukus.indexOf(val);
                            this.curRoomDanmukus.splice(index,1);
                        } else {
                            let val = danmuku[1];
                            let index = this.allRoomDanmukus.indexOf(val);
                            this.allRoomDanmukus.splice(index,1);
                        }
                    }
                    localStorage.setItem(this.roomId + '-danmukus',JSON.stringify(this.curRoomDanmukus));
                    localStorage.setItem("allRoomDanmukus",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);
                    }
                },
                "getAllRoomDanmukus": function () {
                    if (localStorage.allRoomDanmukus) {
                        this.allRoomDanmukus = JSON.parse(localStorage.allRoomDanmukus);
                    }
                },
                "getCurRoomDanmukus": function () {
                    if (localStorage.getItem(this.roomId + '-danmukus')){
                        this.curRoomDanmukus = JSON.parse(localStorage.getItem(this.roomId + '-danmukus'));
                    }
                },
                "handleDanmukus": function () {
                    this.options[0].danmukus = [];
                    this.options[1].danmukus = [];
                    for (let i=0;i<this.allRoomDanmukus.length;i++) {
                        this.options[0].danmukus.push({label:this.allRoomDanmukus[i],value:this.allRoomDanmukus[i]});
                    }
                    for (let i=0;i<this.curRoomDanmukus.length;i++) {
                        this.options[1].danmukus.push({label:this.curRoomDanmukus[i],value:this.curRoomDanmukus[i]});
                    }
                },
                "addDanmuku": function () {
                    if (this.select == "cur") {
                        this.curRoomDanmukus.push(this.danmuku4add);
                        localStorage.setItem(this.roomId + '-danmukus',JSON.stringify(this.curRoomDanmukus));
                        this.danmuku4add = '';
                        this.$message.success("添加成功");
                        this.handleDanmukus();
                    } else {
                        this.allRoomDanmukus.push(this.danmuku4add);
                        localStorage.setItem("allRoomDanmukus",JSON.stringify(this.allRoomDanmukus));
                        this.danmuku4add = '';
                        this.$message.success("添加成功");
                        this.handleDanmukus();
                    }
                },
                "sendDanmuku": function (danmuku4send) {
                    var cookie = document.cookie;
                    var jct = getCookie('bili_jct');
                    var url = 'https://api.live.bilibili.com/msg/send';
                    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.msg);
                        }
                    }).catch(()=>{
                        this.$message.error('发送失败 - ' + danmuku4send);
                    }).finally(()=>{
                        this.value = '';
                    });
                }
            } ,
            created: function () {
                this.getRoomId();
                this.getAllRoomDanmukus();
                this.getCurRoomDanmukus();
                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()
})();