1
0
forked from sent/waves

Compare commits

...

98 Commits
main ... main

Author SHA1 Message Date
𓍼
b2ad89c28a remove subjects 2025-06-07 17:17:38 -05:00
𓍼
ee3092a590 Smaller 2025-06-07 16:56:39 -05:00
𓍼
265de4f542 UPDATEEEE 2025-06-07 16:54:12 -05:00
𓍼
c2a6cb8639 uh 2025-06-06 19:06:46 -05:00
𓍼
6fd71fa6fa ? 2025-06-06 19:02:40 -05:00
𓍼
994cb17641 hi 2025-06-06 19:01:51 -05:00
𓍼
c265e724c9 Fix latest commit 2025-06-06 12:52:49 -05:00
𓍼
dc72461a68 Fix latest commit 2025-06-06 12:44:31 -05:00
2b1a912478 Update others/scaler.mjs 2025-06-05 21:26:40 -07:00
78fbc42a0c Add others/scaler.mjs 2025-06-05 21:25:37 -07:00
65bc526a91 Delete others/scaler.mjs 2025-06-05 21:24:46 -07:00
bc878dfb64 Add others/scaler.mjs 2025-06-05 21:23:14 -07:00
a083758325 Delete others/scaler.mjs 2025-06-05 21:22:22 -07:00
b622f3cb9b Cool Thingy 2025-06-05 21:18:57 -07:00
ff50de3064 Update index.mjs 2025-06-05 21:12:54 -07:00
c13a708584 Update others/scaler.mjs 2025-06-05 21:12:21 -07:00
8845426001 60000 2025-06-05 21:10:10 -07:00
𓍼
89279a6735 Something 2025-06-05 22:52:01 -05:00
𓍼
526ec4f236 Merge branch 'main' of https://gitea.sentt.lol/sent/waves 2025-06-05 22:50:24 -05:00
𓍼
f78a14b79c Something 2025-06-05 22:49:17 -05:00
e50b65dde1 Update public/$.html 2025-06-01 19:53:00 -07:00
f0529b100e Update public/assets/js/register.js 2025-06-01 19:49:22 -07:00
4658e475ef idk 2025-06-01 19:40:51 -07:00
𓍼
7b3737d44c Rename the API 2025-05-25 17:41:29 -05:00
𓍼
91e44ce19a Remove ads on 1v1.LOL 2025-05-25 14:43:27 -05:00
𓍼
ac7cc48119 ok 2025-05-25 14:27:15 -05:00
𓍼
d9de280d3d Last update for today 2025-05-25 14:25:58 -05:00
𓍼
1fb3876cd4 Fixes 2025-05-25 14:24:32 -05:00
𓍼
c568949e74 cool 2025-05-25 12:48:11 -05:00
𓍼
6f84c2a9e5 okay 2025-05-25 12:34:36 -05:00
𓍼
97a6a4a94a Remove lat updated label and only keep latest commit id 2025-05-25 12:27:18 -05:00
𓍼
e1b5f73c31 Whoops 2025-05-25 09:50:37 -05:00
𓍼
87f8a54656 Wrong one 2025-05-25 09:49:18 -05:00
𓍼
84b0c084de only get latest update 2025-05-25 09:47:27 -05:00
𓍼
6a269bbaae Accidentaly remove the banned ad 2025-05-25 09:36:22 -05:00
𓍼
9f9a892798 wv 2025-05-25 09:33:51 -05:00
𓍼
ff7390d3ae Top 2025-05-25 09:32:20 -05:00
𓍼
7ae9abb1ad Remove a game (it wasn't supposed to be push) and update the verification script 2025-05-25 09:30:11 -05:00
𓍼
cd4c462e62 Small Update 🤍 2025-05-25 09:20:08 -05:00
𓍼
b5a927077a Back to DuckDuckGo 2025-05-22 11:48:45 -05:00
𓍼
5996c1a6e0 Brave? 2025-05-21 23:33:19 -05:00
𓍼
ffe52a61e7 Colors Change 2025-05-21 23:30:03 -05:00
4551ab18c1 Merge pull request 'Small Little Update' (#2) from master into main
Reviewed-on: https://gitea.sentt.lol/sent/waves/pulls/2
2025-05-21 21:24:35 -07:00
𓍼
806557edb7 Small Little Update 2025-05-21 23:20:31 -05:00
0c080ba2ac Whoops 2025-05-20 22:13:46 -07:00
a9d05bdd84 Update 2025-05-20 22:12:50 -07:00
ecf721aac1 Update 2025-05-20 22:12:31 -07:00
d3875151f8 Update others/scaler.mjs 2025-05-20 21:47:52 -07:00
c87b94b3c6 idk 2025-05-20 20:46:04 -07:00
4f2bddde67 Update index.mjs 2025-05-20 20:43:05 -07:00
fb4ac70c10 Update package.json 2025-05-20 20:42:48 -07:00
ad7d814cd6 .5 2025-05-19 19:25:19 -07:00
72c7699918 Bump Version Up 2025-05-19 19:25:06 -07:00
9f425c87f2 Fix 2025-05-19 19:20:22 -07:00
119776dc29 Peformance 4 2025-05-19 19:17:40 -07:00
41b65cbf24 Performance 3 2025-05-19 19:17:06 -07:00
14e147924d Performance 2 2025-05-19 19:16:48 -07:00
d48831aa9e Perf 2025-05-19 19:10:25 -07:00
e059c26083 Bump Version Up 2025-05-18 16:32:19 -07:00
07f1ebab3c Bump 2025-05-18 16:31:51 -07:00
0b025ea92d Bump 2025-05-18 16:31:25 -07:00
fb43570953 Bump 2025-05-18 16:30:55 -07:00
4d78a56903 Small Update 2025-05-18 16:26:05 -07:00
27277d1ec3 Small Update 2025-05-18 16:25:51 -07:00
fac66a55ce Small Update 2025-05-18 16:25:24 -07:00
c22f4bee3f Bump 2025-05-13 20:53:06 -07:00
dc4ed38d13 Bump 2025-05-13 20:52:52 -07:00
9b3ec83c47 Bump 2025-05-13 20:52:12 -07:00
4155527237 Okay I actually gotta study now 2025-05-13 20:51:25 -07:00
ec39325750 Forgot to define cache 2025-05-12 21:38:08 -07:00
6b19e122d4 Update index.mjs 2025-05-12 21:25:27 -07:00
bee79c2252 Version Update 2025-05-12 21:02:14 -07:00
4f80afe70d Version 2025-05-12 21:01:54 -07:00
4f6be3cf67 Versions 2025-05-12 21:01:30 -07:00
cc13c65dab Versions 2025-05-12 21:01:10 -07:00
c8f0bf86ae Versions 2025-05-12 21:00:54 -07:00
041974094c whoopsies 2025-05-12 19:51:47 -07:00
ddec5ac2c8 overflow 2025-05-12 19:51:24 -07:00
a00a3041d9 Remove 2025-05-12 19:46:37 -07:00
4453299636 One more piece of ad 2025-05-12 19:46:07 -07:00
97cf39783f One more piece of ad 2025-05-12 19:44:53 -07:00
be2114b379 One more piece of ad 2025-05-12 19:42:07 -07:00
62527b3876 Handle HTTP requests 2025-05-11 12:55:10 -07:00
𓍼
c5279de4de chore: trigger hook status refresh 2025-05-06 21:34:11 -05:00
𓍼
ec849ff78d chore: trigger hook status refresh 2025-05-06 21:32:45 -05:00
d3060ace84 Add public/ads.txt 2025-05-06 19:31:25 -07:00
cfac8c113b Revert Invite Link 2025-05-06 12:03:10 -07:00
deaffff0b7 Tuff 2025-05-05 12:25:37 -07:00
ed6fb01010 Update public/!.html 2025-05-05 12:25:16 -07:00
94f5fafbcb Update public/$.html 2025-05-05 12:24:58 -07:00
d5608b0b4a Update public/$.html 2025-05-05 11:54:29 -07:00
418f7ad287 Update public/$.html 2025-05-05 11:49:54 -07:00
beb2cd4b28 Update public/$.html 2025-05-05 11:49:25 -07:00
6a928f5385 Update public/$.html 2025-05-05 11:48:47 -07:00
5cae96f464 Update public/$.html 2025-05-05 11:48:09 -07:00
9453086705 Forgot to change to apps 2025-05-05 11:46:03 -07:00
ea936a72dc . 2025-05-05 08:24:41 -07:00
a7c665e621 . 2025-05-05 08:23:44 -07:00
35 changed files with 3075 additions and 36983 deletions

View File

@ -4,6 +4,7 @@
The following versions of this project that are currently supported and unsupported: The following versions of this project that are currently supported and unsupported:
- **Version 2.3.7** Supported ✅
- **Version 2.3.5** Supported ✅ - **Version 2.3.5** Supported ✅
- **Version 2.3.1** Supported ✅ - **Version 2.3.1** Supported ✅
- **Version 2.3.0** Supported ✅ - **Version 2.3.0** Supported ✅
@ -17,4 +18,4 @@ The following versions of this project that are currently supported and unsuppor
## Support ## Support
If you are experiencing an issue with Waves unrelated to security, feel free to join our [Discord](https://discord.gg/dJvdkPRheV) server and open a ticket. If you are experiencing an issue with Waves unrelated to security, feel free to join our [Discord Server](https://discord.gg/dJvdkPRheV) and open a ticket.

257
index.mjs
View File

@ -1,74 +1,126 @@
import cluster from "cluster"; import cluster from "cluster";
import os from "os"; import os from "os";
import net from "net"; import net from "net";
import fs from "fs";
import path from "path";
import { spawnSync } from "child_process";
import express from "express"; import express from "express";
import { createServer } from "http"; import { createServer } from "http";
import path from "path";
import compression from "compression"; import compression from "compression";
import WebSocket from "ws"; import WebSocket from "ws";
import { LRUCache } from "lru-cache";
import { baremuxPath } from "@mercuryworkshop/bare-mux/node"; import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
import { epoxyPath } from "@mercuryworkshop/epoxy-transport"; import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
import { libcurlPath } from "@mercuryworkshop/libcurl-transport"; import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
import { uvPath } from "@titaniumnetwork-dev/ultraviolet"; import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
import wisp from "wisp-server-node"; import wisp from "wisp-server-node";
import NodeCache from "node-cache";
const surgeConfigPath = path.resolve("surge.config.json");
const isSurgedRun = process.argv.includes("--surged");
let startTime = Date.now();
function applySurgeAndRestartIfNeeded() {
if (isSurgedRun) {
try {
const config = JSON.parse(fs.readFileSync(surgeConfigPath, "utf-8"));
process.env.UV_THREADPOOL_SIZE = String(config.uvThreadpoolSize);
} catch {}
return;
}
const result = spawnSync("node", ["./others/surge.mjs"], { stdio: "inherit" });
if (result.error) process.exit(1);
const config = JSON.parse(fs.readFileSync(surgeConfigPath, "utf-8"));
const nodeArgs = [...config.nodeFlags, path.resolve("index.mjs"), "--surged"];
const env = {
...process.env,
UV_THREADPOOL_SIZE: String(config.uvThreadpoolSize),
ALREADY_SURGED: "true"
};
const relaunch = spawnSync(process.execPath, nodeArgs, { stdio: "inherit", env });
process.exit(relaunch.status || 0);
}
applySurgeAndRestartIfNeeded();
if (global.gc) {
setInterval(() => {
const { heapUsed, heapTotal } = process.memoryUsage();
if (heapTotal > 0 && heapUsed / heapTotal > 0.7) global.gc();
}, 60000);
}
import "./others/scaler.mjs";
import "./others/warmup.mjs";
const cache = new LRUCache({
maxSize: 1000,
ttl: 60_000,
allowStale: false,
sizeCalculation: (value, key) => Buffer.byteLength(value) + Buffer.byteLength(key)
});
const port = parseInt(process.env.PORT || "3000", 10); const port = parseInt(process.env.PORT || "3000", 10);
cluster.schedulingPolicy = cluster.SCHED_RR;
function logInfo(message) { function logInfo(msg) {
console.info(`[INFO] ${message}`); console.info(`[~] ${msg}`);
}
function logError(error) {
const msg = error instanceof Error ? error.message : error;
console.error(`[ERR] ${msg}`);
} }
process.on("uncaughtException", (err) => logError(`Unhandled Exception: ${err}`)); function logSuccess(msg) {
process.on("unhandledRejection", (reason) => logError(`Unhandled Promise Rejection: ${reason}`)); console.info(`[+] ${msg}`);
}
function logError(err) {
console.error(`[!] ${err instanceof Error ? err.message : err}`);
}
process.on("uncaughtException", err => logError(`Unhandled Exception: ${err}`));
process.on("unhandledRejection", reason => logError(`Unhandled Rejection: ${reason}`));
if (cluster.isPrimary) { if (cluster.isPrimary) {
const numCPUs = os.cpus().length; const cpus = os.cpus().length;
logInfo(`Master started. Forking ${numCPUs} workers.`); const workers = Math.max(1, cpus - 1);
for (let i = 0; i < numCPUs; i++) {
logInfo(`Master: forking ${workers} workers`);
for (let i = 0; i < workers; i++) {
cluster.fork(); cluster.fork();
} }
cluster.on("exit", (worker, code, signal) => {
logError(`Worker ${worker.process.pid} terminated (code: ${code}, signal: ${signal}). Restarting...`); cluster.on("exit", worker => {
logError(`Worker ${worker.process.pid} exited. Restarting...`);
cluster.fork(); cluster.fork();
}); });
let currentWorker = 0;
const server = net.createServer({ pauseOnConnect: true }, (connection) => { let current = 0;
const workerIds = Object.keys(cluster.workers); const server = net.createServer({ pauseOnConnect: true }, conn => {
if (workerIds.length === 0) { const workersArr = Object.values(cluster.workers);
connection.destroy(); if (!workersArr.length) return conn.destroy();
return; const worker = workersArr[current++ % workersArr.length];
} worker.send("sticky-session:connection", conn);
const worker = cluster.workers[workerIds[currentWorker % workerIds.length]];
currentWorker++;
if (worker) worker.send("sticky-session:connection", connection);
}); });
server.on("error", (err) => logError(`Server error: ${err}`));
server.listen(port, () => logInfo(`Server running at http://localhost:${port}`)); server.on("error", err => logError(`Server error: ${err}`));
server.listen(port, () => logSuccess(`Server listening on ${port}`));
} else { } else {
process.env.UV_THREADPOOL_SIZE = os.cpus().length * 2;
const __dirname = process.cwd(); const __dirname = process.cwd();
const publicPath = path.join(__dirname, "public"); const publicPath = path.join(__dirname, "public");
const app = express(); const app = express();
let latencySamples = [];
app.use(compression({ level: 9, threshold: 128, memLevel: 9 })); app.use(compression({ level: 4, memLevel: 4, threshold: 1024 }));
const cache = new NodeCache({ stdTTL: 1, checkperiod: 1 });
app.use((req, res, next) => { app.use((req, res, next) => {
const key = req.originalUrl; const key = req.originalUrl;
if (cache.has(key)) { const val = cache.get(key);
if (val) {
res.setHeader("X-Cache", "HIT"); res.setHeader("X-Cache", "HIT");
return res.send(cache.get(key)); return res.send(val);
} }
res.sendResponse = res.send; res.sendResponse = res.send.bind(res);
res.send = (body) => { res.send = body => {
cache.set(key, body); cache.set(key, body);
res.setHeader("X-Cache", "MISS"); res.setHeader("X-Cache", "MISS");
res.sendResponse(body); res.sendResponse(body);
@ -76,7 +128,7 @@ if (cluster.isPrimary) {
next(); next();
}); });
const staticOpts = { maxAge: "1s" }; const staticOpts = { maxAge: "7d", immutable: true };
app.use("/baremux/", express.static(baremuxPath, staticOpts)); app.use("/baremux/", express.static(baremuxPath, staticOpts));
app.use("/epoxy/", express.static(epoxyPath, staticOpts)); app.use("/epoxy/", express.static(epoxyPath, staticOpts));
app.use("/libcurl/", express.static(libcurlPath, staticOpts)); app.use("/libcurl/", express.static(libcurlPath, staticOpts));
@ -84,62 +136,129 @@ if (cluster.isPrimary) {
app.use("/wah/", express.static(uvPath, staticOpts)); app.use("/wah/", express.static(uvPath, staticOpts));
app.use(express.json()); app.use(express.json());
app.get("/", (req, res) => res.sendFile(path.join(publicPath, "$.html"))); const sendHtml = file => (_req, res) => res.sendFile(path.join(publicPath, file));
app.get("/g", (req, res) => res.sendFile(path.join(publicPath, "!.html")));
app.get("/a", (req, res) => res.sendFile(path.join(publicPath, "!!.html"))); app.get("/", sendHtml("$.html"));
app.get("/ai", (req, res) => res.sendFile(path.join(publicPath, "!!!.html"))); app.get("/g", sendHtml("!.html"));
app.get("/resent", (req, res) => res.sendFile(path.join(publicPath, "resent", "index.html"))); app.get("/s", sendHtml("!!.html"));
app.use((req, res) => res.status(404).sendFile(path.join(publicPath, "404.html"))); app.get("/resent", (_req, res) => res.sendFile(path.join(publicPath, "resent", "index.html")));
app.get("/api/info", (_req, res) => {
try {
const average = latencySamples.length
? latencySamples.reduce((a, b) => a + b, 0) / latencySamples.length
: 0;
let speed = "Medium";
if (average < 200) speed = "Fast";
else if (average > 500) speed = "Slow";
const cpus = os.cpus();
const totalMem = os.totalmem() / 1024 / 1024 / 1024;
res.json({
speed,
averageLatency: average.toFixed(2),
specs: `${cpus[0].model} + ${cpus.length} CPU Cores + ${totalMem.toFixed(1)}GB of RAM`,
startTime,
samples: latencySamples.length,
timestamp: Date.now()
});
} catch {
res.status(500).json({ error: "Internal error" });
}
});
app.get("/api/latest-commit", async (_req, res) => {
try {
const ghRes = await fetch(
"https://api.github.com/repos/xojw/waves/commits?per_page=1",
{
headers: {
"User-Agent": "waves-app",
Accept: "application/vnd.github.v3+json"
}
}
);
if (!ghRes.ok) return res.status(ghRes.status).json({ error: "GitHub API error" });
const commits = await ghRes.json();
const updates = commits.map(c => ({
sha: c.sha.slice(0, 7),
message: c.commit.message.split("\n")[0],
author: c.commit.author.name,
date: c.commit.author.date
}));
res.json({ repo: "xojw/waves", updates });
} catch {
res.status(500).json({ error: "Internal server error" });
}
});
app.use((_req, res) => res.status(404).sendFile(path.join(publicPath, "404.html")));
const server = createServer(app); const server = createServer(app);
server.keepAliveTimeout = 0; server.keepAliveTimeout = 0;
server.headersTimeout = 0; server.headersTimeout = 0;
const pingWSS = new WebSocket.Server({ noServer: true, maxPayload: 1048576 }); const pingWSS = new WebSocket.Server({
noServer: true,
maxPayload: 4 * 1024 * 1024,
perMessageDeflate: false
});
pingWSS.on("connection", (ws, req) => { pingWSS.on("connection", (ws, req) => {
const remoteAddress = req.socket.remoteAddress || "unknown"; const remote = req.socket.remoteAddress || "unknown";
let latencies = []; let lat = [];
const pingInterval = setInterval(() => { const interval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) { if (ws.readyState === WebSocket.OPEN) {
const timestamp = Date.now(); ws.send(JSON.stringify({ type: "ping", timestamp: Date.now() }));
ws.send(JSON.stringify({ type: "ping", timestamp }));
} }
}, 1000); }, 1000);
ws.on("message", (message) => {
ws.on("message", msg => {
try { try {
const data = JSON.parse(message); const data = JSON.parse(msg);
if (data.type === "pong" && data.timestamp) { if (data.type === "pong" && data.timestamp) {
const latency = Date.now() - data.timestamp; const d = Date.now() - data.timestamp;
latencies.push(latency); lat.push(d);
if (latencies.length > 5) latencies.shift(); if (lat.length > 5) lat.shift();
ws.send(JSON.stringify({ type: "latency", latency })); latencySamples.push(d);
if (latencySamples.length > 100) latencySamples.shift();
ws.send(JSON.stringify({ type: "latency", latency: d }));
} }
} catch (e) { } catch (e) {
logError(`Ping error: ${e}`); logError(`Ping error: ${e}`);
} }
}); });
ws.on("close", () => { ws.on("close", () => {
clearInterval(pingInterval); clearInterval(interval);
const avgLatency = latencies.length ? latencies.reduce((a, b) => a + b) / latencies.length : 0; const avg = lat.length
logInfo(`Conn from ${remoteAddress} closed. Avg: ${avgLatency.toFixed(2)}ms.`); ? (lat.reduce((a, b) => a + b) / lat.length).toFixed(2)
: 0;
logInfo(`WS ${remote} closed. Avg: ${avg}ms`);
}); });
}); });
server.on("upgrade", (req, socket, head) => { server.on("upgrade", (req, sock, head) => {
if (req.url === "/w/ping") { if (req.url === "/w/ping") {
pingWSS.handleUpgrade(req, socket, head, (ws) => pingWSS.emit("connection", ws, req)); pingWSS.handleUpgrade(req, sock, head, ws =>
pingWSS.emit("connection", ws, req)
);
} else if (req.url.startsWith("/w/")) { } else if (req.url.startsWith("/w/")) {
wisp.routeRequest(req, socket, head); wisp.routeRequest(req, sock, head);
} else { } else {
socket.end(); sock.end();
} }
}); });
server.on("error", (err) => logError(`Worker server error: ${err}`));
server.listen(0, () => logInfo(`Worker ${process.pid} ready.`)); server.on("error", err => logError(`Worker error: ${err}`));
process.on("message", (message, connection) => {
if (message === "sticky-session:connection") { server.listen(0, () => logSuccess(`Worker ${process.pid} ready`));
server.emit("connection", connection);
connection.resume(); process.on("message", (msg, conn) => {
if (msg === "sticky-session:connection" && conn) {
server.emit("connection", conn);
conn.resume();
} }
}); });
} }

36
others/scaler.mjs Normal file
View File

@ -0,0 +1,36 @@
import { LRUCache } from 'lru-cache';
let maxKeys = 10_000;
let cache = makeCache(maxKeys);
function makeCache(maxEntries) {
return new LRUCache({
maxSize: maxEntries,
ttl: 60_000,
allowStale: false,
updateAgeOnGet: false,
updateAgeOnHas: false,
});
}
function scaleCache() {
const { heapUsed, heapTotal } = process.memoryUsage();
const freeHeapRatio = (heapTotal - heapUsed) / heapTotal;
const newMax = freeHeapRatio > 0.5
? 20_000
: freeHeapRatio < 0.2
? 5_000
: 10_000;
if (newMax !== maxKeys) {
maxKeys = newMax;
cache = makeCache(maxKeys);
console.log(`[SCALER] freeHeap ${( (heapTotal - heapUsed)/1e6 ).toFixed(1)}MB → maxKeys: ${maxKeys}`);
}
}
setInterval(scaleCache, 60_000);
scaleCache();
export { cache };

57
others/surge.mjs Normal file
View File

@ -0,0 +1,57 @@
import { execSync } from "child_process";
import os from "os";
import fs from "fs";
import path from "path";
const log = (msg) => console.log(`[SURGE] ${msg}`);
const surgePath = path.resolve("surge.config.json");
function generateSurgeFlags() {
const cpus = os.cpus().length;
const flags = [
"--max-old-space-size=4096",
"--optimize_for_size",
"--gc-global",
"--max-semi-space-size=256",
"--no-warnings",
"--expose-gc"
];
if (process.platform !== "win32") {
flags.push("--use-largepages=on");
}
return {
uvThreadpoolSize: cpus * 2,
nodeFlags: flags
};
}
function writeSurgeFile(flags) {
fs.writeFileSync(surgePath, JSON.stringify(flags, null, 2));
log("Surge config saved.");
}
function launchSurgedBackend(flags) {
const args = [
...flags.nodeFlags,
"index.mjs",
"--surged"
];
log(`Launching backend: node ${args.join(" ")}`);
execSync(`node ${args.join(" ")}`, { stdio: "inherit" });
}
function isSurgedRun() {
return process.argv.includes("--surged");
}
(async () => {
if (isSurgedRun()) return;
log("Detecting best settings...");
const flags = generateSurgeFlags();
writeSurgeFile(flags);
launchSurgedBackend(flags);
process.exit(0);
})();

59
others/warmup.mjs Normal file
View File

@ -0,0 +1,59 @@
import http from 'http';
const endpoints = [
'http://localhost:3000/',
'http://localhost:3000/g',
'http://localhost:3000/a'
];
function httpGet(url, timeout = 5000) {
return new Promise((resolve) => {
const req = http.get(url, (res) => {
res.on('data', () => {});
res.on('end', () => {
resolve({ url, statusCode: res.statusCode });
});
});
req.on('error', (e) => {
resolve({ url, error: e.message });
});
req.setTimeout(timeout, () => {
req.abort();
resolve({ url, error: 'Timeout' });
});
});
}
async function warm(retries = 2) {
const results = await Promise.all(endpoints.map(async (url) => {
for (let i = 0; i <= retries; i++) {
const res = await httpGet(url);
if (!res.error) {
console.log(`[WARMUP] ${url}${res.statusCode}`);
return res;
} else {
console.warn(`[WARMUP] ${url} attempt ${i + 1} failed: ${res.error}`);
}
}
return { url, error: `Failed after ${retries + 1} attempts` };
}));
const failed = results.filter(r => r.error);
if (failed.length) {
console.warn(`[WARMUP] Some endpoints failed to warm:`, failed);
} else {
console.log('[WARMUP] All endpoints warmed successfully');
}
}
async function periodicWarmup(intervalMs = 5 * 60 * 1000) {
while (true) {
await warm();
console.log('[WARMUP] Cycle done');
await new Promise(res => setTimeout(res, intervalMs));
}
}
setTimeout(() => periodicWarmup(), 2000);

3285
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,41 @@
{ {
"name": "waves", "name": "waves",
"version": "2.3.5", "version": "2.8.7",
"description": "A sleek and minimalist Web Proxy.", "description": "A sleek and minimalist Web Proxy.",
"type": "module", "type": "module",
"engines": { "engines": {
"npm": ">=7.0.0", "npm": ">=7.0.0",
"node": ">=16.0.0" "node": ">=16.0.0"
}, },
"scripts": { "scripts": {
"start": "node index.mjs", "start": "node index.mjs",
"dev": "nodemon index.mjs", "dev": "nodemon index.mjs",
"lint": "eslint ." "lint": "eslint ."
}, },
"author": { "author": {
"name": "sent", "name": "sent",
"email": "sentttt@proton.me" "email": "sentttt@proton.me"
}, },
"dependencies": { "dependencies": {
"@mercuryworkshop/bare-mux": "latest", "@mercuryworkshop/bare-mux": "latest",
"@mercuryworkshop/epoxy-transport": "latest", "@mercuryworkshop/epoxy-transport": "latest",
"@mercuryworkshop/libcurl-transport": "latest", "@mercuryworkshop/libcurl-transport": "latest",
"@titaniumnetwork-dev/ultraviolet": "latest", "@titaniumnetwork-dev/ultraviolet": "latest",
"axios": "^1.8.2", "axios": "latest",
"cache": "^3.0.0", "cache": "latest",
"compression": "latest", "compression": "latest",
"cors": "^2.8.5", "cors": "latest",
"express": "latest", "express": "latest",
"express-rate-limit": "^7.5.0", "express-rate-limit": "latest",
"fs": "^0.0.1-security", "lru-cache": "latest",
"node": "^23.9.0", "wisp-server-node": "latest",
"node-cache": "latest", "ws": "latest"
"node-fetch": "latest", },
"wisp-server-node": "latest", "devDependencies": {
"ws": "latest" "eslint": "latest",
}, "glob": "latest",
"devDependencies": { "nodemon": "latest",
"eslint": "latest", "prettier": "latest",
"glob": "latest", "rimraf": "latest"
"nodemon": "latest", }
"prettier": "latest", }
"rimraf": "latest"
}
}

View File

@ -1,100 +1,155 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves. - Apps"/> <meta property="og:title" content="Waves." />
<meta property="og:description" content="A sleek and minimalist web proxy."/> <meta property="og:description" content="A sleek and minimalist web proxy." />
<meta property="og:image" content="/assets/images/icons/favicon.ico"/> <meta property="og:image" content="/assets/images/icons/favicon.ico" />
<meta name="theme-color" content="#ffffff"/> <meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff"/> <meta name="msapplication-TileColor" content="#ffffff" />
<title>Waves</title> <title>Waves.</title>
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico">
<link rel="stylesheet" href="/assets/css/$.css"> <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="stylesheet" href="/assets/css/settings.css">
<link rel="stylesheet" href="/assets/css/toast.css"> <link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
<link rel="stylesheet" href="/assets/css/a.css">
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet"> <link rel="stylesheet" href="/assets/css/$.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script> <link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-WGJ2192JZY');</script> <link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script> <link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
</head> <link rel="preload" href="/assets/css/s.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<body> <noscript>
<script src="/baremux/index.js"></script> <link rel="stylesheet" href="/assets/css/settings.css" />
<script src="/wah/uv.bundle.js" defer></script> <link rel="stylesheet" href="/assets/css/toast.css" />
<script src="/wah/cute1.js" defer></script> <link rel="stylesheet" href="/assets/css/nprogress.css" />
<script src="/assets/js/navbar.js" defer></script> <link rel="stylesheet" href="/assets/css/s.css" />
<script src="/assets/js/load.js" defer></script> </noscript>
<script src="/assets/js/eruda.js" defer></script>
<script src="/assets/js/register.js" defer></script> <link rel="preload" as="style" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" onload="this.onload=null;this.rel='stylesheet'" />
<script src="/assets/js/settings.js" defer></script> <noscript>
<script src="/assets/js/greetings.js" defer></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
<script src="/assets/js/shortcuts.js" defer></script> </noscript>
<script src="/assets/js/$.js" defer></script>
<script src="/assets/js/a.js" defer></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg"> <script>
<div class="absolute inset-0 overflow-hidden"> window.dataLayer = window.dataLayer || [];
<div class="god-rays absolute -inset-[10px] opacity-50"></div> function gtag() {
</div> dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-WGJ2192JZY");
</script>
</head>
<body>
<script src="/baremux/index.js" defer></script>
<script src="/assets/js/nprogress.js?v=0.2.0" defer></script>
<script src="/wah/uv.bundle.js" defer></script>
<script src="/wah/cute1.js" defer></script>
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
<script src="/assets/js/register.js?v=2.8.9" defer></script>
<script src="/assets/js/settings.js?v=2.8.9" defer></script>
<script src="/assets/js/greetings.js?v=2.8.9" defer></script>
<script src="/assets/js/shortcuts.js?v=2.8.9" defer></script>
<script src="/assets/js/$.js?v=2.8.9" defer></script>
<script src="/assets/js/s.js?v=2.8.9" defer></script>
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
<div class="absolute inset-0 overflow-hidden">
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
</div> </div>
<div class="home-navbar"> </div>
<img src="/assets/images/icons/favicon.ico" class="favicon">
<span id="waves">Waves</span> <div class="home-navbar">
<a href="/" id="home">Home</a> <img src="/assets/images/icons/favicon.ico" class="favicon" alt="favicon" />
<a href="/g" id="games">Games</a> <span id="waves">Waves.</span>
<a href="/a" id="apps">Apps</a> <a href="/" id="home">Home</a>
<a href="#" id="movies">Movies</a> <a href="/g" id="games">Games</a>
<a href="#" id="ai">AI</a> <a href="/s" id="shortcuts" style="color: #ffffff;">Shortcuts</a>
<a href="#" id="settings-icon"> <a href="#" id="movies">Movies</a>
<i class="settings-icon fa-regular fa-gear"></i> <a href="#" id="ai">AI</a>
</a> <a href="#" id="settings-icon">
<i class="settings-icon fa-regular fa-gear"></i>
</a>
</div>
<div id="settings-menu" class="settings-menu"></div>
<div class="navbar">
<ul class="nav-buttons">
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
<li>
<div class="small-searchbar" style="position: relative;">
<i id="lockIcon" class="fa-solid fa-lock"></i>
<input class="waves" type="text" id="searchInputt" placeholder="Search for a query or enter a URL..." autocomplete="off" style="padding-left: 40px;" />
</div>
</li>
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
<li><a href="/s"><i class="fa-regular fa-rocket"></i></a></li>
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
</ul>
</div>
<div class="content shortcuts-page">
<h1>Shortcuts</h1>
<div class="shortcuts-search-bar">
<input type="text" id="shortcutSearchInput" placeholder="Search shortcuts..." autocomplete="off" />
<span class="shortcut-indicator-4">Ctrl + S</span>
</div> </div>
<div id="settings-menu" class="settings-menu"></div> <div class="shortcuts-grid"></div>
<div class="navbar"> </div>
<ul class="nav-buttons">
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li> <div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li> <div id="overlay" class="overlay"></div>
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li> <div id="namePrompt" class="popup">
<li> <div class="input-container">
<div class="small-searchbar" style="position: relative;"> <label for="userName">Please enter a name so we know what to call you:</label>
<i id="lockIcon" class="fa-solid fa-lock"></i> <div class="input-wrapper">
<input class="waves" type="text" id="searchInputt" <input type="text" id="userName" placeholder="Your name" autocomplete="off" />
placeholder="Search for a query or enter a URL..." autocomplete="off" </div>
style="padding-left: 40px;"> <button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
<span class="shortcut-indicator-2">Ctrl + S</span>
</div>
</li>
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
<li><a href="/a"><i class="fa-regular fa-grid-2"></i></a></li>
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
</ul>
</div> </div>
<div class="content apps-page"> </div>
<h1>Apps</h1>
<div class="apps-search-bar"> <iframe id="cool-iframe" class="iframe"></iframe>
<input type="text" id="appSearchInput" placeholder="Search apps..." autocomplete="off" />
<span class="shortcut-indicator-4">Ctrl + S</span> <script defer>
</div> document.addEventListener("DOMContentLoaded", function () {
<div class="apps-grid"> NProgress.configure({ showSpinner: false });
</div> NProgress.start();
</div>
<div id="overlay" class="overlay"></div> const titleElement = document.querySelector(".search-title");
<div id="namePrompt" class="popup"> if (titleElement) {
<div class="input-container"> const text = titleElement.textContent.trim();
<label for="userName">Please enter a name so we know what to call you:</label> titleElement.textContent = "";
<div class="input-wrapper"> text.split("").forEach((letter, i) => {
<input type="text" id="userName" placeholder="Your name" oninput="checkInput()" autocomplete="off" /> const span = document.createElement("span");
</div> span.textContent = letter;
<button id="doneButton" onclick="submitName()" disabled> span.style.animationDelay = `${i * 0.05}s`;
<i class="fas fa-check"></i> Done titleElement.appendChild(span);
</button> });
</div> }
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div> window.addEventListener("load", function () {
<iframe id="cool-iframe" class="iframe"></iframe> NProgress.done();
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script> });
</body> });
</script>
<script>
requestIdleCallback(() => {
const ad = document.createElement("script");
ad.src = "//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js";
ad.async = true;
document.body.appendChild(ad);
});
</script>
</body>
</html> </html>

View File

@ -1,101 +1,155 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves. - Games"/> <meta property="og:title" content="Waves." />
<meta property="og:description" content="A sleek and minimalist web proxy."/> <meta property="og:description" content="A sleek and minimalist web proxy." />
<meta property="og:image" content="/assets/images/icons/favicon.ico"/> <meta property="og:image" content="/assets/images/icons/favicon.ico" />
<meta name="theme-color" content="#ffffff"/> <meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff"/> <meta name="msapplication-TileColor" content="#ffffff" />
<title>Waves</title> <title>Waves.</title>
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico">
<link rel="stylesheet" href="/assets/css/$.css"> <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="stylesheet" href="/assets/css/settings.css">
<link rel="stylesheet" href="/assets/css/toast.css"> <link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
<link rel="stylesheet" href="/assets/css/g.css">
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet" /> <link rel="stylesheet" href="/assets/css/$.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script> <link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-WGJ2192JZY');</script> <link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script> <link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
</head> <link rel="preload" href="/assets/css/g.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<body> <noscript>
<script src="/baremux/index.js"></script> <link rel="stylesheet" href="/assets/css/settings.css" />
<script src="/wah/uv.bundle.js" defer></script> <link rel="stylesheet" href="/assets/css/toast.css" />
<script src="/wah/cute1.js" defer></script> <link rel="stylesheet" href="/assets/css/nprogress.css" />
<script src="/assets/js/navbar.js" defer></script> <link rel="stylesheet" href="/assets/css/g.css" />
<script src="/assets/js/load.js" defer></script> </noscript>
<script src="/assets/js/eruda.js" defer></script>
<script src="/assets/js/register.js" defer></script> <link rel="preload" as="style" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" onload="this.onload=null;this.rel='stylesheet'" />
<script src="/assets/js/settings.js" defer></script> <noscript>
<script src="/assets/js/greetings.js" defer></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
<script src="/assets/js/shortcuts.js" defer></script> </noscript>
<script src="/assets/js/$.js" defer></script>
<script src="/assets/js/g.js" defer></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg"> <script>
<div class="absolute inset-0 overflow-hidden"> window.dataLayer = window.dataLayer || [];
<div class="god-rays absolute -inset-[10px] opacity-50"></div> function gtag() {
</div> dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-WGJ2192JZY");
</script>
</head>
<body>
<script src="/baremux/index.js" defer></script>
<script src="/assets/js/nprogress.js?v=0.2.0" defer></script>
<script src="/wah/uv.bundle.js" defer></script>
<script src="/wah/cute1.js" defer></script>
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
<script src="/assets/js/register.js?v=2.8.9" defer></script>
<script src="/assets/js/settings.js?v=2.8.9" defer></script>
<script src="/assets/js/greetings.js?v=2.8.9" defer></script>
<script src="/assets/js/shortcuts.js?v=2.8.9" defer></script>
<script src="/assets/js/$.js?v=2.8.9" defer></script>
<script src="/assets/js/g.js?v=2.8.9" defer></script>
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
<div class="absolute inset-0 overflow-hidden">
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
</div> </div>
<div class="home-navbar"> </div>
<img src="/assets/images/icons/favicon.ico" class="favicon">
<span id="waves">Waves</span> <div class="home-navbar">
<a href="/" id="home">Home</a> <img src="/assets/images/icons/favicon.ico" class="favicon" alt="favicon" />
<a href="/g" id="games">Games</a> <span id="waves">Waves.</span>
<a href="/a" id="apps">Apps</a> <a href="/" id="home">Home</a>
<a href="#" id="movies">Movies</a> <a href="/g" id="games" style="color: #ffffff;">Games</a>
<a href="#" id="ai">AI</a> <a href="/s" id="apps">Shortcuts</a>
<a href="#" id="settings-icon"> <a href="#" id="movies">Movies</a>
<i class="settings-icon fa-regular fa-gear"></i> <a href="#" id="ai">AI</a>
</a> <a href="#" id="settings-icon">
<i class="settings-icon fa-regular fa-gear"></i>
</a>
</div>
<div id="settings-menu" class="settings-menu"></div>
<div class="navbar">
<ul class="nav-buttons">
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
<li>
<div class="small-searchbar" style="position: relative;">
<i id="lockIcon" class="fa-solid fa-lock"></i>
<input class="waves" type="text" id="searchInputt" placeholder="Search for a query or enter a URL..." autocomplete="off" style="padding-left: 40px;" />
</div>
</li>
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
<li><a href="/s"><i class="fa-regular fa-rocket"></i></a></li>
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
</ul>
</div>
<div class="content games-page">
<h1>Games</h1>
<div class="games-search-bar">
<input type="text" id="gameSearchInput" placeholder="Search games..." autocomplete="off" />
<span class="shortcut-indicator-3">Ctrl + S</span>
</div> </div>
<div id="settings-menu" class="settings-menu"></div> <div class="games-grid"></div>
<div class="navbar"> </div>
<ul class="nav-buttons">
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li> <div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li> <div id="overlay" class="overlay"></div>
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li> <div id="namePrompt" class="popup">
<li> <div class="input-container">
<div class="small-searchbar" style="position: relative;"> <label for="userName">Please enter a name so we know what to call you:</label>
<i id="lockIcon" class="fa-solid fa-lock"></i> <div class="input-wrapper">
<input class="waves" type="text" id="searchInputt" <input type="text" id="userName" placeholder="Your name" autocomplete="off" />
placeholder="Search for a query or enter a URL..." autocomplete="off" </div>
style="padding-left: 40px;"> <button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
<span class="shortcut-indicator-2">Ctrl + S</span>
</div>
</li>
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
<li><a href="/a"><i class="fa-regular fa-grid-2"></i></a></li>
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
</ul>
</div> </div>
<div class="content games-page"> </div>
<h1>Games</h1>
<div class="games-search-bar"> <iframe id="cool-iframe" class="iframe"></iframe>
<input type="text" id="gameSearchInput" placeholder="Search games..." autocomplete="off" />
<span class="shortcut-indicator-3">Ctrl + S</span> <script defer>
</div> document.addEventListener("DOMContentLoaded", function () {
<div class="games-grid"> NProgress.configure({ showSpinner: false });
</div> NProgress.start();
</div>
<div id="overlay" class="overlay"></div> const titleElement = document.querySelector(".search-title");
<div id="namePrompt" class="popup"> if (titleElement) {
<div class="input-container"> const text = titleElement.textContent.trim();
<label for="userName">Please enter a name so we know what to call you:</label> titleElement.textContent = "";
<div class="input-wrapper"> text.split("").forEach((letter, i) => {
<input type="text" id="userName" placeholder="Your name" oninput="checkInput()" autocomplete="off" /> const span = document.createElement("span");
</div> span.textContent = letter;
<button id="doneButton" onclick="submitName()" disabled> span.style.animationDelay = `${i * 0.05}s`;
<i class="fas fa-check"></i> Done titleElement.appendChild(span);
</button> });
</div> }
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div> window.addEventListener("load", function () {
<iframe id="cool-iframe" class="iframe"></iframe> NProgress.done();
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script> });
</div> });
</body> </script>
<script>
requestIdleCallback(() => {
const ad = document.createElement("script");
ad.src = "//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js";
ad.async = true;
document.body.appendChild(ad);
});
</script>
</body>
</html> </html>

View File

@ -1,99 +1,172 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves."/> <meta property="og:title" content="Waves." />
<meta property="og:description" content="A sleek and minimalist web proxy."/> <meta property="og:description" content="A sleek and minimalist web proxy." />
<meta property="og:image" content="/assets/images/icons/favicon.ico"/> <meta property="og:image" content="/assets/images/icons/favicon.ico" />
<meta name="theme-color" content="#ffffff"/> <meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff"/> <meta name="msapplication-TileColor" content="#ffffff" />
<title>Waves.</title> <title>Waves.</title>
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico">
<link rel="stylesheet" href="/assets/css/$.css"> <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="stylesheet" href="/assets/css/settings.css">
<link rel="stylesheet" href="/assets/css/toast.css"> <link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css"> <link rel="stylesheet" href="/assets/css/$.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-WGJ2192JZY');</script> <link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script> <link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
</head> <link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<body> <noscript>
<script src="/baremux/index.js"></script> <link rel="stylesheet" href="/assets/css/settings.css" />
<script src="/wah/uv.bundle.js" defer></script> <link rel="stylesheet" href="/assets/css/toast.css" />
<script src="/wah/cute1.js" defer></script> <link rel="stylesheet" href="/assets/css/nprogress.css" />
<script src="/assets/js/navbar.js" defer></script> </noscript>
<script src="/assets/js/load.js" defer></script>
<script src="/assets/js/eruda.js" defer></script> <link rel="preload" as="style" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" onload="this.onload=null;this.rel='stylesheet'" />
<script src="/assets/js/register.js" defer></script> <noscript>
<script src="/assets/js/settings.js" defer></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
<script src="/assets/js/ping.js" defer></script> </noscript>
<script src="/assets/js/greetings.js" defer></script>
<script src="/assets/js/shortcuts.js" defer></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
<script src="/assets/js/$.js" defer></script> <script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-white transition-bg"> window.dataLayer = window.dataLayer || [];
<div class="absolute inset-0 overflow-hidden"> function gtag() {
<div class="god-rays absolute -inset-[10px] opacity-50"></div> dataLayer.push(arguments);
</div> }
gtag("js", new Date());
gtag("config", "G-WGJ2192JZY");
</script>
</head>
<body>
<script src="/baremux/index.js"></script>
<script src="/assets/js/nprogress.js?v=0.2.0" defer></script>
<script src="/wah/uv.bundle.js" defer></script>
<script src="/wah/cute1.js" defer></script>
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
<script src="/assets/js/register.js?v=2.8.9" defer></script>
<script src="/assets/js/settings.js?v=2.8.9" defer></script>
<script src="/assets/js/ping.js?v=2.8.9" defer></script>
<script src="/assets/js/greetings.js?v=2.8.9" defer></script>
<script src="/assets/js/shortcuts.js?v=2.8.9" defer></script>
<script src="/assets/js/$.js?v=2.8.9" defer></script>
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
<div class="absolute inset-0 overflow-hidden">
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
</div> </div>
<div class="home-navbar"> </div>
<img src="/assets/images/icons/favicon.ico" class="favicon">
<span id="waves">Waves</span> <div class="home-navbar">
<a href="/" id="home">Home</a> <img src="/assets/images/icons/favicon.ico" class="favicon" />
<a href="/g" id="games">Games</a> <span id="waves">Waves</span>
<a href="/a" id="apps">Apps</a> <a href="/" id="home" style="color: #ffffff;">Home</a>
<a href="#" id="movies">Movies</a> <a href="/g" id="games">Games</a>
<a href="#" id="ai">AI</a> <a href="/s" id="apps">Shortcuts</a>
<a href="#" id="settings-icon"> <a href="#" id="movies">Movies</a>
<i id="settings-icon" class="settings-icon fa-regular fa-gear"></i> <a href="#" id="ai">AI</a>
</a> <a href="#" id="settings-icon"><i class="settings-icon fa-regular fa-gear"></i></a>
</div>
<div id="settings-menu" class="settings-menu"></div>
<div class="navbar">
<ul class="nav-buttons">
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
<li>
<div class="small-searchbar" style="position: relative;">
<i id="lockIcon" class="fa-solid fa-lock"></i>
<input class="waves" type="text" id="searchInputt" placeholder="Search for a query or enter a URL..." autocomplete="off" style="padding-left: 40px;" />
<span class="shortcut-indicator-2">Ctrl + S</span>
</div>
</li>
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
<li><a href="/s"><i class="fa-regular fa-rocket"></i></a></li>
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
</ul>
</div>
<div class="search-container">
<div class="search-title">Waves.</div>
<div class="search-bar">
<input class="waves" type="text" id="searchInput" placeholder="What's been on your mind lately?" autocomplete="off" />
<span class="shortcut-indicator">Ctrl + S</span>
</div> </div>
<div id="settings-menu" class="settings-menu"></div> </div>
<div class="navbar">
<ul class="nav-buttons"> <div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li> <div id="overlay" class="overlay"></div>
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li> <div id="namePrompt" class="popup">
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li> <div class="input-container">
<li> <label for="userName">Please enter a name so we know what to call you:</label>
<div class="small-searchbar" style="position: relative;"> <div class="input-wrapper">
<i id="lockIcon" class="fa-solid fa-lock"></i> <input type="text" id="userName" placeholder="Your name" autocomplete="off" />
<input class="waves" type="text" id="searchInputt" </div>
placeholder="Search for a query or enter a URL..." autocomplete="off" <button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
style="padding-left: 40px;">
<span class="shortcut-indicator-2">Ctrl + S</span>
</div>
</li>
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
<li><a href="/a"><i class="fa-regular fa-grid-2"></i></a></li>
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
</ul>
</div> </div>
<div class="search-container"> </div>
<div class="search-title">Waves.</div>
<div class="search-bar"> <div id="pingDisplay"><i class="fa-regular fa-wifi"></i> Ping: Connecting...</div>
<input class="waves" type="text" id="searchInput" placeholder="What's been on your mind lately?" autocomplete="off"> <div id="greeting"></div>
<span class="shortcut-indicator">Ctrl + S</span> <iframe id="cool-iframe" class="iframe"></iframe>
</div> <div id="lastest-commit">Loading latest commit</div>
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div> <div id="copyright">
<div id="overlay" class="overlay"></div> <i class="fa-regular fa-copyright"></i> 2025
<div id="namePrompt" class="popup"> <a class="hover-link" href="https://discord.gg/ire" target="_blank" rel="noopener noreferrer"><span class="copyrightname">Waves Services</span></a>.
<div class="input-container"> All Rights Reserved.
<label for="userName">Please enter a name so we know what to call you:</label> </div>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" autocomplete="off"> <div id="discord">
</div> <a class="hover-link" href="https://discord.gg/ire" target="_blank" rel="noopener noreferrer">
<button id="doneButton" onclick="submitName()" disabled> <i class="fa-brands fa-discord"></i> Discord
<i class="fa-regular fa-check"></i> Done </a>
</button> </div>
</div>
</div> <div id="github">
<div id="pingDisplay">Ping: Connecting...</div> <a class="hover-link" href="https://github.com/xojw/waves" target="_blank" rel="noopener noreferrer">
<div id="greeting"></div> <i class="fa-brands fa-github"></i> Github
<iframe id="cool-iframe" class="iframe"></iframe> </a>
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script> </div>
</body>
<script defer>
document.addEventListener("DOMContentLoaded", function () {
NProgress.configure({ showSpinner: false });
NProgress.start();
const titleElement = document.querySelector(".search-title");
if (titleElement) {
const text = titleElement.textContent.trim();
titleElement.textContent = "";
text.split("").forEach((letter, i) => {
const span = document.createElement("span");
span.textContent = letter;
span.style.animationDelay = `${i * 0.05}s`;
titleElement.appendChild(span);
});
}
window.addEventListener("load", function () {
NProgress.done();
});
});
</script>
<script>
requestIdleCallback(() => {
const ad = document.createElement("script");
ad.src = "//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js";
ad.async = true;
document.body.appendChild(ad);
});
</script>
</body>
</html> </html>

View File

@ -7,6 +7,7 @@ body {
color: #e0e0e0; color: #e0e0e0;
overflow-x: hidden; overflow-x: hidden;
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
animation: fadeIn 0.3s ease;
scroll-behavior: smooth; scroll-behavior: smooth;
position: relative; position: relative;
z-index: 1; z-index: 1;
@ -17,6 +18,23 @@ body {
color: #000000; color: #000000;
} }
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: #000000;
}
::-webkit-scrollbar-thumb {
background: #4e4e4e;
border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover {
background: #6b6b6b;
}
#nprogress .bar { #nprogress .bar {
background: #ffffff !important; background: #ffffff !important;
z-index: 99999 !important; z-index: 99999 !important;
@ -45,7 +63,7 @@ body {
.home-navbar { .home-navbar {
transform: translateX(-50%); transform: translateX(-50%);
width: 670px; width: 700px;
top: 1%; top: 1%;
margin-bottom: -10px; margin-bottom: -10px;
margin-left: 50%; margin-left: 50%;
@ -54,7 +72,6 @@ body {
height: 35px; height: 35px;
color: #818181; color: #818181;
padding: 10px; padding: 10px;
animation: fadeIn 2s ease;
text-align: center; text-align: center;
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
@ -69,14 +86,14 @@ body {
} }
.home-navbar .favicon { .home-navbar .favicon {
width: 24px; width: 28px;
height: 24px; height: 24px;
margin-right: -10px; margin-right: -10px;
vertical-align: middle; vertical-align: middle;
} }
.home-navbar a { .home-navbar a {
color: #e6e6e6; color: #7c7c7c;
text-decoration: none; text-decoration: none;
padding: 8px 16px; padding: 8px 16px;
font-size: 14px; font-size: 14px;
@ -87,7 +104,8 @@ body {
} }
.home-navbar a:hover { .home-navbar a:hover {
font-size: 16px; color: #bbbbbb;
font-size: 18px;
} }
.home-navbar a:active { .home-navbar a:active {
@ -100,23 +118,6 @@ body {
margin-left: 115px; margin-left: 115px;
} }
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: #000000;
}
::-webkit-scrollbar-thumb {
background: #4e4e4e;
border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover {
background: #6b6b6b;
}
.navbar { .navbar {
top: 1%; top: 1%;
background-color: #1111119c; background-color: #1111119c;
@ -222,6 +223,26 @@ body {
color: #818181; color: #818181;
} }
.shortcut-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(calc(-50% + 235px), -50%);
font-size: 12px;
font-weight: 500;
color: #000000;
background-color: #c4c4c4;
padding: 2px 6px;
border-radius: 7px;
cursor: pointer;
transition: all 0.3s ease;
animation: fadeIn 0.3s ease;
}
.shortcut-indicator:hover {
background-color: #ffffff;
}
.shortcut-indicator-2 { .shortcut-indicator-2 {
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -235,12 +256,20 @@ body {
border-radius: 7px; border-radius: 7px;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
animation: fadeUp 0.3s ease;
} }
.shortcut-indicator-2:hover { .shortcut-indicator-2:hover {
background-color: #ffffff; background-color: #ffffff;
} }
.arrow-mode {
display: inline-block;
margin-left: 17px;
transition: all 0.3s ease;
animation: fadeIn 0.3s ease;
}
#lockIcon { #lockIcon {
position: absolute; position: absolute;
left: 25px; left: 25px;
@ -255,7 +284,6 @@ body {
margin-top: 20%; margin-top: 20%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
animation: fadeIn 2s ease;
text-align: center; text-align: center;
width: 90%; width: 90%;
} }
@ -265,25 +293,22 @@ body {
font-weight: bolder; font-weight: bolder;
text-align: center; text-align: center;
display: inline-block; display: inline-block;
background: linear-gradient(-45deg, #4e4e4e, #ffffff); background: linear-gradient(-45deg, #8d8d8d, #ffffff);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
color: transparent; color: transparent;
cursor: default; cursor: default;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.search-title span { .search-title span {
display: inline-block; display: inline-block;
background: inherit;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
opacity: 0; opacity: 0;
transform: translateX(-50px); background: inherit;
animation: fadeInFromLeft 0.5s ease-in-out forwards; color: transparent;
transform: translateY(4rem);
animation: fadeSlideIn 0.6s forwards;
} }
.search-bar { .search-bar {
@ -323,25 +348,6 @@ body {
color: #ffffff69; color: #ffffff69;
} }
.shortcut-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(calc(-50% + 235px), -50%);
font-size: 12px;
font-weight: 500;
color: #000000;
background-color: #c4c4c4;
padding: 2px 6px;
border-radius: 7px;
cursor: pointer;
transition: all 0.3s ease;
}
.shortcut-indicator:hover {
background-color: #ffffff;
}
#erudaLoadingScreen { #erudaLoadingScreen {
position: fixed; position: fixed;
top: 50%; top: 50%;
@ -387,13 +393,13 @@ body {
} }
.hover-link { .hover-link {
color: #949494; color: #b3b3b3;
text-decoration: none; text-decoration: none;
transition: color 0.3s ease; transition: color 0.3s ease;
} }
.hover-link:hover { .hover-link:hover {
color: #dadada; color: #ffffff;
} }
#pingDisplay { #pingDisplay {
@ -401,10 +407,9 @@ body {
margin-top: -46px; margin-top: -46px;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
font-weight: bold; font-weight: 550;
color: #888888; color: #888888;
cursor: default; cursor: default;
animation: fadeIn 2s ease;
padding: 5px 10px; padding: 5px 10px;
transition: all 0.3s ease; transition: all 0.3s ease;
z-index: -1; z-index: -1;
@ -412,7 +417,7 @@ body {
} }
#pingDisplay:hover { #pingDisplay:hover {
color: #b6b6b6; color: #d3d3d3;
} }
.god-rays { .god-rays {
@ -426,7 +431,6 @@ body {
background-image: var(--stripes), var(--rays); background-image: var(--stripes), var(--rays);
background-size: 300%, 200%; background-size: 300%, 200%;
background-position: 50% 50%, 50% 50%; background-position: 50% 50%, 50% 50%;
animation: fadeIn 2s ease;
mask-image: radial-gradient(ellipse at 100% 0%, transparent 40%, transparent 70%); mask-image: radial-gradient(ellipse at 100% 0%, transparent 40%, transparent 70%);
-webkit-mask-image: radial-gradient(ellipse at 100% 0%, white 40%, transparent 70%); -webkit-mask-image: radial-gradient(ellipse at 100% 0%, white 40%, transparent 70%);
pointer-events: none; pointer-events: none;
@ -456,7 +460,7 @@ body {
display: none; display: none;
opacity: 0; opacity: 0;
transition: opacity 0.3s ease-in-out; transition: opacity 0.3s ease-in-out;
animation: fadeInOverlay 0.3s ease-in-out forwards; animation: fadeIn 0.3s ease-in-out forwards;
} }
#namePrompt { #namePrompt {
@ -572,7 +576,6 @@ body {
position: fixed; position: fixed;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
animation: fadeIn 2s ease;
opacity: 0; opacity: 0;
transition: all 0.3s ease; transition: all 0.3s ease;
cursor: default; cursor: default;
@ -580,42 +583,94 @@ body {
} }
#greeting:hover { #greeting:hover {
color: #b6b6b6; color: #d3d3d3;
} }
#namePrompt.fade-out { #namePrompt.fade-out {
animation: fadeOutPrompt 0.3s ease-in-out forwards; animation: fadeOut 0.3s ease-in-out forwards;
} }
@keyframes fadeInFromLeft { #lastest-commit {
0% { position: fixed;
opacity: 0; bottom: 10px;
transform: translateX(-50px); left: 10px;
} z-index: 9999;
background-color: #08080894;
100% { border: 1px solid #ffffff21;
opacity: 1; color: #cfcfcf;
transform: translateX(0); font-weight: 540;
} transition: all 0.3s ease;
cursor: default;
padding: 8px 12px;
border-radius: 15px;
font-size: 14px;
} }
@keyframes fadeIn { #copyright {
from { position: fixed;
opacity: 0; bottom: 10px;
} left: 50%;
transform: translateX(-50%);
z-index: 9999;
background-color: #08080894;
border: 1px solid #ffffff21;
color: #858585;
font-weight: 540;
transition: all 0.3s ease;
cursor: default;
padding: 8px 12px;
border-radius: 15px;
font-size: 14px;
}
#copyright:hover {
color: #afafaf;
}
#discord {
position: fixed;
bottom: 10px;
right: 100px;
z-index: 9999;
background-color: #08080894;
border: 1px solid #ffffff21;
color: #858585;
font-weight: 540;
transition: all 0.3s ease;
cursor: default;
padding: 8px 12px;
border-radius: 15px;
font-size: 14px;
}
#github {
position: fixed;
bottom: 10px;
right: 10px;
z-index: 9999;
background-color: #08080894;
border: 1px solid #ffffff21;
color: #858585;
font-weight: 540;
transition: all 0.3s ease;
cursor: default;
padding: 8px 12px;
border-radius: 15px;
font-size: 14px;
}
.fadeIn {
animation: fadeIn 0.3s ease-in-out forwards;
}
.fadeOut {
animation: fadeOut 0.3s ease-in-out forwards;
}
@keyframes fadeSlideIn {
to { to {
opacity: 1; opacity: 1;
} transform: translateY(0);
}
@keyframes fadeInOverlay {
0% {
opacity: 0;
}
100% {
opacity: 1;
} }
} }
@ -631,7 +686,17 @@ body {
} }
} }
@keyframes fadeOutPrompt { @keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOut {
0% { 0% {
opacity: 1; opacity: 1;
} }
@ -651,47 +716,6 @@ body {
} }
} }
@keyframes swing {
0%,
100% {
transform: rotate(3deg);
}
50% {
transform: rotate(-3deg);
}
}
@keyframes steamLarge {
0% {
stroke-dashoffset: 13;
opacity: 0.6;
}
100% {
stroke-dashoffset: 39;
opacity: 0;
}
}
@keyframes steamSmall {
10% {
stroke-dashoffset: 9;
opacity: 0.6;
}
80% {
stroke-dashoffset: 27;
opacity: 0;
}
100% {
stroke-dashoffset: 27;
opacity: 0;
}
}
@keyframes spin { @keyframes spin {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);

View File

@ -5,7 +5,6 @@
} }
.games-page h1 { .games-page h1 {
animation: fadeIn 2s ease;
font-size: 2.5rem; font-size: 2.5rem;
margin-bottom: 20px; margin-bottom: 20px;
color: #fff; color: #fff;
@ -82,7 +81,6 @@
margin-top: 20px; margin-top: 20px;
margin-bottom: 20px; margin-bottom: 20px;
color: #a8a8a8; color: #a8a8a8;
animation: fadeIn 2s ease;
position: relative; position: relative;
} }

