Compare commits
6 Commits
main
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
db94e9fe49 | |||
9389d0c7e4 | |||
daf54267b4 | |||
acd6d2e9e2 | |||
cbdf039eab | |||
fa52034fb7 |
@ -4,4 +4,8 @@ HCAPTCHA_SECRET=hcaptcha
|
||||
ANNOUNCEMENT_KEY=text.
|
||||
GROQ_API_KEY=["groq_api"]
|
||||
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
|
25
accounts/music.js
Normal file
25
accounts/music.js
Normal file
@ -0,0 +1,25 @@
|
||||
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;
|
||||
}
|
||||
async function download(url) {
|
||||
try {
|
||||
const info = await sc.getByUrl(url);
|
||||
|
||||
const { stream } = await info.getStream();
|
||||
|
||||
return stream.path;
|
||||
} catch (err) {
|
||||
console.error('Stream error:', err)
|
||||
return(err.message || 'Failed to stream track')
|
||||
}
|
||||
}
|
||||
|
||||
export { search, download };
|
@ -4,6 +4,7 @@ import sanitizeHtml from "sanitize-html";
|
||||
import sharp from "sharp";
|
||||
import { accs } from "../database.js";
|
||||
import { getUserFromCookie, isBanned, decryptCookie, verifyCookie } from "./manage.js";
|
||||
import { download } from "./music.js";
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime.js";
|
||||
@ -37,8 +38,8 @@ let rawProfileHTML = fs.readFileSync("./html/profile.html").toString();
|
||||
let rawEditProfileHTML = fs.readFileSync("./html/profile_edit.html").toString();
|
||||
let profile404 = fs.readFileSync("./html/profile_404.html").toString();
|
||||
let profileBan = fs.readFileSync("./html/profile_ban.html").toString();
|
||||
let gamesJSON = JSON.parse(fs.readFileSync("./selenite/data/games.json").toString());
|
||||
let appsJSON = JSON.parse(fs.readFileSync("./selenite/data/apps.json").toString());
|
||||
let gamesJSON = JSON.parse(fs.readFileSync("./public/resources/games.json").toString());
|
||||
let appsJSON = JSON.parse(fs.readFileSync("./public/resources/apps.json").toString());
|
||||
let profileReadyJSON = {};
|
||||
for (let i = 0; i < gamesJSON.length; i++) {
|
||||
profileReadyJSON[gamesJSON[i].directory] = { name: gamesJSON[i].name, image: gamesJSON[i].image };
|
||||
@ -193,21 +194,53 @@ async function editProfile(body, token, admin) {
|
||||
let fileType = (await fileTypeFromBuffer(pfp))["ext"];
|
||||
if (["png", "jpg", "gif", "avif", "webp", "tiff"].includes(fileType)) {
|
||||
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 path = `${process.env.DATA_PATH}/data/${existingAccount.id}/${uuid}.webp`;
|
||||
url = `/data/${existingAccount.id}/${uuid}.webp`;
|
||||
let path = `${process.env.DATA_PATH}/data/${userData.id}/${uuid}.webp`;
|
||||
url = `/data/${userData.id}/${uuid}.webp`;
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.writeFileSync(path, "");
|
||||
await sharp(pfp, { animated: fileType == "gif" })
|
||||
.resize({ width: 300, withoutEnlargement: true })
|
||||
.webp({ quality: 70, effort: 4 })
|
||||
.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`)
|
||||
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 path = await download(body.url);
|
||||
console.log("exit download");
|
||||
let file = Bun.file(path);
|
||||
let request = new Request({
|
||||
url: process.env.PROCESSING_SERVER + "/process",
|
||||
method: "POST",
|
||||
body: await file.arrayBuffer(),
|
||||
headers: {
|
||||
"X-Authentication": process.env.PROCESSING_SERVER_SECRET
|
||||
}
|
||||
});
|
||||
console.log("created request");
|
||||
let oggFile = await fetch(request);
|
||||
console.log("finished 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 });
|
||||
console.log("database");
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
@ -228,6 +261,7 @@ async function generateAccountPage(name, cookie, admin) {
|
||||
}
|
||||
|
||||
let modifiedHTML = rawProfileHTML;
|
||||
let songData = JSON.parse(userData.music) || false;
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, allowNone));
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow());
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ about }}", sanitizeHtml(userData.about, sanitizeConfig) || "No about me available..");
|
||||
@ -235,7 +269,15 @@ async function generateAccountPage(name, cookie, admin) {
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ user_pfp }}", userData.pfp_url || "/img/user.svg");
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ custom_css }}", userData.custom_css || "");
|
||||
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 = "";
|
||||
|
||||
if (userData.badges !== null) {
|
||||
@ -260,6 +302,7 @@ async function generateAccountPage(name, cookie, admin) {
|
||||
return modified_ban;
|
||||
}
|
||||
let modifiedHTML = rawEditProfileHTML;
|
||||
let songData = JSON.parse(userData.music) || false;
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, sanitizeConfig));
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ username }}", userData.username);
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow());
|
||||
@ -269,7 +312,14 @@ async function generateAccountPage(name, cookie, admin) {
|
||||
modifiedHTML = modifiedHTML.replaceAll("{{ url_gen }}", `https://selenite.cc/u/${userData.username}`);
|
||||
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("{{ played_games }}", buildGameHTML(userData));
|
||||
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 = "";
|
||||
|
||||
if (userData.badges !== null) {
|
||||
@ -282,43 +332,7 @@ async function generateAccountPage(name, cookie, admin) {
|
||||
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) {
|
||||
let amount = 12;
|
||||
if (!page) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
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>
|
||||
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<link rel="stylesheet" href="/css/main.css" />
|
||||
<link rel="stylesheet" href="/css/pages.css" />
|
||||
|
||||
<!-- seo + other things -->
|
||||
<title>Login | Selenite</title>
|
||||
@ -60,27 +61,17 @@
|
||||
</script>
|
||||
</head>
|
||||
<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>
|
||||
<main id="main" class="noscroll">
|
||||
<h2>Login to your account</h2>
|
||||
<body>
|
||||
<h2>login..</h2>
|
||||
<form onsubmit="return false;" id="login">
|
||||
<input type="text" id="username" placeholder="username" />
|
||||
<input type="password" id="password" placeholder="password" />
|
||||
<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>
|
||||
<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>
|
||||
</main>
|
||||
<popups>
|
||||
<div id="popup" style="display: none">
|
||||
<h1 id="title"></h1>
|
||||
@ -88,13 +79,5 @@
|
||||
<button id="close">X</button>
|
||||
</div>
|
||||
</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>
|
||||
</html>
|
||||
|
@ -1,67 +1,139 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
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 -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
||||
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script>
|
||||
<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 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="#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.min.js"></script>
|
||||
<script src="/js/all.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 -->
|
||||
<style>{{ custom_css }}</style>
|
||||
<title>{{ name }}'s Profile | 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>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", ()=>{
|
||||
let music = {{ is_music }};
|
||||
let audioObject;
|
||||
if(music) {
|
||||
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;
|
||||
}, 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;
|
||||
document.getElementById("playbar").value = (audioObject.currentTime / audioObject.duration) * 1000;
|
||||
});
|
||||
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>
|
||||
<alerts> </alerts>
|
||||
<body class="profile">
|
||||
<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>
|
||||
<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>
|
||||
<body>
|
||||
<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>
|
||||
<h1 class="title">{{ name }}'s profile</h1>
|
||||
<section>
|
||||
<img src="{{ user_pfp }}" class="pfp" />
|
||||
<div class="profile-element">
|
||||
<h1>{{ name }}</h1>
|
||||
<p>/u/{{ username }}</p>
|
||||
<div class="badges">{{ badges }}</div>
|
||||
</div>
|
||||
<div class="profile played">
|
||||
<h2>Top Games:</h2>
|
||||
<div id="played-games">
|
||||
{{ played_games }}
|
||||
</div>
|
||||
<div class="profile-element">
|
||||
<h2>{{ song_title }}</h2>
|
||||
<h3>{{ song_artist }}</h3>
|
||||
<div class="samerow">
|
||||
<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>
|
||||
</main>
|
||||
<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>
|
||||
<div class="profile-element">
|
||||
<h2>Joined {{ join_date }}</h2>
|
||||
<h2>Last online {{ online_time }}</h2>
|
||||
</div>
|
||||
</section>
|
||||
<section class="column">
|
||||
<h1>about me</h1>
|
||||
<p>{{ about }}</p>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
@ -1,25 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
||||
<!-- initialize externals -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
|
||||
<script src=" https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js "></script>
|
||||
<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 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="#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.min.js"></script>
|
||||
<script src="/js/all.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 -->
|
||||
<title>{{ name }}'s Profile | 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>
|
||||
<!-- <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>
|
||||
let username = "{{ username }}";
|
||||
let userData;
|
||||
let songData;
|
||||
(async () => {
|
||||
userData = await (await fetch("/u/raw")).json();
|
||||
})();
|
||||
@ -53,6 +101,9 @@
|
||||
console.log("promise finished");
|
||||
body = { pfp: fileData };
|
||||
console.log("body set");
|
||||
} else if (state == "song") {
|
||||
body = songData;
|
||||
console.log("body set");
|
||||
} else if (state == "clearpfp") {
|
||||
body = { pfp: "del" };
|
||||
} else if (state == "close") {
|
||||
@ -79,10 +130,12 @@
|
||||
document.getElementById("title").innerText = "Upload successful!";
|
||||
document.getElementById("text").style.display = "none";
|
||||
document.getElementById("popup").style.display = "flex";
|
||||
document.getElementById("blur").style.display = "flex";
|
||||
} 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("text").style.display = "none";
|
||||
document.getElementById("popup").style.display = "flex";
|
||||
document.getElementById("blur").style.display = "flex";
|
||||
}
|
||||
return;
|
||||
} else if (state == "download") {
|
||||
@ -105,11 +158,13 @@
|
||||
document.getElementById("title").innerText = "Download successful!";
|
||||
document.getElementById("text").style.display = "none";
|
||||
document.getElementById("popup").style.display = "flex";
|
||||
document.getElementById("blur").style.display = "flex";
|
||||
} else {
|
||||
document.getElementById("title").innerText = "Download failed.";
|
||||
document.getElementById("body-text").innerText = data.reason;
|
||||
document.getElementById("body-text").style.display = "flex";
|
||||
document.getElementById("popup").style.display = "flex";
|
||||
document.getElementById("blur").style.display = "flex";
|
||||
}
|
||||
console.log(data);
|
||||
data = JSON.parse(data.data);
|
||||
@ -131,7 +186,19 @@
|
||||
}
|
||||
console.log("sending");
|
||||
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",
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8",
|
||||
@ -140,9 +207,24 @@
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
});
|
||||
console.log("sent");
|
||||
document.getElementById("popup").style.display = "none";
|
||||
location.reload();
|
||||
let resp = await data.json();
|
||||
if(data.status == 200) {
|
||||
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.getElementById("pfp_upload").addEventListener("change", (e) => {
|
||||
@ -153,71 +235,108 @@
|
||||
});
|
||||
document.getElementById("submit").addEventListener("click", await setProfile);
|
||||
document.getElementById("clear").addEventListener("click", async()=>{state="clearpfp";await setProfile()});
|
||||
document.querySelectorAll("#edit").forEach((element) => {
|
||||
element.addEventListener("click", (e) => {
|
||||
console.log(e.target.parentElement.children[0].id);
|
||||
if (e.target.parentElement.children[0].id == "name") {
|
||||
state = "name";
|
||||
document.getElementById("title").innerText = "Set 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";
|
||||
} 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("pfp").addEventListener("click", () => {
|
||||
state = "pfp";
|
||||
document.getElementById("title").innerText = "upload a 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("blur").style.display = "flex";
|
||||
document.getElementById("search").style.display = "none";
|
||||
document.querySelector("results").style.display = "none";
|
||||
});
|
||||
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("popup").style.display = "none";
|
||||
document.getElementById("blur").style.display = "none";
|
||||
});
|
||||
document.getElementById("text").addEventListener("input", () => {
|
||||
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 () => {
|
||||
state = "upload";
|
||||
document.getElementById("title").innerText = "Warning";
|
||||
@ -230,6 +349,7 @@
|
||||
document.getElementById("counter").style.display = "none";
|
||||
document.getElementById("submit").style.display = "flex";
|
||||
document.getElementById("popup").style.display = "flex";
|
||||
document.getElementById("blur").style.display = "flex";
|
||||
});
|
||||
document.getElementById("download").addEventListener("click", async () => {
|
||||
state = "download";
|
||||
@ -243,79 +363,84 @@
|
||||
document.getElementById("counter").style.display = "none";
|
||||
document.getElementById("submit").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>
|
||||
</head>
|
||||
<alerts> </alerts>
|
||||
<body>
|
||||
<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>
|
||||
<main>
|
||||
<!-- <a class="friend-icon" href="/friends"><img src="/img/friend.svg"></a> -->
|
||||
<input type="text" readonly value="{{ url_gen }}" />
|
||||
<div class="samerow">
|
||||
<button id="download">Download Backup</button>
|
||||
<button id="upload">Upload Backup</button>
|
||||
<div id="blur"></div>
|
||||
<div id="popup" style="display: none">
|
||||
<h1 id="title"></h1>
|
||||
<p id="body-text"></p>
|
||||
<input type="text" id="text" />
|
||||
<input type="text" id="search" placeholder="search a song title here.."/>
|
||||
<results id="results">
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<result><h2></h2><p></p><p></p></result>
|
||||
<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 Backup</button>
|
||||
<button id="upload">Upload Backup</button>
|
||||
</div>
|
||||
<h1 class="title">{{ name }}'s profile</h1>
|
||||
<h3>click on one of the following areas to edit</h3>
|
||||
<h3>profile picture, name, song, and about me</h3>
|
||||
<p style="font-size: 16px;">share your profile at {{ url_gen }}</p>
|
||||
<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 id="custom"></div>
|
||||
{{ css_edit }}
|
||||
<div class="profile-element edit" id="song">
|
||||
<h2>{{ song_title }}</h2>
|
||||
<h3>{{ song_artist }}</h3>
|
||||
<div class="samerow">
|
||||
<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 class="profile top">
|
||||
<img src="{{ user_pfp }}" class="pfp" id="pfp" />
|
||||
<img src="/img/edit.svg" id="edit" />
|
||||
<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 class="profile-element">
|
||||
<h2>Joined {{ join_date }}</h2>
|
||||
<h2>Last online {{ online_time }}</h2>
|
||||
</div>
|
||||
<div class="profile played">
|
||||
<h2>Top Games:</h2>
|
||||
<div id="played-games">
|
||||
{{ played_games }}
|
||||
</div>
|
||||
</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>
|
||||
</section>
|
||||
<section class="column edit" id="about">
|
||||
<h1>about me</h1>
|
||||
<p class="about">{{ about }}</p>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
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>
|
||||
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<link rel="stylesheet" href="/css/main.css" />
|
||||
<link rel="stylesheet" href="/css/pages.css" />
|
||||
|
||||
<!-- seo + other things -->
|
||||
<title>Register | Selenite</title>
|
||||
<title>Login | Selenite</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.getElementById("close").addEventListener("click", () => {
|
||||
document.getElementById("popup").style.display = "none";
|
||||
if (document.getElementById("title").innerText == "Registered successfully") {
|
||||
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.addEventListener("DOMContentLoaded", () => {
|
||||
document.getElementById("close").addEventListener("click", () => {
|
||||
document.getElementById("popup").style.display = "none";
|
||||
if (document.getElementById("title").innerText == "Registered successfully") {
|
||||
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";
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<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>
|
||||
<main id="main" class="noscroll">
|
||||
<h2>Register a new account</h2>
|
||||
<body>
|
||||
<h2>register..</h2>
|
||||
<div>
|
||||
<input type="text" id="username" placeholder="username" />
|
||||
<p>3-16 characters<br />capital, lowercase, numbers, dash, underscore, and dots allowed</p>
|
||||
<input type="password" id="password" placeholder="password" />
|
||||
<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>
|
||||
<p><a href="/login">Or login</a></p>
|
||||
<button type="submit" value="Submit" id="register">Register</button>
|
||||
</main>
|
||||
<p><a href="/login">already have an account? login here.</a></p>
|
||||
<button type="submit" value="Submit" id="register">create an account</button>
|
||||
</div>
|
||||
<popups>
|
||||
<div id="popup" style="display: none">
|
||||
<h1 id="title"></h1>
|
||||
@ -106,13 +97,5 @@
|
||||
<button id="close">X</button>
|
||||
</div>
|
||||
</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>
|
||||
</html>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
@ -42,17 +42,93 @@
|
||||
|
||||
<link rel="stylesheet" href="/css/main.css" />
|
||||
<link rel="stylesheet" href="/css/pages.css" />
|
||||
<link rel="stylesheet" href="/css/users.css" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<!-- seo + other things -->
|
||||
<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.floor(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" />
|
||||
<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">users</h1>
|
||||
<div id="users">
|
||||
|
||||
</div>
|
||||
<div id="users"></div>
|
||||
<div id="pages"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="sl-theme-dark" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- initialize theme vars
|
||||
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
|
||||
|
167
index.js
167
index.js
@ -1,4 +1,3 @@
|
||||
const io = require('@pm2/io')
|
||||
import { log } from "./log.js";
|
||||
import bodyParser from "body-parser";
|
||||
import express from "express";
|
||||
@ -10,6 +9,7 @@ import mime from "mime-types";
|
||||
import compression from "compression";
|
||||
import { accs, infdb, polytrack } from "./database.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 { } from "./accounts/misc.js";
|
||||
import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js";
|
||||
@ -26,34 +26,17 @@ app.use(cookieParser());
|
||||
app.use(express.json({ limit: "10mb" }));
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(express.text());
|
||||
let requests = 0;
|
||||
const requestsPerSec = io.meter({
|
||||
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(()=>{
|
||||
|
||||
// }, 1000)
|
||||
import WebSocket, { WebSocketServer } from "ws";
|
||||
import { request } from "node:http";
|
||||
const wss = new WebSocketServer({ noServer: true });
|
||||
let openSockets = 0;
|
||||
wss.on("connection", function connection(ws, req, res) {
|
||||
openSockets++;
|
||||
sockets.set(openSockets);
|
||||
setInterval(() => {
|
||||
ws.send("ping");
|
||||
}, 30000);
|
||||
@ -77,32 +60,11 @@ wss.on("connection", function connection(ws, req, res) {
|
||||
if (ws.id) {
|
||||
const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`)
|
||||
updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id });
|
||||
if (message.substring(4)) {
|
||||
const existingAccount = accs.query(`SELECT * FROM accounts WHERE username LIKE $1`)
|
||||
let userData = existingAccount.get({ $1: ws.id });
|
||||
if (userData == null) {
|
||||
return { success: false, reason: "The account doesn't exist." };
|
||||
}
|
||||
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--;
|
||||
sockets.set(openSockets);});
|
||||
ws.on("close", () => {openSockets--;});
|
||||
});
|
||||
app.post(
|
||||
"/api/event",
|
||||
@ -120,11 +82,6 @@ app.post(
|
||||
})
|
||||
}
|
||||
);
|
||||
// app.use("*.json", async (req, res, next) => {
|
||||
// optimize json
|
||||
// console.log("got data");
|
||||
// next()
|
||||
// });
|
||||
app.post("/register", async (req, res) => {
|
||||
let status = await createAccount(req.body.username, req.body.password, req.body["h-captcha-response"]);
|
||||
if (status["success"]) {
|
||||
@ -227,110 +184,6 @@ app.get("/api/chat/recent", async (req, res) => {
|
||||
// get last 50 recent messages
|
||||
// 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) => {
|
||||
if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
|
||||
let status = await retrieveData(req.cookies.token);
|
||||
@ -387,7 +240,7 @@ app.use("/ai", async (req, res, next) => {
|
||||
next();
|
||||
}
|
||||
});
|
||||
app.use("/", express.static("./selenite", { extensions: ["html"] }));
|
||||
app.use("/", express.static("./public", { extensions: ["html"] }));
|
||||
app.use("/data/:id/:file", async (req, res) => {
|
||||
const id = path.basename(req.params.id);
|
||||
const file = path.basename(req.params.file);
|
||||
@ -400,6 +253,9 @@ app.use("/data/:id/:file", async (req, res) => {
|
||||
if (mime.lookup(filePath) == "image/webp") {
|
||||
res.type("image/webp");
|
||||
res.status(200).send(image);
|
||||
} else if (mime.lookup(filePath) == "audio/ogg") {
|
||||
res.type("audio/ogg");
|
||||
res.status(200).send(image);
|
||||
} else {
|
||||
res.status(404).send("File not found");
|
||||
}
|
||||
@ -477,6 +333,15 @@ app.post("/api/admin/ban", async (req, res) => {
|
||||
let status = await banUser(req.body.name, req.body.reason, req.cookies.token);
|
||||
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, () => {
|
||||
console.log(log.success("Express is online."));
|
||||
console.log("- " + log.info("http://localhost:" + port));
|
||||
@ -490,6 +355,6 @@ server.on("upgrade", (request, socket, head) => {
|
||||
app.use(async (req, res) => {
|
||||
res
|
||||
.type("text/html")
|
||||
.send(await fs.readFile(`./selenite/404.html`))
|
||||
.send(await fs.readFile(`./public/404.html`))
|
||||
.status(404);
|
||||
});
|
||||
|
207
package-lock.json
generated
207
package-lock.json
generated
@ -21,6 +21,7 @@
|
||||
"fast-glob": "^3.3.2",
|
||||
"file-type": "^19.0.0",
|
||||
"install": "^0.13.0",
|
||||
"lucida": "^2.0.0-54",
|
||||
"mime-types": "^2.1.35",
|
||||
"node-html-parser": "^6.1.13",
|
||||
"openai": "^4.85.3",
|
||||
@ -40,6 +41,15 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz",
|
||||
@ -569,6 +579,70 @@
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@tokenizer/token": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
||||
@ -664,9 +738,9 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
|
||||
"integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
|
||||
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
@ -674,6 +748,17 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/blowfish-cbc": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/blowfish-cbc/-/blowfish-cbc-1.0.1.tgz",
|
||||
"integrity": "sha512-o1JN6g6+ATW/4k7q1BZzy14VqLxwYa1mCii47qT4kmAaYD0NAfdM6/pz6uizbhTra/xunsPQI27LZt08OQS4sA==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.0.2.tgz",
|
||||
@ -1661,6 +1746,21 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
|
||||
"integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"queue": "6.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"image-size": "bin/image-size.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/inflection": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz",
|
||||
@ -1754,11 +1854,39 @@
|
||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/librespot": {
|
||||
"version": "0.2.22",
|
||||
"resolved": "https://registry.npmjs.org/librespot/-/librespot-0.2.22.tgz",
|
||||
"integrity": "sha512-szLknWSrgF+mRuypNXQTmdq8PGGhgPRAazm8sJmD8wiCAbtO9LYHihZhQcRmCzmVz818sRHZM/BU6K6XslXSHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"protobufjs": "^7.2.5",
|
||||
"undici": "^5.27.0"
|
||||
}
|
||||
},
|
||||
"node_modules/librespot/node_modules/undici": {
|
||||
"version": "5.29.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
||||
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
@ -1771,6 +1899,19 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lucida": {
|
||||
"version": "2.0.0-54",
|
||||
"resolved": "https://registry.npmjs.org/lucida/-/lucida-2.0.0-54.tgz",
|
||||
"integrity": "sha512-3Y24WkCI1Ks6EjOAElYAeYXkxT/HtunEW+SnhDKFb681B/QEMhS/EzLzFi8D5l95/pOVODUZQMMxYNKmMMC1fQ==",
|
||||
"license": "OQL",
|
||||
"dependencies": {
|
||||
"blowfish-cbc": "^1.0.1",
|
||||
"image-size": "^1.1.1",
|
||||
"librespot": "^0.2.21",
|
||||
"undici": "^6.19.4",
|
||||
"xmldom-qsa": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||
@ -1897,6 +2038,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.4.0.tgz",
|
||||
"integrity": "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
@ -2125,6 +2275,30 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.3.tgz",
|
||||
"integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"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"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@ -2157,6 +2331,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/queue": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
||||
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
@ -2826,6 +3009,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.21.3",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
|
||||
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
@ -2924,6 +3116,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmldom-qsa": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/xmldom-qsa/-/xmldom-qsa-1.1.3.tgz",
|
||||
"integrity": "sha512-IJBOczBpAYrIBJFFsmCBwfBhwe4zdMR3Xz0ZBX0OFtgO49rLy/BWbhkegOwsthdBWb1gUtFK6ZZnGdT8ZqPRBA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
@ -24,6 +24,7 @@
|
||||
"fast-glob": "^3.3.2",
|
||||
"file-type": "^19.0.0",
|
||||
"install": "^0.13.0",
|
||||
"lucida": "^2.0.0-54",
|
||||
"mime-types": "^2.1.35",
|
||||
"node-html-parser": "^6.1.13",
|
||||
"openai": "^4.85.3",
|
||||
|
Reference in New Issue
Block a user