Greasy Fork is available in English.
screw flash!
// ==UserScript== // @name BiliBili HTML5 Live // @version 200706 // @description screw flash! // @author esterTion // @match http://live.bilibili.com/* // @match https://live.bilibili.com/* // @require https://static.hdslb.com/live-static/libs/jquery/jquery-1.11.3.min.js // @require https://cdn.bootcss.com/hls.js/0.6.21/hls.min.js // @require https://gitcdn.xyz/cdn/esterTion/live_html5_lib/067dad61e9de705e7171c332a75627328cabc3ae/google-style-loading.min.js // @require https://gitcdn.xyz/cdn/esterTion/live_html5_lib/6a39476b149bea7922c8311242979ec9e77fc276/mp4-lib.min.js // @require https://gitcdn.xyz/cdn/esterTion/live_html5_lib/1d91fc3f4f7f4e43e7c20a42898ec9d91e421485/live_html5_pack.min.js // @require https://gitcdn.xyz/cdn/esterTion/live_html5_lib/c3c77fa197621a0560a9a9d16cbe8bf8d4d39bbb/flv.min.js // @run-at document-start // @namespace https://greasyfork.org/users/24167 // @grant unsafeWindow // ==/UserScript== /* Original script: https://greasyfork.org/zh-CN/scripts/27239-bilibili-%E7%9B%B4%E6%92%AD-html5-%E6%92%AD%E6%94%BE%E5%99%A8 flv.js: https://github.com/bilibili/flv.js ABPlayer-bilibili-ver: https://github.com/Zhuogu/ABPlayerHTML5-bilibili-ver */ /*global EmbedPlayer unsafeWindow flvjs ABP Hls dots $*/ function _(e, t, n) { var r = null; if ("text" === e) return document.createTextNode(t); r = document.createElement(e); for (var l in t) if ("style" === l) for (var a in t.style) r.style[a] = t.style[a]; else if ("className" === l) r.className = t[l]; else if ("event" === l) for (var a in t[l]) r.addEventListener(a, t[l][a]); else r.setAttribute(l, t[l]); if (n) for (var s = 0; s < n.length; s++)null != n[s] && r.appendChild(n[s]); return r } if (!window.navigator.plugins['Shockwave Flash']) { //假装有flash Object.defineProperty(window.navigator, 'plugins', { value: { 'Shockwave Flash': {}, length: 1 } }); } var log = function () { var arg = [].slice.call(arguments); arg.splice(0, 0, '[Monkey_LivePlayer]'); console.log.apply(console, arg); }; var dispatchEvent = (function () { var dispatcher = function (event, data) { if (eventCallbackMap[event]) return eventCallbackMap[event](data); for (var i in unsafeWindow._playerEventMap) { if (unsafeWindow._playerEventMap[i].action == event) { eventCallbackMap[event] = unsafeWindow._playerEventMap[i].callback; break; } } return eventCallbackMap[event] ? eventCallbackMap[event](data) : false; }; var eventCallbackMap = {}; return dispatcher; })(); unsafeWindow.player_fullwin = function (state) { dispatchEvent('webFullscreen', state); }; var updateCSS = false, css, cssVer = '614fac427cb7cf3d1f8b7ce44f683708e188d0e2'; if (!localStorage.ABPlayer_css) updateCSS = true; else { css = JSON.parse(localStorage.ABPlayer_css); if (css.ver != cssVer) updateCSS = true; } while (updateCSS) { var xhr = new XMLHttpRequest(); xhr.open('GET', 'https://gitcdn.xyz/cdn/esterTion/live_html5_lib/' + cssVer + '/ABPlayer.min.css', false); xhr.send(); if (xhr.status == 200 || xhr.status == 304) updateCSS = false; css = { ver: cssVer, data: xhr.response }; localStorage.ABPlayer_css = JSON.stringify(css); } var style = document.createElement('style'); style.id = 'ABPlayer'; style.textContent = css.data; document.head.appendChild(style); var playerSettings = localStorage.getItem('LIVE_PLAYER_STATUS'); if (playerSettings != null) { var match = playerSettings.match('"type":"html5"'); localStorage.LIVE_PLAYER_STATUS = playerSettings.replace('"type":"html5"', '"type":"flash"'); } window.addEventListener('unload', function(){ unloading = true; destroyPlayer(); }); var room_id, player = { flv: null, hls: null }, flvplayer, abpinst = null, tryCount = 1, i_close_it_myself = false, df_domain = 'broadcastlv.chat.bilibili.com', //df_domain = 'tx.biliplus.com', df_portobj = { 'ws': 7170, 'wss': 7172 }, reconnecting = false, inited = false, living = true, rounding = false, unloading = false, restorePlayer = function () { living = false; rounding = true; if (abpinst != null) { destroyPlayer(); abpinst.playerUnit.style.display = 'none'; document.body.appendChild(abpinst.playerUnit); } unsafeWindow.EmbedPlayer.loader(); var pop = dispatchEvent('receiveMessage', { cmd: 'SYS_MSG', msg: "[BHL]: 轮播状态,正在切回官方播放器" }); setTimeout(function () { pop.close(); }, 3e3); setTimeout(function () { var playerSettings = localStorage.getItem('LIVE_PLAYER_STATUS'); if (playerSettings != null) { var match = playerSettings.match('"type":"html5"'); localStorage.LIVE_PLAYER_STATUS = playerSettings.replace('"type":"html5"', '"type":"flash"'); log('默认播放器设置已重置'); } }, 5e3); }, init = function (room_id) { if (inited) return; inited = true; setInterval(function () { var flashPlayer = document.getElementById('swfobject_placeholder'); if (flashPlayer != null) { abpinst && abpinst.playerUnit.parentNode == null && flashPlayer.parentNode.appendChild(abpinst.playerUnit); flashPlayer.remove(); ["noticeGift","noticeGuard","showComments","sendGiftStatus","play","pause","sendDanmaku","sendGift","init","on","set","switchLine","getPlayerInfo","jwAddEventListener","jwRemoveEventListener","jwGetBuffer","jwGetDuration","jwGetFullscreen","jwGetHeight","jwGetMute","jwGetPlaylist","jwGetPlaylistIndex","jwGetPosition","jwGetState","jwGetWidth","jwGetVersion","jwGetVolume","jwPlay","jwPause","jwStop","jwSeek","jwLoad","jwPlaylistItem","jwPlaylistNext","jwPlaylistPrev","jwDockSetButton","jwSetMute","jwSetVolume","jwSetFullscreen","jwShowControlbar","jwHideControlbar","jwShowDock","jwHideDock","jwShowDisplay","jwHideDisplay","addControllerListener","addModelListener","addViewListener","removeControllerListener","removeModelListener","removeViewListener","getConfig","getPlaylist","getPluginConfig","loadPlugin","sendEvent","loadVideo"] .forEach(i => { flashPlayer[i] = function () { log('flash', i, arguments); } }); flashPlayer.sendDanmaku = send_danmu; flashPlayer.getPlayerInfo = function () { return { "playingStatus": false, "playerStatus": 0, "type": 1, "quality": 4, "version": "PlayerEX2.2.6-f247ab44", "line": 0, "playerType": "flash", "guid": "C80F7AA5-B003-F1B3-8449-B857FCCAA515", "playurl": "http://61.164.142.134/live-bvc/158144/live_9617619_6384511.flv?expires=1526396357&ssig=Baw6hSUQIcvLtrn2k6i8fg&oi=983220655", "liveStatus": 1 } } flashPlayer.on = function () {}; log('Set flash callback'); try{ unsafeWindow.flash_on_ready_callback(); }catch(e){} } }, 500); get_url_and_replace_player(room_id); click_list(); function check(a) { return (a < 10) ? ('0' + a) : a; } var addTimeObserver = new MutationObserver(function (records) { var now = new Date; now = check(now.getMonth() + 1) + '-' + check(now.getDate()) + ' ' + check(now.getHours()) + ':' + check(now.getMinutes()) + ':' + check(now.getSeconds()); records.forEach(function (i) { Array.from(i.addedNodes).forEach(function (i) { i.setAttribute('title', now); }); }); }); addTimeObserver.observe(document.getElementById('chat-history-list'), { childList: true, attributes: false }); }, hlsSpeedMonitor = (function () { var prevBytes = 0, isLoading = false, loadingFrag = null; return { reset: function () { prevBytes = 0; }, interval: setInterval(function () { if (player.hls == null) { prevBytes = 0; return; } var loadedBytes = prevBytes; prevBytes = 0; if (isLoading) { loadedBytes += loadingFrag.loaded; prevBytes = -loadingFrag.loaded; } player.hls.speed = loadedBytes / 1024; }, 1e3), loadStart: function (e, d) { isLoading = true; loadingFrag = d.frag; }, loadEnd: function (e, d) { if (abpinst.video.readyState == 1) { log('playback jumped from ' + abpinst.video.currentTime.toFixed(2) + ' to ' + d.frag.start.toFixed(2)); abpinst.video.currentTime = d.frag.start; } isLoading = false; loadingFrag = null; prevBytes += d.stats.loaded; }, }; })(), hlsBitrateMonitor = (function () { var pending = []; var levels = {}; var currentLevel; return { reset: function () { levels = {}; this.levels = levels; }, levels: levels, levelChanging: function (n, d) { currentLevel = d.level; levels[currentLevel] = levels[currentLevel] || { bitrateMap: [], video: { timeScale: 0, samples: new AVLTree(), bitrateMap: [] }, audio: { timeScale: 0, samples: new AVLTree(), bitrateMap: [] } }; levels.current = levels[currentLevel]; }, interval: setInterval(function () { var workRanges = []; while (pending.length) { var data = pending.shift(); var type = data.type; var buffer = data.data; var offset = 0; var levelData = levels[currentLevel][type]; if (!levelData) continue; while (offset < buffer.length) { var box = boxInfo(buffer, offset); if (box.name == 'moov' || box.name == 'moof') { var moovData = {}; parseMoov(moovData, buffer, 0, box.size); if (box.name == 'moof') { var samples = levelData.samples; var traf = moovData.moof[0].traf[0]; var ts = traf.tfdt.baseMediaDecodeTime; var workRange = [type, Math.floor(ts / levelData.timeScale)]; for (var i = 0; i < traf.trun.sampleCount; i++) { if (!samples.contains(ts)) { samples.insert(ts, traf.trun.sizes[i]); } i < traf.trun.sampleCount - 1 && (ts += traf.trun.durations[i]); } workRange.push(Math.ceil(ts / levelData.timeScale)); workRanges.push(workRange); var bitrateHold = []; samples.range( workRange[1] * levelData.timeScale, workRange[2] * levelData.timeScale, function (node) { var ts = Math.floor(node.key / levelData.timeScale); bitrateHold[ts] = bitrateHold[ts] || 0; bitrateHold[ts] += node.data; } ) for (var i = workRange[1]; i < workRange[2]; i++) { levelData.bitrateMap[i] = bitrateHold[i]; } } else if (box.name == 'moov') { levelData.timeScale = moovData.moov[0].mvhd.timeScale; } } offset += box.size; } } workRanges.forEach(function (workRange) { for (var i = workRange[1]; i < workRange[2]; i++) { levels[currentLevel].bitrateMap[i] = ( (levels[currentLevel].video.bitrateMap[i] || 0) + (levels[currentLevel].audio.bitrateMap[i] || 0) ) * 8 / 1000; } }); }, 1e3), appending: function (n, e) { pending.push(e); } } })(), destroyPlayer = function () { if (player.hls != null) { player.hls.destroy(); player.hls = null; } if (player.flv != null) { player.flv.unload(); player.flv.destroy(); player.flv = null; } hlsSpeedMonitor.reset(); }, createPlayer = { flv: function (url) { destroyPlayer(); var video = document.querySelector('.ABP-Unit video'); player.flv = flvjs.createPlayer({ type: 'flv', isLive: true, url: url }); player.flv.attachMediaElement(video); player.flv.load(); flvplayer = player.flv; video.currentTime = 0; if (abpinst != null) { player.flv.on('error', function () { !unloading && setTimeout(function () { abpinst.createPopup('直播流意外中断', 3e3); changeSrc('', player.hls == null ? 'flv' : 'hls'); }, 1e3); }); video.dispatchEvent(new CustomEvent('autoplay')); var div = abpinst.playerUnit.querySelector('#info-box'); if (div.style.opacity == 0) { div.style.opacity = 1; } div.childNodes[0].childNodes[0].innerHTML = '正在切换'; dots.runTimer(); } }, hls: function (url) { destroyPlayer(); var video = document.querySelector('.ABP-Unit video'); player.hls = new Hls(); player.hls.loadSource(url); player.hls.attachMedia(video); player.hls.on(Hls.Events.FRAG_LOADING, hlsSpeedMonitor.loadStart); player.hls.on(Hls.Events.FRAG_LOADED, hlsSpeedMonitor.loadEnd); player.hls.on(Hls.Events.BUFFER_APPENDING, hlsBitrateMonitor.appending); player.hls.on(Hls.Events.LEVEL_SWITCHING, hlsBitrateMonitor.levelChanging); hlsBitrateMonitor.reset(); hlsBitrateMonitor.levelChanging('', { level: 0 }); video.currentTime = 0; video.dispatchEvent(new CustomEvent('autoplay')); var div = abpinst.playerUnit.querySelector('#info-box'); if (div.style.opacity == 0) { div.style.opacity = 1; } div.childNodes[0].childNodes[0].innerHTML = '正在切换'; dots.runTimer(); } }, tryInterval, blockingGift = false, blockGiftClickListener = function () { if (this.classList.contains('on')) { blockingGift = false; this.className = 'btn block-gift'; } else { blockingGift = true; this.className = 'btn block-gift on'; } localStorage.BHL_blockGift = blockingGift; }; window.hlsBitrateMonitor = hlsBitrateMonitor; unsafeWindow.hlsBitrateMonitor = hlsBitrateMonitor; window.changeSrc = function (b, a) { switch (a) { // https://api.live.bilibili.com/room/v1/Room/playUrl?cid=11588230&quality=3&platform=web case 'flv': $.ajax({ url: '//api.live.bilibili.com/room/v1/Room/playUrl?platform=web&otype=json&cid=' + room_id + '&_=' + Date.now(), type: 'GET', dataType: 'json', success: function (data) { createPlayer.flv(data.data.durl[0].url); } }); break; case 'hls': $.ajax({ url: '//api.live.bilibili.com/room/v1/Room/playUrl?platform=h5&otype=json&cid=' + room_id + '&_=' + Date.now(), type: 'GET', dataType: 'json', success: function (data) { createPlayer.hls(data.data.durl[0].url); } }); break; } }; unsafeWindow.player = player; window.player = player; (function () { var room_matcher = new RegExp('live\.bilibili\.com[\/a-zA-Z]+?(\\d+)(\\?.+)?$'); if (room_matcher.test(location.href)) { var style = document.createElement('style'); style.innerHTML = ` .treasure-box-ctnr{bottom:115px} .block-gift{width:20px;height:20px;position:relative;--color:#999999;background:none !important;display:inline-block;vertical-align:top;margin-left:5px} .block-gift:active{--color:#29ABE1} .block-gift.on{--color:#29ABE1} .block-gift.on:active{--color:#999999} .block-gift .block-gift-inner{width:14px;height:14px;position:absolute;top:3px;left:3px} .block-gift .block-gift-inner g{fill:var(--color)} .block-gift .block-gift-border{width:20px;height:20px;position:absolute} .block-gift .block-gift-border g{stroke:var(--color);fill:transparent} .bp-no-flash-tips{display:none} .live-room-app .app-content .app-body .player-and-aside-area .left-container .player-section{height:100% !important} .player-full-win .gift-control-section{display:none} `; document.head.appendChild(style); var blockGift = document.createElement('div'); blockGift.className = 'btn block-gift'; blockGift.setAttribute('title', '屏蔽礼物信息'); blockGift.innerHTML = ` <!-- Source: http://www.iconninja.com/giftbox-outline-icon-849682 --> <svg class="block-gift-inner" width="935.375px" height="935.375px" viewBox="0 0 935.375 935.375"> <g><path d="M362.189,34.821C325.89,8.479,287.582-3.011,248.316,0.67c-33.322,3.124-60.324,14.123-80.258,32.69 c-19.385,18.057-30.58,42.083-32.374,69.48c-2.367,36.164,12.378,75.592,40.456,108.175c0.492,0.571,0.996,1.132,1.496,1.698 H38.074v265.732h33.219v456.929h792.789V478.447h33.219V212.715H757.736c0.5-0.565,1.004-1.127,1.496-1.698 c28.078-32.583,42.824-72.012,40.457-108.175c-1.795-27.397-12.988-51.425-32.375-69.48 c-19.934-18.568-46.936-29.566-80.258-32.69c-39.266-3.68-77.574,7.809-113.873,34.15c-26.717,19.388-52.33,46.951-76.129,81.925 c-11.295,16.599-21.104,33.273-29.369,48.659c-8.264-15.386-18.072-32.06-29.368-48.659 C414.52,81.771,388.906,54.208,362.189,34.821z M106.074,300.771v-20.056h723.227v20.057v109.674h-33.219h-213.57h-229.65H139.293 h-33.219V300.771z M420.862,478.447h93.65v136.35l-46.825-21.688l-46.825,21.688V478.447z M227.654,166.627 c-16.294-18.909-25.309-41.093-24.114-59.343c0.649-9.924,4.306-18.055,10.867-24.167c8.567-7.98,22.488-13.079,40.257-14.745 c22.491-2.109,44.457,4.815,67.152,21.167c20.247,14.587,40.299,36.274,59.603,64.458c13.919,20.324,25.4,41.105,34.167,58.717 h-110.44C274.073,204.938,246.652,188.675,227.654,166.627z M796.08,867.375H139.293V478.447h213.569v242.787l114.825-53.187 l114.825,53.186V478.447h213.57v388.928H796.08z M553.273,155c19.369-28.464,39.504-50.382,59.85-65.145 c22.846-16.578,44.951-23.606,67.588-21.483c17.77,1.666,31.689,6.765,40.258,14.745c6.561,6.112,10.217,14.242,10.867,24.167 c1.193,18.25-7.82,40.435-24.115,59.343c-18.998,22.047-46.42,38.311-77.49,46.087H519.762 C528.361,195.442,539.605,175.085,553.273,155z"/></g> </svg> <svg class="block-gift-border" width="20px" height="20px"> <g> <circle cx=10 cy=10 r=9 /> <path d="M3.5355,3.5355L16.4645,16.4645" style="stroke-width:2px" /> </g> </svg> `; blockGift.addEventListener('click', blockGiftClickListener); if (localStorage.BHL_blockGift === 'true') blockGift.click(); var observer = new MutationObserver(function () { var btns = document.querySelector('.icon-left-part'); if (btns != null && document.querySelector('#swfobject_placeholder [name="flashvars"]') != null) { observer.disconnect(); btns.appendChild(blockGift); room_id = unsafeWindow.BilibiliLive.ROOMID; init(room_id); }/* else if (document.querySelector('.bp-no-flash-tips') != null) { var parent = document.querySelector('.bp-no-flash-tips').parentNode; document.querySelector('.bp-no-flash-tips').remove(); parent.appendChild(_('object', { id: 'swfobject_placeholder' }, [_('param', {name: 'flashvars'})])); }*/ }); observer.observe(document, { childList: true, subtree: true }); } else { tryInterval = setInterval(function () { if (tryCount > 20) { log('quiting'); clearInterval(tryInterval); return; } log('finding', tryCount++); var link = document.querySelector('#swfobject_placeholder [name="flashvars"]'); if (link == null) return; room_id = link.value.match(/cid=(.*?)&/)[1]; clearInterval(tryInterval); log('found'); init(room_id); }, 1000); } })(); var getWebsocketConfbackoffTime = 1; function get_websocket_config(room_id) { $.ajax({ url: '//api.live.bilibili.com/room/v1/Danmu/getConf?room_id=704808&platform=pc&player=web', type: 'GET', dataType: 'json', success: function (data) { df_domain = data.data.host_server_list[0].host; df_portobj.ws = data.data.host_server_list[0].ws_port; df_portobj.wss = data.data.host_server_list[0].wss_port; df_portobj.token = data.data.token; unsafeWindow.df_danmu_ws = new DanmuSocket(parseInt(room_id), df_domain, df_portobj); unsafeWindow.df_danmu_ws.setListener(danmuListener); getWebsocketConfbackoffTime = 1; }, error: function () { setTimeout(function () { get_websocket_config(room_id); }, getWebsocketConfbackoffTime); getWebsocketConfbackoffTime = Math.min(getWebsocketConfbackoffTime * 2, 60); }, xhrFields: {withCredentials: true} }) } function get_url_and_replace_player(room_id) { $.ajax({ url: '//api.live.bilibili.com/userext/v1/danmuConf/getAll?roomid=' + room_id, type: 'GET', dataType: 'json', success: function (data) { try { var limit = data.data.length; dispatchEvent('initDanmaku', { danmu_length: limit }); setTimeout(function () { dispatchEvent('initDanmaku', { danmu_length: limit }); }, 1e3) } catch (e) { console.error('error processing player data: ', e.message); } }, xhrFields: {withCredentials: true} }); $.ajax({ url: '//api.live.bilibili.com/room/v1/Room/mobileRoomInit?id=' + room_id, type: 'GET', dataType: 'json', success: function (data) { if (data.data.live_status != 1) { if (abpinst != null) { dots.stopTimer(); abpinst.playerUnit.querySelector('#info-box .text-wrapper>div').innerHTML = '未在直播'; destroyPlayer(); } living = false; } }, xhrFields: {withCredentials: true} }); get_websocket_config(room_id); var api_url = '//api.live.bilibili.com/room/v1/Room/playUrl?platform=web&otype=json&cid=' + room_id; $.ajax({ url: api_url, type: 'GET', dataType: 'json', success: function (data) { if (!living) return; data = data.data; replace_player(data.durl[0].url); if (unsafeWindow.df_danmu_ws !== undefined) { i_close_it_myself = true; unsafeWindow.df_danmu_ws.close(); unsafeWindow.df_danmu_ws = undefined; } }, xhrFields: {withCredentials: true} }); createABP(); } function createABP() { var video = document.createElement('video'); document.querySelector('#js-player-decorator').appendChild(video); var abpOptions = { scale: 0.8, opacity: 0.7, speed: 1, useCSS: false, autoOpacity: false }; try { var settings = localStorage.html5Settings || '{}'; settings = JSON.parse(settings); abpOptions.scale = settings.scale || 1; abpOptions.opacity = settings.opacity || 1; abpOptions.speed = settings.speed || 1; abpOptions.volume = settings.volume || 1; abpOptions.useCSS = settings.useCSS || false; abpOptions.autoOpacity = settings.autoOpacity || false; } catch (e) { } abpinst = ABP.create(document.getElementById('js-player-decorator'), { src: { playlist: [ { video: video } ] }, width: '100%', height: '100%', config: abpOptions }); unsafeWindow.abpinst = abpinst; if (settings.commentVisible === false) { abpinst.btnDm.click(); } dots.runTimer(); abpinst.video.addEventListener('ended', function () { if (!living) return; abpinst.createPopup('直播流意外结束', 3e3); changeSrc('', player.hls == null ? 'flv' : 'hls'); }); } function replace_player(flv_url) { var w = $('#js-player-decorator').width(); var h = $('#js-player-decorator').height(); flvjs.LoggingControl.enableVerbose = false; flvjs.LoggingControl.enableInfo = false; flvjs.LoggingControl.enableDebug = false; createPlayer.flv(flv_url); abpinst.playerUnit.querySelector('#info-box .text-wrapper>div').innerHTML = '正在加载视频信息'; unsafeWindow.addEventListener('unload', destroyPlayer); [['flv', ''], ['hls', '']].forEach(function (i) { var div = document.createElement('div'); div.setAttribute('changeto', JSON.stringify(i)); //div.setAttribute('name',availableSrc[i][0]); if (i[0] == 'flv') div.className = 'on'; div.appendChild(document.createTextNode(i[0])); abpinst.playerUnit.querySelector('.BiliPlus-Scale-Menu .Video-Defination').appendChild(div); }); } function click_list() { if (unsafeWindow.location.pathname === '/') { $($('[role="list"]')[0]).children().on('click', function () { var room_id = $(this).attr('data-cid'); get_url_and_replace_player(room_id); }); } } var rawHeaderLen = 16; var packetOffset = 0; var headerOffset = 4; var verOffset = 6; var opOffset = 8; var seqOffset = 12; var pako = unsafeWindow.pako; var textDecoder = getDecoder(true); var textEncoder = getEncoder(); var heartbeatInterval; function getDecoder(isUseful) { if (unsafeWindow['TextDecoder'] && isUseful) { return new unsafeWindow['TextDecoder'](); } else { return { decode: (buf) => { return decodeURIComponent(unsafeWindow.escape(String.fromCharCode.apply(null, new Uint8Array(buf)))); } }; } } function getEncoder() { if (unsafeWindow['TextEncoder']) { return new unsafeWindow['TextEncoder'](); } else { return { encode: (str) => { var buf = new ArrayBuffer(str.length); var bufView = new Uint8Array(buf); for (var 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; } function DanmuSocket(roomid, domain, portobj) { var ws = 'wss'; var 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; this.token = portobj.token; } DanmuSocket.prototype.firstConnection = function () { reconnecting = false; log('Danmu WebSocket Server Connected.'); log('Handshaking...'); var token = JSON.stringify({ 'uid': unsafeWindow.BilibiliLive.UID || 0, 'roomid': this.roomid, 'token': this.token }); 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)); }; DanmuSocket.prototype.heartBeat = function () { 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); }; DanmuSocket.prototype.closeHeartBeat = function () { clearInterval(this.heartBeating); }; DanmuSocket.prototype.send = function (data) { this.connection.send(data); }; DanmuSocket.prototype.close = function () { this.connection.close(); }; DanmuSocket.prototype.setListener = function (listener) { this._listener = listener; }; function onMessage(evt) { var data = evt.data; var dataView = new DataView(data, 0); var packetLen = dataView.getUint32(packetOffset); if (dataView.byteLength >= packetLen) { var headerLen = dataView.getInt16(headerOffset); var ver = dataView.getInt16(verOffset); var op = dataView.getUint32(opOffset); var seq = dataView.getUint32(seqOffset); switch (op) { case 8: this.heartBeat(); heartbeatInterval = setInterval(this.heartBeat.bind(this), 30 * 1000); break; case 3: 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.getUint32(offset); headerLen = packetView.getInt16(offset + headerOffset); if (ver === 2) { // deflated message var inflate = new Zlib.Inflate(new Uint8Array(msg.slice(offset + headerLen, offset + packetLen)), {resize:true}); var inflatedMsg = inflate.decompress(); this.connection.onmessage({data:inflatedMsg.buffer}); } else if (packetLen) { 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() { reconnecting = false; if (heartbeatInterval) clearInterval(heartbeatInterval); if (!i_close_it_myself) { setTimeout(reConnect, 5000); } i_close_it_myself = false; } function onError() { reconnecting = false; log('Client Error.'); setTimeout(reConnect, 5000); } function reConnect() { if (reconnecting) return; reconnecting = true; log('reconnecting socket...'); get_websocket_config(room_id); } unsafeWindow.ws_reConnect = reConnect; function change_online(online) { dispatchEvent('receiveOnlineCount', online); } function emit_danmu(data) { if (data.cmd === 'DANMU_MSG') { abpinst.cmManager.send({ text: data.info[1], mode: data.info[0][1], color: data.info[0][3], hash: data.info[0][7], size: data.info[0][2], border: (data.info[2][0] == unsafeWindow.BilibiliLive.UID) }); } } /*oriServerCb = unsafeWindow.server_callback; unsafeWindow.server_callback = function (data) { if ([ 'SEND_GIFT', 'SYS_MSG', 'SYS_GIFT', 'WELCOME', 'SPECIAL_GIFT', 'SEND_TOP' ].indexOf(data.cmd) != -1 && blockingGift) return; oriServerCb(data); };*/ function append_danmu(data) { switch (data.cmd) { case 'ROUND': log('进入轮播状态', data); restorePlayer(); return; case 'CLOSE': case 'PREPARING': case 'END': log('直播结束', data); if (abpinst != null) { abpinst.createPopup('直播已结束', 60e3); } living = false; dispatchEvent('receiveMessage', data); break; case 'LIVE': log('开始直播', data); if (rounding) { EmbedPlayer.loader(); document.getElementById('js-player-decorator').appendChild(abpinst.playerUnit); abpinst.playerUnit.style.display = ''; rounding = false; } living = true; changeSrc(0, 'flv'); break; } //if (!living) return; if ([ 'SEND_GIFT', 'SYS_MSG', 'SYS_GIFT', 'WELCOME', 'SPECIAL_GIFT', 'SEND_TOP' ].indexOf(data.cmd) != -1 && blockingGift) return; //if (data.cmd == 'DANMU_MSG' && data.info[2][0] == unsafeWindow.BilibiliLive.UID) return; dispatchEvent('receiveMessage', data); } function danmuListener(content_type, content) { if (content_type === 'online') { if (unsafeWindow.dom_changed === undefined) { $('#h5_player').prev().appendTo('#js-player-decorator'); unsafeWindow.dom_changed = true; } change_online(content); } else if (content_type === 'msg') { var content_obj = JSON.parse(content); socketBuffer.push(content_obj); currentGap = (60 / socketBuffer.length) | 0; } } var socketBuffer = []; var currentGap = 0; var currentGapLeft = 0; setInterval(function () { if (!socketBuffer.length) return; if (currentGapLeft > 0) { return currentGapLeft--; } currentGapLeft = currentGap; var next = socketBuffer.shift(); if (unsafeWindow.BHL_Debug) console.log(next); if (next.cmd) { next.cmdOriginal = next.cmd; next.cmd = next.cmd.split(':')[0]; } if (next.cmd == 'DANMU_MSG' && /(不是风动~是dokidoki心动!|哔哩哔哩.+干杯~)/.test(next.info[1])) return; emit_danmu(next); append_danmu(next); }, 1e3 / 60); function send_danmu(data) { var xhr = new XMLHttpRequest(); // xhr.setRequestHeader('X-Cookie', document.cookie); let {msg, color, mode} = data; xhr.open('POST', '//api.live.bilibili.com/msg/send', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.withCredentials = true; xhr.responseType = 'json'; xhr.onload = function () { var data = xhr.response; if (data.code != 0 || data.message) { abpinst.createPopup('发送弹幕失败 ['+data.code+']' + data.message, 3e3); } } xhr.send($.param({ color: color, fontsize: 25, mode: mode, msg: msg, rnd: Math.floor(Date.now() / 1000), roomid: room_id, bubble: 0, csrf_token: (document.cookie.match(/bili_jct=([^;]+)/)||[0,''])[1], csrf: (document.cookie.match(/bili_jct=([^;]+)/)||[0,''])[1] })); } // inflate.min.js /** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';var l=void 0,aa=this;function r(c,d){var a=c.split("."),b=aa;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&d!==l?b[e]=d:b=b[e]?b[e]:b[e]={}};var t="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function v(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,m,n,p,s,x;for(p=0;p<d;++p)c[p]>a&&(a=c[p]),c[p]<b&&(b=c[p]);e=1<<a;f=new (t?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(p=0;p<d;++p)if(c[p]===g){m=0;n=h;for(s=0;s<g;++s)m=m<<1|n&1,n>>=1;x=g<<16|p;for(s=m;s<e;s+=k)f[s]=x;++h}++g;h<<=1;k<<=1}return[f,a,b]};function w(c,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=t?new Uint8Array(c):c;this.m=!1;this.i=y;this.r=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.r=d.resize);switch(this.i){case A:this.b=32768;this.c=new (t?Uint8Array:Array)(32768+this.h+258);break;case y:this.b=0;this.c=new (t?Uint8Array:Array)(this.h);this.e=this.z;this.n=this.v;this.j=this.w;break;default:throw Error("invalid inflate mode"); }}var A=0,y=1,B={t:A,s:y}; w.prototype.k=function(){for(;!this.m;){var c=C(this,3);c&1&&(this.m=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=l,h=l,k=b.length,m=l;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case A:for(;e+ g>b.length;){m=k-e;g-=m;if(t)b.set(d.subarray(a,a+m),e),e+=m,a+=m;else for(;m--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case y:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(t)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(ba,ca);break;case 2:for(var n=C(this,5)+257,p=C(this,5)+1,s=C(this,4)+4,x=new (t?Uint8Array:Array)(D.length),S=l,T=l,U=l,u=l,M=l,F=l,z=l,q=l,V=l,q=0;q<s;++q)x[D[q]]= C(this,3);if(!t){q=s;for(s=x.length;q<s;++q)x[D[q]]=0}S=v(x);u=new (t?Uint8Array:Array)(n+p);q=0;for(V=n+p;q<V;)switch(M=E(this,S),M){case 16:for(z=3+C(this,2);z--;)u[q++]=F;break;case 17:for(z=3+C(this,3);z--;)u[q++]=0;F=0;break;case 18:for(z=11+C(this,7);z--;)u[q++]=0;F=0;break;default:F=u[q++]=M}T=t?v(u.subarray(0,n)):v(u.slice(0,n));U=t?v(u.subarray(n)):v(u.slice(n));this.j(T,U);break;default:throw Error("unknown BTYPE: "+c);}}return this.n()}; var G=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=t?new Uint16Array(G):G,H=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],I=t?new Uint16Array(H):H,J=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],K=t?new Uint8Array(J):J,L=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],da=t?new Uint16Array(L):L,ea=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12, 13,13],N=t?new Uint8Array(ea):ea,O=new (t?Uint8Array:Array)(288),P,fa;P=0;for(fa=O.length;P<fa;++P)O[P]=143>=P?8:255>=P?9:279>=P?7:8;var ba=v(O),Q=new (t?Uint8Array:Array)(30),R,ga;R=0;for(ga=Q.length;R<ga;++R)Q[R]=5;var ca=v(Q);function C(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h;b<d;){if(f>=g)throw Error("input buffer is broken");a|=e[f++]<<b;b+=8}h=a&(1<<d)-1;c.f=a>>>d;c.d=b-d;c.a=f;return h} function E(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],m,n;b<k&&!(f>=g);)a|=e[f++]<<b,b+=8;m=h[a&(1<<k)-1];n=m>>>16;if(n>b)throw Error("invalid code length: "+n);c.f=a>>n;c.d=b-n;c.a=f;return m&65535} w.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b>=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b}; w.prototype.w=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b}; w.prototype.e=function(){var c=new (t?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(t)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.l+=c.length;if(t)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.b=32768;return e}; w.prototype.z=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.u&&(a+=c.u));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;t?(d=new Uint8Array(e),d.set(h)):d=h;return this.c=d}; w.prototype.n=function(){var c=0,d=this.c,a=this.g,b,e=new (t?Uint8Array:Array)(this.l+(this.b-32768)),f,g,h,k;if(0===a.length)return t?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.b;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e}; w.prototype.v=function(){var c,d=this.b;t?this.r?(c=new Uint8Array(d),c.set(this.c.subarray(0,d))):c=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),c=this.c);return this.buffer=c};function W(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case ha:this.method=ha;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.q=new w(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})} W.prototype.k=function(){var c=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f<g;f++)e[f]=(e[f].charCodeAt(0)&255)>>>0;b=e}for(var h=1,k=0,m=b.length,n,p=0;0<m;){n=1024<m?1024:m;m-=n;do h+=b[p++],k+=h;while(--n);h%=65521;k%=65521}if(a!==(k<<16|h)>>>0)throw Error("invalid adler-32 checksum");}return d};var ha=8;r("Zlib.Inflate",W);r("Zlib.Inflate.prototype.decompress",W.prototype.k);var X={ADAPTIVE:B.s,BLOCK:B.t},Y,Z,$,ia;if(Object.keys)Y=Object.keys(X);else for(Z in Y=[],$=0,X)Y[$++]=Z;$=0;for(ia=Y.length;$<ia;++$)Z=Y[$],r("Zlib.Inflate.BufferType."+Z,X[Z]);}).call(this);