bilibili 直播 HTML5 播放器

B 站的直播的 HTML5 播放器

目前為 2017-02-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         bilibili 直播 HTML5 播放器
// @namespace    https://www.kindjeff.com/
// @version      2017.2.21
// @description  B 站的直播的 HTML5 播放器
// @author       kindJeff
// @match        http://live.bilibili.com/*
// @match        https://live.bilibili.com/*
// @require      https://cdn.bootcss.com/hls.js/0.6.21/hls.min.js
// @run-at       document-end
// ==/UserScript==

/***/
(function(t,i){typeof exports==="object"&&typeof module!=="undefined"?module.exports=i():typeof define==="function"&&define.amd?define(i):t.Danmaku=i()})(this,function(){"use strict";function t(){var t=9007199254740991;return[{range:0,time:-t,width:t,height:0},{range:t,time:t,width:0,height:0}]}var i={};function e(){i.ltr=t();i.rtl=t();i.top=t();i.bottom=t()}e();var s=function(t){var e=this;var s=this._hasMedia?this.media.currentTime:Date.now()/1e3;var n=this._hasMedia?this.media.playbackRate:1;function h(t,i){if(i.mode==="top"||i.mode==="bottom"){return s-t.time<e.duration}var h=e.width+t.width;var a=h*(s-t.time)*n/e.duration;if(t.width>a){return true}var r=e.duration+t.time-s;var o=e.duration*e.width/(e.width+i.width);return r>o}var a=i[t.mode];var r=0;var o=0;for(var d=1;d<a.length;d++){var u=a[d];var m=t.height;if(t.mode==="top"||t.mode==="bottom"){m+=u.height}if(u.range-u.height-a[r].range>=m){o=d;break}if(h(u,t)){r=d}}var l=a[r].range;var c={range:l+t.height,time:this._hasMedia?t.time:t._utc,width:t.width,height:t.height};a.splice(r+1,o-r-1,c);if(t.mode==="bottom"){return this.height-t.height-l%this.height}return l%(this.height-t.height)};var n=function(t){var i=document.createElement("div");if(t.html===true){i.innerHTML=t.text}else{i.textContent=t.text}i.style.cssText="position:absolute;";if(t.style){for(var e in t.style){i.style[e]=t.style[e]}}return i};var h=function(){var t=["oTransform","msTransform","mozTransform","webkitTransform","transform"];var i=document.createElement("div").style;for(var e=0;e<t.length;e++){if(t[e]in i){return t[e]}}return"transform"}();var a=function(){var t=Date.now()/1e3;var i=this._hasMedia?this.media.currentTime:t;var e=this._hasMedia?this.media.playbackRate:1;var a=null;var r=0;var o=0;for(o=0;o<this.runningList.length;o++){a=this.runningList[o];r=this._hasMedia?a.time:a._utc;if(i-r>this.duration){this.stage.removeChild(a.node);if(!this._hasMedia){a.node=null}this.runningList.splice(o,1)}}var d=[];var u=document.createDocumentFragment();while(this.position<this.comments.length){a=this.comments[this.position];r=this._hasMedia?a.time:a._utc;if(r>=i){break}a._utc=Date.now()/1e3;a.node=a.node||n(a);this.runningList.push(a);d.push(a);u.appendChild(a.node);++this.position}if(d.length){this.stage.appendChild(u)}for(o=0;o<d.length;o++){a=d[o];a.width=a.width||a.node.offsetWidth;a.height=a.height||a.node.offsetHeight}for(o=0;o<d.length;o++){a=d[o];a.y=s.call(this,a);if(a.mode==="top"||a.mode==="bottom"){a.x=this.width-a.width>>1;a.node.style[h]="translate("+a.x+"px,"+a.y+"px)"}}for(o=0;o<this.runningList.length;o++){a=this.runningList[o];if(a.mode==="top"||a.mode==="bottom"){continue}var m=this.width+a.width;var l=m*(t-a._utc)*e/this.duration;l|=0;if(a.mode==="ltr")a.x=l-a.width;if(a.mode==="rtl")a.x=this.width-l;a.node.style[h]="translate("+a.x+"px,"+a.y+"px)"}};var r=16;var o=16;function d(t){var i=window.getComputedStyle(t,null).getPropertyValue("font-size").match(/(.+)px/)[1]*1;if(t.tagName==="HTML"){o=i}else{r=i}}var u=Object.create(null);var m=function(t){if(u[t]){return u[t]}var i=12;var e=/^(\d+(?:\.\d+)?)(px|%|em|rem)(?:\s*\/\s*(\d+(?:\.\d+)?)(px|%|em|rem)?)?/;var s=t.match(e);if(s){var n=s[1]*1||10;var h=s[2];var a=s[3]*1||1.2;var d=s[4];if(h==="%")n*=r/100;if(h==="em")n*=r;if(h==="rem")n*=o;if(d==="px")i=a;if(d==="%")i=n*a/100;if(d==="em")i=n*a;if(d==="rem")i=o*a;if(d===undefined)i=n*a}u[t]=i;return i};var l=function(t){var i=document.createElement("canvas");var e=i.getContext("2d");var s=t.canvasStyle||{};s.font=s.font||"10px sans-serif";s.textBaseline=s.textBaseline||"bottom";var n=s.lineWidth*1;n=n>0&&n!==Infinity?Math.ceil(n):!!s.strokeStyle*1;e.font=s.font;t.width=t.width||Math.max(1,Math.ceil(e.measureText(t.text).width)+n*2);t.height=t.height||Math.ceil(m(s.font))+n*2;i.width=t.width;i.height=t.height;for(var h in s){e[h]=s[h]}var a=0;switch(s.textBaseline){case"top":case"hanging":a=n;break;case"middle":a=t.height>>1;break;default:a=t.height-n}if(s.strokeStyle){e.strokeText(t.text,n,a)}e.fillText(t.text,n,a);return i};var c=function(){this.stage.context.clearRect(0,0,this.width,this.height);var t=Date.now()/1e3;var i=this._hasMedia?this.media.currentTime:t;var e=this._hasMedia?this.media.playbackRate:1;var n=null;var h=0;var a=0;for(a=0;a<this.runningList.length;a++){n=this.runningList[a];h=this._hasMedia?n.time:n._utc;if(i-h>this.duration){n.canvas=null;this.runningList.splice(a,1)}}while(this.position<this.comments.length){n=this.comments[this.position];h=this._hasMedia?n.time:n._utc;if(h>=i){break}n._utc=Date.now()/1e3;n.canvas=l(n);n.y=s.call(this,n);if(n.mode==="top"||n.mode==="bottom"){n.x=this.width-n.width>>1}this.runningList.push(n);++this.position}for(a=0;a<this.runningList.length;a++){n=this.runningList[a];var r=this.width+n.width;var o=r*(t-n._utc)*e/this.duration;if(n.mode==="ltr")n.x=o-n.width+.5|0;if(n.mode==="rtl")n.x=this.width-o+.5|0;this.stage.context.drawImage(n.canvas,n.x,n.y)}};var f=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||function(t){return setTimeout(t,50/3)};var v=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||clearTimeout;var p=function(){if(!this.visible||!this.paused){return this}this.paused=false;if(this._hasMedia){for(var t=0;t<this.runningList.length;t++){var i=this.runningList[t];i._utc=Date.now()/1e3-(this.media.currentTime-i.time)}}var e=this;var s=this._useCanvas?c:a;function n(){s.call(e);e._requestID=f(n)}this._requestID=f(n);return this};var g=function(){if(!this.visible||this.paused){return this}this.paused=true;v(this._requestID);this._requestID=0;return this};var w=function(t,i,e){var s=0;var n=0;var h=t.length;while(n<h-1){s=n+h>>1;if(e>=t[s][i]){n=s}else{h=s}}if(t[n]&&e<t[n][i]){return n}return h};var _=function(){if(!this._hasMedia){return this}this.clear();e();var t=w(this.comments,"time",this.media.currentTime);this.position=Math.max(0,t-1);return this};var y=null;var x=null;var b=null;function M(){y=p.bind(this);x=g.bind(this);b=_.bind(this);this.media.addEventListener("play",y);this.media.addEventListener("pause",x);this.media.addEventListener("seeking",b)}function C(){this.media.removeEventListener("play",y);this.media.removeEventListener("pause",x);this.media.removeEventListener("seeking",b);y=null;x=null;b=null}var L=function(t){if(!/^(ltr|top|bottom)$/i.test(t)){return"rtl"}return t.toLowerCase()};var T=function(t){t.prototype.init=function(t){if(this._isInited){return this}if(!t||!t.container&&(!t.video||t.video&&!t.video.parentNode)){throw new Error("Danmaku requires container when initializing.")}this._hasInitContainer=!!t.container;this.container=t.container;this.visible=true;this.engine=(t.engine||"DOM").toLowerCase();this._useCanvas=this.engine==="canvas";this._requestID=0;this._speed=Math.max(0,t.speed)||144;this.duration=4;this.comments=JSON.parse(JSON.stringify(t.comments||[]));this.comments.sort(function(t,i){return t.time-i.time});for(var i=0;i<this.comments.length;i++){this.comments[i].mode=L(this.comments[i].mode)}this.runningList=[];this.position=0;this.paused=true;this.media=t.video||t.audio;this._hasMedia=!!this.media;this._hasVideo=!!t.video;if(this._hasVideo&&!this._hasInitContainer){var e=!this.media.paused;this.container=document.createElement("div");this.container.style.position=this.media.style.position;this.media.style.position="absolute";this.media.parentNode.insertBefore(this.container,this.media);this.container.appendChild(this.media);if(e&&this.media.paused){this.media.play()}}if(this._hasMedia){M.call(this)}if(this._useCanvas){this.stage=document.createElement("canvas");this.stage.context=this.stage.getContext("2d")}else{this.stage=document.createElement("div");this.stage.style.cssText="overflow:hidden;white-space:nowrap;transform:translateZ(0);"}this.stage.style.cssText+="position:relative;pointer-events:none;";this.resize();this.container.appendChild(this.stage);d(document.getElementsByTagName("html")[0]);d(this.container);if(!this._hasMedia||!this.media.paused){_.call(this);p.call(this)}this._isInited=true;return this}};var k=function(t){t.prototype.emit=function(t){if(!t||Object.prototype.toString.call(t)!=="[object Object]"){return this}var i=JSON.parse(JSON.stringify(t));i.text=(i.text||"").toString();i.mode=L(i.mode);i._utc=Date.now()/1e3;if(this._hasMedia){var e=0;if(i.time===undefined){i.time=this.media.currentTime;e=this.position}else{e=w(this.comments,"time",i.time)}this.comments.splice(e,0,i)}else{this.comments.push(i)}return this}};var D=function(t){t.prototype.clear=function(){if(this._useCanvas){this.stage.context.clearRect(0,0,this.width,this.height);for(var t=0;t<this.runningList.length;t++){this.runningList[t].canvas=null}}else{var i=this.stage.lastChild;while(i){this.stage.removeChild(i);i=this.stage.lastChild}}this.runningList=[];return this}};var I=function(t){t.prototype.destroy=function(){if(!this._isInited){return this}g.call(this);this.clear();if(this._hasMedia){C.call(this)}e();if(this._hasVideo&&!this._hasInitContainer){var t=!this.media.paused;this.media.style.position=this.container.style.position;this.container.parentNode.appendChild(this.media);this.container.parentNode.removeChild(this.container);if(t&&this.media.paused){this.media.play()}}for(var i in this){if(Object.prototype.hasOwnProperty.call(this,i)){this[i]=null}}return this}};var E=function(t){t.prototype.show=function(){if(this.visible){return this}this.visible=true;if(this._hasMedia&&this.media.paused){return this}_.call(this);p.call(this);return this}};var N=function(t){t.prototype.hide=function(){if(!this.visible){return this}g.call(this);this.clear();this.visible=false;return this}};var O=function(t){t.prototype.resize=function(){if(this._hasInitContainer){this.width=this.container.offsetWidth;this.height=this.container.offsetHeight}if(this._hasVideo&&(!this._hasInitContainer||!this.width||!this.height)){this.width=this.media.clientWidth;this.height=this.media.clientHeight}if(this._useCanvas){this.stage.width=this.width;this.stage.height=this.height}else{this.stage.style.width=this.width+"px";this.stage.style.height=this.height+"px"}this.duration=this.width/this._speed;return this}};var S=function(t){Object.defineProperty(t.prototype,"speed",{get:function(){return this._speed},set:function(t){if(typeof t!=="number"||isNaN(t)||!isFinite(t)||t<=0){return this._speed}this._speed=t;if(this.width){this.duration=this.width/t}return t}})};function q(t){this._isInited=false;t&&this.init(t)}T(q);k(q);D(q);I(q);E(q);N(q);O(q);S(q);return q});
/***/

