v2 #1

Merged
sky merged 13 commits from development into main 2025-10-26 12:54:21 -04:00
23 changed files with 1743 additions and 1396 deletions

View File

@ -5,3 +5,7 @@ ANNOUNCEMENT_KEY=text.
GROQ_API_KEY=["groq_api"] GROQ_API_KEY=["groq_api"]
NTFY_ALERT=ntfy_channel NTFY_ALERT=ntfy_channel
DATA_PATH=where_to_store_data DATA_PATH=where_to_store_data
NODE_ENV=production
DISCORD_AI_WEBHOOK=discord_webhook_url
PROCESSING_SERVER=https://git.ceres.rip/selenite/processing
PROCESSING_SERVER_SECRET=secret

View File

@ -1,3 +1,3 @@
import { accs, friends } from "../database.js"; // import { accs, friends } from "../database.js";
export { }; export { };

153
accounts/music.js Normal file
View File

@ -0,0 +1,153 @@
import Soundcloud from 'lucida/streamers/soundcloud/main.js'
let clientId = process.env.SOUNDCLOUD_CLIENT_ID;
let sc = new Soundcloud({
// oauthToken: clientId
})
async function search(query) {
let data = sc.search(query);
return data;
}
// so um fuck lucida
// based on https://github.com/imputnet/cobalt/blob/58ea4aed01383ead74d5e32e75335eddc2f015be/api/src/processing/services/soundcloud.js
const cachedID = {
version: '',
id: ''
}
async function findClientID() {
try {
const sc = await fetch('https://soundcloud.com/').then(r => r.text()).catch(() => {});
const scVersion = String(sc.match(/<script>window\.__sc_version="[0-9]{10}"<\/script>/)[0].match(/[0-9]{10}/));
if (cachedID.version === scVersion) {
return cachedID.id;
}
const scripts = sc.matchAll(/<script.+src="(.+)">/g);
let clientid;
for (let script of scripts) {
const url = script[1];
if (!url?.startsWith('https://a-v2.sndcdn.com/')) {
return;
}
const scrf = await fetch(url).then(r => r.text()).catch(() => {});
const id = scrf.match(/\("client_id=[A-Za-z0-9]{32}"\)/);
if (id && typeof id[0] === 'string') {
clientid = id[0].match(/[A-Za-z0-9]{32}/)[0];
break;
}
}
cachedID.version = scVersion;
cachedID.id = clientid;
return clientid;
} catch {}
}
const findBestForPreset = (transcodings, preset) => {
let inferior;
for (const entry of transcodings) {
const protocol = entry?.format?.protocol;
if (entry.snipped || protocol?.includes('encrypted')) {
continue;
}
if (entry?.preset?.startsWith(`${preset}_`)) {
if (protocol === 'progressive') {
return entry;
}
inferior = entry;
}
}
return inferior;
}
async function download(obj) {
const clientId = await findClientID();
if (!clientId) return { error: "fetch.fail" };
let link = obj;
const resolveURL = new URL("https://api-v2.soundcloud.com/resolve");
resolveURL.searchParams.set("url", link);
resolveURL.searchParams.set("client_id", clientId);
const json = await fetch(resolveURL).then(r => r.json()).catch(() => {});
if (!json) return { error: "fetch.fail" };
if (json.duration > 60 * 30 * 1000) {
return { error: "content.too_long" };
}
if (json.policy === "BLOCK") {
return { error: "content.region" };
}
if (json.policy === "SNIP") {
return { error: "content.paid" };
}
if (!json.media?.transcodings || !json.media?.transcodings.length === 0) {
return { error: "fetch.empty" };
}
let bestAudio = "opus",
selectedStream = findBestForPreset(json.media.transcodings, "opus");
const mp3Media = findBestForPreset(json.media.transcodings, "mp3");
// use mp3 if present if user prefers it or if opus isn't available
if (mp3Media && (obj.format === "mp3" || !selectedStream)) {
selectedStream = mp3Media;
bestAudio = "mp3"
}
if (!selectedStream) {
return { error: "fetch.empty" };
}
const fileUrl = new URL(selectedStream.url);
fileUrl.searchParams.set("client_id", clientId);
fileUrl.searchParams.set("track_authorization", json.track_authorization);
const file = await fetch(fileUrl)
.then(async r => new URL((await r.json()).url))
.catch(() => {});
if (!file) return { error: "fetch.empty" };
const artist = json.user?.username?.trim();
const fileMetadata = {
title: json.title?.trim(),
album: json.publisher_metadata?.album_title?.trim(),
artist,
album_artist: artist,
composer: json.publisher_metadata?.writer_composer?.trim(),
genre: json.genre?.trim(),
date: json.display_date?.trim().slice(0, 10),
copyright: json.license?.trim(),
}
return {
urls: file.toString(),
filenameAttributes: {
service: "soundcloud",
id: json.id,
...fileMetadata
},
bestAudio,
fileMetadata,
isHLS: file.pathname.endsWith('.m3u8'),
}
}
export { search, download };

View File