View File

@ -0,0 +1 @@
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translate(0,-4px);-ms-transform:rotate(3deg) translate(0,-4px);transform:rotate(3deg) translate(0,-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner 400ms linear infinite;animation:nprogress-spinner 400ms linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}

View File

@ -1,17 +1,16 @@
.apps-page { .shortcuts-page {
padding: 100px 20px 40px; padding: 100px 20px 40px;
text-align: center; text-align: center;
position: relative; position: relative;
} }
.apps-page h1 { .shortcuts-page h1 {
animation: fadeIn 2s ease;
font-size: 2.5rem; font-size: 2.5rem;
margin-bottom: 20px; margin-bottom: 20px;
color: #fff; color: #fff;
} }
.apps-grid { .shortcuts-grid {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
@ -22,14 +21,14 @@
margin: 0 auto; margin: 0 auto;
} }
.content.apps-page { .content.shortcuts-page {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
text-align: center; text-align: center;
} }
.app-card { .shortcut-card {
background-color: #08080894; background-color: #08080894;
border-radius: 25px; border-radius: 25px;
padding: 15px 20px; padding: 15px 20px;
@ -49,7 +48,7 @@
animation: fadeIn 2s ease; animation: fadeIn 2s ease;
} }
.app-card img { .shortcut-card img {
width: 100%; width: 100%;
height: 200px; height: 200px;
object-fit: cover; object-fit: cover;
@ -58,40 +57,39 @@
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.app-card:hover img { .shortcut-card:hover img {
filter: brightness(1); filter: brightness(1);
} }
.app-card:hover { .shortcut-card:hover {
background-color: #333333; background-color: #333333;
} }
.app-card h2 { .shortcut-card h2 {
font-size: 1rem; font-size: 1rem;
margin: 10px 0; margin: 10px 0;
color: #fff; color: #fff;
} }
.app-card p { .shortcut-card p {
font-size: 1rem; font-size: 1rem;
color: #ccc; color: #ccc;
} }
.apps-search-bar { .shortcuts-search-bar {
text-align: center; text-align: center;
margin-top: 20px; margin-top: 20px;
margin-bottom: 20px; margin-bottom: 20px;
color: #a8a8a8; color: #a8a8a8;
animation: fadeIn 2s ease;
position: relative; position: relative;
} }
#appSearchInput { #shortcutSearchInput {
padding: 14px 30px; padding: 14px 30px;
border: 1px solid #ffffff1a; border: 1px solid #ffffff1a;
background-image: url('/assets/images/icons/search.png'); background-image: url('/assets/images/icons/search.png');
background-size: 35px 35px; background-size: 35px 35px;
background-position: 10px center; background-position: 5px center;
background-repeat: no-repeat; background-repeat: no-repeat;
padding-left: 45px; padding-left: 45px;
border-radius: 20px; border-radius: 20px;
@ -104,12 +102,12 @@
transition: all 0.3s ease; transition: all 0.3s ease;
} }
#appSearchInput:focus, #shortcutSearchInput:focus,
#appSearchInput:hover { #shortcutSearchInput:hover {
border: 1px solid #ffffff69; border: 1px solid #ffffff69;
} }
#appSearchInput::placeholder { #shortcutSearchInput::placeholder {
color: #a8a8a8; color: #a8a8a8;
} }

