WebSocket获取虎牙弹幕并展示
效果图
效果图:
JWT 加密
参考 使用 JavaScript 实现 JWT 鉴权:
通过 BootCDN 引入加密库 crypto-js 与 jsrsasign
<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jsrsasign/10.5.8/ext/base64-min.js"></script>
通过 BootCDN 引入加密库 crypto-js 与 jsrsasign
// base64二次加密
function base64UrlEncode(str) {
var encodedSource = CryptoJS.enc.Base64.stringify(str)
var reg = new RegExp('/', 'g')
encodedSource = encodedSource
.replace(/=+$/, '')
.replace(/\+/g, '-')
.replace(reg, '_')
return encodedSource
}
/**
* @description: 获取wss地址
* @param roomId 虎牙房间号
* @param appId 虎牙开发者appId
* @param secret 虎牙开发者secret
* @param expSeconds 签名过期时间
*/
function getWss(roomId, appId, secret, expSeconds) {
var header = JSON.stringify({
alg: 'HS256',
typ: 'JWT',
})
var payload = JSON.stringify({
iat: parseInt(new Date().getTime() / 1000),
exp: parseInt(new Date().getTime() / 1000) + expSeconds,
roomId: roomId,
appId: appId,
})
var before_sign =
base64UrlEncode(CryptoJS.enc.Utf8.parse(header)) +
'.' +
base64UrlEncode(CryptoJS.enc.Utf8.parse(payload))
var signature = CryptoJS.HmacSHA256(before_sign, secret)
signature = base64UrlEncode(signature)
var final_sign = before_sign + '.' + signature
var wss =
'ws://ws-apiext.huya.com/index.html?do=comm&roomId=' +
roomId +
'&appId=' +
appId +
'&iat=' +
parseInt(new Date().getTime() / 1000) +
'&sToken=' +
final_sign
return wss
}
通过 WebSocket 获取弹幕内容
/**
* @description: 获取socket内容
* @param {type}
*/
function getSocketContent(wss) {
// 弹幕数据
let arry = []
let arryItem = {
name: '',
content: '',
}
var socket = new WebSocket(wss)
socket.onopen = function (event) {
//发送subscribeNotice command
socket.send(
'{"command":"subscribeNotice","data":["getMessageNotice","getVipEnterBannerNotice","getSendItemNotice","getOnTVAwardNotice", "getOpenNobleNotice", "getOpenGuardianNotice", "getUserMutedNotice"],"reqId":"123456789"}'
)
//设置定时器以文本数据发送ping,保持与服务器的心跳
setInterval(function () {
socket.send('ping')
// 渲染数据
arry.forEach((item) => {
console.log(item)
})
}, 15000)
}
socket.onmessage = function (event) {
var json = JSON.parse(event.data)
if (json.statusCode == 200) {
//TODO处理数据json.data
if (json.notice == 'getMessageNotice') {
document.getElementById('con').innerHTML += htmlCon(
json.data.sendNick,
json.data.content
)
// div数量大于10条,删除第一条
if (document.getElementById('con').children.length > 20) {
document.getElementById('con').children[0].remove()
}
}
}
}
}
html 模板
随意写了一下样式做美化
/**
* @description: html模板内容
* @param {type}
*/
function htmlCon(nickName, content) {
var html = `
<div class="content">
<div class="name">${nickName} :</div>
<div style="width: 1em;"></div>
<div class="txt">${content}</div>
</div>
`
return html
}
获取 appId 与 secret
登录虎牙开发者平台获取 appId 与 secret
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.content {
display: flex;
}
.name {
color: red;
}
</style>
</head>
<body>
<div id="con">
<div class="content">
<div class="name">用户名:</div>
<div style="width: 0.2em"></div>
<div class="txt">弹幕内容</div>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jsrsasign/10.5.8/ext/base64-min.js"></script>
<script type="text/javascript" charset="utf-8">
// base64二次加密
function base64UrlEncode(str) {
var encodedSource = CryptoJS.enc.Base64.stringify(str)
var reg = new RegExp('/', 'g')
encodedSource = encodedSource
.replace(/=+$/, '')
.replace(/\+/g, '-')
.replace(reg, '_')
return encodedSource
}
/**
* @description: 获取wss地址
* @param roomId 虎牙房间号
* @param appId 虎牙开发者appId
* @param secret 虎牙开发者secret
* @param expSeconds 签名过期时间
*/
function getWss(roomId, appId, secret, expSeconds) {
var header = JSON.stringify({
alg: 'HS256',
typ: 'JWT',
})
var payload = JSON.stringify({
iat: parseInt(new Date().getTime() / 1000),
exp: parseInt(new Date().getTime() / 1000) + expSeconds,
roomId: roomId,
appId: appId,
})
var before_sign =
base64UrlEncode(CryptoJS.enc.Utf8.parse(header)) +
'.' +
base64UrlEncode(CryptoJS.enc.Utf8.parse(payload))
var signature = CryptoJS.HmacSHA256(before_sign, secret)
signature = base64UrlEncode(signature)
var final_sign = before_sign + '.' + signature
var wss =
'ws://ws-apiext.huya.com/index.html?do=comm&roomId=' +
roomId +
'&appId=' +
appId +
'&iat=' +
parseInt(new Date().getTime() / 1000) +
'&sToken=' +
final_sign
return wss
}
/**
* @description: 获取socket内容
* @param {type}
*/
function getSocketContent(wss) {
// 弹幕数据
let arry = []
let arryItem = {
name: '',
content: '',
}
var socket = new WebSocket(wss)
socket.onopen = function (event) {
//发送subscribeNotice command
socket.send(
'{"command":"subscribeNotice","data":["getMessageNotice","getVipEnterBannerNotice","getSendItemNotice","getOnTVAwardNotice", "getOpenNobleNotice", "getOpenGuardianNotice", "getUserMutedNotice"],"reqId":"123456789"}'
)
//设置定时器以文本数据发送ping,保持与服务器的心跳
setInterval(function () {
socket.send('ping')
// 渲染数据
arry.forEach((item) => {
console.log(item)
})
}, 15000)
}
socket.onmessage = function (event) {
var json = JSON.parse(event.data)
if (json.statusCode == 200) {
//TODO处理数据json.data
if (json.notice == 'getMessageNotice') {
document.getElementById('con').innerHTML += htmlCon(
json.data.sendNick,
json.data.content
)
// div数量大于10条,删除第一条
if (document.getElementById('con').children.length > 20) {
document.getElementById('con').children[0].remove()
}
}
}
}
}
/**
* @description: html模板内容
* @param {type}
*/
function htmlCon(nickName, content) {
var html = `
<div class="content">
<div class="name">${nickName} :</div>
<div style="width: 1em;"></div>
<div class="txt">${content}</div>
</div>
`
return html
}
let wss = getWss(
****,
***************,
***************,
600
)
// 调用方法
getSocketContent(wss)
</script>
</body>
</html>