get invite embeds working

This commit is contained in:
MathMan05 2024-09-06 15:43:11 -05:00
parent 7915032462
commit 1502dbec17
8 changed files with 500 additions and 46 deletions

View file

@ -1,5 +1,7 @@
import { Dialog } from "./dialog.js";
import { MarkDown } from "./markdown.js";
import { getapiurls, getInstances } from "./login.js";
import { Guild } from "./guild.js";
class Embed {
type;
owner;
@ -8,8 +10,40 @@ class Embed {
this.type = this.getType(json);
this.owner = owner;
this.json = json;
console.log(this);
}
getType(json) {
const instances = getInstances();
if (instances && json.type === "link" && json.url && URL.canParse(json.url)) {
const Url = new URL(json.url);
for (const instance of instances) {
if (instance.url && URL.canParse(instance.url)) {
const IUrl = new URL(instance.url);
const params = new URLSearchParams(Url.search);
let host;
if (params.has("instance")) {
const url = params.get("instance");
if (URL.canParse(url)) {
host = new URL(url).host;
}
else {
host = Url.host;
}
}
else {
host = Url.host;
}
if (IUrl.host === host) {
const code = Url.pathname.split("/")[Url.pathname.split("/").length - 1];
json.invite = {
url: instance.url,
code
};
return "invite";
}
}
}
}
return json.type || "rich";
}
generateHTML() {
@ -18,6 +52,8 @@ class Embed {
return this.generateRich();
case "image":
return this.generateImage();
case "invite":
return this.generateInvite();
case "link":
return this.generateLink();
case "video":
@ -185,6 +221,105 @@ class Embed {
table.append(bottomtr);
return table;
}
invcache;
generateInvite() {
if (this.invcache && (!this.json.invite || !this.localuser)) {
return this.generateLink();
}
const div = document.createElement("div");
div.classList.add("embed", "inviteEmbed", "flexttb");
const json1 = this.json.invite;
(async () => {
let json;
let info;
if (!this.invcache) {
if (!json1) {
div.append(this.generateLink());
return;
}
const tempinfo = await getapiurls(json1.url);
;
if (!tempinfo) {
div.append(this.generateLink());
return;
}
info = tempinfo;
const res = await fetch(info.api + "/invites/" + json1.code);
if (!res.ok) {
div.append(this.generateLink());
}
json = await res.json();
this.invcache = [json, info];
}
else {
[json, info] = this.invcache;
}
if (!json) {
div.append(this.generateLink());
return;
}
if (json.guild.banner) {
const banner = document.createElement("img");
banner.src = this.localuser.info.cdn + "/icons/" + json.guild.id + "/" + json.guild.banner + ".png?size=256";
banner.classList.add("banner");
div.append(banner);
}
const guild = json.guild;
guild.info = info;
const icon = Guild.generateGuildIcon(guild);
const iconrow = document.createElement("div");
iconrow.classList.add("flexltr", "flexstart");
iconrow.append(icon);
{
const guildinfo = document.createElement("div");
guildinfo.classList.add("flexttb", "invguildinfo");
const name = document.createElement("b");
name.textContent = guild.name;
guildinfo.append(name);
const members = document.createElement("span");
members.innerText = "#" + json.channel.name + " • Members: " + guild.member_count;
guildinfo.append(members);
members.classList.add("subtext");
iconrow.append(guildinfo);
}
div.append(iconrow);
const h2 = document.createElement("h2");
h2.textContent = `You've been invited by ${json.inviter.username}`;
div.append(h2);
const button = document.createElement("button");
button.textContent = "Accept";
if (this.localuser.info.api.startsWith(info.api)) {
if (this.localuser.guildids.has(guild.id)) {
button.textContent = "Already joined";
button.disabled = true;
}
}
button.classList.add("acceptinvbutton");
div.append(button);
button.onclick = _ => {
if (this.localuser.info.api.startsWith(info.api)) {
fetch(this.localuser.info.api + "/invites/" + json.code, {
method: "POST",
headers: this.localuser.headers,
}).then(r => r.json()).then(_ => {
if (_.message) {
alert(_.message);
}
});
}
else {
if (this.json.invite) {
const params = new URLSearchParams("");
params.set("instance", this.json.invite.url);
const encoded = params.toString();
const url = `${location.origin}/invite/${this.json.invite.code}?${encoded}`;
window.open(url, "_blank");
}
}
};
})();
return div;
}
generateArticle() {
const colordiv = document.createElement("div");
colordiv.style.backgroundColor = "#000000";

View file

@ -264,39 +264,62 @@ class Guild extends SnowFlake {
return a.position - b.position;
});
}
generateGuildIcon() {
static generateGuildIcon(guild) {
const divy = document.createElement("div");
divy.classList.add("servernoti");
const noti = document.createElement("div");
noti.classList.add("unread");
divy.append(noti);
this.localuser.guildhtml.set(this.id, divy);
if (this.properties.icon != null) {
if (guild instanceof Guild) {
guild.localuser.guildhtml.set(guild.id, divy);
}
let icon;
if (guild instanceof Guild) {
icon = guild.properties.icon;
}
else {
icon = guild.icon;
}
if (icon !== null) {
const img = document.createElement("img");
img.classList.add("pfp", "servericon");
img.src = this.info.cdn + "/icons/" + this.properties.id + "/" + this.properties.icon + ".png";
img.src = guild.info.cdn + "/icons/" + guild.id + "/" + icon + ".png";
divy.appendChild(img);
img.onclick = () => {
console.log(this.loadGuild);
this.loadGuild();
this.loadChannel();
};
Guild.contextmenu.bindContextmenu(img, this, undefined);
if (guild instanceof Guild) {
img.onclick = () => {
console.log(guild.loadGuild);
guild.loadGuild();
guild.loadChannel();
};
Guild.contextmenu.bindContextmenu(img, guild, undefined);
}
}
else {
const div = document.createElement("div");
const build = this.properties.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "");
let name;
if (guild instanceof Guild) {
name = guild.properties.name;
}
else {
name = guild.name;
}
const build = name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "");
div.textContent = build;
div.classList.add("blankserver", "servericon");
divy.appendChild(div);
div.onclick = () => {
this.loadGuild();
this.loadChannel();
};
Guild.contextmenu.bindContextmenu(div, this, undefined);
if (guild instanceof Guild) {
div.onclick = () => {
guild.loadGuild();
guild.loadChannel();
};
Guild.contextmenu.bindContextmenu(div, guild, undefined);
}
}
return divy;
}
generateGuildIcon() {
return Guild.generateGuildIcon(this);
}
confirmDelete() {
let confirmname = "";
const full = new Dialog([

View file

@ -8,6 +8,7 @@ function setTheme() {
}
document.body.className = name + "-theme";
}
let instances;
setTheme();
function getBulkUsers() {
const json = getBulkInfo();
@ -418,8 +419,12 @@ trimswitcher();
export { mobile, getBulkUsers, getBulkInfo, setTheme, Specialuser, getapiurls, adduser };
const datalist = document.getElementById("instances");
console.warn(datalist);
if (datalist) {
fetch("/instances.json").then(_ => _.json()).then((json) => {
export function getInstances() {
return instances;
}
fetch("/instances.json").then(_ => _.json()).then((json) => {
instances = json;
if (datalist) {
console.warn(json);
if (instancein && instancein.value === "") {
instancein.value = json[0].name;
@ -452,5 +457,5 @@ if (datalist) {
datalist.append(option);
}
checkInstance("");
});
}
}
});

View file

@ -1,7 +1,9 @@
import{Dialog}from"./dialog.js";
import{Message}from"./message.js";
import{MarkDown}from"./markdown.js";
import{ embedjson }from"./jsontypes.js";
import{ embedjson,guildjson, invitejson }from"./jsontypes.js";
import { getapiurls, getInstances } from "./login.js";
import { Guild } from "./guild.js";
class Embed{
type:string;
@ -11,8 +13,38 @@ class Embed{
this.type=this.getType(json);
this.owner=owner;
this.json=json;
console.log(this);
}
getType(json:embedjson){
const instances=getInstances();
if(instances&&json.type==="link"&&json.url&&URL.canParse(json.url)){
const Url=new URL(json.url);
for(const instance of instances){
if(instance.url&&URL.canParse(instance.url)){
const IUrl=new URL(instance.url);
const params=new URLSearchParams(Url.search);
let host:string;
if(params.has("instance")){
const url=params.get("instance") as string;
if(URL.canParse(url)){
host=new URL(url).host;
}else{
host=Url.host;
}
}else{
host=Url.host;
}
if(IUrl.host===host){
const code=Url.pathname.split("/")[Url.pathname.split("/").length-1];
json.invite={
url:instance.url,
code
}
return "invite";
}
}
}
}
return json.type||"rich";
}
generateHTML(){
@ -21,6 +53,8 @@ class Embed{
return this.generateRich();
case"image":
return this.generateImage();
case"invite":
return this.generateInvite();
case"link":
return this.generateLink();
case "video":
@ -192,6 +226,106 @@ class Embed{
table.append(bottomtr);
return table;
}
invcache:[invitejson,{cdn:string,api:string}]|undefined;
generateInvite(){
if(this.invcache&&(!this.json.invite||!this.localuser)){
return this.generateLink();
}
const div=document.createElement("div");
div.classList.add("embed","inviteEmbed","flexttb");
const json1=this.json.invite;
(async ()=>{
let json:invitejson;
let info:{cdn:string,api:string};
if(!this.invcache){
if(!json1){
div.append(this.generateLink());
return;
}
const tempinfo=await getapiurls(json1.url);;
if(!tempinfo){
div.append(this.generateLink());
return;
}
info=tempinfo;
const res=await fetch(info.api+"/invites/"+json1.code)
if(!res.ok){
div.append(this.generateLink());
}
json=await res.json() as invitejson;
this.invcache=[json,info];
}else{
[json,info]=this.invcache;
}
if(!json){
div.append(this.generateLink());
return;
}
if(json.guild.banner){
const banner=document.createElement("img");
banner.src=this.localuser.info.cdn+"/icons/"+json.guild.id+"/"+json.guild.banner+".png?size=256";
banner.classList.add("banner");
div.append(banner);
}
const guild:invitejson["guild"] & {info?:{cdn:string}}=json.guild;
guild.info=info;
const icon=Guild.generateGuildIcon(guild as invitejson["guild"] & {info:{cdn:string}})
const iconrow=document.createElement("div");
iconrow.classList.add("flexltr","flexstart");
iconrow.append(icon);
{
const guildinfo=document.createElement("div");
guildinfo.classList.add("flexttb","invguildinfo");
const name=document.createElement("b");
name.textContent=guild.name;
guildinfo.append(name);
const members=document.createElement("span");
members.innerText="#"+json.channel.name+" • Members: "+guild.member_count
guildinfo.append(members);
members.classList.add("subtext");
iconrow.append(guildinfo);
}
div.append(iconrow);
const h2=document.createElement("h2");
h2.textContent=`You've been invited by ${json.inviter.username}`;
div.append(h2);
const button=document.createElement("button");
button.textContent="Accept";
if(this.localuser.info.api.startsWith(info.api)){
if(this.localuser.guildids.has(guild.id)){
button.textContent="Already joined";
button.disabled=true;
}
}
button.classList.add("acceptinvbutton");
div.append(button);
button.onclick=_=>{
if(this.localuser.info.api.startsWith(info.api)){
fetch(this.localuser.info.api+"/invites/"+json.code,{
method: "POST",
headers: this.localuser.headers,
}).then(r=>r.json()).then(_=>{
if(_.message){
alert(_.message);
}
});
}else{
if(this.json.invite){
const params=new URLSearchParams("");
params.set("instance",this.json.invite.url);
const encoded=params.toString();
const url=`${location.origin}/invite/${this.json.invite.code}?${encoded}`;
window.open(url,"_blank");
}
}
}
})()
return div;
}
generateArticle(){
const colordiv=document.createElement("div");
colordiv.style.backgroundColor="#000000";

View file

@ -7,7 +7,7 @@ import{Member}from"./member.js";
import{Settings}from"./settings.js";
import{Permissions}from"./permissions.js";
import{ SnowFlake }from"./snowflake.js";
import{ channeljson, guildjson, emojijson, memberjson }from"./jsontypes.js";
import{ channeljson, guildjson, emojijson, memberjson, invitejson }from"./jsontypes.js";
import{ User }from"./user.js";
class Guild extends SnowFlake{
@ -274,39 +274,60 @@ class Guild extends SnowFlake{
return a.position-b.position;
});
}
generateGuildIcon(){
static generateGuildIcon(guild:Guild|(invitejson["guild"] & {info:{cdn:string}})){
const divy=document.createElement("div");
divy.classList.add("servernoti");
const noti=document.createElement("div");
noti.classList.add("unread");
divy.append(noti);
this.localuser.guildhtml.set(this.id,divy);
if(this.properties.icon!=null){
if(guild instanceof Guild){
guild.localuser.guildhtml.set(guild.id,divy);
}
let icon:string|null
if(guild instanceof Guild){
icon=guild.properties.icon;
}else{
icon=guild.icon;
}
if(icon!==null){
const img=document.createElement("img");
img.classList.add("pfp","servericon");
img.src=this.info.cdn+"/icons/"+this.properties.id+"/"+this.properties.icon+".png";
img.src=guild.info.cdn+"/icons/"+guild.id+"/"+icon+".png";
divy.appendChild(img);
img.onclick=()=>{
console.log(this.loadGuild);
this.loadGuild();
this.loadChannel();
};
Guild.contextmenu.bindContextmenu(img,this,undefined);
if(guild instanceof Guild){
img.onclick=()=>{
console.log(guild.loadGuild);
guild.loadGuild();
guild.loadChannel();
};
Guild.contextmenu.bindContextmenu(img,guild,undefined);
}
}else{
const div=document.createElement("div");
const build=this.properties.name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
let name:string
if(guild instanceof Guild){
name=guild.properties.name;
}else{
name=guild.name;
}
const build=name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
div.textContent=build;
div.classList.add("blankserver","servericon");
divy.appendChild(div);
div.onclick=()=>{
this.loadGuild();
this.loadChannel();
};
Guild.contextmenu.bindContextmenu(div,this,undefined);
if(guild instanceof Guild){
div.onclick=()=>{
guild.loadGuild();
guild.loadChannel();
};
Guild.contextmenu.bindContextmenu(div,guild,undefined);
}
}
return divy;
}
generateGuildIcon(){
return Guild.generateGuildIcon(this);
}
confirmDelete(){
let confirmname="";
const full= new Dialog([

View file

@ -333,13 +333,79 @@ type embedjson={
provider:{
name:string,
},
video:{
video?:{
url: string,
width?: number|null,
height?: number|null,
proxy_url?: string
},
invite?:{
url:string,
code:string
}
}
type invitejson={
code: string,
temporary: boolean,
uses: number,
max_use: number,
max_age: number,
created_at: string,
expires_at: string,
guild_id: string,
channel_id: string,
inviter_id: string,
target_user_id: string|null,
target_user_type: string|null,
vanity_url: string|null,
flags: number,
guild: {
id: string,
afk_channel_id: string|null,
afk_timeout: number,
banner: string|null,
default_message_notifications: number,
description: string|null,
discovery_splash: string|null,
explicit_content_filter: number,
features: [],
primary_category_id: string|null,
icon: string|null,
large: boolean,
max_members: number,
max_presences: number,
max_video_channel_users: number,
member_count: number,
presence_count: number,
template_id: string|null,
mfa_level: number,
name: string,
owner_id: string,
preferred_locale: string,
premium_subscription_count: number,
premium_tier: number,
public_updates_channel_id: string|null,
rules_channel_id: string|null,
region: string|null,
splash: string|null,
system_channel_id: string|null,
system_channel_flags: number,
verification_level: number,
welcome_screen: {
enabled: boolean,
description: string,
welcome_channels: string[]
},
widget_channel_id: string|null,
widget_enabled: boolean,
nsfw_level: number,
nsfw: boolean,
parent: string|null,
premium_progress_bar_enabled: boolean
},
channel: channeljson,
inviter: userjson
}
type presencejson={
status: string,
since: number|null,
@ -426,4 +492,4 @@ type memberChunk={
chunk_count: number,
not_found: string[]
}
export{readyjson,dirrectjson,channeljson,guildjson,rolesjson,userjson,memberjson,mainuserjson,messagejson,filejson,embedjson,emojijson,presencejson,wsjson,messageCreateJson,memberChunk};
export{readyjson,dirrectjson,channeljson,guildjson,rolesjson,userjson,memberjson,mainuserjson,messagejson,filejson,embedjson,emojijson,presencejson,wsjson,messageCreateJson,memberChunk,invitejson};

View file

@ -10,6 +10,11 @@ function setTheme(){
}
document.body.className=name+"-theme";
}
let instances:{name:string,description?:string,descriptionLong?:string,image?:string,url?:string,display?:boolean,online?:boolean,
uptime:{alltime:number,daytime:number,weektime:number},
urls:{wellknown:string,api:string,cdn:string,gateway:string,login?:string}}[]|null;
setTheme();
function getBulkUsers(){
const json=getBulkInfo();
@ -407,8 +412,15 @@ export{mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser,getapiurls,adduser}
const datalist=document.getElementById("instances");
console.warn(datalist);
if(datalist){
fetch("/instances.json").then(_=>_.json()).then((json:{name:string,online:boolean,description?:string,src?:string,url?:string,display?:boolean,urls:{wellknown:string,api:string,cdn:string,gateway:string,login?:string}}[])=>{
export function getInstances(){
return instances;
}
fetch("/instances.json").then(_=>_.json()).then((json:{name:string,description?:string,descriptionLong?:string,image?:string,url?:string,display?:boolean,online?:boolean,
uptime:{alltime:number,daytime:number,weektime:number},
urls:{wellknown:string,api:string,cdn:string,gateway:string,login?:string}}[])=>{
instances=json;
if(datalist){
console.warn(json);
if(instancein&&instancein.value===""){
instancein.value=json[0].name;
@ -438,5 +450,5 @@ if(datalist){
datalist.append(option);
}
checkInstance("");
});
}
}
});

View file

@ -1478,7 +1478,6 @@ span {
width: 100%;
flex-direction: column;
max-height:100in;
justify-content: flex-end;
}
#connection-container, #app-list-container {
@ -1876,7 +1875,6 @@ form div{
}
.banner{
position:absolute;
z-index: 0;
top:0;
left:0;
width:100%;
@ -2132,3 +2130,63 @@ form div{
background:var(--message-bg-hover);
}
}
.acceptinvbutton{
background:var(--green);
width: 95%;
text-align:center;
font-size:.25in;
box-sizing: border-box;
margin: .1in;
}
.acceptinvbutton:hover{
background:color-mix(in hsl,var(--green) 80%,var(--black));
}
.acceptinvbutton:disabled:hover{
background:color-mix(in hsl,var(--green) 80%,var(--black));
}
.acceptinvbutton:disabled{
background:color-mix(in hsl,var(--green) 80%,var(--black));
}
.inviteEmbed{
border: solid .035in var(--black);
gap: .075in;
min-width:4in;
max-width:6in;
min-height: 1.5in;
display: flex;
align-items: center;
position: relative;
.banner{
height: .5in;
position: relative;
}
;
padding: 0in;
}
.inviteEmbed .flexltr {
display: flex;
flex-wrap: nowrap;
}
.inviteEmbed .invguildinfo{
display:flex;
justify-content: center;
margin-left: .15in;
background: var(--channels-bg);
border: solid .03in var(--black);
border-radius: .1in;
padding: .07in;
flex-grow: 1;
height: fit-content;
backdrop-filter: blur(5px);
margin-right: .15in;
}
.subtext{
color:color-mix(in srgb, var(--black),var(--primary-text) 65%);
}
.flexstart{
align-self:start;
z-index: 1;
margin-left: .04in;
margin-top: .04in;
width: 100%;
}