@d2n0s4ur/chzzk-chat
Version:
chzzk-chat: node.js 개발자를 위한 chzzk 채팅 & 후원 비공식 라이브러리
179 lines (178 loc) • 7.68 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChzzkChat = void 0;
const ws_1 = require("ws");
const chzzkIRCUrl = "wss://kr-ss3.chat.naver.com/chat";
class ChzzkChat {
constructor(chzzkChannelId) {
this.emojiPacks = [];
this.init = async () => {
this.chatChannelId = await this.getChatChannelId(this.chzzkChannelId);
this.chatChannelAccessToken = await this.getChatChannelAccessToken(this.chatChannelId);
this.emojiPacks = await this.getChannelEmojiPacks(this.chzzkChannelId);
this.ws = new ws_1.WebSocket(chzzkIRCUrl);
this.ws.onopen = this.onOpen.bind(this);
this.ws.onmessage = this.onMessage.bind(this);
this.ws.onclose = this.onClose.bind(this);
this.ws.onerror = this.onError.bind(this);
};
this.addMessageHandler = (handler) => {
this.messageHandler = handler;
};
this.addDonationHandler = (handler) => {
this.donationHandler = handler;
};
this.addSubscriptionHandler = (handler) => {
this.subscriptionHandler = handler;
};
this.getChatChannelId = async (chzzkChannelId) => {
const url = `https://api.chzzk.naver.com/polling/v2/channels/${chzzkChannelId}/live-status`;
const response = await fetch(url, {
method: "GET",
headers: {
Origin: "https://chzzk.naver.com",
},
});
const data = await response.json();
return data.content.chatChannelId;
};
this.getChatChannelAccessToken = async (chatChannelId) => {
const url = `https://comm-api.game.naver.com/nng_main/v1/chats/access-token?channelId=${chatChannelId}&chatType=STREAMING`;
const response = await fetch(url, {
method: "GET",
headers: {
Origin: "https://chzzk.naver.com",
},
});
const data = await response.json();
return data.content.accessToken;
};
this.getChannelEmojiPacks = async (channelId) => {
const url = `https://api.chzzk.naver.com/service/v1/channels/${channelId}/emoji-packs`;
const response = await fetch(url, {
method: "GET",
headers: {
Origin: "https://chzzk.naver.com",
"User-Agent": "Mozilla/5.0",
},
});
if (!response.ok) {
console.log("Failed to fetch emoji packs");
return [];
}
const data = await response.json();
const emojiPacks = data?.content?.emojiPacks;
return emojiPacks ? emojiPacks : [];
};
this.getEmojiUrl = (emojiId) => {
for (const emojiPack of this.emojiPacks) {
for (const emoji of emojiPack.emojis) {
if (emoji.emojiId === emojiId) {
return emoji.imageUrl;
}
}
}
return undefined;
};
this.parseBadgeUrl = (badge) => {
if (!badge)
return [];
return badge.map((b) => {
return b.imageUrl;
});
};
this.closs = () => {
if (!this.ws)
return;
this.ws.close();
};
this.chzzkChannelId = chzzkChannelId;
this.chatChannelId = "";
this.chatChannelAccessToken = "";
this.sid = "";
this.uuid = "";
this.initialization = this.init();
}
onOpen(event) {
if (!this.ws)
return;
console.log("Connected to Chzzk IRC");
this.ws.send(`{"ver":"2","cmd":100,"svcid":"game","cid":"${this.chatChannelId}","bdy":{"uid":null,"devType":2001,"accTkn":"${this.chatChannelAccessToken}","auth":"READ"},"tid":1}`);
}
onClose(event) {
console.log("Disconnected from Chzzk IRC");
}
onError(event) {
console.log("Error from Chzzk IRC: ", event);
}
onMessage(event) {
if (!this.ws)
return;
const data = JSON.parse(event.data.toString());
switch (data.cmd) {
case 10100:
this.sid = data.bdy.sid;
this.uuid = data.bdy.uuid;
console.log(`Connected to Chzzk Chat Successfully: ${this.sid}`);
break;
case 0:
this.ws.send(`{"ver": "2", "cmd": 10000}`);
break;
case 94008:
// cleanBot message
break;
default:
if (!data.bdy)
return;
data.bdy.forEach((msg) => {
const profile = JSON.parse(msg.profile);
switch (data.cmd) {
case 93101: // default message
if (!this.messageHandler)
return;
this.messageHandler({
badges: this.parseBadgeUrl(profile ? profile.activityBadges : undefined),
nick: profile.nickname,
message: msg.msgStatusType === "CBOTBLIND"
? "클린봇에 의해 삭제된 메시지입니다."
: msg.msg,
});
break;
case 93102: // donation message
const messageTypeCode = data.bdy[0].msgTypeCode;
const extras = JSON.parse(data.bdy[0].extras);
switch (messageTypeCode) {
case 10: // donation message
if (!this.donationHandler)
return;
this.donationHandler({
badges: this.parseBadgeUrl(profile ? profile.activityBadges : undefined),
nick: msg.uid !== "anonymous"
? profile.nickname
: "익명의 후원자",
message: msg.msg,
isAnonymous: msg.uid === "anonymous",
amount: extras.payAmount,
});
break;
case 11: // subscription message
if (!this.subscriptionHandler)
return;
this.subscriptionHandler({
badges: this.parseBadgeUrl(profile ? profile.activityBadges : undefined),
nick: profile.nickname,
message: msg.msg,
month: extras.month,
tierName: extras.tierName,
tierNo: extras.tierNo,
});
break;
default: // unknown message
break;
}
}
});
}
}
}
exports.ChzzkChat = ChzzkChat;