UNPKG

@d2n0s4ur/chzzk-chat

Version:

chzzk-chat: node.js 개발자를 위한 chzzk 채팅 & 후원 비공식 라이브러리

179 lines (178 loc) 7.68 kB
"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;