View File

@ -63,7 +63,7 @@
#close-settings:hover { #close-settings:hover {
transform: rotate(90deg); transform: rotate(90deg);
color: #d3d3d3; color: #ffffff;
} }
#close-settings i { #close-settings i {
@ -94,9 +94,9 @@
.transport-selected { .transport-selected {
background-color: #141414; background-color: #141414;
border: 1px solid #ffffff1a;
color: #e0e0e0; color: #e0e0e0;
padding: 10px; padding: 10px;
border: 1px solid #4141411a;
border-radius: 15px; border-radius: 15px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
@ -159,7 +159,7 @@
margin-left: -80px; margin-left: -80px;
background-color: #141414; background-color: #141414;
color: #e0e0e0; color: #e0e0e0;
border: 1px solid #4141411a; border: 1px solid #ffffff1a;
border-radius: 15px; border-radius: 15px;
font-size: 15px; font-size: 15px;
outline: none; outline: none;
@ -266,7 +266,7 @@
background-color: #1b1b1b; background-color: #1b1b1b;
color: #e0e0e0; color: #e0e0e0;
padding: 12px 14px; padding: 12px 14px;
border: 1px solid #4141411a; border: 1px solid #ffffff21;
border-radius: 15px; border-radius: 15px;
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
@ -280,9 +280,8 @@
} }
.tab-button.active { .tab-button.active {
background-color: #333; background-color: #5c5c5c;
color: #ffffff; color: #ffffff;
transform: translateY(-4px);
} }
.tab-content { .tab-content {

View File

@ -32,6 +32,10 @@
display: inline-block; display: inline-block;
} }
.toast i {
margin-right: 8px;
}
.toast.show { .toast.show {
animation: slideIn 0.3s forwards; animation: slideIn 0.3s forwards;
} }
@ -51,6 +55,21 @@
animation: progress 3s linear forwards; animation: progress 3s linear forwards;
} }
.toast .toast-close {
background: none;
border: none;
color: #888888;
font-size: 18px;
cursor: pointer;
padding: 0;
margin-left: 10px;
transition: 0.3s;
}
.toast-close:hover {
color: #ffffff;
}
@keyframes slideIn { @keyframes slideIn {
0% { 0% {
right: -300px; right: -300px;
@ -79,19 +98,4 @@
100% { 100% {
width: 0%; width: 0%;
} }
}
.toast .toast-close {
background: none;
border: none;
color: #888888;
font-size: 18px;
cursor: pointer;
padding: 0;
margin-left: 10px;
transition: 0.3s;
}
.toast-close:hover {
color: #d3d3d3;
} }

View File

@ -1,5 +1,5 @@
{ {
"apps": [ "shortcuts": [
{ {
"icon": "/assets/images/a/crazygames.jpg", "icon": "/assets/images/a/crazygames.jpg",
"title": "Crazy Games", "title": "Crazy Games",
@ -51,4 +51,4 @@
"link": "https://store.steampowered.com" "link": "https://store.steampowered.com"
} }
] ]
} }

View File

@ -13,7 +13,6 @@
<script> <script>
var gameLoaded = false; var gameLoaded = false;
window.addEventListener("beforeunload", function (e) { window.addEventListener("beforeunload", function (e) {
if (adsVisible || !gameLoaded || !lockedOccured) return null;
var confirmationMessage = "Are you sure you want to leave? "; var confirmationMessage = "Are you sure you want to leave? ";
(e || window.event).returnValue = confirmationMessage; //Gecko + IE (e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc. return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
@ -86,52 +85,10 @@
}, },
}); });
</script> </script>
<!-- MIDROLL/INTERSTITIAL VIDEO API -->
<script src="js/cpmstar.js"></script>
</head> </head>
<body> <body>
<div class="ads">
<div class="ad-smallscreen">
<div class="ad ad-rectangle-bottom"></div>
</div>
<div class="ad ad-rectangle-upper" id="adRectangleUpper">
<!-- 300X250B PLACEMENT TAG - PLACE INTO BODY (ZONE TAG REQUIRED) -->
<script>
(function (w, pid) {
var r = function (c, m) {
c = c.split("").reduce(function (a, b) {
return ((a << 5) - a + b.charCodeAt(0)) >>> m;
}, 0);
return (10 + ((c * 7) % 26)).toString(36) + c.toString(36);
},
y = r(w.location.href.split("#")[0], 1),
c = r(w.location.href.split("#")[0] + pid, 0);
w.document.write('<div style="width:300px;height:250px" class="' + c + '"></div>');
})(window, 83023);
</script>
</div>
<div class="ad-largescreen">
<div class="ad ad-leaderboard-bottom">
<!-- 300X600B PLACEMENT TAG - PLACE INTO BODY (ZONE TAG REQUIRED) -->
<script>
(function (w, pid) {
var r = function (c, m) {
c = c.split("").reduce(function (a, b) {
return ((a << 5) - a + b.charCodeAt(0)) >>> m;
}, 0);
return (10 + ((c * 7) % 26)).toString(36) + c.toString(36);
},
y = r(w.location.href.split("#")[0], 1),
c = r(w.location.href.split("#")[0] + pid, 0);
w.document.write('<div style="width:300px;height:600px" class="' + c + '"></div>');
})(window, 85420);
</script>
</div>
</div>
</div>
<!-- <div id="interAdsContainer" style="display: none;"></div> -->
<div id="gameContainer"></div> <div id="gameContainer"></div>
<div id="loader"> <div id="loader">
<img class="logo" src="logo.png" /> <img class="logo" src="logo.png" />
@ -222,55 +179,6 @@
var refreshNextTime = true; var refreshNextTime = true;
function showAds() {
document.getElementsByClassName("ad-rectangle-bottom")[0].style.display = "block";
document.getElementsByClassName("ad-leaderboard-bottom")[0].style.display = "block";
document.getElementById("adRectangleUpper").style.display = "block";
if (typeof counter === "undefined") {
startCounter();
resumeCounter();
} else {
resumeCounter();
refresh();
}
}
function hideAds() {
document.getElementsByClassName("ad-rectangle-bottom")[0].style.display = "none";
document.getElementsByClassName("ad-leaderboard-bottom")[0].style.display = "none";
document.getElementById("adRectangleUpper").style.display = "none";
pauseCounter();
}
// hide ads
hideAds();
function refresh() {
//console.log("time since ads refresh = " + timeSinceRefresh + " seconds");
//console.log("time ads visible = " + timeAdsVisible + " seconds");
if (timeSinceRefresh <= 30 || timeAdsVisible <= 2) {
//console.log("don't refresh");
return;
}
if (document.getElementById("adRectangleBottom") != null && window.getComputedStyle(document.getElementsByClassName("ad-smallscreen")[0]).display != "none") {
cpmstarAPI({ kind: "adcmd", module: "POOL 83023", command: "refresh" });
}
if (document.getElementById("adLeaderboardBottom") != null && window.getComputedStyle(document.getElementsByClassName("ad-largescreen")[0]).display != "none") {
cpmstarAPI({ kind: "adcmd", module: "POOL 85420", command: "refresh" });
}
cpmstarAPI({ kind: "adcmd", module: "POOL 83025", command: "refresh" });
timeSinceRefresh = 0;
timeAdsVisible = 0;
//console.log("refresh ads");
}
window.onfocus = function () { window.onfocus = function () {
//console.log("onfocus"); //console.log("onfocus");
resumeCounter(); resumeCounter();
@ -283,26 +191,16 @@
}; };
var timeSinceRefresh = 0; var timeSinceRefresh = 0;
var timeAdsVisible = 0;
var counter; var counter;
var adsVisible = false;
function startCounter() { function startCounter() {
timeSinceRefresh++; timeSinceRefresh++;
if (adsVisible) timeAdsVisible++;
counter = setTimeout(function () { counter = setTimeout(function () {
startCounter(); startCounter();
}, 1000); }, 1000);
} }
function resumeCounter() {
adsVisible = true;
}
function pauseCounter() {
adsVisible = false;
}
</script> </script>
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first --> <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="firebase/firebase-app.js"></script> <script src="firebase/firebase-app.js"></script>
@ -341,4 +239,4 @@
fixMacUserAgent(); fixMacUserAgent();
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,293 +1,485 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const historyStack = [] window.APP = {};
let currentIndex = -1
const refreshIcon = document.getElementById('refreshIcon') const iframe = document.getElementById('cool-iframe');
const fullscreenIcon = document.getElementById('fullscreenIcon') const erudaLoadingScreen = document.getElementById('erudaLoadingScreen');
const backIcon = document.getElementById('backIcon') const searchInput1 = document.getElementById('searchInput');
const forwardIcon = document.getElementById('forwardIcon') const movies = document.getElementById('movies');
const iframe = document.getElementById('cool-iframe') const ai = document.getElementById('ai');
const erudaLoadingScreen = document.getElementById('erudaLoadingScreen') const topBar = document.querySelector('.topbar');
if (!refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon || !iframe) return const refreshIcon = document.getElementById('refreshIcon');
const originalTitle = document.title const fullscreenIcon = document.getElementById('fullscreenIcon');
let loadingHidden = false const backIcon = document.getElementById('backIcon');
function showLoadingScreen(withToast = true, showEruda = false) { const forwardIcon = document.getElementById('forwardIcon');
loadingHidden = false const searchInput2 = document.getElementById('searchInputt');
NProgress.start() const lockIcon = document.getElementById('lockIcon');
document.title = 'Loading... <3' const navbarToggle = document.getElementById('navbar-toggle');
if (withToast) { const navBar = document.querySelector('.navbar');
showToast(
'Consider joining our <a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">Discord</a>&nbsp;<3', const historyStack = [];
'success', let currentIndex = -1;
'heart' const originalTitle = document.title;
) let isLoading = false;
}
} if (!iframe || !refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon) {
function hideLoadingScreen() { return;
if (loadingHidden) return }
loadingHidden = true
NProgress.done() const animationStyle = document.createElement('style');
document.title = originalTitle animationStyle.textContent = `
} @keyframes slideLeft {0% { transform: translateX(0); } 50% { transform: translateX(-5px); } 100% { transform: translateX(0); }}
refreshIcon.addEventListener('click', () => { @keyframes slideRight {0% { transform: translateX(0); } 50% { transform: translateX(5px); } 100% { transform: translateX(0); }}
refreshIcon.classList.add('spin') .button-animate-back { animation: slideLeft 0.3s ease-in-out; }
if (iframe.tagName === 'IFRAME') { .button-animate-forward { animation: slideRight 0.3s ease-in-out; }
const currentUrl = iframe.contentWindow.location.href .spin { animation: spinAnimation 0.3s linear; }
if (normalizeUrl(currentUrl) !== normalizeUrl(historyStack[currentIndex] || '')) { @keyframes spinAnimation { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
addToHistory(currentUrl) `;
} document.head.appendChild(animationStyle);
iframe.contentWindow.location.reload(true)
} function showLoadingScreen(withToast = true) {
setTimeout(() => refreshIcon.classList.remove('spin'), 300) if (isLoading) return;
}) isLoading = true;
fullscreenIcon.addEventListener('click', () => { if (typeof NProgress !== 'undefined') NProgress.start();
if (iframe.requestFullscreen) iframe.requestFullscreen()
else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen() if (withToast) {
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen() showToast(
else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen() 'Consider joining our <a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">Discord</a>&nbsp;<3',
}) 'success',
backIcon.addEventListener('click', () => { 'heart'
if (currentIndex > 0) { );
currentIndex-- }
iframe.src = historyStack[currentIndex] }
showLoadingScreen(false, false)
updateNavButtons() function hideLoadingScreen() {
updateDecodedSearchInput() if (!isLoading) return;
} if (typeof NProgress !== 'undefined') NProgress.done();
}) document.title = originalTitle;
forwardIcon.addEventListener('click', () => { isLoading = false;
if (currentIndex < historyStack.length - 1) { if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none';
currentIndex++ }
iframe.src = historyStack[currentIndex]
showLoadingScreen(false, false) function normalizeUrl(urlStr) {
updateNavButtons() if (!urlStr || urlStr === 'about:blank') return urlStr;
updateDecodedSearchInput() try {
} const url = new URL(urlStr);
}) url.searchParams.delete('ia');
function normalizeUrl(urlStr) { return url.toString();
try { } catch {
const url = new URL(urlStr) return urlStr;
url.searchParams.delete('ia') }
return url.toString() }
} catch {
return urlStr function decodeUrl(encodedUrl) {
} if (!encodedUrl) return '';
} try {
function addToHistory(url) { const prefix = (typeof __uv$config !== 'undefined' && __uv$config.prefix) ? __uv$config.prefix : '/wa/a/';
const normalized = normalizeUrl(url) const decodeFunction = (typeof __uv$config !== 'undefined' && __uv$config.decodeUrl) ? __uv$config.decodeUrl : decodeURIComponent;
if (currentIndex >= 0 && normalizeUrl(historyStack[currentIndex]) === normalized) return const urlObject = new URL(encodedUrl, window.location.origin);
if (currentIndex < historyStack.length - 1) historyStack.splice(currentIndex + 1) if (urlObject.pathname.startsWith(prefix)) {
historyStack.push(url) const encodedPart = urlObject.pathname.slice(prefix.length);
currentIndex++ return decodeFunction(encodedPart) + urlObject.search + urlObject.hash;
updateNavButtons() }
updateDecodedSearchInput() } catch {}
} try {
function updateNavButtons() { return decodeURIComponent(encodedUrl);
backIcon.disabled = currentIndex <= 0 } catch {
forwardIcon.disabled = currentIndex >= historyStack.length - 1 return encodedUrl;
backIcon.classList.toggle('disabled', currentIndex <= 0) }
forwardIcon.classList.toggle('disabled', currentIndex >= historyStack.length - 1) }
}
function updateDecodedSearchInput() { function updateNavButtons() {
const searchInput2 = document.getElementById('searchInputt') if (!backIcon || !forwardIcon) return;
if (!searchInput2) return const canGoBack = currentIndex > 0;
let url = '' const canGoForward = currentIndex < historyStack.length - 1;
if (currentIndex >= 0 && historyStack[currentIndex]) { backIcon.disabled = !canGoBack;
url = historyStack[currentIndex] forwardIcon.disabled = !canGoForward;
} else if (iframe.src) { backIcon.classList.toggle('disabled', !canGoBack);
url = iframe.src forwardIcon.classList.toggle('disabled', !canGoForward);
} }
searchInput2.value = decodeUrl(url)
const lockIcon = document.getElementById('lockIcon') function updateDecodedSearchInput() {
if (lockIcon) { if (!searchInput2) return;
lockIcon.className = decodeUrl(url).startsWith('https://') ? let currentUrl = '';
'fa-regular fa-lock' : if (currentIndex >= 0 && historyStack[currentIndex]) {
'fa-regular fa-lock-open' currentUrl = historyStack[currentIndex];
lockIcon.style.color = '' } else if (iframe.src && iframe.src !== 'about:blank') {
} currentUrl = iframe.src;
} }
iframe.addEventListener('load', () => { const decoded = decodeUrl(currentUrl);
try { searchInput2.value = decoded;
hideLoadingScreen()
} catch { if (lockIcon) {
hideLoadingScreen() const isSecure = decoded.startsWith('https://');
} finally { lockIcon.className = isSecure ? 'fa-regular fa-lock' : 'fa-regular fa-lock-open';
if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none' }
} }
})
iframe.addEventListener('error', () => { function addToHistory(url, isReplacingCurrent = false) {
hideLoadingScreen() if (!url || url === 'about:blank') return;
})
iframe.addEventListener('loadstart', () => { const normalizedNewUrl = normalizeUrl(url);
const navBar = document.querySelector('.navbar') const currentHistoryEntry = historyStack[currentIndex];
const navbarToggle = document.getElementById('navbar-toggle') const normalizedCurrentHistoryEntry = currentIndex >= 0 ? normalizeUrl(currentHistoryEntry) : null;
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block'
showLoadingScreen(false, false) if (isReplacingCurrent && currentIndex >= 0) {
}) if (normalizedCurrentHistoryEntry !== normalizedNewUrl || currentHistoryEntry !== url) {
const navBar = document.querySelector('.navbar') historyStack[currentIndex] = url;
const topBar = document.querySelector('.topbar') } else {
const searchInput1 = document.getElementById('searchInput') return;
const searchInput2 = document.getElementById('searchInputt') }
const movies = document.getElementById('movies') } else {
const ai = document.getElementById('ai') if (normalizedCurrentHistoryEntry === normalizedNewUrl && currentHistoryEntry === url) {
const navbarToggle = document.getElementById('navbar-toggle') return;
if (navbarToggle && navBar) { }
const savedNavbarState = localStorage.getItem('navbarToggled') if (currentIndex < historyStack.length - 1) {
navbarToggle.checked = savedNavbarState === null ? true : savedNavbarState === 'true' historyStack.splice(currentIndex + 1);
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none' }
navbarToggle.addEventListener('change', () => { historyStack.push(url);
localStorage.setItem('navbarToggled', navbarToggle.checked) currentIndex++;
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none' }
}) updateNavButtons();
} updateDecodedSearchInput();
iframe.style.display = 'none' }
window.addEventListener('load', hideLoadingScreen)
;[searchInput1, searchInput2].forEach(input => { function setupIframeNavigationListeners() {
if (input) { try {
input.addEventListener('keyup', e => { const iframeWindow = iframe.contentWindow;
if (e.key === 'Enter') { if (!iframeWindow || iframeWindow === window || iframeWindow.location.href === 'about:blank') return;
const val = input.value.trim()
if (val) handleSearch(val) const handleNav = (isReplace = false) => {
else showToast('Please enter something in the Search Bar.', 'error', 'warning') setTimeout(() => {
} try {
}) const newUrlInIframe = iframeWindow.location.href;
} if (newUrlInIframe === 'about:blank' && historyStack[currentIndex] === 'about:blank') return;
}) addToHistory(newUrlInIframe, isReplace);
if (movies) movies.addEventListener('click', e => { } catch (e) {}
e.preventDefault() }, 0);
handleSearch('https://movies.usewaves.site/') };
})
if (ai) ai.addEventListener('click', e => { if (!iframeWindow.history.pushState.__isPatched) {
e.preventDefault() const originalPushState = iframeWindow.history.pushState;
handleSearch('https://ai.usewaves.site/') iframeWindow.history.pushState = function(...args) {
}) originalPushState.apply(this, args);
function clearBackground() { handleNav(false);
const preserved = [ };
document.querySelector('.navbar'), iframeWindow.history.pushState.__isPatched = true;
document.getElementById('cool-iframe'), }
document.querySelector('.loading-screen'), if (!iframeWindow.history.replaceState.__isPatched) {
erudaLoadingScreen const originalReplaceState = iframeWindow.history.replaceState;
] iframeWindow.history.replaceState = function(...args) {
Array.from(document.body.children).forEach(child => { originalReplaceState.apply(this, args);
if (!preserved.includes(child)) child.remove() handleNav(true);
}) };
} iframeWindow.history.replaceState.__isPatched = true;
async function handleSearch(query) { }
if (!query || !query.trim()) {
showToast('Please enter something in the Search Bar.', 'error', 'warning') iframeWindow.removeEventListener('popstate', iframeWindow.__popstateHandler);
return iframeWindow.__popstateHandler = () => handleNav(false);
} iframeWindow.addEventListener('popstate', iframeWindow.__popstateHandler);
clearBackground()
let searchURL iframeWindow.removeEventListener('hashchange', iframeWindow.__hashchangeHandler);
if ( iframeWindow.__hashchangeHandler = () => handleNav(false);
query.startsWith('/assets/g/') || iframeWindow.addEventListener('hashchange', iframeWindow.__hashchangeHandler);
query.startsWith(window.location.origin + '/assets/g/') } catch (error) {}
) { }
searchURL = query
} else { iframe.addEventListener('loadstart', () => {
searchURL = generateSearchUrl(query) showLoadingScreen(false);
} if (navbarToggle && navbarToggle.checked && navBar) {
if (searchInput2) searchInput2.value = searchURL navBar.style.display = 'block';
historyStack.length = 0 }
currentIndex = -1 });
showLoadingScreen(true, false)
iframe.style.display = 'block' iframe.addEventListener('load', () => {
if (topBar) topBar.style.display = 'none' hideLoadingScreen();
backIcon.disabled = forwardIcon.disabled = true try {
let finalUrl const newUrl = iframe.contentWindow ? iframe.contentWindow.location.href : iframe.src;
try { if (newUrl && newUrl !== 'about:blank') {
const u = new URL(searchURL, window.location.origin) if (currentIndex === -1 || normalizeUrl(historyStack[currentIndex]) !== normalizeUrl(newUrl) || historyStack[currentIndex] !== newUrl) {
if (u.origin === window.location.origin && u.pathname.startsWith('/assets/g/')) { addToHistory(newUrl);
finalUrl = u.href } else if (historyStack[currentIndex] !== newUrl) {
} else { addToHistory(newUrl, true);
finalUrl = await getUrl(searchURL) }
} } else if (newUrl === 'about:blank' && historyStack.length > 0 && historyStack[currentIndex] !== 'about:blank') {
} catch { if (currentIndex > 0) {
finalUrl = await getUrl(searchURL) const previousUrl = historyStack[currentIndex - 1];
} currentIndex--;
iframe.src = finalUrl iframe.src = previousUrl;
iframe.onload = () => { return;
hideLoadingScreen() }
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block' }
generateSubject() setupIframeNavigationListeners();
updateDecodedSearchInput() if (navbarToggle && navbarToggle.checked && navBar) {
} navBar.style.display = 'block';
iframe.onerror = () => { }
hideLoadingScreen() } catch (error) {} finally {
} updateNavButtons();
} updateDecodedSearchInput();
window.handleSearch = handleSearch }
function generateSearchUrl(query) { });
try {
return new URL(query).toString() iframe.addEventListener('error', () => {
} catch { hideLoadingScreen();
try { showToast('Error: Could not load page content.', 'error', 'times-circle');
const u = new URL(`https://${query}`) updateNavButtons();
if (u.hostname.includes('.')) return u.toString() updateDecodedSearchInput();
} catch {} });
}
return `https://duckduckgo.com/?q=${encodeURIComponent(query)}&ia=web` function toggleButtonAnimation(button, animationClass) {
} if (button) {
function showToast(message, type = 'success', iconType = 'check') { button.classList.add(animationClass);
const toast = document.createElement('div') setTimeout(() => button.classList.remove(animationClass), 200);
toast.className = `toast show ${type}` }
const icons = { }
success: '<i class="fa-regular fa-check-circle" style="margin-right: 8px;"></i>',
error: '<i class="fa-regular fa-times-circle" style="margin-right: 8px;"></i>', backIcon.addEventListener('click', () => {
info: '<i class="fa-regular fa-info-circle" style="margin-right: 8px;"></i>', toggleButtonAnimation(backIcon, 'button-animate-back');
warning: '<i class="fa-regular fa-exclamation-triangle" style="margin-right: 8px;"></i>', if (currentIndex > 0) {
heart: '<i class="fa-regular fa-heart" style="margin-right: 8px;"></i>' currentIndex--;
} showLoadingScreen(false);
const icon = icons[iconType] || icons.heart iframe.src = historyStack[currentIndex];
toast.innerHTML = `${icon}${message} ` updateNavButtons();
const progressBar = document.createElement('div') updateDecodedSearchInput();
progressBar.className = 'progress-bar' }
toast.appendChild(progressBar) });
const closeBtn = document.createElement('button')
closeBtn.className = 'toast-close' forwardIcon.addEventListener('click', () => {
closeBtn.innerHTML = '<i class="fa-solid fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>' toggleButtonAnimation(forwardIcon, 'button-animate-forward');
closeBtn.addEventListener('click', () => { if (currentIndex < historyStack.length - 1) {
toast.classList.add('hide') currentIndex++;
setTimeout(() => toast.remove(), 500) showLoadingScreen(false);
}) iframe.src = historyStack[currentIndex];
toast.appendChild(closeBtn) updateNavButtons();
document.body.appendChild(toast) updateDecodedSearchInput();
setTimeout(() => { }
toast.classList.add('hide') });
setTimeout(() => toast.remove(), 500)
}, 3000) refreshIcon.addEventListener('click', () => {
} if (refreshIcon) refreshIcon.classList.add('spin');
function preloadResources(url) { if (iframe.contentWindow) {
if (!url) return showLoadingScreen(false);
try { const currentIframeUrl = iframe.contentWindow.location.href;
const link = document.createElement('link') if (normalizeUrl(currentIframeUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
link.rel = 'preload' addToHistory(currentIframeUrl);
link.href = url }
link.as = 'fetch' iframe.contentWindow.location.reload(true);
link.crossOrigin = 'anonymous' }
document.head.appendChild(link) if (refreshIcon) setTimeout(() => refreshIcon.classList.remove('spin'), 300);
} catch {} });
}
function getUrl(url) { fullscreenIcon.addEventListener('click', () => {
return Promise.resolve(__uv$config.prefix + __uv$config.encodeUrl(url)) if (iframe.requestFullscreen) iframe.requestFullscreen();
} else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen();
function generateSubject() { else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
const subjects = ['math', 'science', 'history', 'art', 'programming', 'philosophy'] else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen();
const random = subjects[Math.floor(Math.random() * subjects.length)] });
history.replaceState({}, '', '/learning?subject=' + random)
} function generateSearchUrl(query) {
function decodeUrl(enc) { query = query.trim();
try { if (!query) return `https://duckduckgo.com/?q=&ia=web`;
const o = new URL(enc, window.location.origin)
const p = (__uv$config && __uv$config.prefix) || '/wa/a/' if (/^[a-zA-Z]+:\/\//.test(query)) {
if (o.pathname.startsWith(p)) { try {
const part = o.pathname.slice(p.length) new URL(query);
return (__uv$config.decodeUrl ? __uv$config.decodeUrl(part) : decodeURIComponent(part)) return query;
} } catch (e) {}
} catch {} }
return enc
} if (/^(localhost|(\d{1,3}\.){3}\d{1,3})(:\d+)?(\/.*)?$/.test(query) || query.toLowerCase() === "localhost") {
window.decodeUrl = decodeUrl if (!query.toLowerCase().startsWith("http:") && !query.toLowerCase().startsWith("https:")) {
window.addToHistory = addToHistory return `http://${query}`;
window.updateDecodedSearchInput = updateDecodedSearchInput }
window.normalizeUrl = normalizeUrl return query;
}) }
try {
const urlWithHttps = new URL(`https://${query}`);
if (urlWithHttps.hostname &&
urlWithHttps.hostname.includes('.') &&
!urlWithHttps.hostname.endsWith('.') &&
urlWithHttps.hostname !== '.' &&
urlWithHttps.hostname.split('.').pop().length >= 2 &&
!/^\d+$/.test(urlWithHttps.hostname.split('.').pop())
) {
return urlWithHttps.toString();
}
} catch (e) {}
return `https://duckduckgo.com/?q=${encodeURIComponent(query)}&ia=web`;
}
async function getUrl(url) {
if (typeof __uv$config !== 'undefined' && __uv$config.encodeUrl) {
return Promise.resolve(__uv$config.prefix + __uv$config.encodeUrl(url));
}
return Promise.resolve(url);
}
function clearBackground() {
const preservedElements = [
navBar, iframe, document.querySelector('.loading-screen'),
erudaLoadingScreen, topBar
].filter(el => el != null);
Array.from(document.body.children).forEach(child => {
if (!preservedElements.includes(child) && child.tagName !== 'SCRIPT' && child.tagName !== 'STYLE' && !child.classList.contains('toast')) {
child.remove();
}
});
}
async function handleSearch(query) {
if (!query || !query.trim()) {
showToast('Please enter something in the Search Bar.', 'error', 'warning');
return;
}
clearBackground();
let searchURL = generateSearchUrl(query);
historyStack.length = 0;
currentIndex = -1;
updateNavButtons();
showLoadingScreen(true);
iframe.style.display = 'block';
if (topBar) topBar.style.display = 'flex';
if (navBar && navbarToggle && navbarToggle.checked) navBar.style.display = 'block';
let finalUrlToLoad;
if (searchURL.startsWith(window.location.origin + '/assets/g/')) {
finalUrlToLoad = searchURL;
} else if (searchURL.startsWith('/assets/g/')) {
finalUrlToLoad = new URL(searchURL, window.location.origin).href;
} else {
try {
const tempUrl = new URL(searchURL);
if (tempUrl.origin === window.location.origin && tempUrl.pathname.startsWith('/assets/g/')) {
finalUrlToLoad = tempUrl.href;
} else {
finalUrlToLoad = await getUrl(searchURL);
}
} catch (e) {
finalUrlToLoad = await getUrl(searchURL);
}
}
if (searchInput2) searchInput2.value = decodeUrl(finalUrlToLoad);
iframe.src = finalUrlToLoad;
}
window.APP.handleSearch = handleSearch;
[searchInput1, searchInput2].forEach(input => {
if (input) {
input.addEventListener('keyup', e => {
if (e.key === 'Enter') {
const queryValue = input.value.trim();
if (queryValue) {
APP.handleSearch(queryValue);
if (input === searchInput1) searchInput1.value = '';
} else {
showToast('Please enter something in the Search Bar.', 'error', 'warning');
}
}
});
if (input === searchInput2) {
input.addEventListener('focus', updateDecodedSearchInput);
}
}
});
if (movies) movies.addEventListener('click', e => {
e.preventDefault();
APP.handleSearch('https://movies.usewaves.site/');
});
if (ai) ai.addEventListener('click', e => {
e.preventDefault();
APP.handleSearch('https://ai.usewaves.site/');
});
function showToast(message, type = 'success', iconType = 'check') {
const toast = document.createElement('div');
toast.className = `toast show ${type}`;
const icons = {
'check': 'fa-regular fa-check-circle',
'times-circle': 'fa-regular fa-times-circle',
'info': 'fa-regular fa-info-circle',
'warning': 'fa-regular fa-exclamation-triangle',
'heart': 'fa-solid fa-heart'
};
toast.innerHTML = `<i class="${icons[iconType] || icons.heart}" style="margin-right: 8px;"></i>${message}`;
const progressBar = document.createElement('div');
progressBar.className = 'progress-bar';
toast.appendChild(progressBar);
const closeBtn = document.createElement('button');
closeBtn.className = 'toast-close';
closeBtn.innerHTML = '<i class="fa-solid fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>';
closeBtn.onclick = () => {
toast.classList.add('hide');
setTimeout(() => toast.remove(), 500);
};
toast.appendChild(closeBtn);
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.add('hide');
setTimeout(() => toast.remove(), 500);
}, 3000);
}
if (navbarToggle && navBar && iframe) {
const savedNavbarState = localStorage.getItem('navbarToggled');
navbarToggle.checked = savedNavbarState !== 'false';
const updateNavbarDisplayBasedOnToggle = () => {
if (iframe.style.display === 'block') {
navBar.style.display = navbarToggle.checked ? 'block' : 'none';
} else {
navBar.style.display = 'none';
}
};
updateNavbarDisplayBasedOnToggle();
navbarToggle.addEventListener('change', () => {
localStorage.setItem('navbarToggled', navbarToggle.checked.toString());
updateNavbarDisplayBasedOnToggle();
});
window.APP.updateNavbarDisplay = updateNavbarDisplayBasedOnToggle;
}
window.addEventListener('load', () => {
let iframeInitiallyHidden = true;
if (iframe.src && iframe.src !== 'about:blank') {
iframeInitiallyHidden = false;
}
if (iframeInitiallyHidden) {
hideLoadingScreen();
if (topBar) topBar.style.display = 'flex';
iframe.style.display = 'none';
} else {
if (topBar) topBar.style.display = 'flex';
iframe.style.display = 'block';
}
if (window.APP.updateNavbarDisplay) window.APP.updateNavbarDisplay();
updateNavButtons();
updateDecodedSearchInput();
});
window.APP.decodeUrl = decodeUrl;
window.APP.normalizeUrl = normalizeUrl;
});
(async () => {
try {
const res = await fetch('/api/latest-commit');
const {
updates
} = await res.json();
const u = updates[0];
const commitUrl = `https://github.com/xojw/waves/commit/${u.sha}`;
document.getElementById('lastest-commit').innerHTML =
`<a href="${commitUrl}" class="hover-link" target="_blank" rel="noopener noreferrer"><i class="fa-solid fa-code-commit"></i> ${u.sha}</a>`;
} catch {
document.getElementById('lastest-commit').textContent =
'Failed to load lastest commit';
}
})();

