はじめに
最近SHOWROOMを見始めて、バーチャル枠を見てると配信画面にコメントやらギフトログを出している人が居るのでそれってどうやって取得できるのかな?と思ったのがこの記事を書くことになった切っ掛けです
調査
双方向通信って事はWebSocketでも使っているのかな?
と言う事で配信画面でブラウザの開発者ツール開いてWS
を見てみると案の定
online.showroom-live.com
にSUB 何かの文字列
を送ることで配信内のコメントなど取得できるようになってるみたいです
謎の文字列
WebSocket使っているのは分かったが、接続した後何の文字列を送っているのか?
色々なルームの文字列を見たところbXXXXX(6文字):XXXXXXXX(8文字)
の形式みたいです
色々調べてみるとAPIがあるみたいでまとめてあるページがあったので参考に調べてみたところ
https://www.showroom-live.com/api/live/onlives
にアクセスした際各ルームのbcsvr_key
と言う所の値がそれっぽいみたいです
bcsvrが何なのか調べてみたらDeNAが開発したギフティングやコメント向けのリアルタイムサーバみたいです
接続してみる
ささっとJavaScriptでコンソールに出力して中身を見てみます
// WebSocket 接続を作成
const socket = new WebSocket('wss://online.showroom-live.com')
// 接続が開いたときのイベント
socket.onopen = (e) => {
socket.send('SUB\tbXXXXX:XXXXXXXX')
}
// メッセージの待ち受け
socket.onmessage = (message) => {
console.log(message.data)
}
コンソールに出力される内容を見てみると、基本的に下記のような形式で取得されているみたいです
// コメント
MSG bXXXXX:XXXXXXXX {"ua":値,"av":値,"d":値,"ac":"値","cm":"値","created_at":値,"u":値,"at":値,"t":"値"}
// ギフト
MSG bXXXXX:XXXXXXXX {"ua":値,"n":値,"av":値,"d":値,"ac":"値","created_at":値,"u":値,"h":値,"g":値,"gt":値,"at":値,"t":"値"}
// テロップ
MSG bXXXXX:XXXXXXXX {"telops":[{"color":{"r":値,"b":値,"g":値},"text":"値","type":"値"},{"color":{"r":値,"b":値,"g":値},"text":"値","type":"値"}],"telop":"値","interval":値,"t":値,"api":"値"}
// 疎通確認
ACK showroom
// 不明
MSG bXXXXX:XXXXXXXX {"created_at":値,"t":値}
MSG bXXXXX:XXXXXXXX {"created_at":値,"u":値,"at":値,"t":値}
// エラー(海外配信者のルームでよく見かける)
Could not decode a text frame as UTF-8.
疎通確認時とエラーのテキスト以外、最初のMSG bXXXXX:XXXXXXXX
を除いた後の文字列はJSONだと思われるのでJSONに変換したら色々加工できると推測
JavaScriptでJSONオブジェクトとして使えるように加工
// (略)
// メッセージの待ち受け
socket.onmessage = (message) => {
if (message.data === "ACK\tshowroom" || message.data === "Could not decode a text frame as UTF-8.") {
console.log("疎通確認又はエラー")
} else {
// JSONオブジェクトとして取得
console.log(JSON.parse(message.data.replace("MSG\tbXXXXX:XXXXXXXX", "")))
}
}
コメントログとギフトログを取得
コンソールのログを見てみるとコメントログの要素数が9、ギフトログの要素数が12と言う事が分かっています
なのでJSONに変換した後、要素数で分けてあげればコメントログとギフトログに分ける事ができます
// (略)
// メッセージの待ち受け
socket.onmessage = (message) => {
if (message.data === "ACK\tshowroom" || message.data === "Could not decode a text frame as UTF-8.") {
console.log("疎通確認はエラー")
} else {
// JSONオブジェクトとして取得
let messageJson = JSON.parse(message.data.replace("MSG\tbXXXXX:XXXXXXXX", ""))
if (Object.keys(messageJson).length === 9) {
// コメントログ
} else if (Object.keys(messageJson).length === 12) {
// ギフトログ
} else {
// テロップなど(今回は無視)
}
}
}
JSON要素の構成
コメント
{
ac: "ユーザ名",
at: 0(不明、固定っぽい?),
av: アバターID,
cm: "コメント",
created_at: 投稿時間,
d: 0(不明、固定っぽい?),
t: "1"(不明、固定っぽい?1がコメント?),
u: ユーザID,
ua: リピーター(3)、初見(2)、ビギナー(1),
}
ギフト
{
ac: "ユーザ名",
at: 0(不明、固定っぽい?),
av: アバターID,
created_at: 投稿時間,
d: 0(不明、固定っぽい?),
g: ギフトID,
gt: 無料(1)、有料(2),
h: 0(不明),
n: ギフトの個数,
t: "2"(不明、固定っぽい?2がギフト?),
u: ユーザID,
ua: リピーター(3)、初見(2)、ビギナー(1),
}
画面にログを出してみる
画面を準備
<div>
<div id="comment">
<!-- コメントログ -->
</div>
<div id="gift">
<!-- ギフトログ -->
</div>
</div>
JavaScriptも少し修正しておきます
// (略)
// メッセージの待ち受け
socket.onmessage = (message) => {
if (message.data === "ACK\tshowroom" || message.data === "Could not decode a text frame as UTF-8.") {
console.log("疎通確認又はエラー")
} else {
// JSONオブジェクトとして取得
let messageJson = JSON.parse(message.data.replace("MSG\tbXXXXX:XXXXXXXX", ""))
if (Object.keys(messageJson).length === 9) {
// コメントログ
showComment(messageJson) // 追加
} else if (Object.keys(messageJson).length === 12) {
// ギフトログ
showGift(messageJson) // 追加
} else {
// テロップなど(今回は無視)
}
}
}
コメント
表示に必要な項目は
- ユーザ名
- アバターID
- コメント
の3つがあれば十分なのでコメントに関してはこの3項目を使用
function showComment(comment) {
// アバター画像要素
let avaElement = document.createElement('img')
avaElement.src = "https://image.showroom-cdn.com/showroom-prod/image/avatar/" + comment.av + ".png"
avaElement.width = 40
avaElement.height = 40
// コメント要素
let commentElement = document.createElement('p')
commentElement.textContent = comment.ac + ":" + comment.cm
// アバターとコメントを纏める
let divElement = document.createElement('div')
divElement.appendChild(avaElement)
divElement.appendChild(commentElement)
// 画面に表示
document.getElementById('comment').appendChild(divElement)
}
ギフト
表示に必要な項目は
- ユーザ名
- アバターID
- ギフトID
- ギフト個数
の4つがあれば十分なのでギフトに関してはこの4項目を使用
function showGift(gift) {
// アバター画像要素
let avaElement = document.createElement('img')
avaElement.src = "https://image.showroom-cdn.com/showroom-prod/image/avatar/" + gift.av + ".png"
avaElement.width = 40
avaElement.height = 40
// ギフト画像要素
let gitfElement = document.createElement('img')
gitfElement.src = "https://image.showroom-cdn.com/showroom-prod/assets/img/gift/" + gift.g + "_s.png"
gitfElement.width = 20
gitfElement.height = 20
// ギフト個数要素
let commentElement = document.createElement('p')
commentElement.textContent = gift.ac + ":" + gift.n + "個"
// アバターとギフトを纏める
let divElement = document.createElement('div')
divElement.appendChild(avaElement)
divElement.appendChild(gitfElement)
divElement.appendChild(commentElement)
// 画面に表示
document.getElementById('gift').appendChild(divElement)
}
完成形
ソースの全体像は下記を参照してください
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>SRコメント、ギフト取得</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div>
<div id="comment"></div>
<div id="gift"></div>
</div>
<script>
window.onload = function () {
// WebSocket 接続を作成
const socket = new WebSocket('wss://online.showroom-live.com')
// 接続が開いたときのイベント
socket.onopen = (e) => {
socket.send('SUB\tbXXXXX:XXXXXXXX')
}
// メッセージの待ち受け
socket.onmessage = (message) => {
if (message.data === "ACK\tshowroom" || message.data === "Could not decode a text frame as UTF-8.") {
console.log("疎通確認又はエラー")
} else {
// JSONオブジェクトとして取得
let messageJson = JSON.parse(message.data.replace("MSG\tbXXXXX:XXXXXXXX", ""))
if (Object.keys(messageJson).length === 9) {
// コメントログ
showComment(messageJson)
} else if (Object.keys(messageJson).length === 12) {
// ギフトログ
showGift(messageJson)
} else {
// テロップなど(今回は無視)
}
}
}
}
function showComment(comment) {
// アバター画像要素
let avaElement = document.createElement('img')
avaElement.src = "https://image.showroom-cdn.com/showroom-prod/image/avatar/" + comment.av + ".png"
avaElement.width = 40
avaElement.height = 40
// コメント要素
let commentElement = document.createElement('p')
commentElement.textContent = comment.ac + ":" + comment.cm
// アバターとコメントを纏める
let divElement = document.createElement('div')
divElement.appendChild(avaElement)
divElement.appendChild(commentElement)
// 画面に表示
document.getElementById('comment').appendChild(divElement)
}
function showGift(gift) {
// アバター画像要素
let avaElement = document.createElement('img')
avaElement.src = "https://image.showroom-cdn.com/showroom-prod/image/avatar/" + gift.av + ".png"
avaElement.width = 40
avaElement.height = 40
// ギフト画像要素
let gitfElement = document.createElement('img')
gitfElement.src = "https://image.showroom-cdn.com/showroom-prod/assets/img/gift/" + gift.g + "_s.png"
gitfElement.width = 20
gitfElement.height = 20
// ギフト個数要素
let commentElement = document.createElement('p')
commentElement.textContent = gift.ac + ":" + gift.n + "個"
// アバターとギフトを纏める
let divElement = document.createElement('div')
divElement.appendChild(avaElement)
divElement.appendChild(gitfElement)
divElement.appendChild(commentElement)
// 画面に表示
document.getElementById('gift').appendChild(divElement)
}
</script>
</body>
</html>
最後に
後はお好みでCSSを適応させて見栄えよくさせればオリジナルのコメントビューワーを手軽に作成することができます!