var room_id;

setTimeout(function(){
    //var xhr = new XMLHttpRequest();
    //xhr.onreadystatechange=function(){
    //    if (xhr.readyState==4 && xhr.status==200){
    //        eval(xhr.responseText);
            var link = $('#player_object').children('[name="flashvars"]').val();
            room_id = link.match(/cid=.*?&/)[0].slice(4,-1);
            get_url_and_replace_player(room_id);
            init_danmaku();
            set_danmu_control();
            click_list();
    //    }
    //};
    //xhr.open('GET', 'https://raw.githubusercontent.com/weizhenye/Danmaku/master/dist/danmaku.min.js');
    //xhr.send();
}, 2000);


function get_url_and_replace_player(room_id){
    var api_url = 'https://api.live.bilibili.com/api/playurl?platform=h5&cid=' + room_id;
    $.ajax({
        url: api_url,
        type: "GET",
        dataType: 'json',
        success: function(data){
            replace_player(data.data);

            if(window.df_danmu_ws!==undefined){
                window.i_close_it_myself = true;
                window.df_danmu_ws.close();
                window.df_danmu_ws = undefined;
            }
            var df_domain = 'broadcastlv.chat.bilibili.com';
            var df_portobj = {'ws':7170, 'wss':7172};
            window.df_danmu_ws = new DanmuSocket(parseInt(room_id), df_domain, df_portobj);
            window.df_danmu_ws.setListener(danmuListener);
        }
    });
}

