diff --git a/src/webpage/audio.ts b/src/webpage/audio/audio.ts similarity index 90% rename from src/webpage/audio.ts rename to src/webpage/audio/audio.ts index 13b90ce..cdc412f 100644 --- a/src/webpage/audio.ts +++ b/src/webpage/audio/audio.ts @@ -1,5 +1,3 @@ -import{ getBulkInfo }from"./login.js"; - class AVoice{ audioCtx: AudioContext; info: { wave: string | Function; freq: number }; @@ -72,10 +70,6 @@ class AVoice{ return(_t: number, _freq: number)=>{ return Math.random() * 2 - 1; }; - case"noise": - return(_t: number, _freq: number)=>{ - return 0; - }; } return new Function(); } @@ -183,14 +177,5 @@ class AVoice{ static get sounds(){ return["three", "zip", "square", "beep"]; } - static setNotificationSound(sound: string){ - const userinfos = getBulkInfo(); - userinfos.preferences.notisound = sound; - localStorage.setItem("userinfos", JSON.stringify(userinfos)); - } - static getNotificationSound(){ - const userinfos = getBulkInfo(); - return userinfos.preferences.notisound; - } } export{ AVoice as AVoice }; diff --git a/src/webpage/audio/index.html b/src/webpage/audio/index.html new file mode 100644 index 0000000..429291e --- /dev/null +++ b/src/webpage/audio/index.html @@ -0,0 +1,22 @@ + + + + + + + Jank Audio + + + + + + + + + + +

Place holder text