View File

@ -1,45 +0,0 @@
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('appSearchInput');
const grid = document.querySelector('.apps-grid');
let appsData = [];
fetch('/assets/data/a.json')
.then(response => response.json())
.then(data => {
appsData = data.apps;
searchInput.placeholder = `Search through ${appsData.length} Apps…`;
displayApps(appsData);
searchInput.addEventListener('input', function() {
const query = searchInput.value.toLowerCase();
const filteredApps = appsData.filter(app => {
const title = app.title ? app.title.toLowerCase() : '';
const description = app.description ? app.description.toLowerCase() : '';
return title.includes(query) || description.includes(query);
});
displayApps(filteredApps);
});
})
.catch(err => console.error('Error loading apps data:', err));
function displayApps(apps) {
grid.innerHTML = '';
if (apps.length === 0) {
grid.innerHTML = '<p>Zero games were found matching your search :(</p>';
}
apps.forEach(app => {
const card = document.createElement('div');
card.classList.add('app-card');
card.innerHTML = `
<img src="${app.icon}" alt="${app.title} Icon" />
<h2>${app.title}</h2>
`;
card.addEventListener('click', function() {
window.handleSearch(app.link);
});
grid.appendChild(card);
});
}
});

View File

@ -1,43 +1,69 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('gameSearchInput'); const searchInput = document.getElementById('gameSearchInput');
const grid = document.querySelector('.games-grid'); const grid = document.querySelector('.games-grid');
let gamesData = []; const sentinel = document.createElement('div');
let allGames = [];
let filteredGames = [];
let renderedCount = 0;
const BATCH_SIZE = 20;
fetch('/assets/data/g.json') const observer = new IntersectionObserver(entries => {
.then(response => response.json()) if (entries[0].isIntersecting) loadNextBatch();
.then(data => { }, { rootMargin: '500px' });
gamesData = data;
searchInput.placeholder = `Search through ${gamesData.length} Games…`;
displayGames(gamesData);
searchInput.addEventListener('input', function() {
const query = searchInput.value.toLowerCase();
const filtered = gamesData.filter(game => {
const name = (game.name || '').toLowerCase();
return name.includes(query);
});
displayGames(filtered);
});
})
.catch(err => console.error('Error loading games data:', err));
function displayGames(games) { fetch('/assets/data/g.json')
grid.innerHTML = ''; .then(res => res.json())
if (games.length === 0) { .then(data => {
grid.innerHTML = '<p>Zero games were found matching your search :(</p>'; allGames = data;
return; filteredGames = data;
} searchInput.placeholder = `Search through ${allGames.length} Games…`;
games.forEach(game => { grid.parentNode.appendChild(sentinel);
const card = document.createElement('div'); observer.observe(sentinel);
card.classList.add('game-card'); resetAndRender();
card.innerHTML = ` })
<img src="/assets/g/${game.directory}/${game.image}" alt="${game.name} Icon" /> .catch(err => console.error(err));
<h2>${game.name}</h2>
`; searchInput.addEventListener('input', function() {
card.addEventListener('click', function() { const q = this.value.toLowerCase();
const url = `/assets/g/${game.directory}`; filteredGames = allGames.filter(game =>
window.handleSearch(url); (game.name || '').toLowerCase().includes(q)
}); );
grid.appendChild(card); resetAndRender();
}); });
function resetAndRender() {
grid.innerHTML = '';
renderedCount = 0;
if (filteredGames.length === 0) {
grid.innerHTML = '<p>Zero games were found matching your search :(</p>';
observer.unobserve(sentinel);
return;
} }
observer.observe(sentinel);
loadNextBatch();
}
function loadNextBatch() {
const nextCount = Math.min(renderedCount + BATCH_SIZE, filteredGames.length);
for (let i = renderedCount; i < nextCount; i++) {
const game = filteredGames[i];
const card = document.createElement('div');
card.classList.add('game-card');
card.innerHTML = `
<img src="/assets/g/${game.directory}/${game.image}" alt="${game.name} Icon" />
<h2>${game.name}</h2>
`;
card.addEventListener('click', () => {
const gameUrl = window.location.origin + `/assets/g/${game.directory}`;
APP.handleSearch(gameUrl);
});
grid.appendChild(card);
}
renderedCount = nextCount;
if (renderedCount >= filteredGames.length) {
observer.unobserve(sentinel);
} else {
grid.parentNode.appendChild(sentinel);
}
}
}); });