function replace_player(m3u8_url){
    var w = $('#js-player-decorator').width();
    var h = $('#js-player-decorator').height();

    remove_player();

    var player = document.createElement('video');
    player.id = 'h5_player';
    player.style.width = '100%';
    player.style.height = '100%';
    player.style.position = 'absolute';
    player.setAttribute('controls', 'controls');
    document.getElementById('js-player-decorator').appendChild(player);

    if(Hls.isSupported()) {
        var video = document.getElementById('h5_player');
        var hls = new Hls();
        hls.loadSource(m3u8_url);
        hls.attachMedia(video);
        hls.on(Hls.Events.MANIFEST_PARSED,function() {
          video.play();
        });
    }
}

function remove_player(){
    var flash_player = document.getElementById('player_object');
    if(flash_player!==null)
        flash_player.remove();

    var html5_player = document.getElementById('h5_player');
    if(html5_player!==null)
        html5_player.remove();
}

function click_list(){
    if(window.location.pathname==='/'){
        $($('[role="list"]')[0]).children().on('click', function(){
            var room_id = $(this).attr('data-cid');
            get_url_and_replace_player(room_id);
        });
    }
}


/* danmaku */
const rawHeaderLen = 16;
const packetOffset = 0;
const headerOffset = 4;
const verOffset = 6;
const opOffset = 8;
const seqOffset = 12;
var pako = window.pako;
var textDecoder = getDecoder(true);
var textEncoder = getEncoder();
var heartbeatInterval;