@ -4,9 +4,11 @@ import sanitizeHtml from "sanitize-html";
import sharp from "sharp"; import sharp from "sharp";
import { accs } from "../database.js"; import { accs } from "../database.js";
import { getUserFromCookie, isBanned, decryptCookie, verifyCookie } from "./manage.js"; import { getUserFromCookie, isBanned, decryptCookie, verifyCookie } from "./manage.js";
import { download } from "./music.js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime.js"; import relativeTime from "dayjs/plugin/relativeTime.js";
import { error } from "node:console";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
const sanitizeConfig = { const sanitizeConfig = {
@ -37,8 +39,8 @@ let rawProfileHTML = fs.readFileSync("./html/profile.html").toString();
let rawEditProfileHTML = fs.readFileSync("./html/profile_edit.html").toString(); let rawEditProfileHTML = fs.readFileSync("./html/profile_edit.html").toString();
let profile404 = fs.readFileSync("./html/profile_404.html").toString(); let profile404 = fs.readFileSync("./html/profile_404.html").toString();
let profileBan = fs.readFileSync("./html/profile_ban.html").toString(); let profileBan = fs.readFileSync("./html/profile_ban.html").toString();
let gamesJSON = JSON.parse(fs.readFileSync("./selenite/data/games.json").toString()); let gamesJSON = JSON.parse(fs.readFileSync("./public/resources/games.json").toString());
let appsJSON = JSON.parse(fs.readFileSync("./selenite/data/apps.json").toString()); let appsJSON = JSON.parse(fs.readFileSync("./public/resources/apps.json").toString());
let profileReadyJSON = {}; let profileReadyJSON = {};
for (let i = 0; i < gamesJSON.length; i++) { for (let i = 0; i < gamesJSON.length; i++) {
profileReadyJSON[gamesJSON[i].directory] = { name: gamesJSON[i].name, image: gamesJSON[i].image }; profileReadyJSON[gamesJSON[i].directory] = { name: gamesJSON[i].name, image: gamesJSON[i].image };
@ -193,21 +195,62 @@ async function editProfile(body, token, admin) {
let fileType = (await fileTypeFromBuffer(pfp))["ext"]; let fileType = (await fileTypeFromBuffer(pfp))["ext"];
if (["png", "jpg", "gif", "avif", "webp", "tiff"].includes(fileType)) { if (["png", "jpg", "gif", "avif", "webp", "tiff"].includes(fileType)) {
let url; let url;
let dir = `${process.env.DATA_PATH}/data/${existingAccount.id}/`; let dir = `${process.env.DATA_PATH}/data/${userData.id}/`;
let uuid = crypto.randomUUID(); let uuid = crypto.randomUUID();
let path = `${process.env.DATA_PATH}/data/${existingAccount.id}/${uuid}.webp`; let path = `${process.env.DATA_PATH}/data/${userData.id}/${uuid}.webp`;
url = `/data/${existingAccount.id}/${uuid}.webp`; url = `/data/${userData.id}/${uuid}.webp`;
fs.mkdirSync(dir, { recursive: true }); fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(path, ""); fs.writeFileSync(path, "");
await sharp(pfp, { animated: fileType == "gif" }) await sharp(pfp, { animated: fileType == "gif" })
.resize({ width: 300, withoutEnlargement: true }) .resize({ width: 400, withoutEnlargement: true })
.webp({ quality: 70, effort: 4 }) .webp({ quality: 70, effort: 4 })
.toFile(path); .toFile(path);
await fs.unlink(`${__dirname}/${existingAccount.pfp_url}`, () => {}); await fs.unlink(`${__dirname}/${userData.pfp_url}`, () => {});
const updateAccount = accs.query(`UPDATE accounts SET pfp_url = $url WHERE username = $user`) const updateAccount = accs.query(`UPDATE accounts SET pfp_url = $url WHERE username = $user`)
updateAccount.get({ $url: url, $user: user }); updateAccount.get({ $url: url, $user: user });
} }
} }
if (body.artist) {
let checkStatus = new Request({
url: process.env.PROCESSING_SERVER + "/status"
});
let checkStatusRequest = await fetch(checkStatus);
if(checkStatusRequest.status != 200) {
return { success: false, err: "processing server is down, try again later"};
}
let data = await download(body.url);
if(data.error) {
if(data.error == "content.too_long") {
return { success: false, err: "the song was too long, pick something shorter!"};
} else if(data.error == "content.region") {
return { success: false, err: "the song could not be downloaded due to the region of the server."};
} else if(data.error == "content.paid") {
return { success: false, err: "the song is go+ only, and we're too poor to pay for that :( pick another song"};
} else if(data.error == "fetch.empty") {
return { success: false, err: "we could not fetch this song successfully"};
} else {
return { success: false, err: "an unknown error happened! error code: " + error};
}
}
let streamingURL = data.urls;
let request = new Request({
url: process.env.PROCESSING_SERVER + "/process",
method: "POST",
body: JSON.stringify({url: streamingURL}),
headers: {
"X-Authentication": process.env.PROCESSING_SERVER_SECRET
}
});
let oggFile = await fetch(request);
let filePath = `/data/${userData.id}/${crypto.randomUUID()}.ogg`;
await Bun.write(process.env.DATA_PATH + filePath, oggFile);
const updateAccount = accs.query(`UPDATE accounts SET music = $music WHERE username = $user`)
updateAccount.get({ $music: JSON.stringify({
path: filePath,
name: body.title,
artist: body.artist
}), $user: user });
}
return { success: true }; return { success: true };
} }
@ -228,6 +271,7 @@ async function generateAccountPage(name, cookie, admin) {
} }
let modifiedHTML = rawProfileHTML; let modifiedHTML = rawProfileHTML;
let songData = JSON.parse(userData.music) || false;
modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, allowNone)); modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow()); modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow());
modifiedHTML = modifiedHTML.replaceAll("{{ about }}", sanitizeHtml(userData.about, sanitizeConfig) || "No about me available.."); modifiedHTML = modifiedHTML.replaceAll("{{ about }}", sanitizeHtml(userData.about, sanitizeConfig) || "No about me available..");
@ -235,7 +279,15 @@ async function generateAccountPage(name, cookie, admin) {
modifiedHTML = modifiedHTML.replaceAll("{{ user_pfp }}", userData.pfp_url || "/img/user.svg"); modifiedHTML = modifiedHTML.replaceAll("{{ user_pfp }}", userData.pfp_url || "/img/user.svg");
modifiedHTML = modifiedHTML.replaceAll("{{ custom_css }}", userData.custom_css || ""); modifiedHTML = modifiedHTML.replaceAll("{{ custom_css }}", userData.custom_css || "");
modifiedHTML = modifiedHTML.replaceAll("{{ online_time }}", dayjs(userData.last_login).fromNow()); modifiedHTML = modifiedHTML.replaceAll("{{ online_time }}", dayjs(userData.last_login).fromNow());
modifiedHTML = modifiedHTML.replaceAll("{{ played_games }}", buildGameHTML(userData)); modifiedHTML = modifiedHTML.replaceAll("{{ username }}", sanitizeHtml(userData.username, allowNone));
if(songData) {
modifiedHTML = modifiedHTML.replaceAll("{{ song_title }}", sanitizeHtml(songData.name, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ song_artist }}", sanitizeHtml(songData.artist, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ song_url }}", sanitizeHtml(songData.path, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ is_music }}", "true");
} else {
modifiedHTML = modifiedHTML.replaceAll("{{ is_music }}", "false");
}
let badges_html = ""; let badges_html = "";
if (userData.badges !== null) { if (userData.badges !== null) {
@ -260,6 +312,7 @@ async function generateAccountPage(name, cookie, admin) {
return modified_ban; return modified_ban;
} }
let modifiedHTML = rawEditProfileHTML; let modifiedHTML = rawEditProfileHTML;
let songData = JSON.parse(userData.music) || false;
modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, sanitizeConfig)); modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, sanitizeConfig));
modifiedHTML = modifiedHTML.replaceAll("{{ username }}", userData.username); modifiedHTML = modifiedHTML.replaceAll("{{ username }}", userData.username);
modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow()); modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow());
@ -269,7 +322,17 @@ async function generateAccountPage(name, cookie, admin) {
modifiedHTML = modifiedHTML.replaceAll("{{ url_gen }}", `https://selenite.cc/u/${userData.username}`); modifiedHTML = modifiedHTML.replaceAll("{{ url_gen }}", `https://selenite.cc/u/${userData.username}`);
modifiedHTML = modifiedHTML.replaceAll("{{ online_time }}", dayjs(userData.last_login).fromNow()); modifiedHTML = modifiedHTML.replaceAll("{{ online_time }}", dayjs(userData.last_login).fromNow());
modifiedHTML = modifiedHTML.replaceAll("{{ css_edit }}", (userData.badges ? userData.badges.length : 0) > 0 ? '<img src="/img/edit.svg" id="edit" />' : ""); modifiedHTML = modifiedHTML.replaceAll("{{ css_edit }}", (userData.badges ? userData.badges.length : 0) > 0 ? '<img src="/img/edit.svg" id="edit" />' : "");
modifiedHTML = modifiedHTML.replaceAll("{{ played_games }}", buildGameHTML(userData)); modifiedHTML = modifiedHTML.replaceAll("{{ staff_buttons }}", await isAdmin(cookie) ? "<a href='/admin'>admin panel</a>" : "");
if(songData) {
modifiedHTML = modifiedHTML.replaceAll("{{ song_title }}", sanitizeHtml(songData.name, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ song_artist }}", sanitizeHtml(songData.artist, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ song_url }}", sanitizeHtml(songData.path, allowNone));
modifiedHTML = modifiedHTML.replaceAll("{{ is_music }}", "true");
} else {
modifiedHTML = modifiedHTML.replaceAll("{{ is_music }}", "false");
modifiedHTML = modifiedHTML.replaceAll("{{ song_title }}", "no song selected...");
modifiedHTML = modifiedHTML.replaceAll("{{ song_artist }}", "");
}
let badges_html = ""; let badges_html = "";
if (userData.badges !== null) { if (userData.badges !== null) {
@ -282,43 +345,7 @@ async function generateAccountPage(name, cookie, admin) {
return modifiedHTML; return modifiedHTML;
} }
} }
function buildGameHTML(existingAccount) {
if (existingAccount.playedgames) {
let games = JSON.parse(existingAccount.playedgames);
let sortedGames = Object.keys(games).sort((a, b) => games[b] - games[a]);
let return_data = [];
if (Object.keys(games).length < 10) {
for (let i = 0; i < sortedGames.length; i++) {
try {
let origin = gamesExceptions[sortedGames[i]] ? "sppa" : "semag";
sortedGames[i] = gamesExceptions[sortedGames[i]] ? gamesExceptions[sortedGames[i]] : sortedGames[i];
return_data[i] = { name: profileReadyJSON[sortedGames[i]].name, image: profileReadyJSON[sortedGames[i]].image, path: sortedGames[i], origin: origin, valid: true };
} catch (e) {
return_data[i] = { valid: false };
}
}
} else {
for (let i = 0; i < 10; i++) {
try {
let origin = gamesExceptions[sortedGames[i]] ? "sppa" : "semag";
sortedGames[i] = gamesExceptions[sortedGames[i]] ? gamesExceptions[sortedGames[i]] : sortedGames[i];
return_data[i] = { name: profileReadyJSON[sortedGames[i]].name, image: profileReadyJSON[sortedGames[i]].image, path: sortedGames[i], origin: origin, valid: true };
} catch (e) {
return_data[i] = { valid: false };
}
}
}
let return_html = "";
for (let i = 0; i < Object.keys(return_data).length; i++) {
if (return_data[i].valid) {
return_html += `<div class="played-game"><img src="/${return_data[i].origin}/${return_data[i].path}/${return_data[i].image}"/><p>${return_data[i].name}</p></div>`;
}
}
return return_html;
} else {
return "<h3>Play some games to view things appear here!</h3>";
}
}
async function getUsers(page, search) { async function getUsers(page, search) {
let amount = 12; let amount = 12;
if (!page) { if (!page) {

23
ai.js
View File

@ -1,6 +1,21 @@
import OpenAI from "openai"; import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { generateText } from 'ai';
const client = new OpenAI({ const model = createOpenAICompatible({
apiKey: process.env.GROQ_API_KEY, name: 'model',
baseURL: "https://api.groq.com/openai/v1" apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL,
includeUsage: true, // Include usage information in streaming responses
}); });
async function callAI(chatHistory) {
console.log("call ai called")
let { text } = await generateText({
model: model(process.env.OPENAI_MODEL),
system: "You are Zen, a helpful AI assistant built by Selenite. Your response should be accurate without hallucination." +
"Over the course of conversation, adapt to the user's tone and preferences. Try to match the user's vibe, tone, and generally how they are speaking. You want the conversation to feel natural. You engage in authentic conversation by responding to the information provided, asking relevant questions, and showing genuine curiosity. If natural, use information you know about the user to personalize your responses and ask a follow up question.",
messages: chatHistory
});
console.log(text);
}
export { callAI };

417
bun.lock Normal file
View File

@ -0,0 +1,417 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "rewrite",
"dependencies": {
"@ai-sdk/openai-compatible": "^1.0.22",
"ai": "^5.0.68",
"axios": "^1.12.2",
"body-parser": "^2.2.0",
"chalk": "^5.6.2",
"compression": "^1.8.1",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dayjs": "^1.11.18",
"dotenv": "^16.6.1",
"express": "^5.1.0",
"file-type": "^19.6.0",
"lucida": "^2.0.0-54",
"mime-types": "^2.1.35",
"rword": "^3.2.1",
"sanitize-html": "^2.17.0",
"sharp": "^0.33.5",
"ws": "^8.18.3",
},
},
},
"packages": {
"@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.39", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.12", "@vercel/oidc": "3.0.2" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ijYCKG2sbn2RBVfIgaXNXvzHAf2HpFXxQODtjMI+T7Z4CLryflytchsZZ9qrGtsjiQVopKOV6m6kj4lq5fnbsg=="],
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.22", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.12" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Q+lwBIeMprc/iM+vg1yGjvzRrp74l316wDpqWdbmd4VXXlllblzGsUgBLTeKvcEapFTgqk0FRETvSb58Y6dsfA=="],
"@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="],
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.12", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg=="],
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ=="],
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="],
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="],
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="],
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="],
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="],
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="],
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="],
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="],
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="],
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="],
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="],
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="],
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="],
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="],
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="],
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="],
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
"@types/node": ["@types/node@20.14.8", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA=="],
"@vercel/oidc": ["@vercel/oidc@3.0.2", "", {}, "sha512-JekxQ0RApo4gS4un/iMGsIL1/k4KUBe3HmnGcDvzHuFBdQdudEJgTqcsJC7y6Ul4Yw5CeykgvQbX2XeEJd0+DA=="],
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"ai": ["ai@5.0.68", "", { "dependencies": { "@ai-sdk/gateway": "1.0.39", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.12", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-SB6r+4TkKVlSg2ozGBSfuf6Is5hrcX/bpGBzOoyHIN3b4ILGhaly0IHEvP8+3GGIHXqtkPVEUmR6V05jKdjNlg=="],
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
"axios": ["axios@1.12.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw=="],
"blowfish-cbc": ["blowfish-cbc@1.0.1", "", { "dependencies": { "node-addon-api": "^8.1.0" } }, "sha512-o1JN6g6+ATW/4k7q1BZzy14VqLxwYa1mCii47qT4kmAaYD0NAfdM6/pz6uizbhTra/xunsPQI27LZt08OQS4sA=="],
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
"compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="],
"compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="],
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
"cookie-parser": ["cookie-parser@1.4.7", "", { "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.6" } }, "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw=="],
"cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="],
"cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
"dayjs": ["dayjs@1.11.18", "", {}, "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
"destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="],
"detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
"domutils": ["domutils@3.1.0", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA=="],
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
"eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
"file-type": ["file-type@19.6.0", "", { "dependencies": { "get-stream": "^9.0.1", "strtok3": "^9.0.1", "token-types": "^6.0.0", "uint8array-extras": "^1.3.0" } }, "sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ=="],
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
"follow-redirects": ["follow-redirects@1.15.6", "", {}, "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA=="],
"form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="],
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": "bin/image-size.js" }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
"is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="],
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
"is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="],
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
"librespot": ["librespot@0.2.22", "", { "dependencies": { "protobufjs": "^7.2.5", "undici": "^5.27.0" } }, "sha512-szLknWSrgF+mRuypNXQTmdq8PGGhgPRAazm8sJmD8wiCAbtO9LYHihZhQcRmCzmVz818sRHZM/BU6K6XslXSHQ=="],
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
"lucida": ["lucida@2.0.0-54", "", { "dependencies": { "blowfish-cbc": "^1.0.1", "image-size": "^1.1.1", "librespot": "^0.2.21", "undici": "^6.19.4", "xmldom-qsa": "^1.1.3" } }, "sha512-3Y24WkCI1Ks6EjOAElYAeYXkxT/HtunEW+SnhDKFb681B/QEMhS/EzLzFi8D5l95/pOVODUZQMMxYNKmMMC1fQ=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.8", "", { "bin": "bin/nanoid.cjs" }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
"negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="],
"node-addon-api": ["node-addon-api@8.4.0", "", {}, "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
"on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"parse-srcset": ["parse-srcset@1.0.2", "", {}, "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="],
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
"path-to-regexp": ["path-to-regexp@8.1.0", "", {}, "sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ=="],
"peek-readable": ["peek-readable@5.4.2", "", {}, "sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg=="],
"picocolors": ["picocolors@1.0.1", "", {}, "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="],
"postcss": ["postcss@8.4.39", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.1", "source-map-js": "^1.2.0" } }, "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw=="],
"protobufjs": ["protobufjs@7.5.3", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw=="],
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
"queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="],
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
"rword": ["rword@3.2.1", "", {}, "sha512-E1PhzHCM8enXQJoVv0ZKvqMNojkbRqMsv66pD0P4mRl1imb+0g+3Q19CtXobZIqOhi3zNZi1br//U87vc/s6OA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
"sanitize-html": ["sanitize-html@2.17.0", "", { "dependencies": { "deepmerge": "^4.2.2", "escape-string-regexp": "^4.0.0", "htmlparser2": "^8.0.0", "is-plain-object": "^5.0.0", "parse-srcset": "^1.0.2", "postcss": "^8.3.11" } }, "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA=="],
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"send": ["send@1.1.0", "", { "dependencies": { "debug": "^4.3.5", "destroy": "^1.2.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^0.5.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA=="],
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
"sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
"source-map-js": ["source-map-js@1.2.0", "", {}, "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg=="],
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
"strtok3": ["strtok3@9.1.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^5.3.1" } }, "sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw=="],
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
"token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="],
"tslib": ["tslib@2.6.3", "", {}, "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="],
"type-is": ["type-is@2.0.0", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-gd0sGezQYCbWSbkZr75mln4YBidWUN60+devscpLF5mtRDUpiaTvKpBNrdaCvel1NdR2k6vclXybU5fBd2i+nw=="],
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
"undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"xmldom-qsa": ["xmldom-qsa@1.1.3", "", {}, "sha512-IJBOczBpAYrIBJFFsmCBwfBhwe4zdMR3Xz0ZBX0OFtgO49rLy/BWbhkegOwsthdBWb1gUtFK6ZZnGdT8ZqPRBA=="],
"zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="],
"accepts/mime-types": ["mime-types@3.0.0", "", { "dependencies": { "mime-db": "^1.53.0" } }, "sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w=="],
"accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"express/cookie-signature": ["cookie-signature@1.2.1", "", {}, "sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw=="],
"express/mime-types": ["mime-types@3.0.0", "", { "dependencies": { "mime-db": "^1.53.0" } }, "sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w=="],
"express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
"librespot/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
"send/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
"send/fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
"serve-static/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
"type-is/mime-types": ["mime-types@3.0.0", "", { "dependencies": { "mime-db": "^1.53.0" } }, "sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w=="],
"accepts/mime-types/mime-db": ["mime-db@1.53.0", "", {}, "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg=="],
"compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"express/mime-types/mime-db": ["mime-db@1.53.0", "", {}, "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg=="],
"serve-static/send/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
"type-is/mime-types/mime-db": ["mime-db@1.53.0", "", {}, "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg=="],
"serve-static/send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
}
}