View File

@ -1,5 +1,6 @@
window.onload = function() { window.onload = function() {
const storedName = localStorage.getItem('userName'); const storedName = localStorage.getItem('userName');
const path = window.location.pathname;
if (!storedName) { if (!storedName) {
document.getElementById('overlay').style.display = 'block'; document.getElementById('overlay').style.display = 'block';
document.getElementById('namePrompt').style.display = 'block'; document.getElementById('namePrompt').style.display = 'block';
@ -11,7 +12,9 @@ window.onload = function() {
}); });
return; return;
} }
showToast(`Hey, ${storedName}! Welcome back to Waves!`, 'success', 'wave'); const welcomeMsg = getWelcomeMessage(storedName);
const iconType = getIconType(path);
showToast(welcomeMsg, 'success', iconType);
const greetingElement = document.getElementById('greeting'); const greetingElement = document.getElementById('greeting');
if (greetingElement) { if (greetingElement) {
updateGreeting(storedName); updateGreeting(storedName);
@ -31,15 +34,93 @@ function submitName() {
}, 300); }, 300);
} }
function updateGreeting(name) { function getWelcomeMessage(name) {
const { text, icon } = getGreeting(); const path = window.location.pathname;
const el = document.getElementById('greeting'); if (path === '/g') {
if (el) { return `Have fun playing games, ${name}!`;
el.innerHTML = `${icon} ${text}, ${name}!`; } else if (path === '/s') {
el.style.opacity = 1; return `Enjoy our collection of, ${name}!`;
} else {
return `Welcome back, ${name}!`;
} }
} }
function getIconType(path) {
if (path === '/g') return 'game';
if (path === '/s') return 'shortcuts';
return 'wave';
}
const generalGreetings = [
{ text: 'Welcome aboard', icon: '<i class="fa-regular fa-rocket"></i>', suffix: '!' },
{ text: 'Hii', icon: '<i class="fa-regular fa-hand-wave"></i>', suffix: '!!' },
{ text: 'Hope you enjoy Waves', icon: '<i class="fa-solid fa-heart"></i>', suffix: ' <3' },
{ text: 'Consider joining our Discord (discord.gg/ire)', icon: '<i class="fa-solid fa-smile"></i>', suffix: '!' },
{ text: 'How you doing today', icon: '<i class="fa-regular fa-question"></i>', suffix: '?' }
];
const timeGreetings = [];
timeGreetings.push(
{ text: 'Good morning, sunshine', icon: '<i class="fa-regular fa-sun"></i>', suffix: ' :D' },
{ text: 'Heres to a bright morning', icon: '<i class="fa-regular fa-cloud-sun"></i>', suffix: '.' },
{ text: 'Enjoy your morning', icon: '<i class="fa-regular fa-mug-hot"></i>', suffix: '!' },
{ text: 'Your day starts here', icon: '<i class="fa-regular fa-star"></i>', suffix: '!' }
);
timeGreetings.push(
{ text: 'Good afternoon', icon: '<i class="fa-regular fa-leaf"></i>', suffix: '!' },
{ text: 'Hope your day is going well', icon: '<i class="fa-regular fa-coffee"></i>', suffix: '.' },
{ text: 'Keep up the pace', icon: '<i class="fa-regular fa-book"></i>', suffix: '!' },
{ text: 'Stay on track today', icon: '<i class="fa-regular fa-sun"></i>', suffix: '.' }
);
timeGreetings.push(
{ text: 'Good evening', icon: '<i class="fa-regular fa-cloud-moon"></i>', suffix: '!' },
{ text: 'Time to unwind', icon: '<i class="fa-regular fa-fire"></i>', suffix: '.' },
{ text: 'Evenings here—relax', icon: '<i class="fa-regular fa-star"></i>', suffix: '.' },
{ text: 'Breathe and recharge', icon: '<i class="fa-regular fa-moon"></i>', suffix: '…' }
);
timeGreetings.push(
{ text: 'Good night', icon: '<i class="fa-regular fa-bed"></i>', suffix: '!' },
{ text: 'Rest well', icon: '<i class="fa-regular fa-blanket"></i>', suffix: '.' },
{ text: 'Sweet dreams', icon: '<i class="fa-regular fa-star-and-crescent"></i>', suffix: '!' },
{ text: 'See you tomorrow', icon: '<i class="fa-regular fa-moon"></i>', suffix: '!' }
);
function getGreeting() {
const now = new Date();
const hour = now.getHours();
let pool = [];
if (hour >= 5 && hour < 12) {
pool = timeGreetings.slice(0, 4);
} else if (hour < 17) {
pool = timeGreetings.slice(4, 8);
} else if (hour < 21) {
pool = timeGreetings.slice(8, 12);
} else {
pool = timeGreetings.slice(12, 16);
}
if (Math.random() < 0.5) {
pool = generalGreetings;
}
const choice = pool[Math.floor(Math.random() * pool.length)];
return { text: choice.text, icon: choice.icon, suffix: choice.suffix };
}
function updateGreeting(name) {
const { text, icon, suffix } = getGreeting();
const el = document.getElementById('greeting');
if (!el) return;
if (text === 'Hope you enjoy Waves') {
el.innerHTML = `${icon} ${text}, ${name}${suffix}`;
} else {
el.innerHTML = `${icon} ${text}, ${name}${suffix}`;
}
el.style.opacity = 1;
}
function showToast(message, type = 'success', iconType = 'wave') { function showToast(message, type = 'success', iconType = 'wave') {
const toast = document.createElement('div'); const toast = document.createElement('div');
toast.className = `toast show ${type}`; toast.className = `toast show ${type}`;
@ -48,9 +129,11 @@ function showToast(message, type = 'success', iconType = 'wave') {
error: '<i class="fas fa-times-circle" style="margin-right: 8px;"></i>', error: '<i class="fas fa-times-circle" style="margin-right: 8px;"></i>',
info: '<i class="fas fa-info-circle" style="margin-right: 8px;"></i>', info: '<i class="fas fa-info-circle" style="margin-right: 8px;"></i>',
warning: '<i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>', warning: '<i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>',
wave: '<i class="fa-regular fa-hand-wave" style="margin-right: 8px;"></i>' wave: '<i class="fa-regular fa-hand-wave" style="margin-right: 8px;"></i>',
game: '<i class="fa-regular fa-gamepad" style="margin-right: 8px;"></i>',
apps: '<i class="fa-regular fa-th" style="margin-right: 8px;"></i>'
}; };
toast.innerHTML = `${icons[iconType] || icons.wave}${message} `; toast.innerHTML = `${icons[iconType] || icons.wave}${message}`;
const progressBar = document.createElement('div'); const progressBar = document.createElement('div');
progressBar.className = 'progress-bar'; progressBar.className = 'progress-bar';
toast.appendChild(progressBar); toast.appendChild(progressBar);
@ -67,64 +150,4 @@ function showToast(message, type = 'success', iconType = 'wave') {
toast.classList.add('hide'); toast.classList.add('hide');
setTimeout(() => toast.remove(), 500); setTimeout(() => toast.remove(), 500);
}, 3000); }, 3000);
}
function getGreeting() {
const now = new Date();
const hour = now.getHours();
const day = now.getDay();
const options = [];
if (hour >= 5 && hour < 12) {
options.push(
{ text: 'Good morning, sunshine', icon: '<i class="fa-regular fa-sun"></i>' },
{ text: 'Heres to a bright morning', icon: '<i class="fa-regular fa-cloud-sun"></i>' },
{ text: 'Morning vibes only', icon: '<i class="fa-regular fa-mug-hot"></i>' },
{ text: 'Your day starts here', icon: '<i class="fa-regular fa-star"></i>' }
);
} else if (hour < 17) {
options.push(
{ text: 'Good afternoon', icon: '<i class="fa-regular fa-leaf"></i>' },
{ text: 'Hope your day is going well', icon: '<i class="fa-regular fa-coffee"></i>' },
{ text: 'Keep up the pace', icon: '<i class="fa-regular fa-book"></i>' },
{ text: 'Stay on track today', icon: '<i class="fa-regular fa-sun"></i>' }
);
} else if (hour < 21) {
options.push(
{ text: 'Good evening', icon: '<i class="fa-regular fa-cloud-moon"></i>' },
{ text: 'Time to unwind', icon: '<i class="fa-regular fa-fire"></i>' },
{ text: 'Evenings here—relax', icon: '<i class="fa-regular fa-star"></i>' },
{ text: 'Breathe and recharge', icon: '<i class="fa-regular fa-moon"></i>' }
);
} else {
options.push(
{ text: 'Good night', icon: '<i class="fa-regular fa-bed"></i>' },
{ text: 'Rest well', icon: '<i class="fa-regular fa-blanket"></i>' },
{ text: 'Sweet dreams', icon: '<i class="fa-regular fa-star-and-crescent"></i>' },
{ text: 'See you tomorrow', icon: '<i class="fa-regular fa-moon"></i>' }
);
}
if (day === 4) {
options.push(
{ text: 'Thursday mode: engaged', icon: '<i class="fa-regular fa-party-popper"></i>' },
{ text: 'Almost Friday', icon: '<i class="fa-regular fa-music"></i>' },
{ text: 'Keep going', icon: '<i class="fa-regular fa-thumbs-up"></i>' }
);
}
if (day === 0 || day === 6) {
options.push(
{ text: 'Happy weekend', icon: '<i class="fa-regular fa-umbrella-beach"></i>' },
{ text: 'Enjoy some downtime', icon: '<i class="fa-regular fa-cocktail"></i>' }
);
} else {
options.push(
{ text: 'Youve got this', icon: '<i class="fa-regular fa-hand-holding-heart"></i>' },
{ text: 'One step at a time', icon: '<i class="fa-regular fa-walking"></i>' },
{ text: 'Summer is coming', icon: '<i class="fa-regular fa-umbrella-beach"></i>' }
);
}
return options[Math.floor(Math.random() * options.length)];
} }