function getDecoder (isUseful) {
    if(window['TextDecoder'] && isUseful) {
        return new window['TextDecoder']();
    } else {
        return {
            decode: (buf) => {
                return decodeURIComponent(window.escape(String.fromCharCode.apply(null, new Uint8Array(buf))));
            }
        }
    }
}

function getEncoder () {
    if(window['TextEncoder']) {
        return new window['TextEncoder']();
    } else {
        return {
            encode: (str) => {
                let buf = new ArrayBuffer(str.length);
                let bufView = new Uint8Array(buf);
                for (let i = 0, strlen = str.length; i < strlen; i++) {
                    bufView[i] = str.charCodeAt(i);
                }
                return bufView;
            }
        }
    }
}

function mergeArrayBuffer(ab1, ab2) {
    var u81 = new Uint8Array(ab1),
        u82 = new Uint8Array(ab2),
        res = new Uint8Array(ab1.byteLength + ab2.byteLength);
    res.set(u81, 0);
    res.set(u82, ab1.byteLength);
    return res.buffer;
}

class DanmuSocket {

    constructor (roomid,domain,portobj) {
        const ws = window.location.protocol.indexOf('https') > -1 ? 'wss' : 'ws';
        const port = portobj[ws];
        this.connection = new WebSocket(ws + "://"+ domain +":"+ port +"/sub");
        this.connection.binaryType = 'arraybuffer';
        this.connection.onopen = this.firstConnection.bind(this);
        this.connection.onmessage = onMessage.bind(this);
        this.connection.onclose = onClose.bind(this);
        this.connection.onerror = onError.bind(this);
        this.roomid = roomid
    }