View File

@ -1,15 +1,50 @@
import fs from "bun:fs";
import { Database } from "bun:sqlite"; import { Database } from "bun:sqlite";
const accs = new Database(`${process.env.DATA_PATH}/accounts.sqlite`); if(!await (Bun.file(process.env.DATA_PATH)).exists()) {
const infdb = new Database(`${process.env.DATA_PATH}/infinitecraft.sqlite`); fs.mkdirSync(process.env.DATA_PATH, { recursive: true });
const friends = new Database(`${process.env.DATA_PATH}/friends.sqlite`); }
const polytrack = new Database(`${process.env.DATA_PATH}/polytrack.sqlite`);
const ai_chats = new Database(`${process.env.DATA_PATH}/ai_chats.sqlite`); const accs = new Database(`${process.env.DATA_PATH}/accounts.sqlite`, { create: true });
// const infdb = new Database(`${process.env.DATA_PATH}/infinitecraft.sqlite`);
// const friends = new Database(`${process.env.DATA_PATH}/friends.sqlite`);
// const polytrack = new Database(`${process.env.DATA_PATH}/polytrack.sqlite`);
// const ai_chats = new Database(`${process.env.DATA_PATH}/ai_chats.sqlite`);
infdb.exec("PRAGMA journal_mode = WAL;");
accs.exec("PRAGMA journal_mode = WAL;"); accs.exec("PRAGMA journal_mode = WAL;");
friends.exec("PRAGMA journal_mode = WAL;"); // infdb.exec("PRAGMA journal_mode = WAL;");
polytrack.exec("PRAGMA journal_mode = WAL;"); // friends.exec("PRAGMA journal_mode = WAL;");
ai_chats.exec("PRAGMA journal_mode = WAL;"); // polytrack.exec("PRAGMA journal_mode = WAL;");
// ai_chats.exec("PRAGMA journal_mode = WAL;");
export { accs, infdb, friends, polytrack, ai_chats }; let accountColumns = [
`"id" INTEGER`,
`"username" TEXT UNIQUE`,
`"name" TEXT`,
`"hashed_pass" INTEGER NOT NULL`,
`"secret_key" TEXT`,
`"about" TEXT`,
`"badges" TEXT`,
`"last_login" TEXT`,
`"type" TEXT`,
`"pfp_url" TEXT`,
`"createdAt" DATETIME NOT NULL`,
`"updatedAt" DATETIME NOT NULL`,
`"banned" TEXT`,
`"music" TEXT`,
`PRIMARY KEY("id")`,
];
let createAccountQuery = `CREATE TABLE IF NOT EXISTS "accounts" (`
accountColumns.forEach((e) => {
if(createAccountQuery.length == 39) {
createAccountQuery+=`${e}`
} else {
createAccountQuery+=`,${e}`
}
});
createAccountQuery+=`)`
// console.log(createAccountQuery)
accs.query(createAccountQuery).run();
// export { accs, infdb, friends, polytrack, ai_chats };
export { accs };

View File