View File

@ -1,21 +0,0 @@
document.addEventListener('DOMContentLoaded', function () {
NProgress.configure({ showSpinner: false });
NProgress.start();
});
window.addEventListener('load', function () {
NProgress.done();
});
const titleElement = document.querySelector('.search-title');
if (titleElement) {
const text = titleElement.textContent;
titleElement.innerHTML = '';
text.split('').forEach((letter, index) => {
const span = document.createElement('span');
span.textContent = letter;
span.style.animationDelay = `${index * 0.2}s`;
titleElement.appendChild(span);
});
}

View File

@ -1,183 +0,0 @@
const style = document.createElement('style');
style.textContent = `
@keyframes slideLeft {0% { transform: translateX(0); } 50% { transform: translateX(-5px); } 100% { transform: translateX(0); }}
@keyframes slideRight {0% { transform: translateX(0); } 50% { transform: translateX(5px); } 100% { transform: translateX(0); }}
.button-animate-back { animation: slideLeft 0.3s ease-in-out; }
.button-animate-forward { animation: slideRight 0.3s ease-in-out; }
`;
document.head.appendChild(style);
const historyStack = [];
let currentIndex = -1;
const elements = {
refreshIcon: document.getElementById('refreshIcon'),
fullscreenIcon: document.getElementById('fullscreenIcon'),
backIcon: document.getElementById('backIcon'),
forwardIcon: document.getElementById('forwardIcon'),
searchInput2: document.getElementById('searchInputt'),
iframe: document.getElementById('cool-iframe')
};
const originalTitle = document.title;
let loadingFallbackTimeout;
elements.refreshIcon.addEventListener('click', handleRefresh);
elements.fullscreenIcon.addEventListener('click', handleFullscreen);
elements.backIcon.addEventListener('click', handleBack);
elements.forwardIcon.addEventListener('click', handleForward);
function showLoadingScreen() {
if (typeof NProgress !== 'undefined') {
NProgress.start();
document.title = 'Loading... <3';
setTimeout(() => {
if (typeof NProgress !== 'undefined') NProgress.done();
}, 10000);
}
}
function hideLoadingScreen() {
if (typeof NProgress !== 'undefined') NProgress.done();
document.title = originalTitle;
}
function handleRefresh() {
elements.refreshIcon.classList.add('spin');
const iframe = elements.iframe;
const currentUrl = iframe.contentWindow.location.href;
if (normalizeUrl(currentUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
addToHistory(currentUrl);
}
iframe.contentWindow.location.reload(true);
setTimeout(() => elements.refreshIcon.classList.remove('spin'), 300);
}
function handleFullscreen() {
const iframe = elements.iframe;
if (iframe && iframe.tagName === 'IFRAME') iframe.requestFullscreen();
}
function handleBack() {
toggleButtonAnimation(elements.backIcon, 'button-animate-back');
if (currentIndex > 0) {
currentIndex--;
updateIframeSrc();
}
}
function handleForward() {
toggleButtonAnimation(elements.forwardIcon, 'button-animate-forward');
if (currentIndex < historyStack.length - 1) {
currentIndex++;
updateIframeSrc();
}
}
function toggleButtonAnimation(button, animationClass) {
button.classList.add(animationClass);
setTimeout(() => button.classList.remove(animationClass), 200);
}
function normalizeUrl(urlStr) {
try {
const url = new URL(urlStr);
url.searchParams.delete('ia');
return url.toString();
} catch (e) {
return urlStr;
}
}
function addToHistory(url) {
const normalized = normalizeUrl(url);
if (currentIndex >= 0 && normalizeUrl(historyStack[currentIndex]) === normalized) return;
if (currentIndex < historyStack.length - 1) historyStack.splice(currentIndex + 1);
historyStack.push(url);
currentIndex++;
updateNavButtons();
updateDecodedSearchInput();
}
function updateIframeSrc() {
showLoadingScreen();
elements.iframe.src = historyStack[currentIndex];
updateNavButtons();
updateDecodedSearchInput();
}
function updateNavButtons() {
const isAtStart = currentIndex <= 0;
const isAtEnd = currentIndex >= historyStack.length - 1;
elements.backIcon.disabled = isAtStart;
elements.forwardIcon.disabled = isAtEnd;
elements.backIcon.classList.toggle('disabled', isAtStart);
elements.forwardIcon.classList.toggle('disabled', isAtEnd);
}
function updateDecodedSearchInput() {
if (elements.searchInput2) {
const url = historyStack[currentIndex] || elements.iframe.src;
elements.searchInput2.value = decodeUrl(url);
}
}
function decodeUrl(url) {
try {
return decodeURIComponent(url);
} catch (e) {
return url;
}
}
window.addToHistory = addToHistory;
window.updateDecodedSearchInput = updateDecodedSearchInput;
window.normalizeUrl = normalizeUrl;
function detectIframeNavigation() {
try {
const iframeWindow = elements.iframe.contentWindow;
const pushState = iframeWindow.history.pushState;
const replaceState = iframeWindow.history.replaceState;
iframeWindow.history.pushState = function() {
pushState.apply(this, arguments);
handleIframeNavigation(iframeWindow.location.href);
};
iframeWindow.history.replaceState = function() {
replaceState.apply(this, arguments);
handleIframeNavigation(iframeWindow.location.href);
};
iframeWindow.addEventListener('popstate', () => handleIframeNavigation(iframeWindow.location.href));
iframeWindow.addEventListener('hashchange', () => handleIframeNavigation(iframeWindow.location.href));
} catch (error) {}
}
function handleIframeNavigation(rawUrl) {
let urlStr = rawUrl;
try {
urlStr = decodeUrl(rawUrl);
} catch {}
try {
const u = new URL(urlStr);
if (u.hostname.endsWith('duckduckgo.com')) {
if (typeof NProgress !== 'undefined') NProgress.done();
return;
}
} catch (e) {}
if (normalizeUrl(urlStr) !== normalizeUrl(historyStack[currentIndex] || '')) {
showLoadingScreen();
addToHistory(urlStr);
} else {
hideLoadingScreen();
}
}
elements.iframe.addEventListener('load', () => {
try {
detectIframeNavigation();
if (historyStack.length === 0) {
addToHistory(elements.iframe.contentWindow.location.href);
} else {
handleIframeNavigation(elements.iframe.contentWindow.location.href);
}
} catch (error) {}
hideLoadingScreen();
});

View File

@ -0,0 +1 @@
!function(n,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():n.NProgress=e()}(this,function(){function n(n,e,t){return e>n?e:n>t?t:n}function e(n){return 100*(-1+n)}function t(n,t,r){var i;return i="translate3d"===c.positionUsing?{transform:"translate3d("+e(n)+"%,0,0)"}:"translate"===c.positionUsing?{transform:"translate("+e(n)+"%,0)"}:{"margin-left":e(n)+"%"},i.transition="all "+t+"ms "+r,i}function r(n,e){var t="string"==typeof n?n:o(n);return t.indexOf(" "+e+" ")>=0}function i(n,e){var t=o(n),i=t+e;r(t,e)||(n.className=i.substring(1))}function s(n,e){var t,i=o(n);r(n,e)&&(t=i.replace(" "+e+" "," "),n.className=t.substring(1,t.length-1))}function o(n){return(" "+(n.className||"")+" ").replace(/\s+/gi," ")}function a(n){n&&n.parentNode&&n.parentNode.removeChild(n)}var u={};u.version="0.2.0";var c=u.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};u.configure=function(n){var e,t;for(e in n)t=n[e],void 0!==t&&n.hasOwnProperty(e)&&(c[e]=t);return this},u.status=null,u.set=function(e){var r=u.isStarted();e=n(e,c.minimum,1),u.status=1===e?null:e;var i=u.render(!r),s=i.querySelector(c.barSelector),o=c.speed,a=c.easing;return i.offsetWidth,l(function(n){""===c.positionUsing&&(c.positionUsing=u.getPositioningCSS()),f(s,t(e,o,a)),1===e?(f(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout(function(){f(i,{transition:"all "+o+"ms linear",opacity:0}),setTimeout(function(){u.remove(),n()},o)},o)):setTimeout(n,o)}),this},u.isStarted=function(){return"number"==typeof u.status},u.start=function(){u.status||u.set(0);var n=function(){setTimeout(function(){u.status&&(u.trickle(),n())},c.trickleSpeed)};return c.trickle&&n(),this},u.done=function(n){return n||u.status?u.inc(.3+.5*Math.random()).set(1):this},u.inc=function(e){var t=u.status;return t?("number"!=typeof e&&(e=(1-t)*n(Math.random()*t,.1,.95)),t=n(t+e,0,.994),u.set(t)):u.start()},u.trickle=function(){return u.inc(Math.random()*c.trickleRate)},function(){var n=0,e=0;u.promise=function(t){return t&&"resolved"!==t.state()?(0===e&&u.start(),n++,e++,t.always(function(){e--,0===e?(n=0,u.done()):u.set((n-e)/n)}),this):this}}(),u.render=function(n){if(u.isRendered())return document.getElementById("nprogress");i(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=c.template;var r,s=t.querySelector(c.barSelector),o=n?"-100":e(u.status||0),l=document.querySelector(c.parent);return f(s,{transition:"all 0 linear",transform:"translate3d("+o+"%,0,0)"}),c.showSpinner||(r=t.querySelector(c.spinnerSelector),r&&a(r)),l!=document.body&&i(l,"nprogress-custom-parent"),l.appendChild(t),t},u.remove=function(){s(document.documentElement,"nprogress-busy"),s(document.querySelector(c.parent),"nprogress-custom-parent");var n=document.getElementById("nprogress");n&&a(n)},u.isRendered=function(){return!!document.getElementById("nprogress")},u.getPositioningCSS=function(){var n=document.body.style,e="WebkitTransform"in n?"Webkit":"MozTransform"in n?"Moz":"msTransform"in n?"ms":"OTransform"in n?"O":"";return e+"Perspective"in n?"translate3d":e+"Transform"in n?"translate":"margin"};var l=function(){function n(){var t=e.shift();t&&t(n)}var e=[];return function(t){e.push(t),1==e.length&&n()}}(),f=function(){function n(n){return n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(n,e){return e.toUpperCase()})}function e(n){var e=document.body.style;if(n in e)return n;for(var t,r=i.length,s=n.charAt(0).toUpperCase()+n.slice(1);r--;)if(t=i[r]+s,t in e)return t;return n}function t(t){return t=n(t),s[t]||(s[t]=e(t))}function r(n,e,r){e=t(e),n.style[e]=r}var i=["Webkit","O","Moz","ms"],s={};return function(n,e){var t,i,s=arguments;if(2==s.length)for(t in e)i=e[t],void 0!==i&&e.hasOwnProperty(t)&&r(n,t,i);else r(n,s[1],s[2])}}();return u});

View File

@ -23,7 +23,7 @@
})); }));
} }
if (data.type === "latency" && typeof data.latency === "number") { if (data.type === "latency" && typeof data.latency === "number") {
pingDisplay.innerHTML = '<i class="fa-regular fa-wifi"></i> Ping: ' + data.latency + ' ms'; pingDisplay.innerHTML = '<i class="fa-solid fa-wifi"></i> Ping: ' + '~' + data.latency + 'ms';
} }
} catch (err) { } catch (err) {
console.error("Error parsing message:", err); console.error("Error parsing message:", err);

View File

@ -1,97 +1,80 @@
document.addEventListener('DOMContentLoaded', function() { ;(function(){
const defaultWispUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/w/`; const origLog = console.log.bind(console);
let currentWispUrl = localStorage.getItem('customWispUrl') || defaultWispUrl; document.addEventListener("DOMContentLoaded", () => {
const wispUrl = currentWispUrl; origLog(
const connection = new BareMux.BareMuxConnection("/baremux/worker.js"); "%c\n" +
" ᶻ 𝗓 𐰁 .ᐟ\n" +
" |\\ _,,,---,,_\n" +
" /, `.-'`' -. ;-;;,_\n" +
" |,4- ) )-,_..;\\ ( `'-'\n" +
" '---''(_/--' `-`\\_)\n discord.gg/dJvdkPRheV",
"color: hotpink; font-size: 16px; display: block; white-space: pre; text-align: center; padding-left: 28%;"
);
});
async function registerSW() { const labelStyle = "background: white; color: black; font-weight: bold; padding: 2px 4px; border-radius: 2px";
try { const messageStyle = "background: black; color: white; padding: 2px 4px; border-radius: 2px";
if (!navigator.serviceWorker) { ["log","info","warn","error","debug"].forEach(method => {
console.log("%c[⚠️]%c Service Workers are not supported by this browser.", "color: orange; font-weight: bold;", "color: black;"); const orig = console[method].bind(console);
return; console[method] = (...args) => {
} const text = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
orig(`%cWaves:%c ${text}`, labelStyle, messageStyle);
};
});
await ensureWebSocketConnection(wispUrl); document.addEventListener("DOMContentLoaded", function(){
const defaultWispUrl = `${window.location.protocol==="https:"?"wss":"ws"}://${window.location.host}/w/`;
let currentWispUrl = localStorage.getItem("customWispUrl") || defaultWispUrl;
const wispUrl = currentWispUrl;
const connection = new BareMux.BareMuxConnection("/baremux/worker.js");
console.log("%c[⚙️]%c Registering Service Worker...", "color: #007bff; font-weight: bold;", "color: #007bff;"); registerSW();
await navigator.serviceWorker.register("/wah/sw.js", {
scope: '/wah/a/'
});
console.log("%c[✅]%c Service Worker registered successfully.", "color: green; font-weight: bold;", "color: green;");
const savedTransport = localStorage.getItem('transport') || "epoxy"; async function registerSW(){
switchTransport(savedTransport); try {
updateTransportUI(savedTransport); if (!navigator.serviceWorker) return console.error("Service Workers are not supported by this browser.");
await ensureWebSocketConnection(wispUrl);
console.log("Registering Service Worker...");
await navigator.serviceWorker.register("/wah/sw.js", { scope: "/wah/a/" });
console.log("Service Worker registered successfully.");
const savedTransport = localStorage.getItem("transport") || "epoxy";
switchTransport(savedTransport);
updateTransportUI(savedTransport);
console.log(`Using ${capitalizeTransport(savedTransport)} transport.`);
} catch (e) {
console.error(`An error occurred during Service Worker registration or WebSocket connection: ${e.message||e}`);
}
}
console.log(`%c[🚀]%c Using ${savedTransport} transport.`, "color: #ffffff 255, 255); font-weight: bold;", "color: #ffffff;"); async function ensureWebSocketConnection(url){
return new Promise((resolve, reject) => {
console.log("Establishing WebSocket connection...");
const ws = new WebSocket(url);
ws.onopen = () => { console.log("WebSocket connection established."); resolve(ws); };
ws.onerror = e => { console.error(`Failed to establish WebSocket connection: ${e.message||e}`); reject(e); };
ws.onclose = ev => {
if (ev.code !== 1000) console.warn(`WebSocket connection closed. Reason: ${ev.reason||"No reason provided"}`);
else console.warn("WebSocket connection closed normally.");
};
});
}
} catch (error) { function switchTransport(t){
logError(error, 'An error occurred during Service Worker registration or WebSocket connection'); const m = { epoxy: "/epoxy/index.mjs", libcurl: "/libcurl/index.mjs" }[t];
} if (m) connection.setTransport(m, [{ wisp: wispUrl }]);
} }
async function ensureWebSocketConnection(url) { function updateTransportUI(t){
return new Promise((resolve, reject) => { document.querySelector(".transport-selected").textContent = capitalizeTransport(t);
console.log("%c[🌐]%c Establishing WebSocket connection...", "color: #007bff; font-weight: bold;", "color: #007bff;"); }
const ws = new WebSocket(url);
ws.onopen = () => { function capitalizeTransport(t){
console.log("%c[✅]%c WebSocket connection established.", "color: green; font-weight: bold;", "color: green;"); return t.charAt(0).toUpperCase() + t.slice(1).toLowerCase();
resolve(ws); }
};
ws.onerror = (error) => { document.addEventListener("wispUrlChanged", function(e){
logError(error, 'Failed to establish WebSocket connection'); currentWispUrl = e.detail;
reject(error); switchTransport(localStorage.getItem("transport") || "epoxy");
}; });
});
ws.onclose = (event) => { })();
if (event.code !== 1000) {
console.warn(`%c[⚠️]%c WebSocket connection closed. Reason: ${event.reason || "No reason provided"}`, "color: orange; font-weight: bold;", "color: orange;");
} else {
console.warn("%c[⚠️]%c WebSocket connection closed normally.", "color: orange; font-weight: bold;", "color: orange;");
}
};
});
}
function logError(error, message) {
console.error(`%c[❌]%c ${message}: ${error.message || error}`, "color: red; font-weight: bold;", "color: red;");
}
function switchTransport(transport) {
const transportMap = {
"epoxy": "/epoxy/index.mjs",
"libcurl": "/libcurl/index.mjs"
};
const transportFile = transportMap[transport];
if (transportFile) {
connection.setTransport(transportFile, [{
wisp: wispUrl
}]);
}
}
async function changeTransport(newTransport) {
try {
localStorage.setItem('transport', newTransport);
switchTransport(newTransport);
updateTransportUI(newTransport);
} catch (error) {
logError(error, 'An error occurred while storing transport preference');
}
}
function updateTransportUI(transport) {
const transportSelected = document.querySelector(".transport-selected");
transportSelected.textContent = transport.charAt(0).toUpperCase() + transport.slice(1);
}
document.addEventListener('wispUrlChanged', function(e) {
currentWispUrl = e.detail;
switchTransport(localStorage.getItem('transport') || "epoxy");
});
registerSW();
});

