v6d3musicapi/app/static/main.js

205 lines
5.7 KiB
JavaScript

const genRanHex = (size) =>
[...Array(size)]
.map(() => Math.floor(Math.random() * 16).toString(16))
.join("");
const sessionStr = () => {
if (!localStorage.getItem("session"))
localStorage.setItem("session", genRanHex(64));
return localStorage.getItem("session");
};
const sessionState = async () => {
const response = await fetch(`/state/?session=${sessionStr()}`);
return await response.json();
};
const sessionStatus = (() => {
let task;
return async () => {
if (task === undefined) {
task = (async () => {
const response = await fetch(`/status/?session=${sessionStr()}`);
return await response.json();
})();
}
return await task;
};
})();
const root = document.querySelector("#root");
const logEl = (msg) => {
const el = document.createElement("pre");
el.innerText = msg;
root.append(el);
};
const sessionClient = async () => {
const session = await sessionStatus();
return session && session["client"];
};
const sessionUser = async () => {
const client = await sessionClient();
return client && client["user"];
};
const userAvatarUrl = async () => {
const user = await sessionUser();
return user && user["avatar"];
};
const userUsername = async () => {
const user = await sessionUser();
return user && user["username"];
};
const userAvatarImg = async () => {
const avatar = await userAvatarUrl();
if (avatar) {
const img = document.createElement("img");
img.src = avatar;
img.width = 64;
img.height = 64;
img.alt = await userUsername();
return img;
} else {
return baseEl("span");
}
};
const userId = async () => {
const user = await sessionUser();
return user && user["id"];
};
const baseEl = (tag, ...appended) => {
const element = document.createElement(tag);
element.append(...appended);
return element;
};
const aLogin = () => {
const a = document.createElement("a");
a.href = "/login/";
a.innerText = "login";
return a;
};
const aAuthLink = async () => {
const response = await fetch("/authlink/");
return await response.text();
};
const aAuth = async () => {
const a = document.createElement("a");
const [authlink, sessionstate] = await Promise.all([
aAuthLink(),
sessionState(),
]);
a.href = authlink + "&state=" + sessionstate;
a.innerText = "auth";
return a;
};
const aApi = async (request) => {
const response = await fetch(`/api/?session=${sessionStr()}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(request),
});
return await response.json();
};
const aGuilds = async () => {
return await aApi({ type: "guilds" });
};
const aQueue = async () => {
const requests = {};
for (const guild of await aGuilds()) {
requests[guild] = {
type: "*",
guild,
voice: null,
main: null,
catches: { "you are not connected to voice": null, "*": null },
requests: { volume: {}, playing: {}, queueformat: {}, queuejson: {} },
};
}
const responses = await aApi({ type: "*", requests });
for (const [guild, response] of Object.entries(responses)) {
if (response !== null && response.error === undefined) {
response.guild = guild;
response.time = Date.now() / 1000;
response.delta = () => Date.now() / 1000 - response.time;
let index = 0;
for (const audio of response.queuejson) {
audio.playing = response.playing && index === 0;
audio.delta = () => (audio.playing ? response.delta() : 0);
audio.now = () => audio.seconds + audio.delta();
audio.ts = () => {
const seconds_total = Math.round(audio.now());
const seconds = seconds_total % 60;
const minutes_total = (seconds_total - seconds) / 60;
const minutes = minutes_total % 60;
const hours = (minutes_total - minutes) / 60;
return `${hours}:${("00" + minutes).slice(-2)}:${(
"00" + seconds
).slice(-2)}`;
};
index += 1;
}
return response;
}
}
return null;
};
const sleep = (s) => {
return new Promise((resolve) => setTimeout(resolve, 1000 * s));
};
const audioWidget = (audio) => {
const description = baseEl("span", audio.description);
const timecode = baseEl("span", audio.timecode);
const duration = baseEl("span", audio.duration);
audio.tce = timecode;
return baseEl("div", "audio", " ", timecode, "/", duration, " ", description);
};
const aUpdateQueueOnce = async (queue, el) => {
el.innerHTML = "";
if (queue !== null) {
for (const audio of queue.queuejson) {
el.append(audioWidget(audio));
}
}
};
const aUpdateQueueSetup = async (el) => {
let queue = await aQueue();
await aUpdateQueueOnce(queue, el);
(async () => {
while (true) {
await sleep(2);
if (queue !== null && queue.queuejson.length > 100) {
await sleep((queue.queuejson.length - 100) / 200);
}
const newQueue = await aQueue();
await aUpdateQueueOnce(newQueue, el);
queue = newQueue;
}
})();
(async () => {
while (true) {
await sleep(0.25);
if (queue !== null) {
for (const audio of queue.queuejson) {
audio.tce.innerText = audio.ts();
break;
}
}
}
})();
};
const aQueueWidget = async () => {
const el = baseEl("div");
if (await sessionUser()) await aUpdateQueueSetup(el);
return el;
};
const pageHome = async () => {
const el = document.createElement("div");
el.append(
baseEl("div", aLogin()),
baseEl("div", await userAvatarImg()),
baseEl("div", await userId()),
baseEl("div", await userUsername()),
baseEl("div", await aQueueWidget())
);
el.id = "homeroot";
return el;
};