    firstConnection () {
        console.log("Danmu WebSocket Server Connected.");
        console.log("Handshaking...");
        var token = JSON.stringify({
            'uid': 0,
            'roomid': this.roomid
        });
        var headerBuf = new ArrayBuffer(rawHeaderLen);
        var headerView = new DataView(headerBuf, 0);
        var bodyBuf = textEncoder.encode(token);
        headerView.setInt32(packetOffset, rawHeaderLen + bodyBuf.byteLength);
        headerView.setInt16(headerOffset, rawHeaderLen);
        headerView.setInt16(verOffset, 1);
        headerView.setInt32(opOffset, 7);
        headerView.setInt32(seqOffset, 1);
        this.connection.send(mergeArrayBuffer(headerBuf, bodyBuf));
    }

    heartBeat () {
        var headerBuf = new ArrayBuffer(rawHeaderLen);
        var headerView = new DataView(headerBuf, 0);
        headerView.setInt32(packetOffset, rawHeaderLen);
        headerView.setInt16(headerOffset, rawHeaderLen);
        headerView.setInt16(verOffset, 1);
        headerView.setInt32(opOffset, 2);
        headerView.setInt32(seqOffset, 1);
        this.connection.send(headerBuf);
    }

    closeHeartBeat () {
        clearInterval(this.heartBeating);
    }

    send (data) {
        this.connection.send(data);
    }

    close () {
        this.connection.close();
    }

    setListener (listener) {
        this._listener = listener;
    }

}

function onMessage (evt) {
    var data = evt.data;
    var dataView = new DataView(data, 0);
    var packetLen = dataView.getInt32(packetOffset);
    var headerLen = dataView.getInt16(headerOffset);
    var ver = dataView.getInt16(verOffset);
    var op = dataView.getInt32(opOffset);
    var seq = dataView.getInt32(seqOffset);

    switch(op) {
        case 8:
            this.heartBeat();
            heartbeatInterval = setInterval(this.heartBeat.bind(this), 30 * 1000);
        break;
        case 3:
            // console.log("online: " + dataView.getInt32(16));
            if (this._listener) this._listener('online', dataView.getInt32(16));
        break;
        case 5:
            var packetView = dataView;
            var msg = data;
            var msgBody;
            for (var offset=0; offset<msg.byteLength; offset+=packetLen) {
                packetLen = packetView.getInt32(offset);
                headerLen = packetView.getInt16(offset+headerOffset);
                msgBody = textDecoder.decode(msg.slice(offset+headerLen, offset+packetLen));
                if (!msgBody) {
                    textDecoder = getDecoder(false);
                    msgBody = textDecoder.decode(msg.slice(offset+headerLen, offset+packetLen));
                }
                if (this._listener) this._listener('msg', msgBody);
            }
        break;
    }
}

function onClose () {
    if (heartbeatInterval) clearInterval(heartbeatInterval);
    if(! i_close_it_myself){
        var delay = Math.floor(Math.random() * (6 - 3) + 3);
        setTimeout(this.firstConnection.bind(this), delay * 1000);
        console.log(delay);
    }
    i_close_it_myself = false;
}

function onError () {
    console.log("Client Error.");
}


/*******************/
function change_online(online) {
    $('span.v-bottom').text(online + ' 人');
}

