diff --git a/.dist/channel.js b/.dist/channel.js index 2aa588d..62367db 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -8,6 +8,8 @@ import { Settings, RoleList } from "./settings.js"; import { Role } from "./role.js"; import { InfiniteScroller } from "./infiniteScroller.js"; import { SnowFlake } from "./snowflake.js"; +import { Emoji } from "./emoji.js"; +new Emoji(); class Channel { editing; type; diff --git a/.dist/emoji.js b/.dist/emoji.js new file mode 100644 index 0000000..9cdf783 --- /dev/null +++ b/.dist/emoji.js @@ -0,0 +1,67 @@ +class Emoji { + static emojis; + static decodeEmojiList(buffer) { + const view = new DataView(buffer, 0); + let i = 0; + function read16() { + const int = view.getUint16(i); + i += 2; + return int; + } + function read8() { + const int = view.getUint8(i); + i += 1; + return int; + } + function readString8() { + return readStringNo(read8()); + } + function readString16() { + return readStringNo(read16()); + } + function readStringNo(length) { + const array = new Uint8Array(length); + for (let i = 0; i < length; i++) { + array[i] = read8(); + } + const decoded = new TextDecoder("utf-8").decode(array.buffer); + ; + //console.log(array); + return decoded; + } + const build = []; + let cats = read16(); + for (; cats !== 0; cats--) { + const name = readString16(); + const emojis = []; + let emojinumber = read16(); + for (; emojinumber !== 0; emojinumber--) { + //console.log(emojis); + const name = readString8(); + const len = read8(); + const skin_tone_support = len > 127; + const emoji = readStringNo(len - (+skin_tone_support * 128)); + emojis.push({ + name, + skin_tone_support, + emoji + }); + } + build.push({ + name, + emojis + }); + } + this.emojis = build; + console.log(build); + } + static grabEmoji() { + fetch("/emoji.bin").then(e => { + return e.arrayBuffer(); + }).then(e => { + Emoji.decodeEmojiList(e); + }); + } +} +Emoji.grabEmoji(); +export { Emoji }; diff --git a/.dist/localuser.js b/.dist/localuser.js index ccdb395..9d1844d 100644 --- a/.dist/localuser.js +++ b/.dist/localuser.js @@ -363,7 +363,7 @@ class Localuser { const div = document.createElement("div"); div.classList.add("home", "servericon"); img.src = "/icons/home.svg"; - img.classList.add("svgtheme"); + img.classList.add("svgtheme", "svgicon"); img["all"] = this.guildids.get("@me"); this.guildids.get("@me").html = outdiv; const unread = document.createElement("div"); @@ -407,7 +407,7 @@ class Localuser { const guilddsdiv = document.createElement("div"); const guildDiscoveryContainer = document.createElement("img"); guildDiscoveryContainer.src = "/icons/explore.svg"; - guildDiscoveryContainer.classList.add("svgtheme"); + guildDiscoveryContainer.classList.add("svgtheme", "svgicon"); guilddsdiv.classList.add("home", "servericon"); guilddsdiv.appendChild(guildDiscoveryContainer); serverlist.appendChild(guilddsdiv); @@ -922,5 +922,57 @@ class Localuser { ]); botDialog.show(); } + //---------- resolving members code ----------- + waitingmembers = new Map(); + async resolvemember(id, guildid) { + console.warn("this function is currently non-functional, either due to a bug in the client or the server, it's currently unclear, use at your own risk"); + if (!this.waitingmembers.has(guildid)) { + this.waitingmembers.set(guildid, new Map()); + } + let res; + const promise = new Promise((r) => { + res = r; + }); + this.waitingmembers.get(guildid).set(id, res); + this.getmembers(); + return await promise; + } + fetchingmembers = new Map(); + async getmembers() { + if (this.ws) { + this.waitingmembers.forEach(async (value, guildid) => { + const keys = value.keys(); + if (this.fetchingmembers.has(guildid)) { + return; + } + const build = []; + for (const key of keys) { + build.push(key); + } + ; + let res; + const promise = new Promise((r) => { + res = r; + }); + this.ws.send(JSON.stringify({ + op: 8, + d: { + query: "", + user_ids: build, + guild_id: guildid, + limit: 100, + nonce: "" + Math.floor(Math.random() * 100000000) + } + })); + this.fetchingmembers.set(guildid, res); + const data = await promise; + for (const thing of data) { + value.get(thing.id)(thing); + value.delete(thing.id); + } + this.getmembers(); + }); + } + } } export { Localuser }; diff --git a/.dist/member.js b/.dist/member.js index 3252692..8681e49 100644 --- a/.dist/member.js +++ b/.dist/member.js @@ -101,6 +101,7 @@ class Member { } const prom1 = fetch(guild.info.api.toString() + "/users/" + id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.snowflake, { headers: guild.headers }); prom1.catch(_ => { console.log(_); }); + guild.localuser.resolvemember(id?.id, guild.id); const promoise = prom1.then(_ => _.json()).then(json => { const memb = new Member(json, guild); Member.already[guild.id][id] = memb; diff --git a/EmojiList/credit.txt b/EmojiList/credit.txt new file mode 100644 index 0000000..e5e6031 --- /dev/null +++ b/EmojiList/credit.txt @@ -0,0 +1,2 @@ +https://github.com/muan/unicode-emoji-json/ +the list is from here, though the actual file isn't included, if you want to compile the binary yourself, just put data-by-group.json in this file and run the needed script. diff --git a/emoji-packer.js b/emoji-packer.js new file mode 100644 index 0000000..2c0845f --- /dev/null +++ b/emoji-packer.js @@ -0,0 +1,115 @@ +const emojilist=require("./EmojiList/data-by-group.json"); +console.log(emojilist); + +const buffer=new ArrayBuffer(2**26); +const view = new DataView(buffer, 0); +let i=0; +function write16(numb){ + view.setUint16(i,numb); + i+=2; +} +function write8(numb){ + view.setUint8(i,numb); + i+=1; +} +function writeString8(str){ + const encode=new TextEncoder("utf-8").encode(str); + write8(encode.length); + for(const thing of encode){ + write8(thing); + } +} +function writeString16(str){ + const encode=new TextEncoder("utf-8").encode(str); + write16(encode.length); + for(const thing of encode){ + write8(thing); + } +} +function writeStringNo(str){ + const encode=new TextEncoder("utf-8").encode(str); + for(const thing of encode){ + write8(thing); + } +} + +write16(emojilist.length); +for(const thing of emojilist){ + writeString16(thing.name); + write16(thing.emojis.length); + for(const emoji of thing.emojis){ + writeString8(emoji.name); + write8(new TextEncoder("utf-8").encode(emoji.emoji).length+128*emoji.skin_tone_support); + writeStringNo(emoji.emoji); + } +} +const out=new ArrayBuffer(i); +const ar=new Uint8Array(out); +const br=new Uint8Array(buffer) +for(const thing in ar){ + ar[thing]=br[thing]; +} +console.log(i,ar); + +function decodeEmojiList(buffer){ + const view = new DataView(buffer, 0); + let i=0; + function read16(){ + const int=view.getUint16(i); + i+=2; + return int; + } + function read8(){ + const int=view.getUint8(i); + i+=1; + return int; + } + function readString8(){ + return readStringNo(read8()); + } + function readString16(){ + return readStringNo(read16()); + } + function readStringNo(length){ + const array=new Uint8Array(length); + + for(let i=0;i127; + const emoji=readStringNo(len-skin_tone_support*128); + emojis.push({ + name, + skin_tone_support, + emoji + }) + } + build.push({ + name, + emojis + }) + } + return build; +} +console.log(JSON.stringify(decodeEmojiList(out))); + +const fs = require('fs'); +fs.writeFile("./webpage/emoji.bin",new Uint8Array(out),_=>{ + +}); diff --git a/webpage/channel.ts b/webpage/channel.ts index 1bcdd83..60af6fa 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -11,7 +11,8 @@ import { Role } from "./role.js"; import {InfiniteScroller} from "./infiniteScroller.js"; import { SnowFlake } from "./snowflake.js"; import { channeljson, messagejson, readyjson } from "./jsontypes.js"; - +import {Emoji} from "./emoji.js"; +new Emoji(); declare global { interface NotificationOptions { image?: string diff --git a/webpage/emoji.bin b/webpage/emoji.bin new file mode 100644 index 0000000..d29585e Binary files /dev/null and b/webpage/emoji.bin differ diff --git a/webpage/emoji.ts b/webpage/emoji.ts new file mode 100644 index 0000000..9ed3c69 --- /dev/null +++ b/webpage/emoji.ts @@ -0,0 +1,75 @@ +class Emoji{ + static emojis:{ + name:string, + emojis:{ + name:string, + emoji:string, + }[] + }[]; + static decodeEmojiList(buffer:ArrayBuffer){ + const view = new DataView(buffer, 0); + let i=0; + function read16(){ + const int=view.getUint16(i); + i+=2; + return int; + } + function read8(){ + const int=view.getUint8(i); + i+=1; + return int; + } + function readString8(){ + return readStringNo(read8()); + } + function readString16(){ + return readStringNo(read16()); + } + function readStringNo(length:number){ + const array=new Uint8Array(length); + + for(let i=0;i127; + const emoji=readStringNo(len-(+skin_tone_support*128)); + emojis.push({ + name, + skin_tone_support, + emoji + }) + } + build.push({ + name, + emojis + }) + } + this.emojis=build; + console.log(build); + } + static grabEmoji(){ + fetch("/emoji.bin").then(e=>{ + return e.arrayBuffer() + }).then(e=>{ + Emoji.decodeEmojiList(e); + }) + } +} +Emoji.grabEmoji(); +export {Emoji}; diff --git a/webpage/localuser.ts b/webpage/localuser.ts index 4f9e1f5..72d25d4 100644 --- a/webpage/localuser.ts +++ b/webpage/localuser.ts @@ -7,7 +7,7 @@ import {Fullscreen} from "./fullscreen.js"; import {setTheme, Specialuser} from "./login.js"; import { SnowFlake } from "./snowflake.js"; import { Message } from "./message.js"; -import { channeljson, readyjson, userjson } from "./jsontypes.js"; +import { channeljson, guildjson, memberjson, readyjson, userjson } from "./jsontypes.js"; const wsCodesRetry=new Set([4000,4003,4005,4007,4008,4009]); @@ -295,7 +295,7 @@ class Localuser{ } }else if(temp.op===10){ - console.log("heartbeat down") + console.log("heartbeat down"); this.wsinterval=setInterval(_=>{ if (this.connectionSucceed===0) this.connectionSucceed=Date.now() @@ -375,7 +375,7 @@ class Localuser{ div.classList.add("home","servericon"); img.src="/icons/home.svg"; - img.classList.add("svgtheme") + img.classList.add("svgtheme","svgicon") img["all"]=this.guildids.get("@me"); this.guildids.get("@me").html=outdiv; const unread=document.createElement("div"); @@ -422,7 +422,7 @@ class Localuser{ const guilddsdiv=document.createElement("div"); const guildDiscoveryContainer=document.createElement("img"); guildDiscoveryContainer.src="/icons/explore.svg"; - guildDiscoveryContainer.classList.add("svgtheme"); + guildDiscoveryContainer.classList.add("svgtheme","svgicon"); guilddsdiv.classList.add("home","servericon"); guilddsdiv.appendChild(guildDiscoveryContainer); serverlist.appendChild(guilddsdiv); @@ -964,5 +964,55 @@ class Localuser{ ); botDialog.show(); } + + //---------- resolving members code ----------- + waitingmembers:Mapvoid>>=new Map(); + async resolvemember(id:string,guildid:string):Promise{ + console.warn("this function is currently non-functional, either due to a bug in the client or the server, it's currently unclear, use at your own risk"); + if(!this.waitingmembers.has(guildid)){ + this.waitingmembers.set(guildid,new Map()); + } + let res:(returns:memberjson|undefined)=>void; + const promise:Promise=new Promise((r)=>{ + res=r; + }) + this.waitingmembers.get(guildid).set(id,res); + this.getmembers(); + return await promise; + } + fetchingmembers:Mapvoid>=new Map(); + async getmembers(){ + if(this.ws){ + this.waitingmembers.forEach(async (value,guildid)=>{ + const keys=value.keys(); + if(this.fetchingmembers.has(guildid)){ + return; + } + const build:string[]=[]; + for(const key of keys){build.push(key)}; + let res:(r:memberjson[])=>void; + const promise:Promise=new Promise((r)=>{ + res=r; + }) + this.ws.send(JSON.stringify({ + op:8, + d:{ + query:"", + user_ids:build, + guild_id:guildid, + limit:100, + nonce:""+Math.floor(Math.random()*100000000) + } + })); + this.fetchingmembers.set(guildid,res); + const data=await promise; + for(const thing of data){ + value.get(thing.id)(thing); + value.delete(thing.id); + } + this.getmembers(); + }) + } + } } export {Localuser}; diff --git a/webpage/member.ts b/webpage/member.ts index 280aaa7..9d19df6 100644 --- a/webpage/member.ts +++ b/webpage/member.ts @@ -94,6 +94,7 @@ class Member{ } const prom1= fetch(guild.info.api.toString()+"/users/"+id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.snowflake,{headers:guild.headers}) prom1.catch(_=>{console.log(_)}) + guild.localuser.resolvemember(id?.id,guild.id); const promoise=prom1.then(_=>_.json()).then(json=>{ const memb=new Member(json,guild); Member.already[guild.id][id]=memb; diff --git a/webpage/style.css b/webpage/style.css index 0a849b5..42a328c 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -1532,3 +1532,7 @@ form div{ .hiddencat{ rotate:-90deg; } +.svgicon{ + width:.5in; + height:.5in; +} \ No newline at end of file