+ + + + diff --git a/src/webpage/audio/page.ts b/src/webpage/audio/page.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/webpage/channel.ts b/src/webpage/channel.ts index 9493308..42717de 100644 --- a/src/webpage/channel.ts +++ b/src/webpage/channel.ts @@ -1,6 +1,6 @@ "use strict"; import{ Message }from"./message.js"; -import{ AVoice }from"./audio.js"; +import{ AVoice }from"./audio/audio.js"; import{ Contextmenu }from"./contextmenu.js"; import{ Guild }from"./guild.js"; import{ Localuser }from"./localuser.js"; @@ -1403,7 +1403,7 @@ class Channel extends SnowFlake{ ); } notify(message: Message, deep = 0){ - AVoice.noises(AVoice.getNotificationSound()); + AVoice.noises(this.localuser.getNotificationSound()); if(!("Notification" in window)){ }else if(Notification.permission === "granted"){ let noticontent: string | undefined | null = message.content.textContent; diff --git a/src/webpage/contextmenu.ts b/src/webpage/contextmenu.ts index 8d6eac3..794fd88 100644 --- a/src/webpage/contextmenu.ts +++ b/src/webpage/contextmenu.ts @@ -1,4 +1,4 @@ -import{ iOS }from"./login.js"; +import{ iOS }from"./utils/utils.js"; class Contextmenu{ static currentmenu: HTMLElement | ""; name: string; diff --git a/src/webpage/embed.ts b/src/webpage/embed.ts index e84105d..73bad4a 100644 --- a/src/webpage/embed.ts +++ b/src/webpage/embed.ts @@ -1,7 +1,7 @@ import{ Message }from"./message.js"; import{ MarkDown }from"./markdown.js"; import{ embedjson, invitejson }from"./jsontypes.js"; -import{ getapiurls, getInstances }from"./login.js"; +import{ getapiurls, getInstances }from"./utils/utils.js"; import{ Guild }from"./guild.js"; import { I18n } from "./i18n.js"; import { ImagesDisplay } from "./disimg.js"; diff --git a/src/webpage/emoji.ts b/src/webpage/emoji.ts index 03b1d42..b6e04e8 100644 --- a/src/webpage/emoji.ts +++ b/src/webpage/emoji.ts @@ -2,6 +2,7 @@ import{ Contextmenu }from"./contextmenu.js"; import{ Guild }from"./guild.js"; import { emojijson } from "./jsontypes.js"; import{ Localuser }from"./localuser.js"; +import { BinRead } from "./utils/binaryUtils.js"; //I need to recompile the emoji format for translation class Emoji{ @@ -64,51 +65,24 @@ class Emoji{ } } 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; i < length; i++){ - array[i] = read8(); - } - //console.log(array); - return new TextDecoder("utf8").decode(array.buffer as ArrayBuffer); - } - const build: { name: string; emojis: { name: string; emoji: string }[] }[] = - []; - let cats = read16(); + const reader=new BinRead(buffer) + const build: { name: string; emojis: { name: string; emoji: string }[] }[] = []; + let cats = reader.read16(); for(; cats !== 0; cats--){ - const name = readString16(); + const name = reader.readString16(); const emojis: { name: string; skin_tone_support: boolean; emoji: string; }[] = []; - let emojinumber = read16(); + let emojinumber = reader.read16(); for(; emojinumber !== 0; emojinumber--){ //console.log(emojis); - const name = readString8(); - const len = read8(); + const name = reader.readString8(); + const len = reader.read8(); const skin_tone_support = len > 127; - const emoji = readStringNo(len - Number(skin_tone_support) * 128); + const emoji = reader.readStringNo(len - Number(skin_tone_support) * 128); emojis.push({ name, skin_tone_support, diff --git a/src/webpage/home.ts b/src/webpage/home.ts index a04772b..20cac87 100644 --- a/src/webpage/home.ts +++ b/src/webpage/home.ts @@ -1,5 +1,5 @@ import { I18n } from "./i18n.js"; -import{ mobile }from"./login.js"; +import{ mobile }from"./utils/utils.js"; console.log(mobile); const serverbox = document.getElementById("instancebox") as HTMLDivElement; diff --git a/src/webpage/index.ts b/src/webpage/index.ts index 6499fcb..b7fa3bb 100644 --- a/src/webpage/index.ts +++ b/src/webpage/index.ts @@ -1,6 +1,7 @@ import{ Localuser }from"./localuser.js"; import{ Contextmenu }from"./contextmenu.js"; -import{ mobile, getBulkUsers, setTheme, Specialuser }from"./login.js"; +import{ mobile }from"./utils/utils.js"; +import { getBulkUsers, setTheme, Specialuser } from "./utils/utils.js"; import{ MarkDown }from"./markdown.js"; import{ Message }from"./message.js"; import{File}from"./file.js"; diff --git a/src/webpage/invite.ts b/src/webpage/invite.ts index 15ebeca..fcc053b 100644 --- a/src/webpage/invite.ts +++ b/src/webpage/invite.ts @@ -1,5 +1,6 @@ import { I18n } from "./i18n.js"; -import{ getBulkUsers, Specialuser, getapiurls }from"./login.js"; +import{ getapiurls }from"./utils/utils.js"; +import { getBulkUsers, Specialuser } from "./utils/utils.js"; (async ()=>{ const users = getBulkUsers(); diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index d27d44b..b7b4087 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -1,9 +1,10 @@ import{ Guild }from"./guild.js"; import{ Channel }from"./channel.js"; import{ Direct }from"./direct.js"; -import{ AVoice }from"./audio.js"; +import{ AVoice }from"./audio/audio.js"; import{ User }from"./user.js"; -import{ getapiurls, getBulkInfo, setTheme, Specialuser, SW }from"./login.js"; +import{ getapiurls, SW }from"./utils/utils.js"; +import { getBulkInfo, setTheme, Specialuser } from "./utils/utils.js"; import{channeljson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,presencejson,readyjson,startTypingjson,wsjson,}from"./jsontypes.js"; import{ Member }from"./member.js"; import{ Dialog, Form, FormError, Options, Settings }from"./settings.js"; @@ -1237,10 +1238,10 @@ class Localuser{ .addSelect( I18n.getTranslation("localuser.notisound"), _=>{ - AVoice.setNotificationSound(sounds[_]); + this.setNotificationSound(sounds[_]); }, sounds, - { defaultIndex: sounds.indexOf(AVoice.getNotificationSound()) } + { defaultIndex: sounds.indexOf(this.getNotificationSound()) } ) .watchForChange(_=>{ AVoice.noises(sounds[_]); @@ -2121,5 +2122,14 @@ class Localuser{ dialog.options.addText(I18n.getTranslation("instanceStats.members",json.counts.members)); dialog.show(); } + setNotificationSound(sound: string){ + const userinfos = getBulkInfo(); + userinfos.preferences.notisound = sound; + localStorage.setItem("userinfos", JSON.stringify(userinfos)); + } + getNotificationSound(){ + const userinfos = getBulkInfo(); + return userinfos.preferences.notisound; + } } export{ Localuser }; diff --git a/src/webpage/login.ts b/src/webpage/login.ts index a85a36a..099b67e 100644 --- a/src/webpage/login.ts +++ b/src/webpage/login.ts @@ -1,95 +1,12 @@ +import { getBulkInfo, Specialuser } from "./utils/utils.js"; import { I18n } from "./i18n.js"; import { Dialog, FormError } from "./settings.js"; +import { checkInstance } from "./utils/utils.js"; -const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); -const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent); -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; -const datalist = document.getElementById("instances"); -console.warn(datalist); -const instancefetch=fetch("/instances.json") - .then(res=>res.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; - } - for(const instance of json){ - if(instance.display === false){ - continue; - } - const option = document.createElement("option"); - option.disabled = !instance.online; - option.value = instance.name; - if(instance.url){ - stringURLMap.set(option.value, instance.url); - if(instance.urls){ - stringURLsMap.set(instance.url, instance.urls); - } - }else if(instance.urls){ - stringURLsMap.set(option.value, instance.urls); - }else{ - option.disabled = true; - } - if(instance.description){ - option.label = instance.description; - }else{ - option.label = instance.name; - } - datalist.append(option); - } - checkInstance(""); - } - } - ); -setTheme(); -await I18n.done -function setTheme(){ - let name = localStorage.getItem("theme"); - if(!name){ - localStorage.setItem("theme", "Dark"); - name = "Dark"; - } - document.body.className = name + "-theme"; -} + +await I18n.done; + (async ()=>{ @@ -108,13 +25,7 @@ function setTheme(){ } })() -function getBulkUsers(){ - const json = getBulkInfo(); - for(const thing in json.users){ - json.users[thing] = new Specialuser(json.users[thing]); - } - return json; -} + function trimswitcher(){ const json = getBulkInfo(); const map = new Map(); @@ -148,133 +59,8 @@ function trimswitcher(){ console.log(json); } -function getBulkInfo(){ - return JSON.parse(localStorage.getItem("userinfos") as string); -} -function setDefaults(){ - let userinfos = getBulkInfo(); - if(!userinfos){ - localStorage.setItem( - "userinfos", - JSON.stringify({ - currentuser: null, - users: {}, - preferences: { - theme: "Dark", - notifications: false, - notisound: "three", - }, - }) - ); - userinfos = getBulkInfo(); - } - if(userinfos.users === undefined){ - userinfos.users = {}; - } - if(userinfos.accent_color === undefined){ - userinfos.accent_color = "#3096f7"; - } - document.documentElement.style.setProperty( - "--accent-color", - userinfos.accent_color - ); - if(userinfos.preferences === undefined){ - userinfos.preferences = { - theme: "Dark", - notifications: false, - notisound: "three", - }; - } - if(userinfos.preferences && userinfos.preferences.notisound === undefined){ - console.warn("uhoh") - userinfos.preferences.notisound = "three"; - } - localStorage.setItem("userinfos", JSON.stringify(userinfos)); -} -setDefaults(); -class Specialuser{ - serverurls: { - api: string; - cdn: string; - gateway: string; - wellknown: string; - login: string; - }; - email: string; - token: string; - loggedin; - json; - constructor(json: any){ - if(json instanceof Specialuser){ - console.error("specialuser can't construct from another specialuser"); - } - this.serverurls = json.serverurls; - let apistring = new URL(json.serverurls.api).toString(); - apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9"; - this.serverurls.api = apistring; - this.serverurls.cdn = new URL(json.serverurls.cdn) - .toString() - .replace(/\/$/, ""); - this.serverurls.gateway = new URL(json.serverurls.gateway) - .toString() - .replace(/\/$/, ""); - this.serverurls.wellknown = new URL(json.serverurls.wellknown) - .toString() - .replace(/\/$/, ""); - this.serverurls.login = new URL(json.serverurls.login) - .toString() - .replace(/\/$/, ""); - this.email = json.email; - this.token = json.token; - this.loggedin = json.loggedin; - this.json = json; - this.json.localuserStore ??= {}; - if(!this.serverurls || !this.email || !this.token){ - console.error( - "There are fundamentally missing pieces of info missing from this user" - ); - } - } - set pfpsrc(e){ - this.json.pfpsrc = e; - this.updateLocal(); - } - get pfpsrc(){ - return this.json.pfpsrc; - } - set username(e){ - this.json.username = e; - this.updateLocal(); - } - get username(){ - return this.json.username; - } - set localuserStore(e){ - this.json.localuserStore = e; - this.updateLocal(); - } - get localuserStore(){ - return this.json.localuserStore; - } - set id(e){ - this.json.id = e; - this.updateLocal(); - } - get id(){ - return this.json.id; - } - get uid(){ - return this.email + this.serverurls.wellknown; - } - toJSON(){ - return this.json; - } - updateLocal(){ - const info = getBulkInfo(); - info.users[this.uid] = this.toJSON(); - localStorage.setItem("userinfos", JSON.stringify(info)); - } -} + + function adduser(user: typeof Specialuser.prototype.json){ user = new Specialuser(user); const info = getBulkInfo(); @@ -286,167 +72,8 @@ function adduser(user: typeof Specialuser.prototype.json){ const instancein = document.getElementById("instancein") as HTMLInputElement; let timeout: ReturnType | string | number | undefined | null = null; // let instanceinfo; -const stringURLMap = new Map(); -const stringURLsMap = new Map< - string, - { - wellknown: string; - api: string; - cdn: string; - gateway: string; - login?: string; - } - >(); -async function getapiurls(str: string): Promise< - { - api: string; - cdn: string; - gateway: string; - wellknown: string; - login: string; - } - | false - >{ - function appendApi(str:string){ - return str.includes("api")?"" : (str.endsWith("/")? "api" : "/api"); - } - if(!URL.canParse(str)){ - const val = stringURLMap.get(str); - if(stringURLMap.size===0){ - await new Promise(res=>{ - setInterval(()=>{ - if(stringURLMap.size!==0){ - res(); - } - },100); - }); - } - if(val){ - str = val; - }else{ - const val = stringURLsMap.get(str); - if(val){ - const responce = await fetch( - val.api + (val.api.endsWith("/") ? "" : "/") + "ping" - ); - if(responce.ok){ - if(val.login){ - return val as { - wellknown: string; - api: string; - cdn: string; - gateway: string; - login: string; - }; - }else{ - val.login = val.api; - return val as { - wellknown: string; - api: string; - cdn: string; - gateway: string; - login: string; - }; - } - } - } - } - } - if(str.at(-1) !== "/"){ - str += "/"; - } - let api: string; - try{ - const info = await fetch(`${str}.well-known/spacebar`).then(x=>x.json() - ); - api = info.api; - }catch{ - api=str; - } - if(!URL.canParse(api)){ - return false; - } - const url = new URL(api); - try{ - const info = await fetch( - `${api}${ - url.pathname.includes("api") ? "" : "api" - }/policies/instance/domains` - ).then(x=>x.json()); - const apiurl = new URL(info.apiEndpoint); - return{ - api: info.apiEndpoint+appendApi(apiurl.pathname), - gateway: info.gateway, - cdn: info.cdn, - wellknown: str, - login: info.apiEndpoint+appendApi(apiurl.pathname), - }; - }catch{ - const val = stringURLsMap.get(str); - if(val){ - const responce = await fetch( - val.api + (val.api.endsWith("/") ? "" : "/") + "ping" - ); - if(responce.ok){ - if(val.login){ - return val as { - wellknown: string; - api: string; - cdn: string; - gateway: string; - login: string; - }; - }else{ - val.login = val.api; - return val as { - wellknown: string; - api: string; - cdn: string; - gateway: string; - login: string; - }; - } - } - } - return false; - } -} -async function checkInstance(instance?: string){ - await instancefetch; - const verify = document.getElementById("verify"); - try{ - verify!.textContent = I18n.getTranslation("login.checking"); - const instanceValue = instance || (instancein as HTMLInputElement).value; - const instanceinfo = (await getapiurls(instanceValue)) as { - wellknown: string; - api: string; - cdn: string; - gateway: string; - login: string; - value: string; - }; - if(instanceinfo){ - instanceinfo.value = instanceValue; - localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo)); - verify!.textContent = I18n.getTranslation("login.allGood"); - // @ts-ignore - if(checkInstance.alt){ - // @ts-ignore - checkInstance.alt(); - } - setTimeout((_: any)=>{ - console.log(verify!.textContent); - verify!.textContent = ""; - }, 3000); - }else{ - verify!.textContent = I18n.getTranslation("login.invalid"); - } - }catch{ - console.log("catch"); - verify!.textContent = I18n.getTranslation("login.invalid"); - } -} + if(instancein){ console.log(instancein); @@ -456,7 +83,7 @@ if(instancein){ if(timeout !== null && typeof timeout !== "string"){ clearTimeout(timeout); } - timeout = setTimeout(()=>checkInstance(), 1000); + timeout = setTimeout(()=>checkInstance((instancein as HTMLInputElement).value), 1000); }); if(localStorage.getItem("instanceinfo")){ const json = JSON.parse(localStorage.getItem("instanceinfo")!); @@ -597,51 +224,6 @@ if(document.getElementById("form")){ if(!localStorage.getItem("SWMode")){ localStorage.setItem("SWMode","true"); } -class SW{ - static worker:undefined|ServiceWorker; - static setMode(mode:"false"|"offlineOnly"|"true"){ - localStorage.setItem("SWMode",mode); - if(this.worker){ - this.worker.postMessage({data:mode,code:"setMode"}); - } - } - static checkUpdate(){ - if(this.worker){ - this.worker.postMessage({code:"CheckUpdate"}); - } - } - static forceClear(){ - if(this.worker){ - this.worker.postMessage({code:"ForceClear"}); - } - } -} -export {SW}; -if ("serviceWorker" in navigator){ - navigator.serviceWorker.register("/service.js", { - scope: "/", - }).then((registration) => { - let serviceWorker:ServiceWorker|undefined; - if (registration.installing) { - serviceWorker = registration.installing; - console.log("installing"); - } else if (registration.waiting) { - serviceWorker = registration.waiting; - console.log("waiting"); - } else if (registration.active) { - serviceWorker = registration.active; - console.log("active"); - } - SW.worker=serviceWorker; - SW.setMode(localStorage.getItem("SWMode") as "false"|"offlineOnly"|"true"); - if (serviceWorker) { - console.log(serviceWorker.state); - serviceWorker.addEventListener("statechange", (_) => { - console.log(serviceWorker.state); - }); - } - }) -} const switchurl = document.getElementById("switch") as HTMLAreaElement; if(switchurl){ @@ -653,22 +235,13 @@ if(switchurl){ checkInstance(""); } } -export{ checkInstance }; trimswitcher(); + export{ - mobile, - iOS, - getBulkUsers, - getBulkInfo, - setTheme, - Specialuser, - getapiurls, adduser, }; -export function getInstances(){ - return instances; -} + diff --git a/src/webpage/message.ts b/src/webpage/message.ts index 7a9a7ad..d13cc3c 100644 --- a/src/webpage/message.ts +++ b/src/webpage/message.ts @@ -10,7 +10,7 @@ import{ File }from"./file.js"; import{ SnowFlake }from"./snowflake.js"; import{ memberjson, messagejson }from"./jsontypes.js"; import{ Emoji }from"./emoji.js"; -import{ mobile }from"./login.js"; +import{ mobile }from"./utils/utils.js"; import { I18n } from "./i18n.js"; import { Hover } from "./hover.js"; import { Dialog } from "./settings.js"; diff --git a/src/webpage/oauth2/auth.ts b/src/webpage/oauth2/auth.ts index 2345f15..a7a5d41 100644 --- a/src/webpage/oauth2/auth.ts +++ b/src/webpage/oauth2/auth.ts @@ -1,5 +1,6 @@ import { I18n } from "../i18n.js"; -import{ getBulkUsers, Specialuser, getapiurls }from"../login.js"; +import{ getapiurls }from"../utils/utils.js"; +import { getBulkUsers, Specialuser } from "../utils/utils.js"; import { Permissions } from "../permissions.js"; type botjsonfetch={ guilds:{ diff --git a/src/webpage/register.ts b/src/webpage/register.ts index 7a9555c..bdba6ed 100644 --- a/src/webpage/register.ts +++ b/src/webpage/register.ts @@ -1,5 +1,6 @@ import { I18n } from "./i18n.js"; -import{ checkInstance, adduser }from"./login.js"; +import{ checkInstance }from"./utils/utils.js"; +import {adduser} from"./login.js"; import { MarkDown } from "./markdown.js"; await I18n.done const registerElement = document.getElementById("register"); diff --git a/src/webpage/utils/binaryUtils.ts b/src/webpage/utils/binaryUtils.ts new file mode 100644 index 0000000..322f192 --- /dev/null +++ b/src/webpage/utils/binaryUtils.ts @@ -0,0 +1,79 @@ +class BinRead{ + private i = 0; + private view:DataView; + constructor(buffer:ArrayBuffer){ + this.view=new DataView(buffer, 0) + } + read16(){ + const int = this.view.getUint16(this.i); + this.i += 2; + return int; + } + read8(){ + const int = this.view.getUint8(this.i); + this.i += 1; + return int; + } + readString8(){ + return this.readStringNo(this.read8()); + } + readString16(){ + return this.readStringNo(this.read16()); + } + readStringNo(length: number){ + const array = new Uint8Array(length); + for(let i = 0; i < length; i++){ + array[i] = this.read8(); + } + //console.log(array); + return new TextDecoder("utf8").decode(array.buffer as ArrayBuffer); + } +} + +class BinWrite{ + private view: DataView; + private buffer:ArrayBuffer; + private i=0; + constructor(maxSize:number=2**26){ + this.buffer=new ArrayBuffer(maxSize); + this.view=new DataView(this.buffer, 0); + } + write16(numb:number){ + this.view.setUint16(this.i,numb); + this.i+=2; + } + write8(numb:number){ + this.view.setUint8(this.i,numb); + this.i+=1; + } + writeString8(str:string){ + const encode=new TextEncoder().encode(str); + this.write8(encode.length); + for(const thing of encode){ + this.write8(thing); + } + } + writeString16(str:string){ + const encode=new TextEncoder().encode(str); + this.write16(encode.length); + for(const thing of encode){ + this.write8(thing); + } + } + writeStringNo(str:string){ + const encode=new TextEncoder().encode(str); + for(const thing of encode){ + this.write8(thing); + } + } + getBuffer(){ + const buf=new ArrayBuffer(this.i); + const ar1=new Uint8Array(buf); + const ar2=new Uint8Array(this.buffer); + for(let i in ar1){ + ar1[+i]=ar2[+i]; + } + return buf; + } +} +export {BinRead,BinWrite} diff --git a/src/webpage/utils/utils.ts b/src/webpage/utils/utils.ts new file mode 100644 index 0000000..abeb73f --- /dev/null +++ b/src/webpage/utils/utils.ts @@ -0,0 +1,436 @@ +import { I18n } from "../i18n.js"; +setTheme(); +export function setTheme() { + let name = localStorage.getItem("theme"); + if (!name) { + localStorage.setItem("theme", "Dark"); + name = "Dark"; + } + document.body.className = name + "-theme"; +} +export function getBulkUsers() { + const json = getBulkInfo(); + for (const thing in json.users) { + json.users[thing] = new Specialuser(json.users[thing]); + } + return json; +} +export function getBulkInfo() { + return JSON.parse(localStorage.getItem("userinfos") as string); +} +export function setDefaults() { + let userinfos = getBulkInfo(); + if (!userinfos) { + localStorage.setItem( + "userinfos", + JSON.stringify({ + currentuser: null, + users: {}, + preferences: { + theme: "Dark", + notifications: false, + notisound: "three", + }, + }) + ); + userinfos = getBulkInfo(); + } + if (userinfos.users === undefined) { + userinfos.users = {}; + } + if (userinfos.accent_color === undefined) { + userinfos.accent_color = "#3096f7"; + } + document.documentElement.style.setProperty( + "--accent-color", + userinfos.accent_color + ); + if (userinfos.preferences === undefined) { + userinfos.preferences = { + theme: "Dark", + notifications: false, + notisound: "three", + }; + } + if (userinfos.preferences && userinfos.preferences.notisound === undefined) { + console.warn("uhoh"); + userinfos.preferences.notisound = "three"; + } + localStorage.setItem("userinfos", JSON.stringify(userinfos)); +} +setDefaults(); +export class Specialuser { + serverurls: { + api: string; + cdn: string; + gateway: string; + wellknown: string; + login: string; + }; + email: string; + token: string; + loggedin; + json; + constructor(json: any) { + if (json instanceof Specialuser) { + console.error("specialuser can't construct from another specialuser"); + } + this.serverurls = json.serverurls; + let apistring = new URL(json.serverurls.api).toString(); + apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9"; + this.serverurls.api = apistring; + this.serverurls.cdn = new URL(json.serverurls.cdn) + .toString() + .replace(/\/$/, ""); + this.serverurls.gateway = new URL(json.serverurls.gateway) + .toString() + .replace(/\/$/, ""); + this.serverurls.wellknown = new URL(json.serverurls.wellknown) + .toString() + .replace(/\/$/, ""); + this.serverurls.login = new URL(json.serverurls.login) + .toString() + .replace(/\/$/, ""); + this.email = json.email; + this.token = json.token; + this.loggedin = json.loggedin; + this.json = json; + this.json.localuserStore ??= {}; + if (!this.serverurls || !this.email || !this.token) { + console.error( + "There are fundamentally missing pieces of info missing from this user" + ); + } + } + set pfpsrc(e) { + this.json.pfpsrc = e; + this.updateLocal(); + } + get pfpsrc() { + return this.json.pfpsrc; + } + set username(e) { + this.json.username = e; + this.updateLocal(); + } + get username() { + return this.json.username; + } + set localuserStore(e) { + this.json.localuserStore = e; + this.updateLocal(); + } + get localuserStore() { + return this.json.localuserStore; + } + set id(e) { + this.json.id = e; + this.updateLocal(); + } + get id() { + return this.json.id; + } + get uid() { + return this.email + this.serverurls.wellknown; + } + toJSON() { + return this.json; + } + updateLocal() { + const info = getBulkInfo(); + info.users[this.uid] = this.toJSON(); + localStorage.setItem("userinfos", JSON.stringify(info)); + } +} +const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); +const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent); +export{ + mobile, + iOS, +} +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; +const datalist = document.getElementById("instances"); +console.warn(datalist); +const instancefetch=fetch("/instances.json") +.then(res=>res.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); + const instancein = document.getElementById("instancein") as HTMLInputElement; + if(instancein && instancein.value === ""){ + instancein.value = json[0].name; + } + for(const instance of json){ + if(instance.display === false){ + continue; + } + const option = document.createElement("option"); + option.disabled = !instance.online; + option.value = instance.name; + if(instance.url){ + stringURLMap.set(option.value, instance.url); + if(instance.urls){ + stringURLsMap.set(instance.url, instance.urls); + } + }else if(instance.urls){ + stringURLsMap.set(option.value, instance.urls); + }else{ + option.disabled = true; + } + if(instance.description){ + option.label = instance.description; + }else{ + option.label = instance.name; + } + datalist.append(option); + } + checkInstance(""); + } + } +); +const stringURLMap = new Map(); + +const stringURLsMap = new Map< + string, + { + wellknown: string; + api: string; + cdn: string; + gateway: string; + login?: string; + } + >(); +export async function getapiurls(str: string): Promise< + { + api: string; + cdn: string; + gateway: string; + wellknown: string; + login: string; + } + | false + >{ + function appendApi(str:string){ + return str.includes("api")?"" : (str.endsWith("/")? "api" : "/api"); + } + if(!URL.canParse(str)){ + const val = stringURLMap.get(str); + if(stringURLMap.size===0){ + await new Promise(res=>{ + setInterval(()=>{ + if(stringURLMap.size!==0){ + res(); + } + },100); + }); + } + if(val){ + str = val; + }else{ + const val = stringURLsMap.get(str); + if(val){ + const responce = await fetch( + val.api + (val.api.endsWith("/") ? "" : "/") + "ping" + ); + if(responce.ok){ + if(val.login){ + return val as { + wellknown: string; + api: string; + cdn: string; + gateway: string; + login: string; + }; + }else{ + val.login = val.api; + return val as { + wellknown: string; + api: string; + cdn: string; + gateway: string; + login: string; + }; + } + } + } + } + } + if(str.at(-1) !== "/"){ + str += "/"; + } + let api: string; + try{ + const info = await fetch(`${str}.well-known/spacebar`).then(x=>x.json() + ); + api = info.api; + }catch{ + api=str; + } + if(!URL.canParse(api)){ + return false; + } + const url = new URL(api); + try{ + const info = await fetch( + `${api}${ + url.pathname.includes("api") ? "" : "api" + }/policies/instance/domains` + ).then(x=>x.json()); + const apiurl = new URL(info.apiEndpoint); + return{ + api: info.apiEndpoint+appendApi(apiurl.pathname), + gateway: info.gateway, + cdn: info.cdn, + wellknown: str, + login: info.apiEndpoint+appendApi(apiurl.pathname), + }; + }catch{ + const val = stringURLsMap.get(str); + if(val){ + const responce = await fetch( + val.api + (val.api.endsWith("/") ? "" : "/") + "ping" + ); + if(responce.ok){ + if(val.login){ + return val as { + wellknown: string; + api: string; + cdn: string; + gateway: string; + login: string; + }; + }else{ + val.login = val.api; + return val as { + wellknown: string; + api: string; + cdn: string; + gateway: string; + login: string; + }; + } + } + } + return false; + } +} +export async function checkInstance(instance: string){ + await instancefetch; + const verify = document.getElementById("verify"); + try{ + verify!.textContent = I18n.getTranslation("login.checking"); + const instanceValue = instance; + const instanceinfo = (await getapiurls(instanceValue)) as { + wellknown: string; + api: string; + cdn: string; + gateway: string; + login: string; + value: string; + }; + if(instanceinfo){ + instanceinfo.value = instanceValue; + localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo)); + verify!.textContent = I18n.getTranslation("login.allGood"); + // @ts-ignore + if(checkInstance.alt){ + // @ts-ignore + checkInstance.alt(); + } + setTimeout((_: any)=>{ + console.log(verify!.textContent); + verify!.textContent = ""; + }, 3000); + }else{ + verify!.textContent = I18n.getTranslation("login.invalid"); + } + }catch{ + console.log("catch"); + verify!.textContent = I18n.getTranslation("login.invalid"); + } +} +export function getInstances(){ + return instances; +} +export class SW{ + static worker:undefined|ServiceWorker; + static setMode(mode:"false"|"offlineOnly"|"true"){ + localStorage.setItem("SWMode",mode); + if(this.worker){ + this.worker.postMessage({data:mode,code:"setMode"}); + } + } + static checkUpdate(){ + if(this.worker){ + this.worker.postMessage({code:"CheckUpdate"}); + } + } + static forceClear(){ + if(this.worker){ + this.worker.postMessage({code:"ForceClear"}); + } + } +} + +if ("serviceWorker" in navigator){ + navigator.serviceWorker.register("/service.js", { + scope: "/", + }).then((registration) => { + let serviceWorker:ServiceWorker|undefined; + if (registration.installing) { + serviceWorker = registration.installing; + console.log("installing"); + } else if (registration.waiting) { + serviceWorker = registration.waiting; + console.log("waiting"); + } else if (registration.active) { + serviceWorker = registration.active; + console.log("active"); + } + SW.worker=serviceWorker; + SW.setMode(localStorage.getItem("SWMode") as "false"|"offlineOnly"|"true"); + if (serviceWorker) { + console.log(serviceWorker.state); + serviceWorker.addEventListener("statechange", (_) => { + console.log(serviceWorker.state); + }); + } + }) +}