@ -1,96 +1,71 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
<!-- initialize externals --> <!-- initialize externals -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script> <meta property="og:title" content="Selenite" />
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script> <meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta content="/favicon.png" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<meta name="googlebot" content="index, follow, snippet" />
<link rel="canonical" href="https://selenite.cc/" />
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta property="og:title" content="Selenite">
<meta property="og:type" content="website">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Selenite",
"alternateName": "selenite.cc",
"url": "https://selenite.cc",
"logo": "https://selenite.cc/favicon.png",
"sameAs": [
"https://github.com/selenite-cc",
"https://youtube.com/@selenitecc",
"https://tiktok.com/@selenitecc",
"https://selenite.cc",
]
}
</script>
<!-- initialize my stuff --> <!-- initialize my stuff -->
<script src="/js/all.min.js"></script> <script src="/js/all.js"></script>
<script src="/js/main.js"></script> <script src="/js/main.js"></script>
<link rel="stylesheet" href="/style.css" /> <link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<link rel="manifest" href="/manifest.json" />
<!-- seo + other things --> <!-- seo + other things -->
<title>Profile</title> <title>Selenite</title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
</head> <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script>
<alerts> </alerts>
<body id="noscroll">
<header>
<a href="/index.html">Home</a>
<a href="/bookmarklets.html">Bookmarklets</a>
<a href="/projects.html">Games</a>
<a href="/apps.html">Apps</a>
<a href="/settings.html">Settings</a>
<a id="blank" href="#">Open Blank</a>
<a href="/u/" class="usericon"><img src="/img/user.svg" /></a>
</header>
<script> <script>
async function addBadge() { function sendAnnouncement() {
let name = prompt("username"); let title = prompt("title");
let badge = prompt("badge name"); let message = prompt("message");
if(prompt("are you sure (y/N)") == "y") {
let run = await fetch("/api/admin/badge", { let cookies = document.cookie.split("; ");
method: "POST", for (let i = 0; i < cookies.length; i++) {
body: JSON.stringify({ if (cookies[i].trim().startsWith("token=")) {
username: name, let socket = new WebSocket("/socket");
badge: badge socket.addEventListener("open", () => {
}), socket.send(`annc;;${cookies[i].trim().split("=")[1]};;${title};;${message}`);
headers: { })
"Content-type": "application/json; charset=UTF-8", }
}, }
}); }
alert(JSON.stringify(run));
}
function announce() {
let key = prompt("enter key");
let announcement = prompt("enter announcement");
socket.send(`${key}.${announcement}`)
}
async function removeAccount() {
let name = prompt("enter username");
let run = await fetch("/api/admin/removeAcc", {
method: "POST",
body: JSON.stringify({
username: name
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
});
}
async function ban() {
let name = prompt("enter username");
let reason = prompt("enter reason");
let run = await fetch("/api/admin/ban", {
method: "POST",
body: JSON.stringify({
name: name,
reason: reason,
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
});
} }
</script> </script>
<main> </head>
<button onclick="addBadge()">Add a badge</button> <alerts> </alerts>
<button onclick="announce()">Send announcement</button> <body>
<button onclick="removeAccount()">remove account</button> <h1 class="title">admin page</h1>
<button onclick="ban()">ban account</button> <sections>
</main> <button onclick="sendAnnouncement()">send announcement</button>
<footer class="noscroll"> </sections>
<a href="https://gitlab.com/skysthelimit.dev/selenite">Source</a>
<a href="https://discord.gg/7jyufnwJNf">Discord</a>
<a href="/suggest.html">Suggestions & Bugs</a>
<a href="/contact.html">Contact</a>
<a href="/support.html">Donate</a>
<a href="/about.html">About</a>
</footer>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
@ -14,7 +14,8 @@
<script src="https://js.hcaptcha.com/1/api.js" async defer></script> <script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<link rel="stylesheet" href="/style.css" /> <link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<!-- seo + other things --> <!-- seo + other things -->
<title>Login | Selenite</title> <title>Login | Selenite</title>
@ -60,27 +61,17 @@
</script> </script>
</head> </head>
<alerts> </alerts> <alerts> </alerts>
<body id="noscroll"> <body>
<header> <h2>login..</h2>
<a href="/index.html">Home</a>
<a href="/bookmarklets.html">Bookmarklets</a>
<a href="/projects.html">Games</a>
<a href="/apps.html">Apps</a>
<a href="/settings.html">Settings</a>
<a id="blank" href="#">Open Blank</a>
<a href="/u/" class="usericon"><img src="/img/user.svg" /></a>
</header>
<main id="main" class="noscroll">
<h2>Login to your account</h2>
<form onsubmit="return false;" id="login"> <form onsubmit="return false;" id="login">
<input type="text" id="username" placeholder="username" /> <input type="text" id="username" placeholder="username" />
<input type="password" id="password" placeholder="password" /> <input type="password" id="password" placeholder="password" />
<br /> <br />
<a href="/reset">Forgot password?</a> or <a href="/register">Create a free account</a><br />
<div class="h-captcha" id="hcaptcha" data-sitekey="1774ec96-39be-4fb0-9e82-f4c62354b8fa"></div> <div class="h-captcha" id="hcaptcha" data-sitekey="1774ec96-39be-4fb0-9e82-f4c62354b8fa"></div>
<button type="submit" value="Submit">Login</button> <a href="/reset">forgot password?</a><br />
<a href="/register">create a free account</a><br />
<button type="submit" value="Submit">login</button>
</form> </form>
</main>
<popups> <popups>
<div id="popup" style="display: none"> <div id="popup" style="display: none">
<h1 id="title"></h1> <h1 id="title"></h1>
@ -88,13 +79,5 @@
<button id="close">X</button> <button id="close">X</button>
</div> </div>
</popups> </popups>
<footer class="noscroll">
<a href="https://gitlab.com/skysthelimit.dev/selenite">Source</a>
<a href="https://discord.gg/7jyufnwJNf">Discord</a>
<a href="/suggest.html">Suggestions & Bugs</a>
<a href="/contact.html">Contact</a>
<a href="/support.html">Donate</a>
<a href="/about.html">About</a>
</footer>
</body> </body>
</html> </html>

View File

@ -1,67 +1,140 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
<meta content="{{ name }}" property="og:title" />
<meta content="{{ about_none }}" property="og:description" />
<meta content="{{ user_pfp }}" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<!-- initialize externals --> <!-- initialize externals -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script> <meta property="og:title" content="Selenite" />
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script> <meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta content="/favicon.png" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<meta name="googlebot" content="index, follow, snippet" />
<link rel="canonical" href="https://selenite.cc/" />
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta property="og:title" content="Selenite">
<meta property="og:type" content="website">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Selenite",
"alternateName": "selenite.cc",
"url": "https://selenite.cc",
"logo": "https://selenite.cc/favicon.png",
"sameAs": [
"https://github.com/selenite-cc",
"https://youtube.com/@selenitecc",
"https://tiktok.com/@selenitecc",
"https://selenite.cc",
]
}
</script>
<!-- initialize my stuff --> <!-- initialize my stuff -->
<script src="/js/all.min.js"></script> <script src="/js/all.min.js"></script>
<script src="/js/main.js"></script> <script src="/js/main.js"></script>
<link rel="stylesheet" href="/style.css" /> <link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<link rel="stylesheet" href="/css/profile.css" />
<link rel="manifest" href="/manifest.json" />
<!-- seo + other things --> <!-- seo + other things -->
<style>{{ custom_css }}</style>
<title>{{ name }}'s Profile | Selenite</title> <title>{{ name }}'s Profile | Selenite</title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", ()=>{
let music = {{ is_music }};
let audioObject;
if(music) {
document.body.classList = "enter-on";
let url = "{{ song_url }}";
audioObject = new Audio(url);
audioObject.addEventListener("loadeddata", () => {
document.getElementById("totalLength").innerText = `${Math.floor(audioObject.duration/60)}:${String(Math.floor(audioObject.duration%60)).padStart(2, "0")}`;
document.getElementById("playbar").value = 0;
})
document.getElementById("enter").addEventListener("click", async ()=>{
document.getElementById("enter").style.backgroundColor = "#00000000"
document.getElementById("enter").style.backdropFilter = "blur(0px)"
document.getElementById("enter").style.opacity = "0";
setTimeout(() => {
audioObject.play();
audioObject.loop = true;
document.body.classList = "";
}, 500)
setTimeout( () => {
document.getElementById("enter").style.display = "none";
}, 950);
});
} else {
document.getElementById("enter").style.display = "none";
document.querySelectorAll("section")[0].querySelectorAll(".profile-element")[1].style.display = "none";
}
document.getElementById("playPause").addEventListener("click", ()=>{
if(audioObject.paused) {
document.getElementById("playPause").src = "/img/pause.svg";
audioObject.play();
} else {
document.getElementById("playPause").src = "/img/play.svg";
audioObject.pause();
}
});
document.getElementById("mute").addEventListener("click", ()=>{
if(audioObject.volume == 0) {
document.getElementById("mute").src = "/img/volume.svg";
audioObject.volume = 1;
} else {
document.getElementById("mute").src = "/img/muted.svg";
audioObject.volume = 0;
}
});
document.getElementById("playbar").addEventListener("input", (e) => {
audioObject.currentTime = document.getElementById("playbar").value/1000*audioObject.duration;
});
audioObject.addEventListener("timeupdate", (e) => {
document.getElementById("totalLength").innerText = `${Math.floor(audioObject.duration/60)}:${String(Math.floor(audioObject.duration%60)).padStart(2, "0")}`
document.getElementById("curPos").innerText = `${Math.floor(audioObject.currentTime/60)}:${String(Math.floor(audioObject.currentTime%60)).padStart(2, "0")}`
document.getElementById("playbar").value = (audioObject.currentTime / audioObject.duration) * 1000;
})
})
</script>
</head> </head>
<alerts> </alerts> <alerts> </alerts>
<body class="profile"> <body>
<header> <div id="enter"><h1 class="title">click to enter</h1><p>this user selected a song, please mute the tab if you don't want to listen</p></div>
<a href="/index.html">Home</a> <h1 class="title">{{ name }}'s profile</h1>
<a href="/bookmarklets.html">Bookmarklets</a> <section>
<a href="/projects.html">Games</a> <img src="{{ user_pfp }}" class="pfp" />
<a href="/apps.html">Apps</a> <div class="profile-element">
<a href="/settings.html">Settings</a> <h1>{{ name }}</h1>
<a id="blank" href="#">Open Blank</a> <p>/u/{{ username }}</p>
<a href="/u/" class="usericon"><img src="/img/user.svg" /></a> <div class="badges">{{ badges }}</div>
</header>
<main>
<div class="profile top">
<img src="{{ user_pfp }}" class="pfp" />
<div class="profile top text">
<h1>{{ name }}</h1>
<div class="samerow">{{ badges }}</div>
<h2>Joined {{ join_date }}</h2>
<h2>Last online {{ online_time }}</h2>
</div>
<div class="profile top text right">
<h1>About Me</h1>
<h2 class="about">{{ about }}</h2>
</div>
</div> </div>
<div class="profile played"> <div class="profile-element">
<h2>Top Games:</h2> <h2>{{ song_title }}</h2>
<div id="played-games"> <h3>{{ song_artist }}</h3>
{{ played_games }} <div class="samerow">
</div> <p id="curPos">0:00</p>
<input type="range" id="playbar" min="1" max="1000" />
<p id="totalLength">9:99</p>
</div>
<div class="samerow">
<img id="playPause" src="/img/pause.svg" class="controls"/>
<img id="mute" src="/img/volume.svg" class="controls"/>
</div>
</div> </div>
</main> <div class="profile-element">
<footer> <h2>Joined {{ join_date }}</h2>
<a href="https://gitlab.com/skysthelimit.dev/selenite">Source</a> <h2>Last online {{ online_time }}</h2>
<a href="https://discord.gg/7jyufnwJNf">Discord</a> </div>
<a href="/suggest.html">Suggestions & Bugs</a> </section>
<a href="/contact.html">Contact</a> <section class="column" id="about">
<a href="/support.html">Donate</a> <h1>about me</h1>
<a href="/about.html">About</a> <p>{{ about }}</p>
</footer> </section>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->

View File

@ -1,25 +1,73 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
<!-- initialize externals --> <!-- initialize externals -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script> <meta property="og:title" content="Selenite" />
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script> <meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta content="/favicon.png" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<meta name="googlebot" content="index, follow, snippet" />
<link rel="canonical" href="https://selenite.cc/" />
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta property="og:title" content="Selenite">
<meta property="og:type" content="website">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Selenite",
"alternateName": "selenite.cc",
"url": "https://selenite.cc",
"logo": "https://selenite.cc/favicon.png",
"sameAs": [
"https://github.com/selenite-cc",
"https://youtube.com/@selenitecc",
"https://tiktok.com/@selenitecc",
"https://selenite.cc",
]
}
</script>
<!-- initialize my stuff --> <!-- initialize my stuff -->
<script src="/js/all.min.js"></script> <script src="/js/all.min.js"></script>
<script src="/js/main.js"></script> <script src="/js/main.js"></script>
<link rel="stylesheet" href="/style.css" /> <link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<link rel="stylesheet" href="/css/profile.css" />
<link rel="manifest" href="/manifest.json" />
<!-- seo + other things --> <!-- seo + other things -->
<title>{{ name }}'s Profile | Selenite</title> <title>{{ name }}'s Profile | Selenite</title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script>
<!-- <script>
let audioObject;
document.addEventListener("DOMContentLoaded", ()=>{
let music = false; // {{ is_music }}
if(music) {
let url = "/api/music/download?url=https://soundcloud.com/archive5077/fostered-alcoholism-grayskies"; // {{ music_url }}
let audioObject = new Audio(url);
document.getElementById("enter").addEventListener("click", async ()=>{
document.getElementById("enter").style.backgroundColor = "#00000000"
document.getElementById("enter").style.backdropFilter = "blur(0px)"
document.getElementById("enter").style.opacity = "0";
setTimeout( () => {
document.getElementById("enter").style.display = "none";
audioObject.play();
}, 700);
});
}
})
</script> -->
<script> <script>
let username = "{{ username }}"; let username = "{{ username }}";
let userData; let userData;
let songData;
(async () => { (async () => {
userData = await (await fetch("/u/raw")).json(); userData = await (await fetch("/u/raw")).json();
})(); })();
@ -53,6 +101,9 @@
console.log("promise finished"); console.log("promise finished");
body = { pfp: fileData }; body = { pfp: fileData };
console.log("body set"); console.log("body set");
} else if (state == "song") {
body = songData;
console.log("body set");
} else if (state == "clearpfp") { } else if (state == "clearpfp") {
body = { pfp: "del" }; body = { pfp: "del" };
} else if (state == "close") { } else if (state == "close") {
@ -79,10 +130,12 @@
document.getElementById("title").innerText = "Upload successful!"; document.getElementById("title").innerText = "Upload successful!";
document.getElementById("text").style.display = "none"; document.getElementById("text").style.display = "none";
document.getElementById("popup").style.display = "flex"; document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
} else { } else {
document.getElementById("title").innerText = "Upload failed. This probably means something bad happened, send an email to support@selenite.cc or ping @skysthelimit.dev"; document.getElementById("title").innerText = "Upload failed. This probably means something bad happened, send an email to support@selenite.cc or ping @skysthelimit.dev";
document.getElementById("text").style.display = "none"; document.getElementById("text").style.display = "none";
document.getElementById("popup").style.display = "flex"; document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
} }
return; return;
} else if (state == "download") { } else if (state == "download") {
@ -105,11 +158,13 @@
document.getElementById("title").innerText = "Download successful!"; document.getElementById("title").innerText = "Download successful!";
document.getElementById("text").style.display = "none"; document.getElementById("text").style.display = "none";
document.getElementById("popup").style.display = "flex"; document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
} else { } else {
document.getElementById("title").innerText = "Download failed."; document.getElementById("title").innerText = "Download failed.";
document.getElementById("body-text").innerText = data.reason; document.getElementById("body-text").innerText = data.reason;
document.getElementById("body-text").style.display = "flex"; document.getElementById("body-text").style.display = "flex";
document.getElementById("popup").style.display = "flex"; document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
} }
console.log(data); console.log(data);
data = JSON.parse(data.data); data = JSON.parse(data.data);
@ -131,7 +186,19 @@
} }
console.log("sending"); console.log("sending");
body.username = username; body.username = username;
await fetch("/api/profile/edit", { document.getElementById("title").innerText = "processing...";
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "none";
document.getElementById("counter").style.display = "none";
document.getElementById("submit").style.display = "none";
document.getElementById("search").style.display = "none";
document.querySelector("results").style.display = "none";
document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
let data = await fetch("/api/profile/edit", {
credentials: "include", credentials: "include",
headers: { headers: {
"Content-type": "application/json; charset=UTF-8", "Content-type": "application/json; charset=UTF-8",
@ -140,9 +207,24 @@
method: "POST", method: "POST",
mode: "cors", mode: "cors",
}); });
console.log("sent"); let resp = await data.json();
document.getElementById("popup").style.display = "none"; if(data.status == 200) {
location.reload(); location.reload();
} else {
document.getElementById("title").innerText = "error!";
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "flex";
document.getElementById("body-text").innerText = resp.err;
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "none";
document.getElementById("counter").style.display = "none";
document.getElementById("submit").style.display = "none";
document.getElementById("search").style.display = "none";
document.querySelector("results").style.display = "none";
document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
}
} }
document.addEventListener("DOMContentLoaded", async () => { document.addEventListener("DOMContentLoaded", async () => {
document.getElementById("pfp_upload").addEventListener("change", (e) => { document.getElementById("pfp_upload").addEventListener("change", (e) => {
@ -153,71 +235,108 @@
}); });
document.getElementById("submit").addEventListener("click", await setProfile); document.getElementById("submit").addEventListener("click", await setProfile);
document.getElementById("clear").addEventListener("click", async()=>{state="clearpfp";await setProfile()}); document.getElementById("clear").addEventListener("click", async()=>{state="clearpfp";await setProfile()});
document.querySelectorAll("#edit").forEach((element) => { document.getElementById("pfp").addEventListener("click", () => {
element.addEventListener("click", (e) => { state = "pfp";
console.log(e.target.parentElement.children[0].id); document.getElementById("title").innerText = "upload a new profile picture";
if (e.target.parentElement.children[0].id == "name") { document.getElementById("pfp_upload").style.display = "flex";
state = "name"; document.getElementById("pfp_reminder").style.display = "flex";
document.getElementById("title").innerText = "Set your name."; document.getElementById("body-text").style.display = "none";
document.getElementById("text").setAttribute("maxlength", "20"); document.getElementById("clear").style.display = "flex";
document.getElementById("pfp_upload").style.display = "none"; document.getElementById("text").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none"; document.getElementById("counter").style.display = "none";
document.getElementById("body-text").style.display = "none"; document.getElementById("submit").style.display = "flex";
document.getElementById("clear").style.display = "none"; document.getElementById("popup").style.display = "flex";
document.getElementById("text").style.display = "flex"; document.getElementById("blur").style.display = "flex";
document.getElementById("text").value = userData["name"]; document.getElementById("search").style.display = "none";
document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`; document.querySelector("results").style.display = "none";
document.getElementById("counter").style.display = "flex";
document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex";
} else if (e.target.parentElement.children[0].id == "bio") {
state = "bio";
document.getElementById("title").innerText = "Set your about me.";
document.getElementById("text").setAttribute("maxlength", "200");
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "flex";
document.getElementById("text").value = userData["about"];
document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`;
document.getElementById("counter").style.display = "flex";
document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex";
} else if (e.target.parentElement.children[0].id == "custom") {
state = "custom";
document.getElementById("title").innerText = "Set your custom CSS.";
document.getElementById("text").setAttribute("maxlength", "2048");
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "flex";
document.getElementById("text").value = userData["css"];
document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`;
document.getElementById("counter").style.display = "flex";
document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex";
} else if (e.target.parentElement.children[0].id == "pfp") {
state = "pfp";
document.getElementById("title").innerText = "Set your new profile picture.";
document.getElementById("pfp_upload").style.display = "flex";
document.getElementById("pfp_reminder").style.display = "flex";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "flex";
document.getElementById("text").style.display = "none";
document.getElementById("counter").style.display = "none";
document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex";
}
});
}); });
document.getElementById("name").addEventListener("click", () => {
state = "name";
document.getElementById("title").innerText = "change your name";
document.getElementById("text").setAttribute("maxlength", "20");
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "flex";
document.getElementById("text").value = userData["name"];
document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`;
document.getElementById("counter").style.display = "flex";
document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
document.getElementById("search").style.display = "none";
document.querySelector("results").style.display = "none";
});
document.getElementById("about").addEventListener("click", () => {
state = "bio";
document.getElementById("title").innerText = "change your about me";
document.getElementById("text").setAttribute("maxlength", "200");
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "flex";
document.getElementById("text").value = userData["about"];
document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`;
document.getElementById("counter").style.display = "flex";
document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
document.getElementById("search").style.display = "none";
document.querySelector("results").style.display = "none";
});
document.getElementById("song").addEventListener("click", () => {
state = "song";
document.getElementById("title").innerText = "pick a song";
document.getElementById("text").setAttribute("maxlength", "2048");
document.getElementById("pfp_upload").style.display = "none";
document.getElementById("pfp_reminder").style.display = "none";
document.getElementById("body-text").style.display = "none";
document.getElementById("clear").style.display = "none";
document.getElementById("text").style.display = "none";
document.getElementById("counter").style.display = "none";
document.getElementById("submit").style.display = "none";
document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
document.getElementById("search").style.display = "flex";
document.querySelector("results").style.display = "flex";
})
document.getElementById("close").addEventListener("click", () => { document.getElementById("close").addEventListener("click", () => {
document.getElementById("popup").style.display = "none"; document.getElementById("popup").style.display = "none";
document.getElementById("blur").style.display = "none";
}); });
document.getElementById("text").addEventListener("input", () => { document.getElementById("text").addEventListener("input", () => {
document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`; document.getElementById("counter").innerText = `${document.getElementById("text").value.length} / ${document.getElementById("text").attributes.maxlength.value}`;
}); });
document.getElementById("search").addEventListener("input", async ()=>{
if(document.getElementById("search").value.length > 0) {
let query = document.getElementById("search").value;
let results = await fetch("/api/music/search?q=" + encodeURIComponent(document.getElementById("search").value));
let json = await results.json();
if(document.getElementById("search").value == query) {
document.querySelector("results").display = "flex";
console.log("searched")
let i = 0;
json.tracks.forEach((e)=>{
document.querySelectorAll("result")[i].querySelector("h2").innerText = e.title;
document.querySelectorAll("result")[i].querySelectorAll("p")[0].innerText = e.artists[0].name;
document.querySelectorAll("result")[i].querySelectorAll("p")[1].innerText = e.url.slice(22);
document.querySelectorAll("result")[i].setAttribute("data-url", e.url);
document.querySelectorAll("result")[i].style.display = "flex";
i++;
})
}
} else {
document.querySelectorAll("result").forEach((e) => {
e.removeAttribute("data-url");
e.querySelector("h2").innerText = null;
e.querySelectorAll("p")[0].innerText = null;
e.querySelectorAll("p")[1].innerText = null;
e.style.display = "none";
})
}
})
document.getElementById("upload").addEventListener("click", async () => { document.getElementById("upload").addEventListener("click", async () => {
state = "upload"; state = "upload";
document.getElementById("title").innerText = "Warning"; document.getElementById("title").innerText = "Warning";
@ -230,6 +349,7 @@
document.getElementById("counter").style.display = "none"; document.getElementById("counter").style.display = "none";
document.getElementById("submit").style.display = "flex"; document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex"; document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
}); });
document.getElementById("download").addEventListener("click", async () => { document.getElementById("download").addEventListener("click", async () => {
state = "download"; state = "download";
@ -243,79 +363,75 @@
document.getElementById("counter").style.display = "none"; document.getElementById("counter").style.display = "none";
document.getElementById("submit").style.display = "flex"; document.getElementById("submit").style.display = "flex";
document.getElementById("popup").style.display = "flex"; document.getElementById("popup").style.display = "flex";
document.getElementById("blur").style.display = "flex";
});
document.querySelectorAll("result").forEach(async e => {
e.addEventListener("click", async (element) => {
songData = {
url: e.getAttribute("data-url"),
title: e.childNodes[0].innerText,
artist: e.childNodes[1].innerText,
}
console.log(songData);
await setProfile();
})
}); });
}); });
</script> </script>
</head> </head>
<alerts> </alerts>
<body> <body>
<header> <div id="blur"></div>
<a href="/index.html">Home</a> <div id="popup" style="display: none">
<a href="/bookmarklets.html">Bookmarklets</a> <h1 id="title"></h1>
<a href="/projects.html">Games</a> <p id="body-text"></p>
<a href="/apps.html">Apps</a> <input type="text" id="text" />
<a href="/settings.html">Settings</a> <input type="text" id="search" placeholder="search a song title here.."/>
<a id="blank" href="#">Open Blank</a> <results id="results">
<a href="/u/" class="usericon"><img src="/img/user.svg" /></a> <result><h2></h2><p></p><p></p></result>
</header> <result><h2></h2><p></p><p></p></result>
<main> <result><h2></h2><p></p><p></p></result>
<!-- <a class="friend-icon" href="/friends"><img src="/img/friend.svg"></a> --> <result><h2></h2><p></p><p></p></result>
<input type="text" readonly value="{{ url_gen }}" /> <result><h2></h2><p></p><p></p></result>
<div class="samerow"> <result><h2></h2><p></p><p></p></result>
<button id="download">Download Backup</button> <result><h2></h2><p></p><p></p></result>
<button id="upload">Upload Backup</button> <result><h2></h2><p></p><p></p></result>
<result><h2></h2><p></p><p></p></result>
<result><h2></h2><p></p><p></p></result>
</results>
<p id="counter">0 / 0</p>
<input type="file" id="pfp_upload" name="filename" accept=".png,.jpg,.jpeg,.gif,.avif,.webp,.tiff,.svg" />
<p id="pfp_reminder">4 MB file upload max</p>
<button id="clear">Clear Profile Picture</button>
<button id="submit">Submit</button>
<button id="close">X</button>
</div>
<div class="samerow">
<button id="download">download cloud backup</button>
<button id="upload">upload cloud backup</button>
</div>
<h1 class="title">{{ name }}'s profile</h1>
<h3>click on an area to edit</h3>
<p style="font-size: 16px;">share your profile at {{ url_gen }}</p>
{{ staff_buttons }}
<section>
<img src="{{ user_pfp }}" class="pfp edit" id="pfp" />
<div class="profile-element edit" id="name">
<h1>{{ name }}</h1>
<p>/u/{{ username }}</p>
<div class="badges">{{ badges }}</div>
</div> </div>
<div> <div class="profile-element edit" id="song">
<div id="custom"></div> <h2>{{ song_title }}</h2>
{{ css_edit }} <h3>{{ song_artist }}</h3>
</div> </div>
<div class="profile top"> <div class="profile-element">
<img src="{{ user_pfp }}" class="pfp" id="pfp" /> <h2>Joined {{ join_date }}</h2>
<img src="/img/edit.svg" id="edit" /> <h2>Last online {{ online_time }}</h2>
<div class="profile top text">
<div class="samerow edit" id="name">
<h1 id="name">{{ name }}</h1>
<img src="/img/edit.svg" id="edit" />
</div>
<div class="samerow">{{ badges }}</div>
<h2>Joined {{ join_date }}</h2>
<h2>Last online {{ online_time }}</h2>
</div>
<div class="profile top text right">
<div class="samerow edit" id="about">
<h1 id="bio">Bio</h1>
<img src="/img/edit.svg" id="edit" />
</div>
<h2 id="about">{{ about }}</h2>
</div>
</div> </div>
<div class="profile played"> </section>
<h2>Top Games:</h2> <section class="column edit" id="about">
<div id="played-games"> <h1>about me</h1>
{{ played_games }} <p class="about">{{ about }}</p>
</div> </section>
</div>
</main>
<popups>
<div id="popup" style="display: none">
<h1 id="title"></h1>
<p id="body-text"></p>
<input type="text" id="text" />
<p id="counter">0 / 0</p>
<input type="file" id="pfp_upload" name="filename" accept=".png,.jpg,.jpeg,.gif,.avif,.webp,.tiff,.svg" />
<p id="pfp_reminder">4 MB file upload max</p>
<button id="clear">Clear Profile Picture</button>
<button id="submit">Submit</button>
<button id="close">X</button>
</div>
</popups>
<footer>
<a href="https://gitlab.com/skysthelimit.dev/selenite">Source</a>
<a href="https://discord.gg/7jyufnwJNf">Discord</a>
<a href="/suggest.html">Suggestions & Bugs</a>
<a href="/contact.html">Contact</a>
<a href="/support.html">Donate</a>
<a href="/about.html">About</a>
</footer>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
@ -14,91 +14,82 @@
<script src="https://js.hcaptcha.com/1/api.js" async defer></script> <script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<link rel="stylesheet" href="/style.css" /> <link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<!-- seo + other things --> <!-- seo + other things -->
<title>Register | Selenite</title> <title>Login | Selenite</title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<script> <script>
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
document.getElementById("close").addEventListener("click", () => { document.getElementById("close").addEventListener("click", () => {
document.getElementById("popup").style.display = "none"; document.getElementById("popup").style.display = "none";
if (document.getElementById("title").innerText == "Registered successfully") { if (document.getElementById("title").innerText == "Registered successfully") {
location.href = "/login"; location.href = "/login";
} }
});
document.getElementById("register").addEventListener("click", async () => {
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
let captcha = document.getElementById("hcaptcha").firstChild.dataset.hcaptchaResponse;
if (!document.getElementById("hcaptcha").firstChild.dataset.hcaptchaResponse) {
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = "You have not done the CAPTCHA. Please complete the CAPTCHA before continuing.";
document.getElementById("popup").style.display = "flex";
return;
}
if (username.length < 17 && username.length > 2 && !/[^a-zA-Z0-9._-]/.test(username)) {
} else {
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = "Your username is invalid. Please make your username within the limits described.";
document.getElementById("popup").style.display = "flex";
return;
}
if (!/^((?=\S*?[A-Z])(?=\S*?[a-z])(?=\S*?[0-9]).{5,})\S$/.test(password)) {
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = "Your password is invalid. Please make your password within the limits described.";
document.getElementById("popup").style.display = "flex";
return;
}
let data = await (
await fetch("/register", {
method: "POST",
body: JSON.stringify({
username: username,
password: password,
"h-captcha-response": captcha,
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
})
).json();
console.log(data);
if (data.success) {
document.getElementById("title").innerText = "Registered successfully";
document.getElementById("reason").innerText = `Please save the following, this is required to reset your password.\n\n${data.key}\n\nExit to continue`;
} else {
console.log("Error: ", data.reason);
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = data.reason;
}
document.getElementById("popup").style.display = "flex";
});
}); });
document.getElementById("register").addEventListener("click", async () => {
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
let captcha = document.getElementById("hcaptcha").firstChild.dataset.hcaptchaResponse;
if (!document.getElementById("hcaptcha").firstChild.dataset.hcaptchaResponse) {
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = "You have not done the CAPTCHA. Please complete the CAPTCHA before continuing.";
document.getElementById("popup").style.display = "flex";
return;
}
if (username.length < 17 && username.length > 2 && !/[^a-zA-Z0-9._-]/.test(username)) {
} else {
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = "Your username is invalid. Please make your username within the limits described.";
document.getElementById("popup").style.display = "flex";
return;
}
if (!/^((?=\S*?[A-Z])(?=\S*?[a-z])(?=\S*?[0-9]).{5,})\S$/.test(password)) {
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = "Your password is invalid. Please make your password within the limits described.";
document.getElementById("popup").style.display = "flex";
return;
}
let data = await (
await fetch("/register", {
method: "POST",
body: JSON.stringify({
username: username,
password: password,
"h-captcha-response": captcha,
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
})
).json();
console.log(data);
if (data.success) {
document.getElementById("title").innerText = "Registered successfully";
document.getElementById("reason").innerText = `Please save the following, this is required to reset your password.\n\n${data.key}\n\nExit to continue`;
} else {
console.log("Error: ", data.reason);
document.getElementById("title").innerText = "Failed to register";
document.getElementById("reason").innerText = data.reason;
}
document.getElementById("popup").style.display = "flex";
});
});
</script> </script>
</head> </head>
<alerts> </alerts> <alerts> </alerts>
<body id="noscroll"> <body>
<header> <h2>register..</h2>
<a href="/index.html">Home</a> <div>
<a href="/bookmarklets.html">Bookmarklets</a>
<a href="/projects.html">Games</a>
<a href="/apps.html">Apps</a>
<a href="/settings.html">Settings</a>
<a id="blank" href="#">Open Blank</a>
<a href="/u/" class="usericon"><img src="/img/user.svg" /></a>
</header>
<main id="main" class="noscroll">
<h2>Register a new account</h2>
<input type="text" id="username" placeholder="username" /> <input type="text" id="username" placeholder="username" />
<p>3-16 characters<br />capital, lowercase, numbers, dash, underscore, and dots allowed</p> <p>3-16 characters<br />capital, lowercase, numbers, dash, underscore, and dots allowed</p>
<input type="password" id="password" placeholder="password" /> <input type="password" id="password" placeholder="password" />
<p>6+ characters<br />one uppercase, lowercase, and number at least</p> <p>6+ characters<br />one uppercase, lowercase, and number at least</p>
<div class="h-captcha" id="hcaptcha" data-sitekey="1774ec96-39be-4fb0-9e82-f4c62354b8fa"></div> <div class="h-captcha" id="hcaptcha" data-sitekey="1774ec96-39be-4fb0-9e82-f4c62354b8fa"></div>
<p><a href="/login">Or login</a></p> <p><a href="/login">already have an account? login here.</a></p>
<button type="submit" value="Submit" id="register">Register</button> <button type="submit" value="Submit" id="register">create an account</button>
</main> </div>
<popups> <popups>
<div id="popup" style="display: none"> <div id="popup" style="display: none">
<h1 id="title"></h1> <h1 id="title"></h1>
@ -106,13 +97,5 @@
<button id="close">X</button> <button id="close">X</button>
</div> </div>
</popups> </popups>
<footer class="noscroll">
<a href="https://gitlab.com/skysthelimit.dev/selenite">Source</a>
<a href="https://discord.gg/7jyufnwJNf">Discord</a>
<a href="/suggest.html">Suggestions & Bugs</a>
<a href="/contact.html">Contact</a>
<a href="/support.html">Donate</a>
<a href="/about.html">About</a>
</footer>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
<!-- initialize externals -->
<meta property="og:title" content="Selenite" />
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta content="/favicon.png" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<meta name="googlebot" content="index, follow, snippet" />
<link rel="canonical" href="https://selenite.cc/" />
<meta property="og:description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta property="og:title" content="Selenite">
<meta property="og:type" content="website">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Selenite",
"alternateName": "selenite.cc",
"url": "https://selenite.cc",
"logo": "https://selenite.cc/favicon.png",
"sameAs": [
"https://github.com/selenite-cc",
"https://youtube.com/@selenitecc",
"https://tiktok.com/@selenitecc",
"https://selenite.cc",
]
}
</script>
<!-- initialize my stuff -->
<script src="/js/all.js"></script>
<script src="/js/main.js"></script>
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<link rel="manifest" href="/manifest.json" />
<!-- seo + other things -->
<title>Selenite</title>
<link rel="icon" href="/favicon.ico" />
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script>
</head>
<alerts> </alerts>
<body>
<h1 class="title">stats</h1>
</body>
</html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
@ -7,7 +7,7 @@
<!-- initialize externals --> <!-- initialize externals -->
<meta property="og:title" content="Selenite" /> <meta property="og:title" content="Selenite" />
<meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." /> <meta property="description" content="Selenite is the best unblocked games site. With over 400 games and an account system, no other websites come close to Selenite." />
<meta name="keywords" content="proxy, web proxy, unblock websites, unblock chromebook, free web proxy, proxy list, proxy sites, un block chromebook, online proxy, proxy server, proxysite, proxy youtube, bypass securly, bypass iboss, bypass lightspeed filter, chromebooks, unblock youtube, youtube proxy, unblocked youtube, youtube unblocked, unblock games, selenite, unblocked games, free games">
<meta content="/favicon.png" property="og:image" /> <meta content="/favicon.png" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" /> <meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<meta name="googlebot" content="index, follow, snippet" /> <meta name="googlebot" content="index, follow, snippet" />
@ -34,7 +34,7 @@
</script> </script>
<!-- initialize my stuff --> <!-- initialize my stuff -->
<script src="/js/all.js"></script> <script src="/js/all.min.js"></script>
<script src="/js/main.js"></script> <script src="/js/main.js"></script>
<!-- <script src="/js/widget.js"></script> --> <!-- <script src="/js/widget.js"></script> -->
<script> <script>
@ -42,17 +42,93 @@
<link rel="stylesheet" href="/css/main.css" /> <link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" /> <link rel="stylesheet" href="/css/pages.css" />
<link rel="stylesheet" href="/css/users.css" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<!-- seo + other things --> <!-- seo + other things -->
<title>Selenite</title> <title>Selenite</title>
<script>
async function loadUsers(query, page) {
let above = false;
let below = false;
let data = await (await fetch(`/api/getUsers?page=${page - 1}&query=${query}`)).json();
let users = data['users'];
let url = new URL(location.href);
pages = Math.ceil(data.count / 12);
document.getElementById("users").innerHTML = "";
for (let i = 0; i < Object.keys(users).length; i++) {
document.getElementById("users").innerHTML += `<a href="/u/${users[i].username}" class="users"><img class="pfp" src="${users[i].pfp_url}"/><div class="user_info"><h1>${users[i].name}</h1><p>${users[i].about}</p></div></a>`;
}
document.getElementById("pages").innerHTML = "";
for (let i = 1; i < pages + 1; i++) {
if (i + 6 > page && i - 6 < page) {
let curPage = parseInt(page);
let element = document.createElement("a");
if (!(i == curPage)) {
url.searchParams.set("page", i);
element.setAttribute("href", url);
}
element.setAttribute("class", `pages-btn`);
element.innerText = i;
document.getElementById("pages").append(element);
} else {
if (i + 6 > page) {
above = true;
}
if (i - 6 < page) {
below = true;
}
}
}
if (above) {
let element = document.createElement("a");
element.setAttribute("class", "pages-btn");
element.innerText = "...";
document.getElementById("pages").append(element);
}
if (below) {
let element = document.createElement("a");
element.setAttribute("class", "pages-btn");
element.innerText = "...";
document.getElementById("pages").prepend(element);
}
}
let pages;
document.addEventListener("DOMContentLoaded", async () => {
let params = location.search.substring(1).split("&");
let query;
let page;
if (params) {
for (let i = 0; i < params.length; i++) {
if (params[i].startsWith("query")) {
query = params[i].substring(6);
}
if (params[i].startsWith("page")) {
page = params[i].substring(5);
if (isNaN(page)) {
page = 1;
}
}
}
}
await loadUsers(query ? query : "", page ? page : 0);
document.getElementById("search").addEventListener("keydown", async (e) => {
if (e.key == "Enter") {
let url = new URL(location.href);
url.searchParams.set("query", document.getElementById("search").value);
url.searchParams.set("page", 1);
location.href = url;
}
});
});
</script>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script> <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script>
</head> </head>
<alerts> </alerts> <alerts> </alerts>
<body> <body>
<h1 class="title">users</h1> <h1 class="title">users</h1>
<div id="users"> <div id="users"></div>
<div id="pages"></div>
</div>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="sl-theme-dark" lang="en"> <html lang="en">
<head> <head>
<!-- initialize theme vars <!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->

230
index.js
View File

@ -1,4 +1,3 @@
const io = require('@pm2/io')
import { log } from "./log.js"; import { log } from "./log.js";
import bodyParser from "body-parser"; import bodyParser from "body-parser";
import express from "express"; import express from "express";
@ -8,12 +7,14 @@ import { fileURLToPath } from "url";
import path, { dirname } from "node:path"; import path, { dirname } from "node:path";
import mime from "mime-types"; import mime from "mime-types";
import compression from "compression"; import compression from "compression";
import { accs, infdb, polytrack } from "./database.js"; // import { accs, infdb, polytrack } from "./database.js";
import { accs } from "./database.js";
import { } from "./accounts/friend.js"; import { } from "./accounts/friend.js";
import { search, download } from "./accounts/music.js";
import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js"; import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js";
import { } from "./accounts/misc.js"; import { } from "./accounts/misc.js";
import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js"; import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js";
// import { infiniteCraft, chatBot } from "./ai.js"; import { callAI } from "./ai.js";
import os from "node:os"; import os from "node:os";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
@ -21,88 +22,59 @@ const __dirname = dirname(__filename);
const port = process.env.PORT || 3000; const port = process.env.PORT || 3000;
const app = express(); const app = express();
// why the fuck does this have to exist?
app.use("/resources/semag/hotline-miami/", (req,res,next) => {
if(req.method == "HEAD") {
req.socket.destroy();
}
next();
});
app.use(compression()); app.use(compression());
app.use(cookieParser()); app.use(cookieParser());
app.use(express.json({ limit: "10mb" })); app.use(express.json({ limit: "10mb" }));
app.use(express.urlencoded({ extended: false })); app.use(express.urlencoded({ extended: false }));
app.use(express.text()); app.use(express.text());
let requests = 0; // app.use("/", (req, res, next) => {
const requestsPerSec = io.meter({ // next();
name: 'req/sec', // });
id: 'app/requests/sec'
});
const requestsPerMin = io.meter({
name: 'req/min',
id: 'app/requests/min'
});
app.use("/", (req, res, next) => {
requestsPerSec.mark();
requestsPerMin.mark();
next();
});
const sockets = io.metric({
name: 'Open Websockets',
id: 'app/requests/sockets',
});
// setInterval(()=>{ // setInterval(()=>{
// }, 1000) // }, 1000)
import WebSocket, { WebSocketServer } from "ws"; import WebSocket, { WebSocketServer } from "ws";
import { request } from "node:http";
const wss = new WebSocketServer({ noServer: true }); const wss = new WebSocketServer({ noServer: true });
let openSockets = 0; // let openSockets = 0;
wss.on("connection", function connection(ws, req, res) { wss.on("connection", function connection(ws, req, res) {
openSockets++; ws.send(`online=${wss.clients.size}`);
sockets.set(openSockets);
setInterval(() => { setInterval(() => {
ws.send("ping"); ws.send(`online=${wss.clients.size}`);
}, 30000); }, 10000);
ws.on("error", console.error); ws.on("error", console.error);
ws.on("message", async function message(data, isBinary) { ws.on("message", async function message(data, isBinary) {
let message = Buffer.from(data).toString(); let message = Buffer.from(data).toString();
if (message.startsWith(process.env.ANNOUNCEMENT_KEY)) { if (message.startsWith("token") && (await verifyCookie(message.substring(6)))) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(message.replace(process.env.ANNOUNCEMENT_KEY, "announce."));
}
});
} else if (message.startsWith("token") && (await verifyCookie(message.substring(6)))) {
ws.id = await getUserFromCookie(message.substring(6)); ws.id = await getUserFromCookie(message.substring(6));
ws.send(ws.id); ws.send(ws.id);
const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`) const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`)
updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id }); updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id });
} else if (message.startsWith("pong")) { } else if (message.startsWith("1")) {
if (ws.id) { if (ws.id) {
const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`) const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`)
updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id }); updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id });
if (message.substring(4)) { }
const existingAccount = accs.query(`SELECT * FROM accounts WHERE username LIKE $1`) } else if (message.startsWith("annc")) {
let userData = existingAccount.get({ $1: ws.id }); let splitMessage = message.split(";;");
if (userData == null) { if(await isAdmin(splitMessage[1])) {
return { success: false, reason: "The account doesn't exist." }; wss.clients.forEach(client => {
} client.send(`annc;;${splitMessage[2]};;${splitMessage[3]}`);
let games; })
if (userData.playedgames) {
games = JSON.parse(userData.playedgames);
} else {
games = {};
}
if (games[message.substring(4)]) {
games[message.substring(4)] += 30;
} else {
games[message.substring(4)] = 30;
}
const updateAccount = accs.query(`UPDATE accounts SET playedgames = $playedgames WHERE username = $user`)
updateAccount.get({ $playedgames: JSON.stringify(games), $user: ws.id });
}
} }
} }
}); });
ws.on("close", () => {openSockets--; ws.on("close", () => {});
sockets.set(openSockets);});
}); });
app.post( app.post(
"/api/event", "/api/event",
@ -120,11 +92,6 @@ app.post(
}) })
} }
); );
// app.use("*.json", async (req, res, next) => {
// optimize json
// console.log("got data");
// next()
// });
app.post("/register", async (req, res) => { app.post("/register", async (req, res) => {
let status = await createAccount(req.body.username, req.body.password, req.body["h-captcha-response"]); let status = await createAccount(req.body.username, req.body.password, req.body["h-captcha-response"]);
if (status["success"]) { if (status["success"]) {
@ -173,24 +140,16 @@ app.post("/api/account/upload", async (req, res, next) => {
res.status(400).send(status); res.status(400).send(status);
} }
} else { } else {
return "KILL YOURSELF"; // return "KILL YOURSELF";
} }
}); });
// ai endpoints
app.post("/api/ai/createChat", async (req, res) => {
// create chat in database and store some metadata about it
// ie: last model, time created, etc etc
})
app.post("/api/ai/sendMessage", async (req, res) => { app.post("/api/ai/sendMessage", async (req, res) => {
// take in chat id and message // take in chat id and message
// stream back reply // stream back reply
}) })
app.get("/api/ai/messages", async (req, res) => {
// take in chat id
// use unique uuid to store every chat
// return messages
})
// friends endpoints // friends endpoints
app.get("/api/friends/list", async (req, res) => { app.get("/api/friends/list", async (req, res) => {
// use auth token to get user // use auth token to get user
@ -227,110 +186,6 @@ app.get("/api/chat/recent", async (req, res) => {
// get last 50 recent messages // get last 50 recent messages
// offset by a page param // offset by a page param
}) })
app.get("/api/infinite/get", async (req, res, next) => {
if (req.query[1] && req.query[2]) {
let success = false;
let data;
try {
let search1Query = infdb.query(`SELECT * FROM caches WHERE 1 = $one AND 2 = $two`)
let search1 = await search1Query.get({ $one: req.query[1], $two: req.query[2] });
console.log(search1);
if (search1 && search1.length > 0) {
data = { item: search1[0].result_item, emoji: search1[0].result_emoji, new: false };
success = true;
} else {
let search2Query = infdb.query(`SELECT * FROM caches WHERE 1 = $two AND 2 = $one`)
let search2 = await search2Query.get({ $one: req.query[1], $two: req.query[2] });
console.log(search2);
if (search2 && search2.length > 0) {
data = { item: search2[0].result_item, emoji: search2[0].result_emoji, new: false };
success = true;
}
}
} catch (error) {
console.error(error);
}
if (success) {
console.log("success");
res.send(data);
return;
}
data = await infiniteCraft(req.query[1], req.query[2]);
try {
let parse = JSON.parse(data);
let keys = Object.keys(parse);
if (keys.indexOf("item") > -1 && keys.indexOf("emoji") > -1) {
parse.new = true;
data = parse;
const createCached = infdb.query(`INSERT INTO caches (1, 2, result_item, result_emoji) VALUES ($one, $two, $item, $emoji)`)
createCached.run({ $one: req.query[1], $two: req.query[2], $item: data.item, $emoji: data.emoji });
res.send(data);
}
} catch (error) {
console.error(error);
data = { item: "N/A", emoji: "N/A" };
res.send(data);
}
}
});
app.use("/semag/polytrack/data/", async (req, res, next) => {
let path = req.path.substring(1, req.path.length);
if(path == "user") {
res.sendStatus(200);
} else if(path == "leaderboard") {
let data = {};
if(req.method == "POST") {
req.body.split("&").forEach((item) => {
data[item.split("=")[0]] = item.split("=")[1]
});
console.log(data);
const getExistingRuns = polytrack.query(`SELECT * FROM polytrack WHERE userid = $usrid AND trackid = $trackid`);
let existingRuns = getExistingRuns.all({ $usrid: data["userToken"], $trackid: data["trackId"] });
let saveRun = true;
if(existingRuns !== null) {
existingRuns.forEach((item) => {
if(saveRun) {
if(data.frames > item.frames) {
saveRun = false;
} else {
let deleteRun = polytrack.query(`DELETE FROM polytrack WHERE id = $id`);
deleteRun.run({ $id: item.id })
}
}
})
}
if(saveRun) {
const addRun = polytrack.query(`INSERT INTO polytrack (trackid, username, colors, recording, frames, userid) VALUES ($id, $usr, $clr, $record, $frames, $usrid)`)
let runData = addRun.run({ $id: data["trackId"], $usr: data["name"], $clr: data["carColors"], $record: data["recording"], $usrid: data["userToken"], $frames: data["frames"] });
console.log("run", runData);
res.send(runData.lastInsertRowid);
}
} else {
let leaderboard = polytrack.query(`SELECT * FROM polytrack WHERE trackid = $id LIMIT $limit OFFSET $offset`).all({ $id: req.query.trackId, $limit: req.query.amount, $offset: req.query.skip })
console.log(leaderboard);
let returnValue = {"total": leaderboard.length, "entries":[]}
for(let i = 0; i<leaderboard.length;i++) {
returnValue["entries"][i] = {};
returnValue["entries"][i]["id"] = leaderboard[i]["id"];
returnValue["entries"][i]["name"] = decodeURIComponent(leaderboard[i]["username"]);
returnValue["entries"][i]["carColors"] = leaderboard[i]["colors"];
returnValue["entries"][i]["frames"] = leaderboard[i]["frames"];
returnValue["entries"][i]["verifiedState"] = true;
returnValue["entries"][i]["isSelf"] = false;
}
res.send(returnValue);
}
} else if(path == "recording") {
let recordingQuery = polytrack.query(`SELECT * FROM polytrack WHERE id = $id`).get({ $id: req.query.recordingId });
res.send({
"recording": recordingQuery.recording,
"frames": recordingQuery.frames,
"verifiedState": true,
"carColors": recordingQuery.colors
});
}
})
app.use("/api/account/load", async (req, res, next) => { app.use("/api/account/load", async (req, res, next) => {
if (req.cookies.token && (await verifyCookie(req.cookies.token))) { if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
let status = await retrieveData(req.cookies.token); let status = await retrieveData(req.cookies.token);
@ -370,7 +225,6 @@ app.use("/api/stats", async (req, res, next) => {
// "cpu": os.cpus(), // "cpu": os.cpus(),
"ram": `${(os.totalmem()-os.freemem())/1000000000}GB / ${os.totalmem()/1000000000}GB`, "ram": `${(os.totalmem()-os.freemem())/1000000000}GB / ${os.totalmem()/1000000000}GB`,
"cpuUsage": os.loadavg(), "cpuUsage": os.loadavg(),
"openWebSockets": openSockets,
"uptime": `${os.uptime()}s` "uptime": `${os.uptime()}s`
}); });
} else { } else {
@ -387,7 +241,7 @@ app.use("/ai", async (req, res, next) => {
next(); next();
} }
}); });
app.use("/", express.static("./selenite", { extensions: ["html"] })); app.use("/", express.static("./public", { extensions: ["html"] }));
app.use("/data/:id/:file", async (req, res) => { app.use("/data/:id/:file", async (req, res) => {
const id = path.basename(req.params.id); const id = path.basename(req.params.id);
const file = path.basename(req.params.file); const file = path.basename(req.params.file);
@ -395,11 +249,12 @@ app.use("/data/:id/:file", async (req, res) => {
const filePath = path.join(process.env.DATA_PATH, "data", id, file); const filePath = path.join(process.env.DATA_PATH, "data", id, file);
try { try {
await fs.access(filePath); await fs.access(filePath);
const image = await fs.readFile(filePath);
if (mime.lookup(filePath) == "image/webp") { if (mime.lookup(filePath) == "image/webp") {
res.type("image/webp"); res.type("image/webp");
res.status(200).send(image); res.status(200).send(await fs.readFile(filePath));
} else if (mime.lookup(filePath) == "audio/ogg") {
res.type("audio/ogg");
res.status(200).send(await fs.readFile(filePath));
} else { } else {
res.status(404).send("File not found"); res.status(404).send("File not found");
} }
@ -477,6 +332,15 @@ app.post("/api/admin/ban", async (req, res) => {
let status = await banUser(req.body.name, req.body.reason, req.cookies.token); let status = await banUser(req.body.name, req.body.reason, req.cookies.token);
res.status(200).send(status); res.status(200).send(status);
}); });
app.use("/api/music/search", async (req, res, next) => {
res.status(200).send(await search(req.query.q))
});
app.use("/api/music/download", async (req, res, next) => {
res.status(200).send(await download(req.query.url))
});
const server = app.listen(port, () => { const server = app.listen(port, () => {
console.log(log.success("Express is online.")); console.log(log.success("Express is online."));
console.log("- " + log.info("http://localhost:" + port)); console.log("- " + log.info("http://localhost:" + port));
@ -490,6 +354,6 @@ server.on("upgrade", (request, socket, head) => {
app.use(async (req, res) => { app.use(async (req, res) => {
res res
.type("text/html") .type("text/html")
.send(await fs.readFile(`./selenite/404.html`)) .send(await fs.readFile(`./public/404.html`))
.status(404); .status(404);
}); });

1083
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,25 +12,23 @@
"license": "ISC", "license": "ISC",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@pm2/io": "^6.1.0", "@ai-sdk/openai-compatible": "^1.0.22",
"axios": "^1.3.1", "ai": "^5.0.68",
"body-parser": "^2.0.2", "axios": "^1.12.2",
"chalk": "^5.3.0", "body-parser": "^2.2.0",
"compression": "^1.7.4", "chalk": "^5.6.2",
"cookie-parser": "^1.4.6", "compression": "^1.8.1",
"dayjs": "^1.11.11", "cookie-parser": "^1.4.7",
"dotenv": "^16.4.5", "cors": "^2.8.5",
"express": "^5.0.0", "dayjs": "^1.11.18",
"fast-glob": "^3.3.2", "dotenv": "^16.6.1",
"file-type": "^19.0.0", "express": "^5.1.0",
"install": "^0.13.0", "file-type": "^19.6.0",
"lucida": "^2.0.0-54",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"node-html-parser": "^6.1.13",
"openai": "^4.85.3",
"rword": "^3.2.1", "rword": "^3.2.1",
"sanitize-html": "^2.13.0", "sanitize-html": "^2.17.0",
"sequelize": "^6.37.3", "sharp": "^0.33.5",
"sharp": "^0.33.4", "ws": "^8.18.3"
"ws": "^8.18.0"
} }
} }

View File

@ -2,4 +2,8 @@ module.exports = {
name: "Selenite", // Name of your application name: "Selenite", // Name of your application
script: "index.js", // Entry point of your application script: "index.js", // Entry point of your application
interpreter: "bun", // Path to the Bun interpreter interpreter: "bun", // Path to the Bun interpreter
watch: true,
cron_restart: '0 0 * * *',
instances : "max",
exec_mode : "cluster"
}; };