function emit_danmu(data) {
    if(data.cmd==='DANMU_MSG'){
        var msg = data.info[1];
        window.df_danmaku.emit({
            text: msg,
            canvasStyle: {
                font: data.info[0][2]+'px sans-serif',
                textAlign: 'start',
                textBaseline: 'bottom',
                direction: 'inherit',
                fillStyle: '#fff',
                strokeStyle: '#000',
                lineWidth: 1.2,
                shadowBlur: 0,
                shadowColor: '#000',
                shadowOffsetX: 0,
                shadowOffsetY: 0,
                filter: 'none',
                globalAlpha: 1.0
            }
        })
    }else if(data.cmd==='WELCOME'){

    }else if(data.cmd==='SEND_GIFT'){

    }
}

function append_danmu(data) {
    if(data.cmd==='DANMU_MSG'){
        var u_name = data.info[2][1];
        var uid = data.info[2][0];
        var lv = data.info[4][0];
        var rank = data.info[4][3]; if(typeof(rank)=='string'&&rank.indexOf('>')!==-1) {rank.replace('>', '&gt;')}
        var msg = data.info[1];
        // console.log(u_name,uid,lv,rank,msg);
        var comment_div = '<div class="msg-item-ctnr"><div class="chat-msg " data-uname="'+u_name+'" data-uid="'+uid+'"><div class="user-level-icon lv-'+lv+'"> UL '+lv+' <div class="user-level-info"><p>用户等级:'+lv+'</p><p><a href="http://live.bilibili.com/rank" target="_blank">排名:'+rank+'</a></p></div></div><span class="user-name color">'+u_name+' : </span><span class="msg-content">'+msg+'</span></div></div>';
        $(comment_div).appendTo('#chat-msg-list');
        if($('#chat-msg-list').children().length>100)
            $('#chat-msg-list').children(':first').remove();
        $("#chat-msg-list").scrollTop($("#chat-msg-list")[0].scrollHeight);
    }
}

function danmuListener(content_type, content){
    if(content_type==='online'){
        if(window.dom_changed===undefined){
            $('#h5_player').prev().appendTo('#js-player-decorator');
            window.dom_changed = true;
        }
        change_online(content);
    }else if(content_type==='msg'){
        var content_obj = JSON.parse(content);
        emit_danmu(content_obj);
        append_danmu(content_obj);
    }
}

function init_danmaku() {
    window.df_danmaku = new Danmaku();
    df_danmaku.init({
        container: $('#js-player-decorator')[0],
        video: $("#h5_player")[0],
        engine:'canvas'
    });
    $('canvas')[0].style.position = 'absolute';

    // send danmu
    function send_danmu(){
        var msg = $("#df-danmu-textbox").val();
        var xhr = new XMLHttpRequest();
        // xhr.setRequestHeader('X-Cookie', document.cookie);
        xhr.open('POST', 'http://live.bilibili.com/msg/send');
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.send($.param({
            color: 16777215,
            fontsize: 25,
            mode: 1,
            msg: msg,
            rnd: Math.floor(Date.now() / 1000),
            roomid: room_id
        }));
    }
    $("#danmu-textbox").off('keypress');
    $("#danmu-textbox").off('keyup');
    $("#danmu-textbox").off('keydown');
    $("#danmu-send-btn").off('click');

    $("#danmu-textbox")[0].id = 'df-danmu-textbox';
    $("#danmu-send-btn")[0].id = 'df-danmu-send-btn';
    $("#df-danmu-textbox").on('keyup', function (e) {
        if(e.keyCode == 13){
            send_danmu();
            $("#df-danmu-textbox").val('');
            e.preventDefault();
            return false;
        }
        return true;
    });
    $("#df-danmu-send-btn").on('click', function (e) {
        e.preventDefault();
        send_danmu();
        $("#df-danmu-textbox").val('');
    });
}

function set_danmu_control(){
    if(location.pathname==='/'){
        return;
    }

    var control_btn = $("<button>关闭弹幕</button>");
    control_btn.css('border-radius', '5px');
    control_btn.css('font-size', '12px');
    control_btn.height('21px');
    $('.room-info.tag-ctnr.v-top').children().remove();
    control_btn.appendTo('.room-info.tag-ctnr.v-top');
    control_btn.on('click', function () {
        if(control_btn.text()=='打开弹幕'){
            control_btn.text('关闭弹幕');
            $('canvas')[0].style.display = 'block';
        }else{
            $('canvas')[0].style.display = 'none';
            control_btn.text('打开弹幕');
        }
    });
}