UNPKG

soop-chat-client

Version:
2 lines (1 loc) 14.5 kB
import K from"ws";import{TypedEmitter as v}from"tiny-typed-emitter";import q from"chalk";var A=class{name="log";isEnabled=!0;constructor(t,s){this.name=t,this.isEnabled=s}verbose=(t,...s)=>{this.isEnabled&&console.log(`[${this.name}:verbose]`,new Date().toISOString(),t,...s)};info=(t,...s)=>{this.isEnabled&&console.info(`[${this.name}:info]`,new Date().toISOString(),t,...s)};warn=(t,...s)=>{this.isEnabled&&console.warn(`[${this.name}:warn]`,new Date().toISOString(),t,...s)}};var j={"User-Agent":"Mozilla/5.0","Content-Type":"application/x-www-form-urlencoded"},H=async O=>await(await fetch(`https://live.sooplive.co.kr/afreeca/player_live_api.php?bjid=${O}`,{method:"POST",headers:j,body:new URLSearchParams({bid:O,type:"live",pwd:"",player_type:"html5",stream_type:"common",mode:"landing",from_api:"0"})})).json(),W=async O=>await(await fetch(`https://live.sooplive.co.kr/api/signature_emoticon_api.php?work=list&szBjId=${O}`,{method:"GET",headers:j})).json();var P=(o=>(o[o.PING=0]="PING",o[o.LOGIN=1]="LOGIN",o[o.JOIN=2]="JOIN",o[o.JOINPART_USER=4]="JOINPART_USER",o[o.USER_TIMEOUT=8]="USER_TIMEOUT",o[o.CHAT=5]="CHAT",o[o.CHAT_OGQ=109]="CHAT_OGQ",o[o.OGQ_GIFT=118]="OGQ_GIFT",o[o.SET_USERFLAG=12]="SET_USERFLAG",o[o.INOUT_MANAGER=13]="INOUT_MANAGER",o[o.SUBNICKNAME=14]="SUBNICKNAME",o[o.ICE1=19]="ICE1",o[o.ICE2=21]="ICE2",o[o.SLOWMODE=23]="SLOWMODE",o[o.BALLOON=18]="BALLOON",o[o.BALLOON_AD=87]="BALLOON_AD",o[o.BALLOON_AD_STATION=107]="BALLOON_AD_STATION",o[o.POLL=50]="POLL",o[o.BLOCK_WORDS_LIST=54]="BLOCK_WORDS_LIST",o[o.STREAM_CLOSED=88]="STREAM_CLOSED",o[o.SUBSCRIPTION_NEW=91]="SUBSCRIPTION_NEW",o[o.SUBSCRIPTION=93]="SUBSCRIPTION",o[o.SUBSCRIPTION_GIFT=108]="SUBSCRIPTION_GIFT",o[o.SYSTEM_NOTICE=58]="SYSTEM_NOTICE",o[o.CHANNEL_NOTICE=104]="CHANNEL_NOTICE",o[o.MISSION=121]="MISSION",o))(P||{}),E=(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))(E||{}),k=(e=>(e[e.SUBSCRIPTION_TIER1=18]="SUBSCRIPTION_TIER1",e[e.SUBSCRIPTION_TIER2=19]="SUBSCRIPTION_TIER2",e[e.SUBSCRIPTION_TIER3=20]="SUBSCRIPTION_TIER3",e))(k||{}),_=(n=>(n[n.FANCLUB=5]="FANCLUB",n[n.SUPPORTER=6]="SUPPORTER",n[n.TOPFAN=7]="TOPFAN",n[n.SUBSCRIPTION=8]="SUBSCRIPTION",n[n.MANAGER=9]="MANAGER",n))(_||{}),Y={5:"\uD32C\uD074\uB7FD",6:"\uC11C\uD3EC\uD130",7:"\uC5F4\uD608\uD32C",8:"\uAD6C\uB3C5\uD32C",9:"\uB9E4\uB2C8\uC800"},J="\x1B 000100000600\f\f\f16\f";var R=(e=>(e[e.STANDBY=0]="STANDBY",e[e.CONNECTED=1]="CONNECTED",e[e.JOINED=2]="JOINED",e))(R||{}),U=(s=>(s[s.TEXT=0]="TEXT",s[s.EMOTE=1]="EMOTE",s))(U||{}),G=(e=>(e[e.NORMAL=0]="NORMAL",e[e.AD=1]="AD",e[e.VOD=2]="VOD",e))(G||{}),D=(s=>(s[s.TIMEOUT=0]="TIMEOUT",s[s.KICK=1]="KICK",s))(D||{});var F=class extends v{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 A("soop-chat",t)}sendPing=()=>{(this.connectedState===1||this.connectedState===2)&&(this.send(0,"\f"),this.log.verbose(`PING: ${this.connection?.channelId}`))};connect=async(t,s="")=>{this.connectedState=0;try{let e=await H(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:s},this.log.name=`soop-chat:${this.connection.channelId}`.padEnd(23);let i=`wss://${this.connection.host.toLowerCase()}:${this.connection.port}/Websocket/${this.connection.channelId}`;this.log.info(`\uC5F0\uACB0\uC2DC\uB3C4: ${i}`);let n=new K(i,"chat");n.binaryType="arraybuffer",n.onopen=()=>{this.connectedState=1,this.log.info(`\uC5F0\uACB0\uB428: ${n.url}`),n.send(J)},n.onclose=()=>{this.connectedState=0,clearInterval(this.loopPingPong),this.log.warn("\uCC44\uD305 \uC11C\uBC84\uC640 \uC5F0\uACB0\uC774 \uB04A\uC5B4\uC84C\uC2B5\uB2C8\uB2E4.")},n.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)},n.onmessage=r=>{r.data&&this.processMessage(r.data)},this.socket=n,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,s)=>{if(!this.socket||this.socket.readyState!==K.OPEN)return!1;let e="\x1B ",i=t.toString().padStart(4,"0"),n=s.length.toString().padStart(6,"0"),c=`${`${e}${i}${n}00`}${s}`;return this.socket?.send(c),!0};loadEmotes=async t=>{try{let s=await W(t);if(this.emotes={},s.version===0){this.log.info("\uCC44\uB110 \uC774\uBAA8\uD2F0\uCF58\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");return}s.data.forEach(e=>{this.emotes[e.title]={title:e.title,tier:e.tier_type??1,pcImg:s.img_path+e.pc_img,pcAltImg:e.pc_alternate_img?s.img_path+e.pc_alternate_img:"",mobileImg:s.img_path+e.mobile_img,mobileAltImg:e.mob_alternate_img?s.img_path+e.mob_alternate_img:"",isAnimated:e.move_img==="Y",orderNo:e.order_no,blackKeyword:e.black_keyword==="Y"}})}catch(s){s instanceof Error&&this.log.warn(s.message);return}};joinChannel=()=>{if(!this.stream)return;let t=this.stream.CHANNEL,s=[`\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,s.join(""))};processMessage=t=>{let s=t.slice(0,14),e=parseInt(this.decoder.decode(s.slice(2,6))),i=t.slice(15),n=this.decoder.decode(i).split("\f");switch(e){case 1:this.log.info(`\uB85C\uADF8\uC778: ${this.connection?.channelId}`),this.joinChannel();break;case 2:this.onMsgJoin(n);break;case 4:this.onMsgJoinPartUser(n);break;case 8:this.onMsgSetUserTimeout(n);break;case 5:this.onMsgChatMsg(n);break;case 109:this.onMsgChatOgq(n);break;case 118:this.onMsgOgqGift(n);break;case 12:this.onMsgSetUserflag(n);break;case 13:this.onMsgInoutManager(n);break;case 19:break;case 21:this.onMsgIce(n);break;case 23:this.onMsgSlowMode(n);break;case 18:this.onMsgBalloon(n);break;case 87:this.onMsgBalloonAd(n);break;case 107:this.onMsgBalloonAdStation(n);break;case 50:this.onMsgPoll(n);break;case 54:this.onMsgBlockWordsList(n);break;case 88:this.onMsgStreamClosed(n);break;case 58:this.onMsgNoticeSystem(n);break;case 104:this.onMsgNotice(n);break;case 108:this.onMsgSubscriptionGift(n);break;case 91:this.onMsgSubscriptionNew(n);break;case 93:this.onMsgSubscription(n);break;default:this.log.verbose(`${P[e]}(${e}): ${n.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[s,e,i,n,r,c,g,h]=t;this.connectedState=2,this.log.info(`\uCC44\uB110 \uC785\uC7A5: ${e}`),this.emit("join",e)};onMsgJoinPartUser=t=>{let[s,e,i,n,r,c]=t;s==="1"?this.log.verbose(`\uC785\uC7A5: ${i}(${e}),${s},${n},${r},${c}`):n==="1"?this.log.verbose(`\uD1F4\uC7A5: ${i}(${e}),${s},${n},${r},${c}`):(this.log.verbose(`\uAC15\uD1F4: ${i}(${e}),${s},${n},${r},${c}`),this.emit("block",{type:1,duration:0,userId:e,nickname:i,by:"manager"}))};onMsgSetUserTimeout=t=>{let[s,e,i,n,r,c,g,h,d]=t;this.log.verbose(`\uCC44\uD305 \uAE08\uC9C0: ${h}(${s}) ${i}s by ${r}`),this.emit("block",{type:0,duration:parseInt(i),userId:s,nickname:h,by:r})};onMsgChatMsg=t=>{let[s,e,i,n,r,c,g,h,d,u,l]=t,p;switch(parseInt(n)){case 1:p="staff";break;case 2:p="police";break;case 3:case 0:default:p="normal"}let a=parseInt(l),f=parseInt(g.split("|")[0]),N=parseInt(g.split("|")[1]),T=this.isUserflag(2,f),m=this.isUserflag(5,f),w=this.isUserflag(28,f),b=this.isUserflag(15,f),x=this.isUserflag(8,f),$=this.isUserflag(9,f),C=$?"[\uC5EC]":"[\uB0A8]",y=a>0?`[${l.padStart(2,"0")}]`:" ",L=T?"[\uC2A4]":x?"[\uB9E4]":b?"[\uC5F4]":m?"[\uD32C]":" ",o=[];for(let I in Object.values(E))[2,5,28,15,8,9].includes(Number(I))||E[I]!=null&&this.isUserflag(Number(I),f)&&o.push(E[I]);let M=[];for(let I in Object.values(k))k[I]!=null&&this.isUserflag(Number(I),N)&&M.push(k[I]);this.log.verbose(`\uCC44\uD305: ${C}${y}${L}${q.hex("#"+u)(`${c}(${e})`)}: ${s}`," |",r,`${p}(${n})`,o.join(" "),"|",M.join(" "));let[S,B]=this.parseContent(s,w);this.emit("chat",{content:s,emotes:B,parsedContent:S,channelId:this.connection?.channelId??"",userId:e,normalColor:i,language:r,userType:p,nickname:c,subscription:a,isStreamer:T,isFan:m,isTopfan:b,isManager:x,isFemale:$,color:d,colorDarkmode:u,userflag1:f,userflag2:N,stickerUrl:""})};parseContent=(t,s)=>{let e={};if(!s)return[[{type:0,body:t}],e];let i=[],n=/\/([^\/]+)\//g,r=0,c;for(;(c=n.exec(t))!==null;){let g=c[1],h=this.emotes[g];h&&(r<c.index&&i.push({type:0,body:t.slice(r,c.index)}),e[g]||(e[g]=h),i.push({type:1,body:g}),r=c.index+c[0].length)}return r<t.length&&i.push({type:0,body:t.slice(r)}),[i,e]};onMsgChatOgq=t=>{let[s,e,i,n,r,c,g,h,d,u,l,p,a,f,N,T]=t,m;switch(parseInt(l)){case 1:m="staff";break;case 2:m="police";break;case 3:case 0:default:m="normal"}let w=parseInt(T),b=parseInt(h.split("|")[0]),x=parseInt(h.split("|")[1]),$=this.isUserflag(2,b),C=this.isUserflag(5,b),y=this.isUserflag(28,b),L=this.isUserflag(15,b),o=this.isUserflag(8,b),M=this.isUserflag(9,b),S=`${i}/${n}_40.${p}?ver=${r}`,[B,I]=this.parseContent(e,y);this.log.verbose(`OGQ: ${q.hex("#"+N)(`${g}(${c})`)}: ${e} ${S}`),this.emit("chat",{content:e,emotes:I,parsedContent:B,channelId:this.connection?.channelId??"",userId:c,normalColor:"",language:u,userType:m,nickname:g,subscription:w,isStreamer:$,isFan:C,isTopfan:L,isManager:o,isFemale:M,color:f,colorDarkmode:N,userflag1:b,userflag2:x,stickerUrl:S})};onMsgOgqGift=t=>{let[s,e,i,n,r,c,g]=t;this.log.verbose(`OGQ \uC120\uBB3C: ${r}(${n}) ${c} from ${i}(${e}) ${g}`)};onMsgSetUserflag=t=>{let[s,e,i,n,r,c,g]=t,h=s.split("|").map(Number),d=c.split("|").map(Number),u=[];for(let l in Object.values(E)){if(E[l]==null)continue;let p=this.isUserflag(Number(l),h[0]),a=this.isUserflag(Number(l),d[0]);p!=a&&u.push([E[l],p,a])}for(let l in Object.values(k)){if(k[l]==null)continue;let p=this.isUserflag(Number(l),h[1]),a=this.isUserflag(Number(l),d[1]);p!=a&&u.push([k[l],p,a])}this.log.verbose(`\uC720\uC800 \uD50C\uB798\uADF8 \uBCC0\uACBD: ${i}(${e}): `,u.map(([l,p,a])=>`${l} -> ${a}`))};onMsgInoutManager=t=>{let[s,e,i,n]=t,r=parseInt(e.split("|")[0]),c=this.isUserflag(8,r);this.log.info(`\uB9E4\uB2C8\uC800: ${n}(${s}) ${c?"\uC784\uBA85":"\uD574\uC784"}`)};onMsgIce=t=>{let[s,e,i,n,r]=t,c=parseInt(i);if(s==="1"){let g=[];for(let h in Object.values(_))_[h]!=null&&this.isIceflag(Number(h),c)&&g.push(Y[Number(h)]);this.log.info(`\uC5BC\uB9AC\uAE30: \uC124\uC815 \uC2A4\uD2B8\uB9AC\uBA38, ${g.join(", ")} \uC774\uC0C1, \uCD5C\uC18C \uBCC4\uD48D\uAC1C\uC218: ${n}, \uCD5C\uC18C \uAD6C\uB3C5 \uAC1C\uC6D4\uC218: ${r}`)}else this.log.info("\uC5BC\uB9AC\uAE30: \uD574\uC81C")};onMsgSlowMode=t=>{let[s,e]=t;this.log.info(`\uC800\uC18D\uBAA8\uB4DC: ${e==="0"?"\uD574\uC81C":e+"\uCD08"}`)};onMsgBalloon=t=>{let[s,e,i,n,r,c,g,h,d,u,l]=t,p=parseInt(r)>0?"\uB85C "+r+"\uBC88\uC9F8 \uD32C\uD074\uB7FD \uAC00\uC785":"";this.log.verbose(`\uBCC4\uD48D\uC120: ${i}(${e}) ${n}\uAC1C${p}`,l,h),this.emit("balloon",{type:0,userId:e,nickname:i,count:parseInt(n),fanClubOrder:parseInt(r),isStation:!1,imageName:h,ttsType:l})};onMsgBalloonAd=t=>{let[s,e,i,n,r,c,g,h,d,u,l,p,a,f,N,T]=t;this.log.verbose(`\uC560\uB4DC\uBC8C\uB8EC: ${n}(${i}) ${u}\uAC1C${parseInt(l)>0?"\uB85C "+l+"\uBC88\uC9F8 \uD32C\uD074\uB7FD \uAC00\uC785":""}`,N),this.emit("balloon",{type:1,userId:i,nickname:n,count:parseInt(u),fanClubOrder:parseInt(l),isStation:!1,imageName:d,ttsType:N})};onMsgBalloonAdStation=t=>{let[s,e,i,n,r,c,g]=t;this.log.verbose(`\uBC29\uC1A1\uAD6D \uC560\uB4DC\uBC8C\uB8EC: ${i}(${e}) ${n}\uAC1C`),this.emit("balloon",{type:1,userId:e,nickname:i,count:parseInt(n),fanClubOrder:0,isStation:!0,imageName:r,ttsType:""})};onMsgPoll=t=>{let[s,e,i,n]=t;s==="1"?this.log.info(`\uD22C\uD45C \uC2DC\uC791: ${i}`):s==="4"&&this.log.info(`\uD22C\uD45C \uC885\uB8CC: ${i}`)};onMsgBlockWordsList=t=>{let[s,e]=t;if(e==="")return;let i=e.split("");i.length>0&&this.log.verbose(`\uAE08\uCE59\uC5B4 \uBAA9\uB85D: ${i.join(", ")} -> ${s}`)};onMsgStreamClosed=t=>{this.log.warn(`\uBC29\uC1A1 \uC885\uB8CC\uB428: ${this.connection?.channelId}`),this.disconnect()};onMsgNoticeSystem=t=>{let[s,e]=t;this.log.info(`\uC2DC\uC2A4\uD15C \uACF5\uC9C0: ${s}`)};onMsgNotice=t=>{let[s,e,i,n]=t;this.log.info(`\uACF5\uC9C0: ${n}`)};onMsgSubscriptionGift=t=>{let[s,e,i,n,r,c,g,h,d,u,l,p,a,f,N,T]=t;this.log.verbose(`\uAD6C\uB3C5\uAD8C \uC120\uBB3C: ${r}(${n}) ${h}\uAC1C\uC6D4 from ${g}(${c}) ${d}`)};onMsgSubscriptionNew=t=>{let[s,e,i,n,r,c]=t;this.log.verbose(`\uC2E0\uADDC \uAD6C\uB3C5: ${n}(${i}) ${r}, ${c}`)};onMsgSubscription=t=>{let[s,e,i,n,r,c]=t;this.log.verbose(`\uAD6C\uB3C5: ${i}(${e}) ${n}\uAC1C\uC6D4\uC9F8 ${c}`)};isUserflag=(t,s)=>!!(s>>>t&1);isIceflag=(t,s)=>!!(s>>>t&1)};export{R as ConnectedState,G as SoopBalloonType,D as SoopBlockType,F as SoopChatClient,U as SoopChatMessageContentType};