diff --git a/.dist/channel.js b/.dist/channel.js index 3efee21..ab677cf 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -6,7 +6,7 @@ import { Fullscreen } from "./fullscreen.js"; import { Permissions } from "./permissions.js"; import { Settings, RoleList } from "./settings.js"; import { InfiniteScroller } from "./infiniteScroller.js"; -Settings; +import { SnowFlake } from "./snowflake.js"; class Channel { editing; type; @@ -35,8 +35,8 @@ class Channel { static contextmenu = new Contextmenu("channel menu"); replyingto; infinite; - idToPrev = {}; - idToNext = {}; + idToPrev = new Map(); + idToNext = new Map(); static setupcontextmenu() { this.contextmenu.addbutton("Copy channel id", function () { console.log(this); @@ -73,22 +73,24 @@ class Channel { setUpInfiniteScroller() { const ids = {}; this.infinite = new InfiniteScroller(async function (id, offset) { + const snowflake = SnowFlake.getSnowFlakeFromID(id, Message); if (offset === 1) { - if (this.idToPrev[id]) { - return this.idToPrev[id]; + if (this.idToPrev.get(snowflake)) { + return this.idToPrev.get(snowflake)?.id; } else { - await this.grabmoremessages(id); - return this.idToPrev[id]; + await this.grabBefore(id); + return this.idToPrev.get(snowflake)?.id; } } else { - return this.idToNext[id]; + return this.idToNext.get(snowflake)?.id; } }.bind(this), function (id) { let res; const promise = new Promise(_ => { res = _; }); - const html = this.messageids[id].buildhtml(this.messageids[this.idToPrev[id]], promise); + const snowflake = SnowFlake.getSnowFlakeFromID(id, Message); + const html = this.messageids.get(snowflake).buildhtml(this.messageids.get(this.idToPrev.get(snowflake)), promise); ids[id] = res; return html; }.bind(this), async function (id) { @@ -106,28 +108,27 @@ class Channel { this.owner = owner; this.headers = this.owner.headers; this.name = JSON.name; - this.id = JSON.id; - this.parent_id = JSON.parent_id; + this.id = new SnowFlake(JSON.id, this); + this.parent_id = new SnowFlake(JSON.parent_id, undefined); this.parent = null; this.children = []; this.guild_id = JSON.guild_id; - this.messageids = {}; - this.permission_overwrites = {}; + this.messageids = new Map(); + this.permission_overwrites = new Map(); this.permission_overwritesar = []; for (const thing of JSON.permission_overwrites) { - console.log(thing); if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") { continue; } ; - this.permission_overwrites[thing.id] = new Permissions(thing.allow, thing.deny); - this.permission_overwritesar.push([thing.id, this.permission_overwrites[thing.id]]); + this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny)); + this.permission_overwritesar.push([thing.id, this.permission_overwrites.get(thing.id)]); } this.topic = JSON.topic; this.nsfw = JSON.nsfw; this.position = JSON.position; this.lastreadmessageid = null; - this.lastmessageid = JSON.last_message_id; + this.lastmessageid = SnowFlake.getSnowFlakeFromID(JSON.last_message_id, Message); this.setUpInfiniteScroller(); } isAdmin() { @@ -143,7 +144,7 @@ class Channel { return this.owner.info; } readStateInfo(json) { - this.lastreadmessageid = json.last_message_id; + this.lastreadmessageid = SnowFlake.getSnowFlakeFromID(json.last_message_id, Message); this.mentions = json.mention_count; this.mentions ??= 0; this.lastpin = json.last_pin_timestamp; @@ -152,15 +153,15 @@ class Channel { if (!this.hasPermission("VIEW_CHANNEL")) { return false; } - return this.lastmessageid !== this.lastreadmessageid && this.type !== 4; + return this.lastmessageid !== this.lastreadmessageid && this.type !== 4 && !!this.lastmessageid.id; } hasPermission(name, member = this.guild.member) { if (member.isAdmin()) { return true; } for (const thing of member.roles) { - if (this.permission_overwrites[thing.id]) { - let perm = this.permission_overwrites[thing.id].getPermission(name); + if (this.permission_overwrites.get(thing.id.id)) { + let perm = this.permission_overwrites.get(thing.id.id).getPermission(name); if (perm) { return perm === 1; } @@ -181,7 +182,7 @@ class Channel { this.children.sort((a, b) => { return a.position - b.position; }); } resolveparent(guild) { - this.parent = guild.channelids[this.parent_id]; + this.parent = guild.channelids[this.parent_id?.id]; this.parent ??= null; if (this.parent !== null) { this.parent.children.push(this); @@ -343,7 +344,7 @@ class Channel { if (!this.hasunreads) { return; } - fetch(this.info.api.toString() + "/v9/channels/" + this.id + "/messages/" + this.lastmessageid + "/ack", { + fetch(this.info.api.toString() + "/channels/" + this.id + "/messages/" + this.lastmessageid + "/ack", { method: "POST", headers: this.headers, body: JSON.stringify({}) @@ -433,8 +434,8 @@ class Channel { ["textbox", "Channel name:", this.name, function () { name = this.value; }], ["mdbox", "Channel topic:", this.topic, function () { topic = this.value; }], ["checkbox", "NSFW Channel", this.nsfw, function () { nsfw = this.checked; }], - ["button", "", "submit", function () { - fetch(this.info.api.toString() + "/v9/channels/" + thisid, { + ["button", "", "submit", () => { + fetch(this.info.api.toString() + "/channels/" + thisid, { method: "PATCH", headers: this.headers, body: JSON.stringify({ @@ -457,7 +458,7 @@ class Channel { console.log(full); } deleteChannel() { - fetch(this.info.api.toString() + "/v9/channels/" + this.id, { + fetch(this.info.api.toString() + "/channels/" + this.id, { method: "DELETE", headers: this.headers }); @@ -495,11 +496,12 @@ class Channel { } } async getmessage(id) { - if (this.messageids[id]) { - return this.messageids[id]; + const snowflake = SnowFlake.getSnowFlakeFromID(id, Message); + if (snowflake.getObject()) { + return snowflake.getObject(); } else { - const gety = await fetch(this.info.api.toString() + "/v9/channels/" + this.id + "/messages?limit=1&around=" + id, { headers: this.headers }); + const gety = await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages?limit=1&around=" + id, { headers: this.headers }); const json = await gety.json(); return new Message(json[0], this); } @@ -527,8 +529,9 @@ class Channel { history.pushState(null, null, "/channels/" + this.guild_id + "/" + this.id); document.getElementById("channelname").textContent = "#" + this.name; console.log(this); - document.getElementById("typebox").disabled = !this.canMessage; + document.getElementById("typebox").contentEditable = "" + this.canMessage; } + lastmessage; async putmessages() { if (this.allthewayup) { return; @@ -545,12 +548,15 @@ class Channel { for (const thing of response) { const message = new Message(thing, this); if (prev) { - this.idToNext[message.id] = prev.id; - this.idToPrev[prev.id] = message.id; + this.idToNext.set(message.id, prev.id); + this.idToPrev.set(prev.id, message.id); + } + else { + this.lastmessage = message; } prev = message; - if (this.messageids[message.id] === undefined) { - this.messageids[message.id] = message; + if (this.messageids.get(message.id) === undefined) { + this.messageids.set(message.id, message); } } } @@ -563,7 +569,7 @@ class Channel { } this.children = build; } - async grabmoremessages(id) { + async grabBefore(id) { if (this.allthewayup) { return; } @@ -574,7 +580,7 @@ class Channel { if (response.length === 0) { this.allthewayup = true; } - let previd = id; + let previd = SnowFlake.getSnowFlakeFromID(id, Message); for (const i in response) { let messager; if (!next) { @@ -590,11 +596,11 @@ class Channel { next = undefined; console.log("ohno", +i + 1); } - if (this.messageids[messager.id] === undefined) { - this.idToNext[messager.id] = previd; - this.idToPrev[previd] = messager.id; + if (this.messageids.get(messager.id) === undefined) { + this.idToNext.set(messager.id, previd); + this.idToPrev.set(previd, messager.id); previd = messager.id; - this.messageids[messager.id] = messager; + this.messageids.set(messager.id, messager); } else { console.log("How???"); @@ -611,17 +617,47 @@ class Channel { buildmessages() { const messages = document.getElementById("channelw"); messages.innerHTML = ""; - messages.append(this.infinite.getDiv(this.lastmessageid)); + let id; + if (this.messageids.get(this.lastreadmessageid)) { + id = this.lastreadmessageid; + } + else if (this.lastmessage.id) { + id = this.goBackIds(this.lastmessage.id, 50); + console.log("shouldn't"); + } + messages.append(this.infinite.getDiv(id.id)); + } + goBackIds(id, back) { + while (back !== 0) { + const nextid = this.idToPrev.get(id); + if (nextid) { + id = nextid; + console.log(id); + back--; + } + else { + break; + } + } + return id; } updateChannel(JSON) { this.type = JSON.type; this.name = JSON.name; - this.parent_id = JSON.parent_id; + this.parent_id = new SnowFlake(JSON.parent_id, undefined); this.parent = null; this.children = []; this.guild_id = JSON.guild_id; - this.messageids = {}; - this.permission_overwrites = JSON.permission_overwrites; + this.messageids = new Map(); + this.permission_overwrites = new Map(); + for (const thing of JSON.permission_overwrites) { + if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") { + continue; + } + ; + this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny)); + this.permission_overwritesar.push([thing.id, this.permission_overwrites.get(thing.id)]); + } this.topic = JSON.topic; this.nsfw = JSON.nsfw; } @@ -706,10 +742,11 @@ class Channel { return; } const messagez = new Message(messagep.d, this); - this.idToNext[this.lastmessageid] = messagez.id; - this.idToPrev[messagez.id] = this.lastmessageid; + console.log(this.lastmessageid, messagez.id, ":3"); + this.idToNext.set(this.lastmessageid, messagez.id); + this.idToPrev.set(messagez.id, this.lastmessageid); this.lastmessageid = messagez.id; - this.messageids[messagez.id] = messagez; + this.messageids.set(messagez.id, messagez); if (messagez.author === this.localuser.user) { this.lastreadmessageid = messagez.id; if (this.myhtml) { @@ -789,11 +826,11 @@ class Channel { }) }); const perm = new Permissions("0", "0"); - this.permission_overwrites[role.id] = perm; + this.permission_overwrites.set(role.id.id, perm); this.permission_overwritesar.push([role.id, perm]); } async updateRolePermissions(id, perms) { - const permission = this.permission_overwrites[id]; + const permission = this.permission_overwrites.get(id); permission.allow = perms.allow; permission.deny = perms.deny; await fetch(this.info.api.toString() + "/channels/" + this.id + "/permissions/" + id, { diff --git a/.dist/direct.js b/.dist/direct.js index e8a9620..87cd5fd 100644 --- a/.dist/direct.js +++ b/.dist/direct.js @@ -2,6 +2,7 @@ import { Guild } from "./guild.js"; import { Channel } from "./channel.js"; import { Message } from "./message.js"; import { User } from "./user.js"; +import { SnowFlake } from "./snowflake.js"; class Direct extends Guild { constructor(JSON, owner) { super(-1, owner, null); @@ -14,16 +15,16 @@ class Direct extends Guild { this.headers = this.localuser.headers; this.channels = []; this.channelids = {}; - this.id = "@me"; + this.id = new SnowFlake("@me", this); this.properties = {}; this.roles = []; - this.roleids = {}; + this.roleids = new Map(); this.prevchannel = undefined; this.properties.name = "Direct Messages"; for (const thing of JSON) { const temp = new Group(thing, this); this.channels.push(temp); - this.channelids[temp.id] = temp; + this.channelids[temp.id.id] = temp; } this.headchannels = this.channels; } @@ -36,7 +37,7 @@ class Direct extends Guild { } sortchannels() { this.headchannels.sort((a, b) => { - const result = (BigInt(a.lastmessageid) - BigInt(b.lastmessageid)); + const result = (a.lastmessageid.getUnixTime() - b.lastmessageid.getUnixTime()); return Number(-result); }); } @@ -72,15 +73,15 @@ class Group extends Channel { this.user = this.localuser.user; } this.name ??= this.localuser.user.username; - this.id = JSON.id; + this.id = new SnowFlake(JSON.id, this); this.parent_id = null; this.parent = null; this.children = []; this.guild_id = "@me"; - this.messageids = {}; - this.permission_overwrites = {}; - this.lastmessageid = JSON.last_message_id; - this.lastmessageid ??= "0"; + this.messageids = new Map(); + this.permission_overwrites = new Map(); + this.lastmessageid = SnowFlake.getSnowFlakeFromID(JSON.last_message_id, Message); + this.lastmessageid ??= new SnowFlake("0", undefined); this.mentions = 0; this.setUpInfiniteScroller(); } @@ -116,10 +117,10 @@ class Group extends Channel { } messageCreate(messagep) { const messagez = new Message(messagep.d, this); - this.idToNext[this.lastmessageid] = messagez.id; - this.idToPrev[messagez.id] = this.lastmessageid; + this.idToNext.set(this.lastmessageid, messagez.id); + this.idToPrev.set(messagez.id, this.lastmessageid); this.lastmessageid = messagez.id; - this.messageids[messagez.id] = messagez; + this.messageids.set(messagez.id, messagez); if (messagez.author === this.localuser.user) { this.lastreadmessageid = messagez.id; if (this.myhtml) { diff --git a/.dist/guild.js b/.dist/guild.js index ff6b29d..1290ae2 100644 --- a/.dist/guild.js +++ b/.dist/guild.js @@ -4,6 +4,7 @@ import { Role } from "./role.js"; import { Fullscreen } from "./fullscreen.js"; import { Member } from "./member.js"; import { Settings, RoleList } from "./settings.js"; +import { SnowFlake } from "./snowflake.js"; class Guild { owner; headers; @@ -67,30 +68,30 @@ class Guild { s1.options.push(new RoleList(permlist, this, this.updateRolePermissions.bind(this))); settings.show(); } - constructor(JSON, owner, member) { - if (JSON === -1) { + constructor(json, owner, member) { + if (json === -1) { return; } this.owner = owner; this.headers = this.owner.headers; this.channels = []; this.channelids = {}; - this.id = JSON.id; - this.properties = JSON.properties; + this.id = new SnowFlake(json.id, this); + this.properties = json.properties; this.roles = []; - this.roleids = {}; + this.roleids = new Map(); this.prevchannel = undefined; this.message_notifications = 0; - for (const roley of JSON.roles) { + for (const roley of json.roles) { const roleh = new Role(roley, this); this.roles.push(roleh); - this.roleids[roleh.id] = roleh; + this.roleids.set(roleh.id, roleh); } Member.resolve(member, this).then(_ => this.member = _); - for (const thing of JSON.channels) { + for (const thing of json.channels) { const temp = new Channel(thing, this); this.channels.push(temp); - this.channelids[temp.id] = temp; + this.channelids[temp.id.id] = temp; } this.headchannels = []; for (const thing of this.channels) { @@ -118,7 +119,7 @@ class Guild { headers: this.headers, body: JSON.stringify({ "guilds": { - [this.id]: { + [this.id.id]: { "message_notifications": noti } } @@ -237,7 +238,7 @@ class Guild { const noti = document.createElement("div"); noti.classList.add("unread"); divy.append(noti); - this.localuser.guildhtml[this.id] = divy; + this.localuser.guildhtml[this.id.id] = divy; if (this.properties.icon != null) { const img = document.createElement("img"); img.classList.add("pfp", "servericon"); @@ -366,16 +367,10 @@ class Guild { body: JSON.stringify(build) }); } - getRole(ID) { - if (!this.roleids[ID]) { - console.error(`role id ${ID} does not exist`, this.roleids); - } - return this.roleids[ID]; - } hasRole(r) { console.log("this should run"); - if ((typeof r) !== (typeof "")) { - r = r.id; + if (r instanceof Role) { + r = r.id.id; } return this.member.hasRole(r); } @@ -397,10 +392,10 @@ class Guild { } } loadGuild() { - this.localuser.loadGuild(this.id); + this.localuser.loadGuild(this.id.id); } updateChannel(JSON) { - this.channelids[JSON.id].updateChannel(JSON); + SnowFlake.getSnowFlakeFromID(JSON.id, Channel).getObject().updateChannel(JSON); this.headchannels = []; for (const thing of this.channels) { thing.children = []; @@ -507,7 +502,7 @@ class Guild { }); const json = await fetched.json(); const role = new Role(json, this); - this.roleids[role.id] = role; + this.roleids[role.id.id] = role; this.roles.push(role); return role; } diff --git a/.dist/localuser.js b/.dist/localuser.js index db9bb47..5284388 100644 --- a/.dist/localuser.js +++ b/.dist/localuser.js @@ -4,6 +4,8 @@ import { Voice } from "./audio.js"; import { User } from "./user.js"; import { Fullscreen } from "./fullscreen.js"; import { setTheme } from "./login.js"; +import { SnowFlake } from "./snowflake.js"; +import { Message } from "./message.js"; const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]); class Localuser { packets; @@ -43,14 +45,14 @@ class Localuser { this.initialized = true; this.ready = ready; this.guilds = []; - this.guildids = {}; + this.guildids = new Map(); this.user = new User(ready.d.user, this); this.userinfo.username = this.user.username; this.userinfo.pfpsrc = this.user.getpfpsrc(); this.status = this.ready.d.user_settings.status; this.channelfocus = null; this.lookingguild = null; - this.guildhtml = {}; + this.guildhtml = new Map(); const members = {}; for (const thing of ready.d.merged_members) { members[thing[0].guild_id] = thing[0]; @@ -58,12 +60,12 @@ class Localuser { for (const thing of ready.d.guilds) { const temp = new Guild(thing, this, members[thing.id]); this.guilds.push(temp); - this.guildids[temp.id] = temp; + this.guildids[temp.id.id] = temp; } { const temp = new Direct(ready.d.private_channels, this); this.guilds.push(temp); - this.guildids[temp.id] = temp; + this.guildids[temp.id.id] = temp; } console.log(ready.d.user_guild_settings.entries); for (const thing of ready.d.user_guild_settings.entries) { @@ -79,7 +81,7 @@ class Localuser { continue; } const guildid = guild.id; - this.guildids[guildid].channelids[thing.channel_id].readStateInfo(thing); + this.guildids[guildid.id].channelids[thing.channel_id].readStateInfo(thing); } this.typing = []; } @@ -97,7 +99,7 @@ class Localuser { clearInterval(this.wsinterval); this.outoffocus(); this.guilds = []; - this.guildids = {}; + this.guildids = new Map(); this.ws.close(4000); } async initwebsocket() { @@ -128,90 +130,85 @@ class Localuser { })); }); this.ws.addEventListener('message', (event) => { - try { - const temp = JSON.parse(event.data); - console.log(temp); - if (temp.op == 0) { - switch (temp.t) { - case "MESSAGE_CREATE": - if (this.initialized) { - this.messageCreate(temp); + const temp = JSON.parse(event.data); + console.log(temp); + if (temp.op == 0) { + switch (temp.t) { + case "MESSAGE_CREATE": + if (this.initialized) { + this.messageCreate(temp); + } + break; + case "MESSAGE_DELETE": + console.log(temp.d); + SnowFlake.getSnowFlakeFromID(temp.d.id, Message).getObject().deleteEvent(); + break; + case "READY": + this.gottenReady(temp); + this.genusersettings(); + returny(); + break; + case "MESSAGE_UPDATE": + const message = SnowFlake.getSnowFlakeFromID(temp.d.id, Message).getObject(); + message.giveData(temp.d); + break; + case "TYPING_START": + if (this.initialized) { + this.typingStart(temp); + } + break; + case "USER_UPDATE": + if (this.initialized) { + const users = SnowFlake.getSnowFlakeFromID(temp.d.id, User).getObject(); + console.log(users, temp.d.id); + if (users) { + users.userupdate(temp.d); } + } + break; + case "CHANNEL_UPDATE": + if (this.initialized) { + this.updateChannel(temp.d); + } + break; + case "CHANNEL_CREATE": + if (this.initialized) { + this.createChannel(temp.d); + } + break; + case "CHANNEL_DELETE": + if (this.initialized) { + this.delChannel(temp.d); + } + break; + case "GUILD_DELETE": + { + const guildy = this.guildids[temp.d.id]; + delete this.guildids[temp.d.id]; + this.guilds.splice(this.guilds.indexOf(guildy), 1); + guildy.html.remove(); break; - case "MESSAGE_DELETE": - console.log(temp.d); - this.guildids[temp.d.guild_id].channelids[temp.d.channel_id].messageids[temp.d.id].deleteEvent(); - break; - case "READY": - this.gottenReady(temp); - this.genusersettings(); - returny(); - break; - case "MESSAGE_UPDATE": - const message = this.resolveChannelFromID(temp.d.channel_id).messageids[temp.d.id]; - message.giveData(temp.d); - break; - case "TYPING_START": - if (this.initialized) { - this.typingStart(temp); - } - break; - case "USER_UPDATE": - if (this.initialized) { - const users = User.userids[temp.d.id]; - console.log(users, temp.d.id); - if (users) { - users.userupdate(temp.d); - } - } - break; - case "CHANNEL_UPDATE": - if (this.initialized) { - this.updateChannel(temp.d); - } - break; - case "CHANNEL_CREATE": - if (this.initialized) { - this.createChannel(temp.d); - } - break; - case "CHANNEL_DELETE": - if (this.initialized) { - this.delChannel(temp.d); - } - break; - case "GUILD_DELETE": - { - const guildy = this.guildids[temp.d.id]; - delete this.guildids[temp.d.id]; - this.guilds.splice(this.guilds.indexOf(guildy), 1); - guildy.html.remove(); - break; - } - case "GUILD_CREATE": - { - const guildy = new Guild(temp.d, this, this.user); - this.guilds.push(guildy); - this.guildids[guildy.id] = guildy; - document.getElementById("servers").insertBefore(guildy.generateGuildIcon(), document.getElementById("bottomseparator")); - } - } - } - else if (temp.op === 10) { - console.log("heartbeat down"); - this.wsinterval = setInterval(_ => { - if (this.connectionSucceed === 0) - this.connectionSucceed = Date.now(); - this.ws.send(JSON.stringify({ op: 1, d: this.packets })); - }, temp.d.heartbeat_interval); - this.packets = 1; - } - else if (temp.op != 11) { - this.packets++; + } + case "GUILD_CREATE": + { + const guildy = new Guild(temp.d, this, this.user); + this.guilds.push(guildy); + this.guildids[guildy.id.id] = guildy; + document.getElementById("servers").insertBefore(guildy.generateGuildIcon(), document.getElementById("bottomseparator")); + } } } - catch (error) { - console.error(error); + else if (temp.op === 10) { + console.log("heartbeat down"); + this.wsinterval = setInterval(_ => { + if (this.connectionSucceed === 0) + this.connectionSucceed = Date.now(); + this.ws.send(JSON.stringify({ op: 1, d: this.packets })); + }, temp.d.heartbeat_interval); + this.packets = 1; + } + else if (temp.op != 11) { + this.packets++; } }); this.ws.addEventListener("close", event => { @@ -253,15 +250,15 @@ class Localuser { return undefined; } updateChannel(JSON) { - this.guildids[JSON.guild_id].updateChannel(JSON); - if (JSON.guild_id === this.lookingguild.id) { + SnowFlake.getSnowFlakeFromID(JSON.guild_id, Guild).getObject().updateChannel(JSON); + if (JSON.guild_id === this.lookingguild.id.id) { this.loadGuild(JSON.guild_id); } } createChannel(JSON) { JSON.guild_id ??= "@me"; - this.guildids[JSON.guild_id].createChannelpac(JSON); - if (JSON.guild_id === this.lookingguild.id) { + SnowFlake.getSnowFlakeFromID(JSON.guild_id, Guild).getObject().createChannelpac(JSON); + if (JSON.guild_id === this.lookingguild.id.id) { this.loadGuild(JSON.guild_id); } } @@ -469,10 +466,10 @@ class Localuser { unreads() { console.log(this.guildhtml); for (const thing of this.guilds) { - if (thing.id === "@me") { + if (thing.id.id === "@me") { continue; } - thing.unreads(this.guildhtml[thing.id]); + thing.unreads(this.guildhtml[thing.id.id]); } } typingStart(typing) { diff --git a/.dist/member.js b/.dist/member.js index 7143cbf..dbbbd4b 100644 --- a/.dist/member.js +++ b/.dist/member.js @@ -1,6 +1,8 @@ import { User } from "./user.js"; +import { Role } from "./role.js"; import { Guild } from "./guild.js"; import { Contextmenu } from "./contextmenu.js"; +import { SnowFlake } from "./snowflake.js"; class Member { static already = {}; owner; @@ -39,7 +41,7 @@ class Member { } if (thing === "roles") { for (const strrole of membery["roles"]) { - const role = this.guild.getRole(strrole); + const role = SnowFlake.getSnowFlakeFromID(strrole, Role).getObject(); this.roles.push(role); } continue; @@ -67,50 +69,50 @@ class Member { console.error(guild); } let user; - let id = ""; + let id; if (unkown instanceof User) { user = unkown; id = user.id; } else if (typeof unkown === typeof "") { - id = unkown; + id = new SnowFlake(unkown, undefined); } else { return new Member(unkown, guild); } - if (guild.id === "@me") { + if (guild.id.id === "@me") { return null; } - if (!Member.already[guild.id]) { - Member.already[guild.id] = {}; + if (!Member.already[guild.id.id]) { + Member.already[guild.id.id] = {}; } - else if (Member.already[guild.id][id]) { - const memb = Member.already[guild.id][id]; + else if (Member.already[guild.id.id][id]) { + const memb = Member.already[guild.id.id][id]; if (memb instanceof Promise) { return await memb; } return memb; } - const promoise = fetch(guild.info.api.toString() + "/v9/users/" + id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => { + const promoise = fetch(guild.info.api.toString() + "/users/" + id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => { const memb = new Member(json, guild); - Member.already[guild.id][id] = memb; + Member.already[guild.id.id][id] = memb; console.log("resolved"); return memb; }); - Member.already[guild.id][id] = promoise; + Member.already[guild.id.id][id] = promoise; try { return await promoise; } catch (_) { const memb = new Member(user, guild, true); - Member.already[guild.id][id] = memb; + Member.already[guild.id.id][id] = memb; return memb; } } hasRole(ID) { console.log(this.roles, ID); for (const thing of this.roles) { - if (thing.id === ID) { + if (thing.id.id === ID) { return true; } } @@ -131,7 +133,7 @@ class Member { return true; } } - return this.guild.properties.owner_id === this.user.id; + return this.guild.properties.owner_id === this.user.id.id; } bind(html) { if (html.tagName === "SPAN") { diff --git a/.dist/message.js b/.dist/message.js index 78c8519..5ed5d0c 100644 --- a/.dist/message.js +++ b/.dist/message.js @@ -4,6 +4,7 @@ import { Member } from "./member.js"; import { MarkDown } from "./markdown.js"; import { Embed } from "./embed.js"; import { File } from "./file.js"; +import { SnowFlake } from "./snowflake.js"; class Message { static contextmenu = new Contextmenu("message menu"); owner; @@ -39,7 +40,7 @@ class Message { this.channel.setReplying(this); }); Message.contextmenu.addbutton("Copy message id", function () { - navigator.clipboard.writeText(this.id); + navigator.clipboard.writeText(this.id.id); }); Message.contextmenu.addbutton("Edit", function () { this.channel.editing = this; @@ -69,6 +70,10 @@ class Message { this.content = new MarkDown(messagejson[thing], this.channel); continue; } + else if (thing === "id") { + this.id = new SnowFlake(messagejson.id, this); + continue; + } this[thing] = messagejson[thing]; } for (const thing in this.embeds) { @@ -132,14 +137,14 @@ class Message { return build; } async edit(content) { - return await fetch(this.info.api.toString() + "/channels/" + this.channel.id + "/messages/" + this.id, { + return await fetch(this.info.api.toString() + "/channels/" + this.channel.id + "/messages/" + this.id.id, { method: "PATCH", headers: this.headers, body: JSON.stringify({ content: content }) }); } delete() { - fetch(`${this.info.api.toString()}/channels/${this.channel.id}/messages/${this.id}`, { + fetch(`${this.info.api.toString()}/channels/${this.channel.id}/messages/${this.id.id}`, { headers: this.headers, method: "DELETE", }); @@ -149,19 +154,22 @@ class Message { this.div.innerHTML = ""; this.div = null; } - const prev = this.channel.idToPrev[this.id]; - const next = this.channel.idToNext[this.id]; + const prev = this.channel.idToPrev[this.id.id]; + const next = this.channel.idToNext[this.id.id]; this.channel.idToNext[prev] = next; this.channel.idToPrev[next] = prev; - delete this.channel.messageids[this.id]; + delete this.channel.messageids[this.id.id]; const regen = this.channel.messageids[prev]; if (regen) { regen.generateMessage(); } + if (this.channel.lastmessage === this) { + this.channel.lastmessage = this.channel.messageids[prev]; + } } generateMessage(premessage = null) { if (!premessage) { - premessage = this.channel.messageids[this.channel.idToNext[this.id]]; + premessage = this.channel.messageids[this.channel.idToNext[this.id.id]]; } const div = this.div; if (this === this.channel.replyingto) { diff --git a/.dist/role.js b/.dist/role.js index 32a1bbb..58c5b11 100644 --- a/.dist/role.js +++ b/.dist/role.js @@ -1,5 +1,6 @@ export { Role }; import { Permissions } from "./permissions.js"; +import { SnowFlake } from "./snowflake.js"; class Role { permissions; owner; @@ -16,6 +17,10 @@ class Role { this.headers = owner.headers; this.info = owner.info; for (const thing of Object.keys(JSON)) { + if (thing === "id") { + this.id = new SnowFlake(JSON.id, this); + continue; + } this[thing] = JSON[thing]; } this.permissions = new Permissions(JSON.permissions); diff --git a/.dist/settings.js b/.dist/settings.js index 18d032a..9d1fe94 100644 --- a/.dist/settings.js +++ b/.dist/settings.js @@ -1,4 +1,6 @@ import { Permissions } from "./permissions.js"; +import { SnowFlake } from "./snowflake.js"; +import { Role } from "./role.js"; class Buttons { name; buttons; @@ -154,16 +156,17 @@ class RoleList extends Buttons { options.addPermissionToggle(thing, this.permission); // } for (const i of permissions) { - this.buttons.push([guild.getRole(i[0]).name, i[0]]); // + console.log(i); + this.buttons.push([i[0].getObject().name, i[0].id]); // } this.options = options; } handleString(str) { this.curid = str; - const perm = this.permissions.find(_ => _[0] === str)[1]; + const perm = this.permissions.find(_ => _[0].id === str)[1]; this.permission.deny = perm.deny; this.permission.allow = perm.allow; - this.options.name = this.guild.getRole(str).name; + this.options.name = SnowFlake.getSnowFlakeFromID(str, Role).getObject().name; this.options.haschanged = false; return this.options.generateHTML(); } diff --git a/.dist/snowflake.js b/.dist/snowflake.js new file mode 100644 index 0000000..0f394b8 --- /dev/null +++ b/.dist/snowflake.js @@ -0,0 +1,51 @@ +class SnowFlake { + id; + static SnowFlakes = new Map(); + static FinalizationRegistry = new FinalizationRegistry((id) => { + SnowFlake.SnowFlakes.delete(id); + }); + obj; + constructor(id, obj) { + if (!obj) { + this.id = id; + return; + } + if (!SnowFlake.SnowFlakes.get(obj.constructor)) { + SnowFlake.SnowFlakes.set(obj.constructor, new Map()); + } + if (SnowFlake.SnowFlakes.get(obj.constructor).get(id)) { + const snowflake = SnowFlake.SnowFlakes.get(obj.constructor).get(id).deref(); + snowflake.obj = obj; + return snowflake; + } + this.id = id; + SnowFlake.SnowFlakes.get(obj.constructor).set(id, new WeakRef(this)); + SnowFlake.FinalizationRegistry.register(this, id); + this.obj = obj; + } + static getSnowFlakeFromID(id, type) { + if (!SnowFlake.SnowFlakes.get(type)) { + SnowFlake.SnowFlakes.set(type, new Map()); + } + const snowflake = SnowFlake.SnowFlakes.get(type).get(id); + if (snowflake) { + return snowflake.deref(); + } + { + const snowflake = new SnowFlake(id, undefined); + SnowFlake.SnowFlakes.get(type).set(id, new WeakRef(snowflake)); + SnowFlake.FinalizationRegistry.register(snowflake, id); + return snowflake; + } + } + getUnixTime() { + return Number((BigInt(this.id) >> 22n) + 1420070400000n); + } + toString() { + return this.id; + } + getObject() { + return this.obj; + } +} +export { SnowFlake }; diff --git a/.dist/user.js b/.dist/user.js index 401b8a9..2b2c1fc 100644 --- a/.dist/user.js +++ b/.dist/user.js @@ -2,6 +2,7 @@ import { Member } from "./member.js"; import { MarkDown } from "./markdown.js"; import { Contextmenu } from "./contextmenu.js"; +import { SnowFlake } from "./snowflake.js"; class User { static userids = {}; owner; @@ -16,12 +17,12 @@ class User { static contextmenu = new Contextmenu("User Menu"); static setUpContextMenu() { this.contextmenu.addbutton("Copy user id", function () { - navigator.clipboard.writeText(this.id); + navigator.clipboard.writeText(this.id.id); }); this.contextmenu.addbutton("Message user", function () { fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST", - body: JSON.stringify({ "recipients": [this.id] }), - headers: this.headers + body: JSON.stringify({ "recipients": [this.id.id] }), + headers: this.localuser.headers }); }); } @@ -52,6 +53,10 @@ class User { this.bio = new MarkDown(userjson[thing], this.localuser); continue; } + if (thing === "id") { + this.id = new SnowFlake(userjson[thing], this); + continue; + } this[thing] = userjson[thing]; } this.hypotheticalpfp = false; @@ -67,7 +72,7 @@ class User { const pfp = document.createElement('img'); pfp.src = this.getpfpsrc(); pfp.classList.add("pfp"); - pfp.classList.add("userid:" + this.id); + pfp.classList.add("userid:" + this.id.id); return pfp; } userupdate(json) { @@ -77,7 +82,7 @@ class User { } } bind(html, guild = null) { - if (guild && guild.id !== "@me") { + if (guild && guild.id.id !== "@me") { Member.resolve(this, guild).then(_ => { _.bind(html); }).catch(_ => { @@ -96,7 +101,7 @@ class User { this.hypotheticalpfp = false; const src = this.getpfpsrc(); console.log(src); - for (const thing of document.getElementsByClassName("userid:" + this.id)) { + for (const thing of document.getElementsByClassName("userid:" + this.id.id)) { thing.src = src; } } @@ -105,7 +110,7 @@ class User { return this.avatar; } if (this.avatar != null) { - return this.info.cdn.toString() + "avatars/" + this.id + "/" + this.avatar + ".png"; + return this.info.cdn.toString() + "avatars/" + this.id.id + "/" + this.avatar + ".png"; } else { return this.info.cdn.toString() + "embed/avatars/3.png"; diff --git a/webpage/channel.ts b/webpage/channel.ts index 1f1eca6..0fb5a13 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -3,14 +3,14 @@ import { Message } from "./message.js"; import {Voice} from "./audio.js"; import {Contextmenu} from "./contextmenu.js"; import {Fullscreen} from "./fullscreen.js"; -import {MarkDown} from "./markdown.js"; import {Guild} from "./guild.js"; import { Localuser } from "./localuser.js"; import { Permissions } from "./permissions.js"; import { Settings, RoleList } from "./settings.js"; import { Role } from "./role.js"; -import {InfiniteScroller} from "./infiniteScroller.js" -Settings; +import {InfiniteScroller} from "./infiniteScroller.js"; +import { SnowFlake } from "./snowflake.js"; + declare global { interface NotificationOptions { image?: string @@ -22,30 +22,30 @@ class Channel{ owner:Guild; headers:Localuser["headers"]; name:string; - id:string; - parent_id:string; + id:SnowFlake; + parent_id:SnowFlake; parent:Channel; children:Channel[]; guild_id:string; - messageids:{[key : string]:Message}; - permission_overwrites:{[key:string]:Permissions}; - permission_overwritesar:[string,Permissions][] + messageids:Map,Message>; + permission_overwrites:Map; + permission_overwritesar:[SnowFlake,Permissions][] topic:string; nsfw:boolean; position:number; - lastreadmessageid:string; - lastmessageid:string; + lastreadmessageid:SnowFlake; + lastmessageid:SnowFlake; mentions:number; lastpin:string; - move_id:string; + move_id:SnowFlake; typing:number; message_notifications:number; allthewayup:boolean; static contextmenu=new Contextmenu("channel menu"); replyingto:Message; infinite:InfiniteScroller; - idToPrev:{[key:string]:string}={}; - idToNext:{[key:string]:string}={}; + idToPrev:Map,SnowFlake>=new Map(); + idToNext:Map,SnowFlake>=new Map(); static setupcontextmenu(){ this.contextmenu.addbutton("Copy channel id",function(){ console.log(this) @@ -87,26 +87,28 @@ class Channel{ } setUpInfiniteScroller(){ const ids:{[key:string]:Function}={}; - this.infinite=new InfiniteScroller(async function(id:string,offset:number){ + this.infinite=new InfiniteScroller(async function(this:Channel,id:string,offset:number):Promise{ + const snowflake=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake; if(offset===1){ - if(this.idToPrev[id]){ - return this.idToPrev[id]; + if(this.idToPrev.get(snowflake)){ + return this.idToPrev.get(snowflake)?.id; }else{ - await this.grabmoremessages(id); - return this.idToPrev[id]; + await this.grabBefore(id); + return this.idToPrev.get(snowflake)?.id; } }else{ - return this.idToNext[id]; + return this.idToNext.get(snowflake)?.id; } }.bind(this), function(this:Channel,id:string){ let res:Function; const promise=new Promise(_=>{res=_;}) as Promise; - const html=this.messageids[id].buildhtml(this.messageids[this.idToPrev[id]],promise); + const snowflake=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake; + const html=this.messageids.get(snowflake).buildhtml(this.messageids.get(this.idToPrev.get(snowflake)),promise); ids[id]=res; return html; }.bind(this), - async function(id:string){ + async function(this:Channel,id:string){ ids[id](); delete ids[id]; return true; @@ -125,26 +127,25 @@ class Channel{ this.owner=owner; this.headers=this.owner.headers; this.name=JSON.name; - this.id=JSON.id; - this.parent_id=JSON.parent_id; + this.id=new SnowFlake(JSON.id,this); + this.parent_id=new SnowFlake(JSON.parent_id,undefined); this.parent=null; this.children=[]; this.guild_id=JSON.guild_id; - this.messageids={}; - this.permission_overwrites={}; + this.messageids=new Map(); + this.permission_overwrites=new Map(); this.permission_overwritesar=[]; for(const thing of JSON.permission_overwrites){ - console.log(thing); if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){continue;}; - this.permission_overwrites[thing.id]=new Permissions(thing.allow,thing.deny); - this.permission_overwritesar.push([thing.id,this.permission_overwrites[thing.id]]); + this.permission_overwrites.set(thing.id,new Permissions(thing.allow,thing.deny)); + this.permission_overwritesar.push([thing.id,this.permission_overwrites.get(thing.id)]); } this.topic=JSON.topic; this.nsfw=JSON.nsfw; this.position=JSON.position; this.lastreadmessageid=null; - this.lastmessageid=JSON.last_message_id; + this.lastmessageid=SnowFlake.getSnowFlakeFromID(JSON.last_message_id,Message); this.setUpInfiniteScroller(); } isAdmin(){ @@ -160,22 +161,22 @@ class Channel{ return this.owner.info; } readStateInfo(json){ - this.lastreadmessageid=json.last_message_id; + this.lastreadmessageid=SnowFlake.getSnowFlakeFromID(json.last_message_id,Message); this.mentions=json.mention_count; this.mentions??=0; this.lastpin=json.last_pin_timestamp; } get hasunreads():boolean{ if(!this.hasPermission("VIEW_CHANNEL")){return false;} - return this.lastmessageid!==this.lastreadmessageid&&this.type!==4; + return this.lastmessageid!==this.lastreadmessageid&&this.type!==4&&!!this.lastmessageid.id; } hasPermission(name:string,member=this.guild.member):boolean{ if(member.isAdmin()){ return true; } for(const thing of member.roles){ - if(this.permission_overwrites[thing.id]){ - let perm=this.permission_overwrites[thing.id].getPermission(name); + if(this.permission_overwrites.get(thing.id.id)){ + let perm=this.permission_overwrites.get(thing.id.id).getPermission(name); if(perm){ return perm===1; } @@ -196,7 +197,7 @@ class Channel{ this.children.sort((a,b)=>{return a.position-b.position}); } resolveparent(guild:Guild){ - this.parent=guild.channelids[this.parent_id]; + this.parent=guild.channelids[this.parent_id?.id]; this.parent??=null; if(this.parent!==null){ this.parent.children.push(this); @@ -354,7 +355,7 @@ class Channel{ if(!this.hasunreads){ return; } - fetch(this.info.api.toString()+"/v9/channels/"+this.id+"/messages/"+this.lastmessageid+"/ack",{ + fetch(this.info.api.toString()+"/channels/"+this.id+"/messages/"+this.lastmessageid+"/ack",{ method:"POST", headers:this.headers, body:JSON.stringify({}) @@ -445,8 +446,8 @@ class Channel{ ["textbox","Channel name:",this.name,function(){name=this.value}], ["mdbox","Channel topic:",this.topic,function(){topic=this.value}], ["checkbox","NSFW Channel",this.nsfw,function(){nsfw=this.checked}], - ["button","","submit",function(){ - fetch(this.info.api.toString()+"/v9/channels/"+thisid,{ + ["button","","submit",()=>{ + fetch(this.info.api.toString()+"/channels/"+thisid,{ method:"PATCH", headers:this.headers, body:JSON.stringify({ @@ -470,7 +471,7 @@ class Channel{ console.log(full) } deleteChannel(){ - fetch(this.info.api.toString()+"/v9/channels/"+this.id,{ + fetch(this.info.api.toString()+"/channels/"+this.id,{ method:"DELETE", headers:this.headers }) @@ -508,10 +509,11 @@ class Channel{ } } async getmessage(id:string):Promise{ - if(this.messageids[id]){ - return this.messageids[id]; + const snowflake=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake; + if(snowflake.getObject()){ + return snowflake.getObject(); }else{ - const gety=await fetch(this.info.api.toString()+"/v9/channels/"+this.id+"/messages?limit=1&around="+id,{headers:this.headers}) + const gety=await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=1&around="+id,{headers:this.headers}) const json=await gety.json(); return new Message(json[0],this); } @@ -539,13 +541,15 @@ class Channel{ history.pushState(null, null,"/channels/"+this.guild_id+"/"+this.id); document.getElementById("channelname").textContent="#"+this.name; console.log(this); - (document.getElementById("typebox") as HTMLInputElement).disabled=!this.canMessage; + (document.getElementById("typebox") as HTMLInputElement).contentEditable=""+this.canMessage; } + lastmessage:Message; async putmessages(){ if(this.allthewayup){return}; const j=await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=100",{ headers: this.headers, - }) + }); + const response=await j.json(); if(response.length!==100){ this.allthewayup=true; @@ -554,12 +558,14 @@ class Channel{ for(const thing of response){ const message=new Message(thing,this); if(prev){ - this.idToNext[message.id]=prev.id; - this.idToPrev[prev.id]=message.id; + this.idToNext.set(message.id,prev.id); + this.idToPrev.set(prev.id,message.id); + }else{ + this.lastmessage=message; } prev=message; - if(this.messageids[message.id]===undefined){ - this.messageids[message.id]=message; + if(this.messageids.get(message.id)===undefined){ + this.messageids.set(message.id,message); } } } @@ -572,7 +578,7 @@ class Channel{ } this.children=build; } - async grabmoremessages(id:string){ + async grabBefore(id:string){ if(this.allthewayup){ return; } @@ -584,7 +590,7 @@ class Channel{ if(response.length===0){ this.allthewayup=true; } - let previd=id; + let previd=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake; for(const i in response){ let messager:Message; if(!next){ @@ -598,11 +604,11 @@ class Channel{ next=undefined; console.log("ohno",+i+1); } - if(this.messageids[messager.id]===undefined){ - this.idToNext[messager.id]=previd; - this.idToPrev[previd]=messager.id; + if(this.messageids.get(messager.id)===undefined){ + this.idToNext.set(messager.id,previd); + this.idToPrev.set(previd,messager.id); previd=messager.id; - this.messageids[messager.id]=messager; + this.messageids.set(messager.id,messager); }else{ console.log("How???") } @@ -618,17 +624,42 @@ class Channel{ buildmessages(){ const messages=document.getElementById("channelw"); messages.innerHTML=""; - messages.append(this.infinite.getDiv(this.lastmessageid)); + let id:SnowFlake; + if(this.messageids.get(this.lastreadmessageid)){ + id=this.lastreadmessageid; + }else if(this.lastmessage.id){ + id=this.goBackIds(this.lastmessage.id,50); + console.log("shouldn't") + } + messages.append(this.infinite.getDiv(id.id)); + } + private goBackIds(id:SnowFlake,back:number):SnowFlake{ + while(back!==0){ + const nextid=this.idToPrev.get(id); + if(nextid){ + id=nextid; + console.log(id); + back--; + }else{ + break; + } + } + return id; } updateChannel(JSON){ this.type=JSON.type; this.name=JSON.name; - this.parent_id=JSON.parent_id; + this.parent_id=new SnowFlake(JSON.parent_id,undefined); this.parent=null; this.children=[]; this.guild_id=JSON.guild_id; - this.messageids={}; - this.permission_overwrites=JSON.permission_overwrites; + this.messageids=new Map(); + this.permission_overwrites=new Map(); + for(const thing of JSON.permission_overwrites){ + if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){continue;}; + this.permission_overwrites.set(thing.id,new Permissions(thing.allow,thing.deny)); + this.permission_overwritesar.push([thing.id,this.permission_overwrites.get(thing.id)]); + } this.topic=JSON.topic; this.nsfw=JSON.nsfw; } @@ -707,10 +738,11 @@ class Channel{ messageCreate(messagep:any):void{ if(!this.hasPermission("VIEW_CHANNEL")){return} const messagez=new Message(messagep.d,this); - this.idToNext[this.lastmessageid]=messagez.id; - this.idToPrev[messagez.id]=this.lastmessageid; + console.log(this.lastmessageid,messagez.id,":3"); + this.idToNext.set(this.lastmessageid,messagez.id); + this.idToPrev.set(messagez.id,this.lastmessageid); this.lastmessageid=messagez.id; - this.messageids[messagez.id]=messagez; + this.messageids.set(messagez.id,messagez); if(messagez.author===this.localuser.user){ this.lastreadmessageid=messagez.id; if(this.myhtml){ @@ -785,11 +817,11 @@ class Channel{ }) }) const perm=new Permissions("0","0"); - this.permission_overwrites[role.id]=perm; + this.permission_overwrites.set(role.id.id,perm); this.permission_overwritesar.push([role.id,perm]); } async updateRolePermissions(id:string,perms:Permissions){ - const permission=this.permission_overwrites[id]; + const permission=this.permission_overwrites.get(id); permission.allow=perms.allow; permission.deny=perms.deny; await fetch(this.info.api.toString()+"/channels/"+this.id+"/permissions/"+id,{ diff --git a/webpage/direct.ts b/webpage/direct.ts index 3d4ad35..2f9ce66 100644 --- a/webpage/direct.ts +++ b/webpage/direct.ts @@ -4,6 +4,7 @@ import { Message } from "./message.js"; import { Localuser } from "./localuser.js"; import {User} from "./user.js"; import { Member } from "./member.js"; +import { SnowFlake } from "./snowflake.js"; class Direct extends Guild{ constructor(JSON,owner:Localuser){ @@ -17,16 +18,16 @@ class Direct extends Guild{ this.headers=this.localuser.headers; this.channels=[]; this.channelids={}; - this.id="@me"; + this.id=new SnowFlake("@me",this); this.properties={}; this.roles=[]; - this.roleids={}; + this.roleids=new Map(); this.prevchannel=undefined; this.properties.name="Direct Messages"; for(const thing of JSON){ const temp=new Group(thing,this); this.channels.push(temp); - this.channelids[temp.id]=temp; + this.channelids[temp.id.id]=temp; } this.headchannels=this.channels; } @@ -39,7 +40,7 @@ class Direct extends Guild{ } sortchannels(){ this.headchannels.sort((a,b)=>{ - const result=(BigInt(a.lastmessageid)-BigInt(b.lastmessageid)); + const result=(a.lastmessageid.getUnixTime()-b.lastmessageid.getUnixTime()); return Number(-result); }); } @@ -74,15 +75,15 @@ class Group extends Channel{ this.user=this.localuser.user; } this.name??=this.localuser.user.username; - this.id=JSON.id; + this.id=new SnowFlake(JSON.id,this); this.parent_id=null; this.parent=null; this.children=[]; this.guild_id="@me"; - this.messageids={}; - this.permission_overwrites={}; - this.lastmessageid=JSON.last_message_id; - this.lastmessageid??="0"; + this.messageids=new Map(); + this.permission_overwrites=new Map(); + this.lastmessageid=SnowFlake.getSnowFlakeFromID(JSON.last_message_id,Message); + this.lastmessageid??=new SnowFlake("0",undefined); this.mentions=0; this.setUpInfiniteScroller(); } @@ -118,10 +119,10 @@ class Group extends Channel{ } messageCreate(messagep){ const messagez=new Message(messagep.d,this); - this.idToNext[this.lastmessageid]=messagez.id; - this.idToPrev[messagez.id]=this.lastmessageid; + this.idToNext.set(this.lastmessageid,messagez.id); + this.idToPrev.set(messagez.id,this.lastmessageid); this.lastmessageid=messagez.id; - this.messageids[messagez.id]=messagez; + this.messageids.set(messagez.id,messagez); if(messagez.author===this.localuser.user){ this.lastreadmessageid=messagez.id; if(this.myhtml){ diff --git a/webpage/guild.ts b/webpage/guild.ts index e5a77ce..9b69c6a 100644 --- a/webpage/guild.ts +++ b/webpage/guild.ts @@ -6,15 +6,16 @@ import {Fullscreen} from "./fullscreen.js"; import {Member} from "./member.js"; import {Settings,RoleList} from "./settings.js"; import {Permissions} from "./permissions.js"; +import { SnowFlake } from "./snowflake.js"; class Guild{ owner:Localuser; headers:Localuser["headers"]; channels:Channel[]; channelids:{[key:string]:Channel}; - id:string; + id:SnowFlake; properties roles:Role[]; - roleids:{[key:string]:Role}; + roleids:Map,Role>; prevchannel:Channel; message_notifications:number; headchannels:Channel[]; @@ -75,30 +76,30 @@ class Guild{ s1.options.push(new RoleList(permlist,this,this.updateRolePermissions.bind(this))); settings.show(); } - constructor(JSON,owner:Localuser,member){ - if(JSON===-1){ + constructor(json,owner:Localuser,member){ + if(json===-1){ return; } this.owner=owner; this.headers=this.owner.headers; this.channels=[]; this.channelids={}; - this.id=JSON.id; - this.properties=JSON.properties; + this.id=new SnowFlake(json.id,this); + this.properties=json.properties; this.roles=[]; - this.roleids={}; + this.roleids=new Map(); this.prevchannel=undefined; this.message_notifications=0; - for(const roley of JSON.roles){ + for(const roley of json.roles){ const roleh=new Role(roley,this); this.roles.push(roleh) - this.roleids[roleh.id]=roleh; + this.roleids.set(roleh.id,roleh); } Member.resolve(member,this).then(_=>this.member=_); - for(const thing of JSON.channels){ + for(const thing of json.channels){ const temp=new Channel(thing,this); this.channels.push(temp); - this.channelids[temp.id]=temp; + this.channelids[temp.id.id]=temp; } this.headchannels=[]; for(const thing of this.channels){ @@ -128,7 +129,7 @@ class Guild{ headers:this.headers, body:JSON.stringify({ "guilds":{ - [this.id]:{ + [this.id.id]:{ "message_notifications": noti } } @@ -247,7 +248,7 @@ class Guild{ const noti=document.createElement("div"); noti.classList.add("unread"); divy.append(noti); - this.localuser.guildhtml[this.id]=divy; + this.localuser.guildhtml[this.id.id]=divy; if(this.properties.icon!=null){ const img=document.createElement("img"); img.classList.add("pfp","servericon"); @@ -373,16 +374,12 @@ class Guild{ body:JSON.stringify(build) }) } - getRole(ID:string):Role{ - if(!this.roleids[ID]){console.error(`role id ${ID} does not exist`,this.roleids)} - return this.roleids[ID]; - } hasRole(r:Role|string){ console.log("this should run"); - if((typeof r)!==(typeof "")){ - r=(r as Role).id; + if(r instanceof Role){ + r=r.id.id; } - return this.member.hasRole(r as string); + return this.member.hasRole(r); } loadChannel(ID:string=undefined){ if(ID&&this.channelids[ID]){ @@ -402,10 +399,10 @@ class Guild{ } } loadGuild(){ - this.localuser.loadGuild(this.id); + this.localuser.loadGuild(this.id.id); } updateChannel(JSON){ - this.channelids[JSON.id].updateChannel(JSON); + SnowFlake.getSnowFlakeFromID(JSON.id,Channel).getObject().updateChannel(JSON); this.headchannels=[]; for(const thing of this.channels){ thing.children=[]; @@ -516,7 +513,7 @@ class Guild{ }) const json=await fetched.json(); const role=new Role(json,this); - this.roleids[role.id]=role; + this.roleids[role.id.id]=role; this.roles.push(role); return role; } diff --git a/webpage/localuser.ts b/webpage/localuser.ts index e1ce1a5..c4f2744 100644 --- a/webpage/localuser.ts +++ b/webpage/localuser.ts @@ -7,6 +7,8 @@ import {Member} from "./member.js"; import {MarkDown} from "./markdown.js"; import {Fullscreen} from "./fullscreen.js"; import {setTheme, Specialuser} from "./login.js"; +import { SnowFlake } from "./snowflake.js"; +import { Message } from "./message.js"; const wsCodesRetry=new Set([4000,4003,4005,4007,4008,4009]); @@ -23,12 +25,12 @@ class Localuser{ devPortal:Fullscreen; ready; guilds:Guild[]; - guildids:{ [key: string]: Guild }; + guildids:Map; user:User; status:string; channelfocus:Channel; lookingguild:Guild; - guildhtml:Record; + guildhtml:Map; ws:WebSocket; typing:[string,number][]; wsinterval:NodeJS.Timeout; @@ -48,14 +50,14 @@ class Localuser{ this.initialized=true; this.ready=ready; this.guilds=[]; - this.guildids={}; + this.guildids=new Map(); this.user=new User(ready.d.user,this); this.userinfo.username=this.user.username; this.userinfo.pfpsrc=this.user.getpfpsrc(); this.status=this.ready.d.user_settings.status; this.channelfocus=null; this.lookingguild=null; - this.guildhtml={}; + this.guildhtml=new Map(); const members={}; for(const thing of ready.d.merged_members){ members[thing[0].guild_id]=thing[0]; @@ -64,12 +66,12 @@ class Localuser{ for(const thing of ready.d.guilds){ const temp=new Guild(thing,this,members[thing.id]); this.guilds.push(temp); - this.guildids[temp.id]=temp; + this.guildids[temp.id.id]=temp; } { const temp=new Direct(ready.d.private_channels,this); this.guilds.push(temp); - this.guildids[temp.id]=temp; + this.guildids[temp.id.id]=temp; } console.log(ready.d.user_guild_settings.entries); @@ -86,7 +88,7 @@ class Localuser{ continue } const guildid=guild.id; - this.guildids[guildid].channelids[thing.channel_id].readStateInfo(thing); + this.guildids[guildid.id].channelids[thing.channel_id].readStateInfo(thing); } this.typing=[]; } @@ -104,7 +106,7 @@ class Localuser{ clearInterval(this.wsinterval); this.outoffocus(); this.guilds=[]; - this.guildids={}; + this.guildids=new Map(); this.ws.close(4000) } async initwebsocket():Promise{ @@ -138,7 +140,7 @@ class Localuser{ this.ws.addEventListener('message', (event) => { - try{ + const temp=JSON.parse(event.data); console.log(temp) if(temp.op==0){ @@ -150,7 +152,7 @@ class Localuser{ break; case "MESSAGE_DELETE": console.log(temp.d); - this.guildids[temp.d.guild_id].channelids[temp.d.channel_id].messageids[temp.d.id].deleteEvent(); + SnowFlake.getSnowFlakeFromID(temp.d.id,Message).getObject().deleteEvent(); break; case "READY": this.gottenReady(temp); @@ -158,7 +160,7 @@ class Localuser{ returny(); break; case "MESSAGE_UPDATE": - const message=this.resolveChannelFromID(temp.d.channel_id).messageids[temp.d.id]; + const message=SnowFlake.getSnowFlakeFromID(temp.d.id,Message).getObject(); message.giveData(temp.d); break; case "TYPING_START": @@ -168,7 +170,7 @@ class Localuser{ break; case "USER_UPDATE": if(this.initialized){ - const users=User.userids[temp.d.id]; + const users=SnowFlake.getSnowFlakeFromID(temp.d.id,User).getObject() as User; console.log(users,temp.d.id) if(users){ users.userupdate(temp.d); @@ -202,7 +204,7 @@ class Localuser{ { const guildy=new Guild(temp.d,this,this.user); this.guilds.push(guildy); - this.guildids[guildy.id]=guildy; + this.guildids[guildy.id.id]=guildy; document.getElementById("servers").insertBefore(guildy.generateGuildIcon(),document.getElementById("bottomseparator")); } } @@ -218,9 +220,7 @@ class Localuser{ }else if(temp.op!=11){ this.packets++ } - }catch(error){ - console.error(error) - } + }); @@ -264,15 +264,15 @@ class Localuser{ return undefined; } updateChannel(JSON):void{ - this.guildids[JSON.guild_id].updateChannel(JSON); - if(JSON.guild_id===this.lookingguild.id){ + SnowFlake.getSnowFlakeFromID(JSON.guild_id,Guild).getObject().updateChannel(JSON); + if(JSON.guild_id===this.lookingguild.id.id){ this.loadGuild(JSON.guild_id); } } createChannel(JSON):void{ JSON.guild_id??="@me"; - this.guildids[JSON.guild_id].createChannelpac(JSON); - if(JSON.guild_id===this.lookingguild.id){ + SnowFlake.getSnowFlakeFromID(JSON.guild_id,Guild).getObject().createChannelpac(JSON); + if(JSON.guild_id===this.lookingguild.id.id){ this.loadGuild(JSON.guild_id); } } @@ -497,8 +497,8 @@ class Localuser{ unreads():void{ console.log(this.guildhtml) for(const thing of this.guilds){ - if(thing.id==="@me"){continue;} - thing.unreads(this.guildhtml[thing.id]); + if(thing.id.id==="@me"){continue;} + thing.unreads(this.guildhtml[thing.id.id]); } } typingStart(typing):void{ diff --git a/webpage/member.ts b/webpage/member.ts index 2154cd7..c181d2e 100644 --- a/webpage/member.ts +++ b/webpage/member.ts @@ -2,6 +2,7 @@ import {User} from "./user.js"; import {Role} from "./role.js"; import {Guild} from "./guild.js"; import { Contextmenu } from "./contextmenu.js"; +import { SnowFlake } from "./snowflake.js"; class Member{ static already={}; @@ -38,7 +39,7 @@ class Member{ if(thing==="owner"){continue} if(thing==="roles"){ for(const strrole of membery["roles"]){ - const role=this.guild.getRole(strrole); + const role=SnowFlake.getSnowFlakeFromID(strrole,Role).getObject(); this.roles.push(role); } continue; @@ -65,44 +66,45 @@ class Member{ console.error(guild) } let user:User; - let id=""; + let id:SnowFlake; if(unkown instanceof User){ user=unkown as User; id=user.id; }else if(typeof unkown===typeof ""){ - id=unkown as string; + id=new SnowFlake(unkown as string,undefined); }else{ return new Member(unkown,guild); } - if(guild.id==="@me"){return null} - if(!Member.already[guild.id]){ - Member.already[guild.id]={}; - }else if(Member.already[guild.id][id]){ - const memb=Member.already[guild.id][id] + if(guild.id.id==="@me"){return null} + if(!Member.already[guild.id.id]){ + Member.already[guild.id.id]={}; + }else if(Member.already[guild.id.id][id]){ + const memb=Member.already[guild.id.id][id] if(memb instanceof Promise){ return await memb; } return memb; } - const promoise= fetch(guild.info.api.toString()+"/v9/users/"+id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.id,{headers:guild.headers}).then(_=>_.json()).then(json=>{ + const promoise= fetch(guild.info.api.toString()+"/users/"+id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.id,{headers:guild.headers}).then(_=>_.json()).then(json=>{ const memb=new Member(json,guild); - Member.already[guild.id][id]=memb; + Member.already[guild.id.id][id]=memb; console.log("resolved") return memb }) - Member.already[guild.id][id]=promoise; + Member.already[guild.id.id][id]=promoise; try{ return await promoise }catch(_){ + const memb=new Member(user,guild,true); - Member.already[guild.id][id]=memb; + Member.already[guild.id.id][id]=memb; return memb; } } hasRole(ID:string){ console.log(this.roles,ID); for(const thing of this.roles){ - if(thing.id===ID){ + if(thing.id.id===ID){ return true; } } @@ -123,7 +125,7 @@ class Member{ return true; } } - return this.guild.properties.owner_id===this.user.id; + return this.guild.properties.owner_id===this.user.id.id; } bind(html:HTMLElement){ if(html.tagName==="SPAN"){ diff --git a/webpage/message.ts b/webpage/message.ts index b287411..6830793 100644 --- a/webpage/message.ts +++ b/webpage/message.ts @@ -7,6 +7,7 @@ import { Channel } from "./channel.js"; import {Localuser} from "./localuser.js"; import { Role } from "./role.js"; import {File} from "./file.js"; +import { SnowFlake } from "./snowflake.js"; class Message{ static contextmenu=new Contextmenu("message menu"); @@ -17,7 +18,7 @@ class Message{ mentions:User[]; mention_roles:Role[]; attachments:File[];//probably should be its own class tbh, should be Attachments[] - id:string; + id:SnowFlake; message_reference; type:number; timestamp:number; @@ -43,7 +44,7 @@ class Message{ this.channel.setReplying(this); }); Message.contextmenu.addbutton("Copy message id",function(){ - navigator.clipboard.writeText(this.id); + navigator.clipboard.writeText(this.id.id); }); Message.contextmenu.addbutton("Edit",function(){ this.channel.editing=this; @@ -72,6 +73,9 @@ class Message{ }else if(thing==="content"){ this.content=new MarkDown(messagejson[thing],this.channel); continue; + }else if(thing ==="id"){ + this.id=new SnowFlake(messagejson.id,this); + continue; } this[thing]=messagejson[thing]; } @@ -135,14 +139,14 @@ class Message{ return build; } async edit(content){ - return await fetch(this.info.api.toString()+"/channels/"+this.channel.id+"/messages/"+this.id,{ + return await fetch(this.info.api.toString()+"/channels/"+this.channel.id+"/messages/"+this.id.id,{ method: "PATCH", headers: this.headers, body:JSON.stringify({content:content}) }); } delete(){ - fetch(`${this.info.api.toString()}/channels/${this.channel.id}/messages/${this.id}`,{ + fetch(`${this.info.api.toString()}/channels/${this.channel.id}/messages/${this.id.id}`,{ headers:this.headers, method:"DELETE", }) @@ -152,19 +156,22 @@ class Message{ this.div.innerHTML=""; this.div=null; } - const prev=this.channel.idToPrev[this.id]; - const next=this.channel.idToNext[this.id]; + const prev=this.channel.idToPrev[this.id.id]; + const next=this.channel.idToNext[this.id.id]; this.channel.idToNext[prev]=next; this.channel.idToPrev[next]=prev; - delete this.channel.messageids[this.id]; + delete this.channel.messageids[this.id.id]; const regen=this.channel.messageids[prev] if(regen){ regen.generateMessage(); } + if(this.channel.lastmessage===this){ + this.channel.lastmessage=this.channel.messageids[prev]; + } } generateMessage(premessage:Message=null){ if(!premessage){ - premessage=this.channel.messageids[this.channel.idToNext[this.id]]; + premessage=this.channel.messageids[this.channel.idToNext[this.id.id]]; } const div=this.div; if(this===this.channel.replyingto){ diff --git a/webpage/role.ts b/webpage/role.ts index 9a1145c..079df86 100644 --- a/webpage/role.ts +++ b/webpage/role.ts @@ -2,11 +2,12 @@ export {Role}; import {Permissions} from "./permissions.js"; import {Localuser} from "./localuser.js"; import {Guild} from "./guild.js"; +import { SnowFlake } from "./snowflake.js"; class Role{ permissions:Permissions; owner:Guild; color:number; - id:string; + readonly id:SnowFlake; name:string; info:Guild["info"]; hoist:boolean; @@ -18,6 +19,10 @@ class Role{ this.headers=owner.headers; this.info=owner.info; for(const thing of Object.keys(JSON)){ + if(thing==="id"){ + this.id=new SnowFlake(JSON.id,this); + continue; + } this[thing]=JSON[thing]; } this.permissions=new Permissions(JSON.permissions); diff --git a/webpage/settings.ts b/webpage/settings.ts index 1b2f095..1b2b54a 100644 --- a/webpage/settings.ts +++ b/webpage/settings.ts @@ -1,5 +1,7 @@ import { Permissions } from "./permissions.js"; import { Guild } from "./guild.js"; +import { SnowFlake } from "./snowflake.js"; +import { Role } from "./role.js"; class Buttons{ readonly name:string; @@ -126,7 +128,7 @@ class PermissionToggle{ } } class RoleList extends Buttons{ - readonly permissions:[string,Permissions][]; + readonly permissions:[SnowFlake,Permissions][]; permission:Permissions; readonly guild:Guild; readonly channel:boolean; @@ -134,7 +136,7 @@ class RoleList extends Buttons{ readonly options:Options; onchange:Function; curid:string; - constructor(permissions:[string,Permissions][],guild:Guild,onchange:Function,channel=false){ + constructor(permissions:[SnowFlake,Permissions][],guild:Guild,onchange:Function,channel=false){ super("Roles"); this.guild=guild; this.permissions=permissions; @@ -150,16 +152,17 @@ class RoleList extends Buttons{ options.addPermissionToggle(thing,this.permission);// } for(const i of permissions){ - this.buttons.push([guild.getRole(i[0]).name,i[0]])// + console.log(i); + this.buttons.push([i[0].getObject().name,i[0].id])// } this.options=options; } handleString(str:string):HTMLElement{ this.curid=str; - const perm=this.permissions.find(_=>_[0]===str)[1]; + const perm=this.permissions.find(_=>_[0].id===str)[1]; this.permission.deny=perm.deny; this.permission.allow=perm.allow; - this.options.name=this.guild.getRole(str).name; + this.options.name=SnowFlake.getSnowFlakeFromID(str,Role).getObject().name; this.options.haschanged=false; return this.options.generateHTML(); } diff --git a/webpage/snowflake.ts b/webpage/snowflake.ts new file mode 100644 index 0000000..2da4c1a --- /dev/null +++ b/webpage/snowflake.ts @@ -0,0 +1,53 @@ +class SnowFlake{ + public readonly id:string; + private static readonly SnowFlakes:Map>>>=new Map(); + private static readonly FinalizationRegistry=new FinalizationRegistry((id:string)=>{ + SnowFlake.SnowFlakes.delete(id); + }); + private obj:x; + constructor(id:string,obj:x){ + if(!obj){ + this.id=id; + return; + } + if(!SnowFlake.SnowFlakes.get(obj.constructor)){ + SnowFlake.SnowFlakes.set(obj.constructor,new Map()); + } + if(SnowFlake.SnowFlakes.get(obj.constructor).get(id)){ + const snowflake=SnowFlake.SnowFlakes.get(obj.constructor).get(id).deref(); + snowflake.obj=obj; + return snowflake; + } + this.id=id; + SnowFlake.SnowFlakes.get(obj.constructor).set(id,new WeakRef(this)); + SnowFlake.FinalizationRegistry.register(this,id); + this.obj=obj; + } + static getSnowFlakeFromID(id:string,type:any):SnowFlake{ + if(!SnowFlake.SnowFlakes.get(type)){ + SnowFlake.SnowFlakes.set(type,new Map()); + } + const snowflake=SnowFlake.SnowFlakes.get(type).get(id); + if(snowflake){ + return snowflake.deref(); + } + { + const snowflake=new SnowFlake(id,undefined); + + SnowFlake.SnowFlakes.get(type).set(id,new WeakRef(snowflake)); + SnowFlake.FinalizationRegistry.register(snowflake,id); + + return snowflake; + } + } + getUnixTime():number{ + return Number((BigInt(this.id)>>22n)+1420070400000n); + } + toString(){ + return this.id; + } + getObject():x{ + return this.obj; + } +} +export {SnowFlake}; diff --git a/webpage/style.css b/webpage/style.css index eb1a459..a5691dc 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -115,12 +115,17 @@ samp { } .infosection { + hr{ + width:100%; + } display: inline-block; background-color: var(--profile-info-bg); border-radius: 10%; padding: .3cm; width: calc(100% - .6cm); height: calc(100% - .75in); + display: flex; + flex-direction: column; } .profile { @@ -1390,3 +1395,12 @@ span { width:22px; height:22px; } +#typebox[contenteditable=false]{ + + cursor:not-allowed; + +} +#typebox[contenteditable=false]:before{ + content:'You can\'t chat here'; + color:color-mix(in hsl, var(--primary-bg),var(--primary-text)); +} \ No newline at end of file diff --git a/webpage/user.ts b/webpage/user.ts index d62433b..85c3993 100644 --- a/webpage/user.ts +++ b/webpage/user.ts @@ -4,12 +4,13 @@ import {MarkDown} from "./markdown.js"; import {Contextmenu} from "./contextmenu.js"; import {Localuser} from "./localuser.js"; import {Guild} from "./guild.js"; +import { SnowFlake } from "./snowflake.js"; class User{ static userids={}; owner:Localuser; hypotheticalpfp:boolean; - id:string; + id:SnowFlake; avatar:string; username:string; bio:MarkDown; @@ -19,13 +20,13 @@ class User{ static contextmenu:Contextmenu=new Contextmenu("User Menu"); static setUpContextMenu(){ this.contextmenu.addbutton("Copy user id",function(){ - navigator.clipboard.writeText(this.id); + navigator.clipboard.writeText(this.id.id); }); this.contextmenu.addbutton("Message user",function(){ fetch(this.info.api.toString()+"/v9/users/@me/channels", {method:"POST", - body:JSON.stringify({"recipients":[this.id]}), - headers: this.headers + body:JSON.stringify({"recipients":[this.id.id]}), + headers: this.localuser.headers }); }) } @@ -53,6 +54,10 @@ class User{ this.bio=new MarkDown(userjson[thing],this.localuser); continue; } + if(thing === "id"){ + this.id=new SnowFlake(userjson[thing],this); + continue; + } this[thing]=userjson[thing]; } this.hypotheticalpfp=false; @@ -67,7 +72,7 @@ class User{ const pfp=document.createElement('img'); pfp.src=this.getpfpsrc(); pfp.classList.add("pfp"); - pfp.classList.add("userid:"+this.id); + pfp.classList.add("userid:"+this.id.id); return pfp; } userupdate(json){ @@ -77,7 +82,7 @@ class User{ } } bind(html:HTMLElement,guild:Guild=null){ - if(guild&&guild.id!=="@me"){ + if(guild&&guild.id.id!=="@me"){ Member.resolve(this,guild).then(_=>{ _.bind(html); }).catch(_=>{ @@ -98,7 +103,7 @@ class User{ this.hypotheticalpfp=false; const src=this.getpfpsrc(); console.log(src) - for(const thing of document.getElementsByClassName("userid:"+this.id)){ + for(const thing of document.getElementsByClassName("userid:"+this.id.id)){ (thing as HTMLImageElement).src=src; } } @@ -107,7 +112,7 @@ class User{ return this.avatar; } if(this.avatar!=null){ - return this.info.cdn.toString()+"avatars/"+this.id+"/"+this.avatar+".png"; + return this.info.cdn.toString()+"avatars/"+this.id.id+"/"+this.avatar+".png"; }else{ return this.info.cdn.toString()+"embed/avatars/3.png"; }