soop-chat-client
Version:
SOOP Live Chat Client
2 lines (1 loc) • 15.3 kB
JavaScript
;var z=Object.create;var A=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var et=Object.getPrototypeOf,nt=Object.prototype.hasOwnProperty;var st=(p,t)=>{for(var n in t)A(p,n,{get:t[n],enumerable:!0})},Y=(p,t,n,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of tt(t))!nt.call(p,o)&&o!==n&&A(p,o,{get:()=>t[o],enumerable:!(e=Z(t,o))||e.enumerable});return p};var J=(p,t,n)=>(n=p!=null?z(et(p)):{},Y(t||!p||!p.__esModule?A(n,"default",{value:p,enumerable:!0}):n,p)),ot=p=>Y(A({},"__esModule",{value:!0}),p);var it={};st(it,{ConnectedState:()=>C,SoopBalloonType:()=>L,SoopBlockType:()=>B,SoopChatClient:()=>P,SoopChatMessageContentType:()=>y});module.exports=ot(it);var H=J(require("ws")),V=require("tiny-typed-emitter"),W=J(require("chalk"));var _=class{name="log";isEnabled=!0;constructor(t,n){this.name=t,this.isEnabled=n}verbose=(t,...n)=>{this.isEnabled&&console.log(`[${this.name}:verbose]`,new Date().toISOString(),t,...n)};info=(t,...n)=>{this.isEnabled&&console.info(`[${this.name}:info]`,new Date().toISOString(),t,...n)};warn=(t,...n)=>{this.isEnabled&&console.warn(`[${this.name}:warn]`,new Date().toISOString(),t,...n)}};var K={"User-Agent":"Mozilla/5.0","Content-Type":"application/x-www-form-urlencoded"},q=async p=>await(await fetch(`https://live.sooplive.co.kr/afreeca/player_live_api.php?bjid=${p}`,{method:"POST",headers:K,body:new URLSearchParams({bid:p,type:"live",pwd:"",player_type:"html5",stream_type:"common",mode:"landing",from_api:"0"})})).json(),v=async p=>await(await fetch(`https://live.sooplive.co.kr/api/signature_emoticon_api.php?work=list&szBjId=${p}`,{method:"GET",headers:K})).json();var j=(i=>(i[i.PING=0]="PING",i[i.LOGIN=1]="LOGIN",i[i.JOIN=2]="JOIN",i[i.JOINPART_USER=4]="JOINPART_USER",i[i.USER_TIMEOUT=8]="USER_TIMEOUT",i[i.CHAT=5]="CHAT",i[i.CHAT_OGQ=109]="CHAT_OGQ",i[i.OGQ_GIFT=118]="OGQ_GIFT",i[i.SET_USERFLAG=12]="SET_USERFLAG",i[i.INOUT_MANAGER=13]="INOUT_MANAGER",i[i.SUBNICKNAME=14]="SUBNICKNAME",i[i.ICE1=19]="ICE1",i[i.ICE2=21]="ICE2",i[i.SLOWMODE=23]="SLOWMODE",i[i.BALLOON=18]="BALLOON",i[i.BALLOON_AD=87]="BALLOON_AD",i[i.BALLOON_AD_STATION=107]="BALLOON_AD_STATION",i[i.POLL=50]="POLL",i[i.BLOCK_WORDS_LIST=54]="BLOCK_WORDS_LIST",i[i.STREAM_CLOSED=88]="STREAM_CLOSED",i[i.SUBSCRIPTION_NEW=91]="SUBSCRIPTION_NEW",i[i.SUBSCRIPTION=93]="SUBSCRIPTION",i[i.SUBSCRIPTION_GIFT=108]="SUBSCRIPTION_GIFT",i[i.SYSTEM_NOTICE=58]="SYSTEM_NOTICE",i[i.CHANNEL_NOTICE=104]="CHANNEL_NOTICE",i[i.MISSION=121]="MISSION",i))(j||{}),k=(a=>(a[a.HOST=2]="HOST",a[a.FANCLUB=5]="FANCLUB",a[a.MANAGER1=6]="MANAGER1",a[a.MANAGER2=8]="MANAGER2",a[a.FEMALE=9]="FEMALE",a[a.TIMEOUT_BY_DOBAE1=11]="TIMEOUT_BY_DOBAE1",a[a.TIMEOUT_BY_DOBAE2=12]="TIMEOUT_BY_DOBAE2",a[a.TIMEOUT_BY_DOBAE3=24]="TIMEOUT_BY_DOBAE3",a[a.MOBILE=14]="MOBILE",a[a.TOPFAN=15]="TOPFAN",a[a.DM_BLCOKED=17]="DM_BLCOKED",a[a.QUICKVIEW=19]="QUICKVIEW",a[a.MOBILE_WEB=23]="MOBILE_WEB",a[a.FOLLOWER=28]="FOLLOWER",a))(k||{}),m=(e=>(e[e.SUBSCRIPTION_TIER1=18]="SUBSCRIPTION_TIER1",e[e.SUBSCRIPTION_TIER2=19]="SUBSCRIPTION_TIER2",e[e.SUBSCRIPTION_TIER3=20]="SUBSCRIPTION_TIER3",e))(m||{}),w=(s=>(s[s.FANCLUB=5]="FANCLUB",s[s.SUPPORTER=6]="SUPPORTER",s[s.TOPFAN=7]="TOPFAN",s[s.SUBSCRIPTION=8]="SUBSCRIPTION",s[s.MANAGER=9]="MANAGER",s))(w||{}),Q={5:"\uD32C\uD074\uB7FD",6:"\uC11C\uD3EC\uD130",7:"\uC5F4\uD608\uD32C",8:"\uAD6C\uB3C5\uD32C",9:"\uB9E4\uB2C8\uC800"},X="\x1B 000100000600\f\f\f16\f";var C=(e=>(e[e.STANDBY=0]="STANDBY",e[e.CONNECTED=1]="CONNECTED",e[e.JOINED=2]="JOINED",e))(C||{}),y=(n=>(n[n.TEXT=0]="TEXT",n[n.EMOTE=1]="EMOTE",n))(y||{}),L=(e=>(e[e.NORMAL=0]="NORMAL",e[e.AD=1]="AD",e[e.VOD=2]="VOD",e))(L||{}),B=(n=>(n[n.TIMEOUT=0]="TIMEOUT",n[n.KICK=1]="KICK",n))(B||{});var P=class extends V.TypedEmitter{socket=null;log;_connection=null;set connection(t){this._connection=t}get connection(){return this._connection}_stream=null;set stream(t){this._stream=t}get stream(){return this._stream}_emotes={};set emotes(t){this._emotes=t}get emotes(){return this._emotes}_connectedState=0;set connectedState(t){this._connectedState=t,t===0?clearInterval(this.loopPingPong):t===1&&(clearInterval(this.loopPingPong),this.loopPingPong=setInterval(this.sendPing,6e4))}get connectedState(){return this._connectedState}loopPingPong;decoder=new TextDecoder;constructor({logging:t=!1}){super(),this.loopPingPong=setInterval(this.sendPing,6e4),this.log=new _("soop-chat",t)}sendPing=()=>{(this.connectedState===1||this.connectedState===2)&&(this.send(0,"\f"),this.log.verbose(`PING: ${this.connection?.channelId}`))};connect=async(t,n="")=>{this.connectedState=0;try{let e=await q(t);if(e.CHANNEL?.RESULT!==1)throw new Error(`\uBC29\uC1A1 \uC911\uC774 \uC544\uB2D9\uB2C8\uB2E4. (${t})`);this.stream=e,this.connection={channelId:this.stream.CHANNEL.BJID,host:this.stream.CHANNEL.CHDOMAIN,port:parseInt(this.stream.CHANNEL.CHPT)+1,password:n},this.log.name=`soop-chat:${this.connection.channelId}`.padEnd(23);let o=`wss://${this.connection.host.toLowerCase()}:${this.connection.port}/Websocket/${this.connection.channelId}`;this.log.info(`\uC5F0\uACB0\uC2DC\uB3C4: ${o}`);let s=new H.default(o,"chat");s.binaryType="arraybuffer",s.onopen=()=>{this.connectedState=1,this.log.info(`\uC5F0\uACB0\uB428: ${s.url}`),s.send(X)},s.onclose=()=>{this.connectedState=0,clearInterval(this.loopPingPong),this.log.warn("\uCC44\uD305 \uC11C\uBC84\uC640 \uC5F0\uACB0\uC774 \uB04A\uC5B4\uC84C\uC2B5\uB2C8\uB2E4.")},s.onerror=r=>{this.connectedState=0,r.message=="unable to verify the first certificate"?this.log.warn("\uCC44\uD305 \uC11C\uBC84 \uC778\uC99D\uC11C \uC624\uB958\uB85C \uC778\uD574 \uC5F0\uACB0\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."):this.log.warn("\uCC44\uD305 \uC11C\uBC84\uC640 \uC5F0\uACB0 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. "+r.error)},s.onmessage=r=>{r.data&&this.processMessage(r.data)},this.socket=s,this.loadEmotes(t)}catch(e){e instanceof Error&&this.log.warn(e.message)}};disconnect=()=>{this.socket&&(this.log.warn("\uCC44\uD305 \uC11C\uBC84\uC640 \uC5F0\uACB0\uC744 \uC885\uB8CC\uD569\uB2C8\uB2E4."),this.emit("part",this.connection?.channelId??""),this.connectedState=0,this.socket.close(),this.connection=null,this.emotes={})};close=this.disconnect;send=(t,n)=>{if(!this.socket||this.socket.readyState!==H.default.OPEN)return!1;let e="\x1B ",o=t.toString().padStart(4,"0"),s=n.length.toString().padStart(6,"0"),c=`${`${e}${o}${s}00`}${n}`;return this.socket?.send(c),!0};loadEmotes=async t=>{try{let n=await v(t);if(this.emotes={},n.version===0){this.log.info("\uCC44\uB110 \uC774\uBAA8\uD2F0\uCF58\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");return}n.data.forEach(e=>{this.emotes[e.title]={title:e.title,tier:e.tier_type??1,pcImg:n.img_path+e.pc_img,pcAltImg:e.pc_alternate_img?n.img_path+e.pc_alternate_img:"",mobileImg:n.img_path+e.mobile_img,mobileAltImg:e.mob_alternate_img?n.img_path+e.mob_alternate_img:"",isAnimated:e.move_img==="Y",orderNo:e.order_no,blackKeyword:e.black_keyword==="Y"}})}catch(n){n instanceof Error&&this.log.warn(n.message);return}};joinChannel=()=>{if(!this.stream)return;let t=this.stream.CHANNEL,n=[`\f${t.CHATNO}`,`\f${t.FTK}`,"\f0\f\flog","&set_bps=",t.BPS,"&view_bps=",t.BPS,"&quality=","ori","&geo_cc=",t.geo_cc,"&geo_rc=",t.geo_rc,"&acpt_lang=",t.acpt_lang,"&svc_lang=",t.svc_lang,"&subscribe=0","&lowlatency=1","",`pwd${this.connection?.password??""}`,"auth_infoNULL","pver2","access_systemhtml5","\f"];this.stream.CHANNEL.BPWD==="Y"&&this.log.info("\uBE44\uBC88\uBC29\uC5D0 \uC811\uC18D\uD569\uB2C8\uB2E4."),this.send(2,n.join(""))};processMessage=t=>{let n=t.slice(0,14),e=parseInt(this.decoder.decode(n.slice(2,6))),o=t.slice(15),s=this.decoder.decode(o).split("\f");switch(e){case 1:this.log.info(`\uB85C\uADF8\uC778: ${this.connection?.channelId}`),this.joinChannel();break;case 2:this.onMsgJoin(s);break;case 4:this.onMsgJoinPartUser(s);break;case 8:this.onMsgSetUserTimeout(s);break;case 5:this.onMsgChatMsg(s);break;case 109:this.onMsgChatOgq(s);break;case 118:this.onMsgOgqGift(s);break;case 12:this.onMsgSetUserflag(s);break;case 13:this.onMsgInoutManager(s);break;case 19:break;case 21:this.onMsgIce(s);break;case 23:this.onMsgSlowMode(s);break;case 18:this.onMsgBalloon(s);break;case 87:this.onMsgBalloonAd(s);break;case 107:this.onMsgBalloonAdStation(s);break;case 50:this.onMsgPoll(s);break;case 54:this.onMsgBlockWordsList(s);break;case 88:this.onMsgStreamClosed(s);break;case 58:this.onMsgNoticeSystem(s);break;case 104:this.onMsgNotice(s);break;case 108:this.onMsgSubscriptionGift(s);break;case 91:this.onMsgSubscriptionNew(s);break;case 93:this.onMsgSubscription(s);break;default:this.log.verbose(`${j[e]}(${e}): ${s.join(" ")}`);break}};onMsgJoin=t=>{if(t[0]==="\uBE44\uBC00\uBC88\uD638\uAC00 \uD2C0\uB838\uC2B5\uB2C8\uB2E4."){this.log.warn("\uCC44\uB110 \uC785\uC7A5 \uC2E4\uD328: \uBE44\uBC00\uBC88\uD638\uAC00 \uD2C0\uB838\uC2B5\uB2C8\uB2E4."),this.disconnect();return}let[n,e,o,s,r,c,g,h]=t;this.connectedState=2,this.log.info(`\uCC44\uB110 \uC785\uC7A5: ${e}`),this.emit("join",e)};onMsgJoinPartUser=t=>{let[n,e,o,s,r,c]=t;n==="1"?this.log.verbose(`\uC785\uC7A5: ${o}(${e}),${n},${s},${r},${c}`):s==="1"?this.log.verbose(`\uD1F4\uC7A5: ${o}(${e}),${n},${s},${r},${c}`):(this.log.verbose(`\uAC15\uD1F4: ${o}(${e}),${n},${s},${r},${c}`),this.emit("block",{type:1,duration:0,userId:e,nickname:o,by:"manager"}))};onMsgSetUserTimeout=t=>{let[n,e,o,s,r,c,g,h,b]=t;this.log.verbose(`\uCC44\uD305 \uAE08\uC9C0: ${h}(${n}) ${o}s by ${r}`),this.emit("block",{type:0,duration:parseInt(o),userId:n,nickname:h,by:r})};onMsgChatMsg=t=>{let[n,e,o,s,r,c,g,h,b,f,l]=t,u;switch(parseInt(s)){case 1:u="staff";break;case 2:u="police";break;case 3:case 0:default:u="normal"}let a=parseInt(l),d=parseInt(g.split("|")[0]),E=parseInt(g.split("|")[1]),T=this.isUserflag(2,d),O=this.isUserflag(5,d),R=this.isUserflag(28,d),I=this.isUserflag(15,d),x=this.isUserflag(8,d),$=this.isUserflag(9,d),U=$?"[\uC5EC]":"[\uB0A8]",G=a>0?`[${l.padStart(2,"0")}]`:" ",D=T?"[\uC2A4]":x?"[\uB9E4]":I?"[\uC5F4]":O?"[\uD32C]":" ",i=[];for(let N in Object.values(k))[2,5,28,15,8,9].includes(Number(N))||k[N]!=null&&this.isUserflag(Number(N),d)&&i.push(k[N]);let M=[];for(let N in Object.values(m))m[N]!=null&&this.isUserflag(Number(N),E)&&M.push(m[N]);this.log.verbose(`\uCC44\uD305: ${U}${G}${D}${W.default.hex("#"+f)(`${c}(${e})`)}: ${n}`," |",r,`${u}(${s})`,i.join(" "),"|",M.join(" "));let[S,F]=this.parseContent(n,R);this.emit("chat",{content:n,emotes:F,parsedContent:S,channelId:this.connection?.channelId??"",userId:e,normalColor:o,language:r,userType:u,nickname:c,subscription:a,isStreamer:T,isFan:O,isTopfan:I,isManager:x,isFemale:$,color:b,colorDarkmode:f,userflag1:d,userflag2:E,stickerUrl:""})};parseContent=(t,n)=>{let e={};if(!n)return[[{type:0,body:t}],e];let o=[],s=/\/([^\/]+)\//g,r=0,c;for(;(c=s.exec(t))!==null;){let g=c[1],h=this.emotes[g];h&&(r<c.index&&o.push({type:0,body:t.slice(r,c.index)}),e[g]||(e[g]=h),o.push({type:1,body:g}),r=c.index+c[0].length)}return r<t.length&&o.push({type:0,body:t.slice(r)}),[o,e]};onMsgChatOgq=t=>{let[n,e,o,s,r,c,g,h,b,f,l,u,a,d,E,T]=t,O;switch(parseInt(l)){case 1:O="staff";break;case 2:O="police";break;case 3:case 0:default:O="normal"}let R=parseInt(T),I=parseInt(h.split("|")[0]),x=parseInt(h.split("|")[1]),$=this.isUserflag(2,I),U=this.isUserflag(5,I),G=this.isUserflag(28,I),D=this.isUserflag(15,I),i=this.isUserflag(8,I),M=this.isUserflag(9,I),S=`${o}/${s}_40.${u}?ver=${r}`,[F,N]=this.parseContent(e,G);this.log.verbose(`OGQ: ${W.default.hex("#"+E)(`${g}(${c})`)}: ${e} ${S}`),this.emit("chat",{content:e,emotes:N,parsedContent:F,channelId:this.connection?.channelId??"",userId:c,normalColor:"",language:f,userType:O,nickname:g,subscription:R,isStreamer:$,isFan:U,isTopfan:D,isManager:i,isFemale:M,color:d,colorDarkmode:E,userflag1:I,userflag2:x,stickerUrl:S})};onMsgOgqGift=t=>{let[n,e,o,s,r,c,g]=t;this.log.verbose(`OGQ \uC120\uBB3C: ${r}(${s}) ${c} from ${o}(${e}) ${g}`)};onMsgSetUserflag=t=>{let[n,e,o,s,r,c,g]=t,h=n.split("|").map(Number),b=c.split("|").map(Number),f=[];for(let l in Object.values(k)){if(k[l]==null)continue;let u=this.isUserflag(Number(l),h[0]),a=this.isUserflag(Number(l),b[0]);u!=a&&f.push([k[l],u,a])}for(let l in Object.values(m)){if(m[l]==null)continue;let u=this.isUserflag(Number(l),h[1]),a=this.isUserflag(Number(l),b[1]);u!=a&&f.push([m[l],u,a])}this.log.verbose(`\uC720\uC800 \uD50C\uB798\uADF8 \uBCC0\uACBD: ${o}(${e}): `,f.map(([l,u,a])=>`${l} -> ${a}`))};onMsgInoutManager=t=>{let[n,e,o,s]=t,r=parseInt(e.split("|")[0]),c=this.isUserflag(8,r);this.log.info(`\uB9E4\uB2C8\uC800: ${s}(${n}) ${c?"\uC784\uBA85":"\uD574\uC784"}`)};onMsgIce=t=>{let[n,e,o,s,r]=t,c=parseInt(o);if(n==="1"){let g=[];for(let h in Object.values(w))w[h]!=null&&this.isIceflag(Number(h),c)&&g.push(Q[Number(h)]);this.log.info(`\uC5BC\uB9AC\uAE30: \uC124\uC815 \uC2A4\uD2B8\uB9AC\uBA38, ${g.join(", ")} \uC774\uC0C1, \uCD5C\uC18C \uBCC4\uD48D\uAC1C\uC218: ${s}, \uCD5C\uC18C \uAD6C\uB3C5 \uAC1C\uC6D4\uC218: ${r}`)}else this.log.info("\uC5BC\uB9AC\uAE30: \uD574\uC81C")};onMsgSlowMode=t=>{let[n,e]=t;this.log.info(`\uC800\uC18D\uBAA8\uB4DC: ${e==="0"?"\uD574\uC81C":e+"\uCD08"}`)};onMsgBalloon=t=>{let[n,e,o,s,r,c,g,h,b,f,l]=t,u=parseInt(r)>0?"\uB85C "+r+"\uBC88\uC9F8 \uD32C\uD074\uB7FD \uAC00\uC785":"";this.log.verbose(`\uBCC4\uD48D\uC120: ${o}(${e}) ${s}\uAC1C${u}`,l,h),this.emit("balloon",{type:0,userId:e,nickname:o,count:parseInt(s),fanClubOrder:parseInt(r),isStation:!1,imageName:h,ttsType:l})};onMsgBalloonAd=t=>{let[n,e,o,s,r,c,g,h,b,f,l,u,a,d,E,T]=t;this.log.verbose(`\uC560\uB4DC\uBC8C\uB8EC: ${s}(${o}) ${f}\uAC1C${parseInt(l)>0?"\uB85C "+l+"\uBC88\uC9F8 \uD32C\uD074\uB7FD \uAC00\uC785":""}`,E),this.emit("balloon",{type:1,userId:o,nickname:s,count:parseInt(f),fanClubOrder:parseInt(l),isStation:!1,imageName:b,ttsType:E})};onMsgBalloonAdStation=t=>{let[n,e,o,s,r,c,g]=t;this.log.verbose(`\uBC29\uC1A1\uAD6D \uC560\uB4DC\uBC8C\uB8EC: ${o}(${e}) ${s}\uAC1C`),this.emit("balloon",{type:1,userId:e,nickname:o,count:parseInt(s),fanClubOrder:0,isStation:!0,imageName:r,ttsType:""})};onMsgPoll=t=>{let[n,e,o,s]=t;n==="1"?this.log.info(`\uD22C\uD45C \uC2DC\uC791: ${o}`):n==="4"&&this.log.info(`\uD22C\uD45C \uC885\uB8CC: ${o}`)};onMsgBlockWordsList=t=>{let[n,e]=t;if(e==="")return;let o=e.split("");o.length>0&&this.log.verbose(`\uAE08\uCE59\uC5B4 \uBAA9\uB85D: ${o.join(", ")} -> ${n}`)};onMsgStreamClosed=t=>{this.log.warn(`\uBC29\uC1A1 \uC885\uB8CC\uB428: ${this.connection?.channelId}`),this.disconnect()};onMsgNoticeSystem=t=>{let[n,e]=t;this.log.info(`\uC2DC\uC2A4\uD15C \uACF5\uC9C0: ${n}`)};onMsgNotice=t=>{let[n,e,o,s]=t;this.log.info(`\uACF5\uC9C0: ${s}`)};onMsgSubscriptionGift=t=>{let[n,e,o,s,r,c,g,h,b,f,l,u,a,d,E,T]=t;this.log.verbose(`\uAD6C\uB3C5\uAD8C \uC120\uBB3C: ${r}(${s}) ${h}\uAC1C\uC6D4 from ${g}(${c}) ${b}`)};onMsgSubscriptionNew=t=>{let[n,e,o,s,r,c]=t;this.log.verbose(`\uC2E0\uADDC \uAD6C\uB3C5: ${s}(${o}) ${r}, ${c}`)};onMsgSubscription=t=>{let[n,e,o,s,r,c]=t;this.log.verbose(`\uAD6C\uB3C5: ${o}(${e}) ${s}\uAC1C\uC6D4\uC9F8 ${c}`)};isUserflag=(t,n)=>!!(n>>>t&1);isIceflag=(t,n)=>!!(n>>>t&1)};0&&(module.exports={ConnectedState,SoopBalloonType,SoopBlockType,SoopChatClient,SoopChatMessageContentType});