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);
+ });
+ }
+ })
+}