45
public/assets/js/s.js Normal file
View File

@ -0,0 +1,45 @@
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('shortcutSearchInput');
const grid = document.querySelector('.shortcuts-grid');
let shortcutsData = [];
fetch('/assets/data/s.json')
.then(response => response.json())
.then(data => {
shortcutsData = data.shortcuts;
searchInput.placeholder = `Search through ${shortcutsData.length} Shortcuts...`;
displayShortcuts(shortcutsData);
searchInput.addEventListener('input', function() {
const query = searchInput.value.toLowerCase();
const filteredShortcuts = shortcutsData.filter(shortcut => {
const title = shortcut.title ? shortcut.title.toLowerCase() : '';
const description = shortcut.description ? shortcut.description.toLowerCase() : '';
return title.includes(query) || description.includes(query);
});
displayShortcuts(filteredShortcuts);
});
})
.catch(err => console.error('Error loading shortcuts data:', err));
function displayShortcuts(shortcuts) {
grid.innerHTML = '';
if (shortcuts.length === 0) {
grid.innerHTML = '<p>Zero shortcuts were found matching your search :(</p>';
}
shortcuts.forEach(shortcut => {
const card = document.createElement('div');
card.classList.add('shortcut-card');
card.innerHTML = `
<img src="${shortcut.icon}" alt="${shortcut.title} Icon" />
<h2>${shortcut.title}</h2>
`;
card.addEventListener('click', function() {
APP.handleSearch(shortcut.link);
});
grid.appendChild(card);
});
}
});

View File

@ -1,253 +1,350 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const settingsMenu = document.getElementById('settings-menu'); const settingsMenu = document.getElementById('settings-menu');
settingsMenu.innerHTML = ` settingsMenu.innerHTML = `
<h2>Settings</h2> <h2>Settings</h2>
<div class="settings-tabs"> <div class="settings-tabs">
<button class="tab-button active" id="proxy-tab"><i class="fa-regular fa-server"></i> Proxy</button> <button class="tab-button active" id="proxy-tab">
<button class="tab-button" id="cloak-tab"><i class="fa-regular fa-user-secret"></i> Cloak</button> <i class="fa-regular fa-server"></i> Proxy
<button class="tab-button" id="appearance-tab"><i class="fa-regular fa-palette"></i> Appearance</button> </button>
<button class="tab-button" id="info-tab"><i class="fa-regular fa-info"></i> Info</button> <button class="tab-button" id="cloak-tab">
</div> <i class="fa-regular fa-user-secret"></i> Cloak
<div id="proxy-content" class="tab-content"> </button>
<label for="transport-selector">Transport</label> <button class="tab-button" id="appearance-tab">
<p>Transport is how the proxy will send information.</p> <i class="fa-regular fa-palette"></i> Appearance
<div class="transport-selector"> </button>
<div class="transport-selected">Epoxy</div> <button class="tab-button" id="info-tab">
<div class="transport-options"> <i class="fa-regular fa-info"></i> Info
<div>Epoxy</div> </button>
<div>Libcurl</div> </div>
<div id="proxy-content" class="tab-content">
<label for="transport-selector">Transport</label>
<p>Transport is how the proxy will send information.</p>
<div class="transport-selector">
<div class="transport-selected">Epoxy</div>
<div class="transport-options">
<div>Epoxy</div>
<div>Libcurl</div>
</div>
</div>
<label for="wisp-server">Wisp Server</label>
<p>Enter a different Wisp Server to connect to.</p>
<p>Recommended to keep this as default.</p>
<input type="text" id="wisp-server" placeholder="Wisp Server URL Here..." autocomplete="off">
<button id="save-wisp-url">Save</button>
</div>
<div id="cloak-content" class="tab-content">
<label for="aboutblank-toggle">Auto About:Blank</label>
<p>Turn this on to go into about:blank every time the page loads (Recommended).</p>
<input type="checkbox" id="aboutblank-toggle">
</div>
<div id="appearance-content" class="tab-content">
<label for="navbar-toggle">Navigation Bar</label>
<p>Keep this on for the navigation bar when searching (Recommended).</p>
<input type="checkbox" id="navbar-toggle">
</div>
<div id="info-content" class="tab-content">
<label>Version 2.8.7</label>
<label
onmouseover="this.querySelector('span').style.color='lime'"
onmouseout="this.querySelector('span').style.color='green'">
Server Status:
<span style="color: green; transition: color 0.3s ease; font-size: 0.95em;">Running</span>
</label>
<label
onmouseover="this.querySelector('span').style.color='lime'"
onmouseout="this.querySelector('span').style.color='green'">
Server Speed:
<span id="server-speed" style="color: green; transition: color 0.3s ease; font-size: 0.95em;">Checking...</span>
</label>
<label
onmouseover="this.querySelector('span').style.color='#dadada'"
onmouseout="this.querySelector('span').style.color='#949494'">
Server Uptime:
<span id="server-uptime" style="color: #949494; transition: color 0.3s ease; font-size: 0.95em;">Calculating...</span>
</label>
<label
onmouseover="this.querySelector('span').style.color='#dadada'"
onmouseout="this.querySelector('span').style.color='#949494'">
Server Specs:
<span id="server-specs" style="color: #949494; transition: color 0.3s ease; font-size: 0.95em;">Loading...</span>
</label>
<p>Having any problems? Join our Discord Server below or open an issue on GitHub for support.</p>
<div style="display: flex; gap: 10px; justify-content: left; align-items: left; margin-top: 10px; margin-bottom: -20px;">
<label>
<a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">
<i class="fab fa-discord" style="font-size: 20px;"></i>
</a>
</label>
<label>
<a href="https://github.com/xojw/waves" target="_blank" class="hover-link">
<i class="fab fa-github" style="font-size: 20px;"></i>
</a>
</label>
</div> </div>
</div> </div>
<label for="wisp-server">Wisp Server</label>
<p>Enter a different Wisp Server to connect to.</p> <button id="close-settings">
<p>Recommended to keep this as default.</p> <i class="fa-regular fa-times"></i>
<input type="text" id="wisp-server" placeholder="Wisp Server URL Here..." autocomplete="off"> </button>
<button id="save-wisp-url">Save</button>
</div>
<div id="cloak-content" class="tab-content">
<label for="aboutblank-toggle">About:Blank</label>
<p>Turn this on to go into about:blank every time the page loads (Recommended).</p>
<input type="checkbox" id="aboutblank-toggle">
</div>
<div id="appearance-content" class="tab-content">
<label for="navbar-toggle">Navigation Bar</label>
<p>Keep this on for the navigation bar when searching (Recommended).</p>
<input type="checkbox" id="navbar-toggle">
</div>
<div id="info-content" class="tab-content">
<label>Version 2.3.5</label>
<label onmouseover="this.querySelector('span').style.color='lime'" onmouseout="this.querySelector('span').style.color='green'">
Server Status: <span style="color: green; transition: color 0.3s ease;">Running</span>
</label>
<p>If you want to see Waves status please visit <a href="https://status.usewaves.site" target="_blank" class="hover-link">https://status.usewaves.site</a>.</p>
<div style="display: flex; gap: 10px; justify-content: left; align-items: left; margin-top: 10px; margin-bottom: -20px;">
<label><a href="https://discord.gg/wves" target="_blank" class="hover-link"><i class="fab fa-discord" style="font-size: 20px;"></i></a></label>
<label><a href="https://github.com/xojw/waves" target="_blank" class="hover-link"><i class="fab fa-github" style="font-size: 20px;"></i></a></label>
</div>
</div>
<button id="close-settings"><i class="fa-regular fa-times"></i></button>
`; `;
const settingsIcon = document.getElementById('settings-icon');
const closeSettingsButton = document.getElementById('close-settings');
const saveButton = document.getElementById('save-wisp-url');
const transportSelector = document.querySelector('.transport-selector');
const transportSelected = transportSelector.querySelector('.transport-selected');
const transportOptions = transportSelector.querySelector('.transport-options');
const navbarToggle = document.getElementById('navbar-toggle');
const defaultWispUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/w/`;
let currentWispUrl = localStorage.getItem('customWispUrl') || defaultWispUrl;
const wispInput = document.querySelector("#wisp-server");
wispInput.value = currentWispUrl;
function isValidUrl(url) { const settingsIcon = document.getElementById('settings-icon');
try { const closeSettingsBtn = document.getElementById('close-settings');
const parsedUrl = new URL(url); const saveWispBtn = document.getElementById('save-wisp-url');
return (parsedUrl.protocol === "wss:" || parsedUrl.protocol === "ws:") && url.endsWith('/'); const transportSelector = document.querySelector('.transport-selector');
} catch (_) { const transportSelected = transportSelector.querySelector('.transport-selected');
return false; const transportOptions = transportSelector.querySelector('.transport-options');
} const navbarToggle = document.getElementById('navbar-toggle');
} const defaultWispUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/w/`;
let currentWispUrl = localStorage.getItem('customWispUrl') || defaultWispUrl;
const wispInput = document.querySelector("#wisp-server");
wispInput.value = currentWispUrl;
let isToggling = false;
function updateWispServerUrl(url) { navbarToggle.checked = localStorage.getItem('navbarToggled') !== 'false';
if (isValidUrl(url)) {
currentWispUrl = url;
localStorage.setItem('customWispUrl', url);
document.dispatchEvent(new CustomEvent('wispUrlChanged', {
detail: currentWispUrl
}));
wispInput.value = currentWispUrl;
showToast('success', `WISP URL successfully updated to: ${currentWispUrl}`);
location.reload();
} else {
console.log("%c[❌]%c Invalid WISP URL. Please enter a valid one.", "color: red; font-weight: bold;", "color: inherit;");
currentWispUrl = defaultWispUrl;
localStorage.setItem('customWispUrl', defaultWispUrl);
wispInput.value = defaultWispUrl;
showToast('error', "Invalid URL. Reverting back to default...");
location.reload();
}
}
saveButton.addEventListener('click', () => {
const customUrl = wispInput.value.trim();
updateWispServerUrl(customUrl);
});
settingsIcon.addEventListener('click', (event) => {
event.preventDefault();
toggleSettingsMenu();
});
closeSettingsButton.addEventListener('click', () => {
toggleSettingsMenu();
});
function toggleSettingsMenu() { function isValidUrl(url) {
const icon = document.querySelector('#settings-icon i.settings-icon'); try {
if (settingsMenu.classList.contains('open')) { const p = new URL(url);
settingsMenu.classList.add('close'); return (p.protocol === "wss:" || p.protocol === "ws:") && url.endsWith('/');
icon.classList.remove('fa-solid'); } catch (_) {
icon.classList.add('fa-regular'); return false;
setTimeout(() => { }
settingsMenu.classList.remove('open', 'close'); }
}, 300);
} else {
settingsMenu.classList.add('open');
icon.classList.remove('fa-regular');
icon.classList.add('fa-solid');
setTimeout(() => {
settingsMenu.classList.remove('close');
}, 300);
}
}
transportSelected.addEventListener('click', function(e) {
e.stopPropagation();
transportOptions.classList.toggle('transport-show');
this.classList.toggle('transport-arrow-active');
});
const optionDivs = transportOptions.getElementsByTagName('div');
for (let i = 0; i < optionDivs.length; i++) {
optionDivs[i].addEventListener('click', function(e) {
e.stopPropagation();
const selectedValue = this.innerHTML;
transportSelected.innerHTML = selectedValue;
localStorage.setItem('transport', selectedValue.toLowerCase());
transportOptions.classList.remove('transport-show');
transportSelected.classList.remove('transport-arrow-active');
const event = new Event('newTransport', {
detail: selectedValue.toLowerCase()
});
document.dispatchEvent(event);
showToast('success', `Transport successfully changed to ${selectedValue}`);
location.reload();
});
}
document.getElementById('proxy-content').classList.add('active');
function switchTab(tabId, contentId, otherTabId1, otherContentId1, otherTabId2, otherContentId2, otherTabId3, otherContentId3) { function runScriptIfChecked() {
document.getElementById(otherContentId1).classList.remove('active'); let inFrame;
document.getElementById(otherContentId2).classList.remove('active'); try {
document.getElementById(otherContentId3).classList.remove('active'); inFrame = window !== top;
document.getElementById(otherTabId1).classList.remove('active'); } catch (e) {
document.getElementById(otherTabId2).classList.remove('active'); inFrame = true;
document.getElementById(otherTabId3).classList.remove('active'); }
document.getElementById(contentId).classList.add('active'); const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
document.getElementById(tabId).classList.add('active'); if (!aboutBlankChecked || inFrame) {
} return;
document.getElementById('proxy-tab').addEventListener('click', function() { }
switchTab('proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content'); const defaultTitle = "Google.";
}); const defaultIcon = "https://www.google.com/favicon.ico";
document.getElementById('cloak-tab').addEventListener('click', function() { const title = localStorage.getItem("siteTitle") || defaultTitle;
switchTab('cloak-tab', 'cloak-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content'); const icon = localStorage.getItem("faviconURL") || defaultIcon;
}); const iframeSrc = "/";
document.getElementById('appearance-tab').addEventListener('click', function() { const popup = window.open("", "_blank");
switchTab('appearance-tab', 'appearance-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content'); if (!popup || popup.closed) {
}); alert("Failed to load automask. Please allow popups and try again.");
document.getElementById('info-tab').addEventListener('click', function() { return;
switchTab('info-tab', 'info-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'cloak-tab', 'cloak-content'); }
}); popup.document.head.innerHTML = `
navbarToggle.addEventListener('change', function() {
if (this.checked) {
showToast('success', 'Navigation Bar is now enabled.');
} else {
showToast('error', 'Navigation Bar is now disabled.');
}
});
function runScriptIfChecked() {
let inFrame;
try {
inFrame = window !== top;
} catch (e) {
inFrame = true;
}
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
if (!aboutBlankChecked || inFrame) {
return;
}
const defaultTitle = "Google.";
const defaultIcon = "https://www.google.com/favicon.ico";
const title = localStorage.getItem("siteTitle") || defaultTitle;
const icon = localStorage.getItem("faviconURL") || defaultIcon;
const iframeSrc = "/";
const popup = window.open("", "_blank");
if (!popup || popup.closed) {
alert("Failed to load automask. Please allow popups and try again.");
return;
}
popup.document.head.innerHTML = `
<title>${title}</title> <title>${title}</title>
<link rel="icon" href="${icon}"> <link rel="icon" href="${icon}">
`; `;
popup.document.body.innerHTML = ` popup.document.body.innerHTML = `
<iframe style="height: 100%; width: 100%; border: none; position: fixed; top: 0; right: 0; left: 0; bottom: 0;" src="${iframeSrc}"></iframe> <iframe style="height: 100%; width: 100%; border: none; position: fixed; top: 0; right: 0; left: 0; bottom: 0;" src="${iframeSrc}"></iframe>
`; `;
window.location.replace("https://bisd.schoology.com/home"); window.location.replace("https://bisd.schoology.com/home");
} }
document.getElementById("aboutblank-toggle").addEventListener("change", function() {
localStorage.setItem("aboutBlankChecked", JSON.stringify(this.checked));
if (this.checked) {
showToast('success', 'About:Blank is now enabled.');
} else {
showToast('error', 'About:Blank is now disabled.');
}
runScriptIfChecked();
});
window.addEventListener("load", function() {
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
document.getElementById("aboutblank-toggle").checked = aboutBlankChecked;
runScriptIfChecked();
});
function showToast(type, message) { document.getElementById("aboutblank-toggle").addEventListener("change", function() {
const toast = document.createElement('div'); localStorage.setItem("aboutBlankChecked", JSON.stringify(this.checked));
toast.className = `toast ${type} show`; if (this.checked) {
const icons = { showToast('success', 'Auto About:Blank is now enabled.');
success: '<i class="fa-regular fa-check-circle" style="margin-right: 8px;"></i>', } else {
error: '<i class="fa-regular fa-times-circle" style="margin-right: 8px;"></i>', showToast('error', 'Auto About:Blank is now disabled.');
info: '<i class="fa-regular fa-info-circle" style="margin-right: 8px;"></i>', }
warning: '<i class="fa-regular fa-exclamation-triangle" style="margin-right: 8px;"></i>' runScriptIfChecked();
}; });
const icon = icons[type] || '';
toast.innerHTML = `${icon}${message}`; window.addEventListener("load", function() {
const progressBar = document.createElement('div'); const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
progressBar.className = 'progress-bar'; document.getElementById("aboutblank-toggle").checked = aboutBlankChecked;
toast.appendChild(progressBar); runScriptIfChecked();
const closeBtn = document.createElement('button'); });
closeBtn.className = 'toast-close';
closeBtn.innerHTML = '<i class="fa-regular fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>'; function updateWispServerUrl(url) {
closeBtn.addEventListener('click', () => { if (isValidUrl(url)) {
toast.classList.remove('show'); currentWispUrl = url;
toast.classList.add('hide'); localStorage.setItem('customWispUrl', url);
setTimeout(() => { document.dispatchEvent(new CustomEvent('wispUrlChanged', {
toast.remove(); detail: currentWispUrl
}, 500); }));
}); showToast('success', `Wisp Server URL changed to: ${currentWispUrl}`);
toast.appendChild(closeBtn); } else {
document.body.appendChild(toast); currentWispUrl = defaultWispUrl;
setTimeout(() => { localStorage.setItem('customWispUrl', defaultWispUrl);
toast.classList.remove('show'); document.dispatchEvent(new CustomEvent('wispUrlChanged', {
toast.classList.add('hide'); detail: currentWispUrl
setTimeout(() => { }));
toast.remove(); showToast('error', "Invalid URL. Reverting to default...");
}, 500); }
}, 3000); }
}
function updateServerInfo() {
const speedSpan = document.getElementById('server-speed');
const uptimeSpan = document.getElementById('server-uptime');
const specsSpan = document.getElementById('server-specs');
let uptimeInterval;
fetch('/api/info')
.then(response => {
if (!response.ok) throw new Error();
return response.json();
})
.then(data => {
if (data?.speed) {
const updateUptimeDisplay = () => {
const uptime = Date.now() - data.startTime;
const days = Math.floor(uptime / 86400000);
const hours = Math.floor((uptime % 86400000) / 3600000);
const minutes = Math.floor((uptime % 3600000) / 60000);
const seconds = Math.floor((uptime % 60000) / 1000);
uptimeSpan.textContent = `${days}d ${hours}h ${minutes}m ${seconds}s`;
};
updateUptimeDisplay();
clearInterval(uptimeInterval);
uptimeInterval = setInterval(updateUptimeDisplay, 1000);
speedSpan.textContent = `${data.speed} (${data.averageLatency}ms)`;
specsSpan.textContent = data.specs;
}
setTimeout(updateServerInfo, 10000);
})
.catch(() => {
speedSpan.textContent = 'Connection error';
setTimeout(updateServerInfo, 30000);
});
}
function initializeInfo() {
const infoTab = document.getElementById('info-tab');
const infoContent = document.getElementById('info-content');
const startMonitoring = () => {
updateServerInfo();
infoTab.removeEventListener('click', startMonitoring);
};
if (infoContent.classList.contains('active')) {
updateServerInfo();
} else {
infoTab.addEventListener('click', startMonitoring, {
once: true
});
}
}
function showToast(type, message) {
const toast = document.createElement('div');
toast.className = `toast ${type} show`;
const icons = {
success: '<i class="fa-regular fa-check-circle"></i>',
error: '<i class="fa-regular fa-times-circle"></i>',
info: '<i class="fa-regular fa-info-circle"></i>',
warning: '<i class="fa-regular fa-exclamation-triangle"></i>'
};
toast.innerHTML = `${icons[type]||''}${message}`;
const progressBar = document.createElement('div');
progressBar.className = 'progress-bar';
toast.appendChild(progressBar);
const closeBtn = document.createElement('button');
closeBtn.className = 'toast-close';
closeBtn.innerHTML = '<i class="fa-regular fa-xmark"></i>';
closeBtn.addEventListener('click', () => {
toast.classList.replace('show', 'hide');
setTimeout(() => toast.remove(), 500);
});
toast.appendChild(closeBtn);
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.replace('show', 'hide');
setTimeout(() => toast.remove(), 500);
}, 3000);
}
saveWispBtn.addEventListener('click', () => updateWispServerUrl(wispInput.value.trim()));
settingsIcon.addEventListener('click', e => {
e.preventDefault();
toggleSettingsMenu();
});
closeSettingsBtn.addEventListener('click', toggleSettingsMenu);
function toggleSettingsMenu() {
if (isToggling) return;
isToggling = true;
const icon = document.querySelector('#settings-icon i.settings-icon');
if (settingsMenu.classList.contains('open')) {
settingsMenu.classList.add('close');
icon.classList.replace('fa-solid', 'fa-regular');
setTimeout(() => {
settingsMenu.classList.remove('open', 'close');
isToggling = false;
}, 300);
} else {
settingsMenu.classList.add('open');
icon.classList.replace('fa-regular', 'fa-solid');
setTimeout(() => {
settingsMenu.classList.remove('close');
isToggling = false;
}, 300);
}
}
transportSelected.addEventListener('click', e => {
e.stopPropagation();
transportOptions.classList.toggle('transport-show');
transportSelected.classList.toggle('transport-arrow-active');
});
Array.from(transportOptions.getElementsByTagName('div')).forEach(option => {
option.addEventListener('click', function(e) {
e.stopPropagation();
const val = this.textContent;
transportSelected.textContent = val;
localStorage.setItem('transport', val.toLowerCase());
transportOptions.classList.remove('transport-show');
transportSelected.classList.remove('transport-arrow-active');
document.dispatchEvent(new CustomEvent('newTransport', {
detail: val.toLowerCase()
}));
showToast('success', `Transport changed to ${val}`);
});
});
document.getElementById('proxy-content').classList.add('active');
function switchTab(activeTab, activeContent, ...others) {
others.forEach(id => document.getElementById(id).classList.remove('active'));
document.getElementById(activeTab).classList.add('active');
document.getElementById(activeContent).classList.add('active');
}
document.getElementById('proxy-tab').addEventListener('click', () => switchTab('proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content'));
document.getElementById('cloak-tab').addEventListener('click', () => switchTab('cloak-tab', 'cloak-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content'));
document.getElementById('appearance-tab').addEventListener('click', () => switchTab('appearance-tab', 'appearance-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content'));
document.getElementById('info-tab').addEventListener('click', () => switchTab('info-tab', 'info-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'appearance-tab', 'appearance-content'));
document.querySelectorAll('.tab-button').forEach(btn => {
btn.addEventListener('click', function() {
const icon = this.querySelector('i');
if (!icon.classList.contains('fa-bounce')) {
icon.classList.add('fa-bounce');
setTimeout(() => icon.classList.remove('fa-bounce'), 750);
}
});
});
navbarToggle.addEventListener('change', function() {
localStorage.setItem('navbarToggled', this.checked.toString());
showToast(this.checked ? 'success' : 'error', `Navigation Bar ${this.checked ? 'enabled' : 'disabled'}`);
if (window.APP && typeof window.APP.updateNavbarDisplay === 'function') {
window.APP.updateNavbarDisplay();
}
});
initializeInfo();
}); });

View File

@ -1,109 +1,147 @@
(function () { (function(){
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function(){
function getSearchInputs() { const indicators = document.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4');
return [ const arrowIndicators = document.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2');
document.getElementById('searchInput'), indicators.forEach(el => {
document.getElementById('searchInputt'), if (!el.dataset.original) el.dataset.original = el.innerHTML;
document.getElementById('gameSearchInput'), });
document.getElementById('appSearchInput')
].filter(Boolean); function getSearchInputs(){
return [
document.getElementById('searchInput'),
document.getElementById('searchInputt'),
document.getElementById('gameSearchInput'),
document.getElementById('shortcutSearchInput')
].filter(Boolean);
}
function isVisible(el){
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
}
function focusFirstVisibleInput(){
const inputs = getSearchInputs();
for (let inp of inputs) {
if (isVisible(inp)) {
inp.focus();
return inp;
}
} }
if (inputs[0]) {
function isVisible(el) { inputs[0].focus();
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); return inputs[0];
} }
return null;
}
function focusFirstVisibleInput() { let arrowMode = false;
const inputs = getSearchInputs();
for (const input of inputs) { function updateIndicatorState(){
if (isVisible(input)) { const hasText = getSearchInputs().some(i => i.value.trim() !== '');
input.focus(); if (hasText === arrowMode) return;
return; arrowMode = hasText;
} arrowIndicators.forEach(ind => {
} ind.classList.remove('fadeIn');
if (inputs.length) { ind.classList.add('fadeOut');
inputs[0].focus(); setTimeout(() => {
} if (hasText) {
ind.innerHTML = '<i class="fa-solid fa-arrow-right"></i>';
ind.classList.add('arrow-mode');
} else {
ind.innerHTML = ind.dataset.original;
ind.classList.remove('arrow-mode');
}
ind.classList.remove('fadeOut');
ind.classList.add('fadeIn');
}, 100);
});
}
function triggerSubmit(input){
const query = input.value.trim();
if (!query) {
showToast('Please enter something in the Search Bar.','error','warning');
return;
} }
if (window.APP && typeof APP.handleSearch === 'function') {
APP.handleSearch(query);
if (input.id === 'searchInput') input.value = '';
}
}
document.addEventListener('keydown', function (e) { function handleIndicatorAction(){
if (e.key === 'Escape') { const inputs = getSearchInputs().filter(isVisible);
const inputs = getSearchInputs(); const active = document.activeElement;
const active = document.activeElement; if (inputs.includes(active) && active.value.trim()) {
if (inputs.includes(active)) { triggerSubmit(active);
active.blur(); return;
e.preventDefault(); }
return; const withText = inputs.find(i => i.value.trim());
} if (withText) {
} triggerSubmit(withText);
return;
}
focusFirstVisibleInput();
}
if (e.ctrlKey && e.key.toLowerCase() === 's') { updateIndicatorState();
e.preventDefault(); getSearchInputs().forEach(i => i.addEventListener('input', updateIndicatorState));
focusFirstVisibleInput();
}
});
document.querySelectorAll( document.addEventListener('keydown', e => {
'.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4' if (e.key === 'Escape') {
).forEach(function (el) { const act = document.activeElement;
el.addEventListener('click', function (e) { if (getSearchInputs().includes(act)) {
e.preventDefault(); act.blur();
focusFirstVisibleInput(); e.preventDefault();
}); }
}); }
if (e.ctrlKey && e.key.toLowerCase() === 's') {
e.preventDefault();
focusFirstVisibleInput();
}
});
document.body.addEventListener('click', function (e) { document.body.addEventListener('click', e => {
if ( const ind = e.target.closest('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4');
e.target.classList.contains('shortcut-indicator') || if (!ind) return;
e.target.classList.contains('shortcut-indicator-2') || e.preventDefault();
e.target.classList.contains('shortcut-indicator-3') || if (ind.classList.contains('arrow-mode')) {
e.target.classList.contains('shortcut-indicator-4') handleIndicatorAction();
) { } else {
e.preventDefault(); focusFirstVisibleInput();
focusFirstVisibleInput(); }
} });
});
const coolIframe = document.getElementById('cool-iframe'); const coolIframe = document.getElementById('cool-iframe');
if (coolIframe) { if (coolIframe){
coolIframe.addEventListener('load', function () { coolIframe.addEventListener('load', () => {
const doc = coolIframe.contentWindow.document; const doc = coolIframe.contentWindow.document;
doc.addEventListener('keydown', innerE => {
doc.addEventListener('keydown', function (e) { if (innerE.key === 'Escape') {
if (e.key === 'Escape') { if (doc.activeElement.blur) doc.activeElement.blur();
if (doc.activeElement && doc.activeElement.blur) { innerE.preventDefault();
doc.activeElement.blur(); }
e.preventDefault(); if (innerE.ctrlKey && innerE.key.toLowerCase() === 's') {
return; innerE.preventDefault();
} document.dispatchEvent(new KeyboardEvent('keydown', { key: 's', ctrlKey: true, bubbles: true }));
} }
if (e.ctrlKey && e.key.toLowerCase() === 's') { });
e.preventDefault(); doc.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4')
document.dispatchEvent(new KeyboardEvent('keydown', { .forEach(el => {
key: 's', el.addEventListener('click', ev => {
ctrlKey: true ev.preventDefault();
})); window.parent.postMessage({ type: 'iframe-focus-search' }, '*');
}
}); });
});
doc.querySelectorAll(
'.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4'
).forEach(function (iframeEl) {
iframeEl.addEventListener('click', function (e) {
e.preventDefault();
window.parent.postMessage({
type: 'iframe-focus-search'
}, '*');
});
});
});
}
window.addEventListener('message', function (event) {
const msg = event.data;
if (msg.type === 'iframe-focus-search') {
focusFirstVisibleInput();
}
}); });
}); }
window.addEventListener('message', msgEvt => {
if (msgEvt.data?.type === 'iframe-focus-search'){
const inp = focusFirstVisibleInput();
if (inp && inp.value.trim()) triggerSubmit(inp);
}
});
});
})(); })();

59
public/assets/js/wv.js Normal file
View File

@ -0,0 +1,59 @@
(async()=>{
const storageKey = 'wv-verified';
const last = localStorage.getItem(storageKey);
if(last && Date.now() - last < 2592000000) return;
const style = document.createElement('style');
style.textContent = `
:root{--bg:#000;--card:rgba(0,0,0,0.85);--accent:#fff;--radius:12px;--trans:.3s}
#wv-overlay{position:fixed;inset:0!important;pointer-events:auto;user-select:none;background:var(--bg);display:flex;align-items:center;justify-content:center;font-family:system-ui;z-index:2147483647!important;opacity:1;transition:opacity .4s}
#wv-card{background:var(--card);backdrop-filter:blur(12px);border-radius:var(--radius);padding:32px;width:320px;text-align:center;color:var(--accent)}
#wv-progress{width:100%;height:6px;background:#333;border-radius:var(--radius);overflow:hidden;margin:16px 0}
#wv-bar{width:0;height:100%;background:var(--accent);transition:width var(--trans)}
#wv-info{font-size:.95rem;opacity:.8}
#wv-complete{display:none;}
#wv-complete.show{display:block;}
`;
document.head.appendChild(style);
const overlay = document.createElement('div'); overlay.id='wv-overlay';
overlay.innerHTML = `
<div id="wv-card">
<h2><i class="fas fa-shield-alt"></i> Verifying Browser</h2>
<div id="wv-progress"><div id="wv-bar"></div></div>
<div id="wv-info"></div>
</div>
<div id="wv-complete"><h2><i class="fas fa-check-circle"></i> Success!</h2><p>You May Continue.</p></div>
`;
document.body.appendChild(overlay);
const info = document.getElementById('wv-info');
const bar = document.getElementById('wv-bar');
const tests = [
{msg:'Automation',pass:!navigator.webdriver},
{msg:'Headless',pass:!/headless|phantomjs|puppeteer|selenium/i.test(navigator.userAgent)},
{msg:'Languages',pass:Array.isArray(navigator.languages) && navigator.languages.length>0},
{msg:'Plugins',pass:navigator.plugins.length>0},
{msg:'WebGL',pass:(()=>{try{const c=document.createElement('canvas');const g=c.getContext('webgl')||c.getContext('experimental-webgl');return!!g;}catch{return false;}})()}
];
let failures = [];
for(let i=0;i<tests.length;i++){
const t=tests[i];
info.textContent = `${t.msg}...`;
if(!t.pass) failures.push(t.msg);
bar.style.width = `${((i+1)/tests.length)*100}%`;
await new Promise(r=>setTimeout(r,200));
}
if(failures.length===0){
localStorage.setItem(storageKey, Date.now());
document.getElementById('wv-card').style.display='none';
const done = document.getElementById('wv-complete'); done.classList.add('show');
setTimeout(()=>overlay.style.opacity='0',500);
setTimeout(()=>overlay.remove(),800);
} else {
info.innerHTML = `Failed:<br>${failures.map(f=>`${f}`).join('<br>')}`;
bar.style.background='red';
}
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,10 @@ cat <<EOF | sudo tee /etc/caddy/Caddyfile > /dev/null
Referrer-Policy "no-referrer" Referrer-Policy "no-referrer"
} }
} }
:80 {
reverse_proxy http://localhost:3000
}
EOF EOF
separator separator
h h