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:
- **Version 2.3.7** Supported ✅
- **Version 2.3.5** Supported ✅
- **Version 2.3.1** Supported ✅
- **Version 2.3.0** Supported ✅
@ -17,4 +18,4 @@ The following versions of this project that are currently supported and unsuppor
## 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 os from "os";
import net from "net";
import fs from "fs";
import path from "path";
import { spawnSync } from "child_process";
import express from "express";
import { createServer } from "http";
import path from "path";
import compression from "compression";
import WebSocket from "ws";
import { LRUCache } from "lru-cache";
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
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);
cluster.schedulingPolicy = cluster.SCHED_RR;
function logInfo(message) {
console.info(`[INFO] ${message}`);
}
function logError(error) {
const msg = error instanceof Error ? error.message : error;
console.error(`[ERR] ${msg}`);
function logInfo(msg) {
console.info(`[~] ${msg}`);
}
process.on("uncaughtException", (err) => logError(`Unhandled Exception: ${err}`));
process.on("unhandledRejection", (reason) => logError(`Unhandled Promise Rejection: ${reason}`));
function logSuccess(msg) {
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) {
const numCPUs = os.cpus().length;
logInfo(`Master started. Forking ${numCPUs} workers.`);
for (let i = 0; i < numCPUs; i++) {
const cpus = os.cpus().length;
const workers = Math.max(1, cpus - 1);
logInfo(`Master: forking ${workers} workers`);
for (let i = 0; i < workers; i++) {
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();
});
let currentWorker = 0;
const server = net.createServer({ pauseOnConnect: true }, (connection) => {
const workerIds = Object.keys(cluster.workers);
if (workerIds.length === 0) {
connection.destroy();
return;
}
const worker = cluster.workers[workerIds[currentWorker % workerIds.length]];
currentWorker++;
if (worker) worker.send("sticky-session:connection", connection);
let current = 0;
const server = net.createServer({ pauseOnConnect: true }, conn => {
const workersArr = Object.values(cluster.workers);
if (!workersArr.length) return conn.destroy();
const worker = workersArr[current++ % workersArr.length];
worker.send("sticky-session:connection", conn);
});
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 {
process.env.UV_THREADPOOL_SIZE = os.cpus().length * 2;
const __dirname = process.cwd();
const publicPath = path.join(__dirname, "public");
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) => {
const key = req.originalUrl;
if (cache.has(key)) {
const val = cache.get(key);
if (val) {
res.setHeader("X-Cache", "HIT");
return res.send(cache.get(key));
return res.send(val);
}
res.sendResponse = res.send;
res.send = (body) => {
res.sendResponse = res.send.bind(res);
res.send = body => {
cache.set(key, body);
res.setHeader("X-Cache", "MISS");
res.sendResponse(body);
@ -76,7 +128,7 @@ if (cluster.isPrimary) {
next();
});
const staticOpts = { maxAge: "1s" };
const staticOpts = { maxAge: "7d", immutable: true };
app.use("/baremux/", express.static(baremuxPath, staticOpts));
app.use("/epoxy/", express.static(epoxyPath, staticOpts));
app.use("/libcurl/", express.static(libcurlPath, staticOpts));
@ -84,62 +136,129 @@ if (cluster.isPrimary) {
app.use("/wah/", express.static(uvPath, staticOpts));
app.use(express.json());
app.get("/", (req, res) => res.sendFile(path.join(publicPath, "$.html")));
app.get("/g", (req, res) => res.sendFile(path.join(publicPath, "!.html")));
app.get("/a", (req, res) => res.sendFile(path.join(publicPath, "!!.html")));
app.get("/ai", (req, res) => res.sendFile(path.join(publicPath, "!!!.html")));
app.get("/resent", (req, res) => res.sendFile(path.join(publicPath, "resent", "index.html")));
app.use((req, res) => res.status(404).sendFile(path.join(publicPath, "404.html")));
const sendHtml = file => (_req, res) => res.sendFile(path.join(publicPath, file));
app.get("/", sendHtml("$.html"));
app.get("/g", sendHtml("!.html"));
app.get("/s", sendHtml("!!.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);
server.keepAliveTimeout = 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) => {
const remoteAddress = req.socket.remoteAddress || "unknown";
let latencies = [];
const pingInterval = setInterval(() => {
const remote = req.socket.remoteAddress || "unknown";
let lat = [];
const interval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
const timestamp = Date.now();
ws.send(JSON.stringify({ type: "ping", timestamp }));
ws.send(JSON.stringify({ type: "ping", timestamp: Date.now() }));
}
}, 1000);
ws.on("message", (message) => {
ws.on("message", msg => {
try {
const data = JSON.parse(message);
const data = JSON.parse(msg);
if (data.type === "pong" && data.timestamp) {
const latency = Date.now() - data.timestamp;
latencies.push(latency);
if (latencies.length > 5) latencies.shift();
ws.send(JSON.stringify({ type: "latency", latency }));
const d = Date.now() - data.timestamp;
lat.push(d);
if (lat.length > 5) lat.shift();
latencySamples.push(d);
if (latencySamples.length > 100) latencySamples.shift();
ws.send(JSON.stringify({ type: "latency", latency: d }));
}
} catch (e) {
logError(`Ping error: ${e}`);
}
});
ws.on("close", () => {
clearInterval(pingInterval);
const avgLatency = latencies.length ? latencies.reduce((a, b) => a + b) / latencies.length : 0;
logInfo(`Conn from ${remoteAddress} closed. Avg: ${avgLatency.toFixed(2)}ms.`);
clearInterval(interval);
const avg = lat.length
? (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") {
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/")) {
wisp.routeRequest(req, socket, head);
wisp.routeRequest(req, sock, head);
} else {
socket.end();
sock.end();
}
});
server.on("error", (err) => logError(`Worker server error: ${err}`));
server.listen(0, () => logInfo(`Worker ${process.pid} ready.`));
process.on("message", (message, connection) => {
if (message === "sticky-session:connection") {
server.emit("connection", connection);
connection.resume();
server.on("error", err => logError(`Worker error: ${err}`));
server.listen(0, () => logSuccess(`Worker ${process.pid} ready`));
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",
"version": "2.3.5",
"description": "A sleek and minimalist Web Proxy.",
"type": "module",
"engines": {
"npm": ">=7.0.0",
"node": ">=16.0.0"
},
"scripts": {
"start": "node index.mjs",
"dev": "nodemon index.mjs",
"lint": "eslint ."
},
"author": {
"name": "sent",
"email": "sentttt@proton.me"
},
"dependencies": {
"@mercuryworkshop/bare-mux": "latest",
"@mercuryworkshop/epoxy-transport": "latest",
"@mercuryworkshop/libcurl-transport": "latest",
"@titaniumnetwork-dev/ultraviolet": "latest",
"axios": "^1.8.2",
"cache": "^3.0.0",
"compression": "latest",
"cors": "^2.8.5",
"express": "latest",
"express-rate-limit": "^7.5.0",
"fs": "^0.0.1-security",
"node": "^23.9.0",
"node-cache": "latest",
"node-fetch": "latest",
"wisp-server-node": "latest",
"ws": "latest"
},
"devDependencies": {
"eslint": "latest",
"glob": "latest",
"nodemon": "latest",
"prettier": "latest",
"rimraf": "latest"
}
"name": "waves",
"version": "2.8.7",
"description": "A sleek and minimalist Web Proxy.",
"type": "module",
"engines": {
"npm": ">=7.0.0",
"node": ">=16.0.0"
},
"scripts": {
"start": "node index.mjs",
"dev": "nodemon index.mjs",
"lint": "eslint ."
},
"author": {
"name": "sent",
"email": "sentttt@proton.me"
},
"dependencies": {
"@mercuryworkshop/bare-mux": "latest",
"@mercuryworkshop/epoxy-transport": "latest",
"@mercuryworkshop/libcurl-transport": "latest",
"@titaniumnetwork-dev/ultraviolet": "latest",
"axios": "latest",
"cache": "latest",
"compression": "latest",
"cors": "latest",
"express": "latest",
"express-rate-limit": "latest",
"lru-cache": "latest",
"wisp-server-node": "latest",
"ws": "latest"
},
"devDependencies": {
"eslint": "latest",
"glob": "latest",
"nodemon": "latest",
"prettier": "latest",
"rimraf": "latest"
}
}

View File

@ -1,100 +1,155 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves. - Apps"/>
<meta property="og:description" content="A sleek and minimalist web proxy."/>
<meta property="og:image" content="/assets/images/icons/favicon.ico"/>
<meta name="theme-color" content="#ffffff"/>
<meta name="msapplication-TileColor" content="#ffffff"/>
<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="stylesheet" href="/assets/css/settings.css">
<link rel="stylesheet" href="/assets/css/toast.css">
<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="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>
<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>
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script>
</head>
<body>
<script src="/baremux/index.js"></script>
<script src="/wah/uv.bundle.js" defer></script>
<script src="/wah/cute1.js" defer></script>
<script src="/assets/js/navbar.js" defer></script>
<script src="/assets/js/load.js" defer></script>
<script src="/assets/js/eruda.js" defer></script>
<script src="/assets/js/register.js" defer></script>
<script src="/assets/js/settings.js" defer></script>
<script src="/assets/js/greetings.js" defer></script>
<script src="/assets/js/shortcuts.js" defer></script>
<script src="/assets/js/$.js" defer></script>
<script src="/assets/js/a.js" 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>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves." />
<meta property="og:description" content="A sleek and minimalist web proxy." />
<meta property="og:image" content="/assets/images/icons/favicon.ico" />
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff" />
<title>Waves.</title>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
<link rel="stylesheet" href="/assets/css/$.css" />
<link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/s.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<noscript>
<link rel="stylesheet" href="/assets/css/settings.css" />
<link rel="stylesheet" href="/assets/css/toast.css" />
<link rel="stylesheet" href="/assets/css/nprogress.css" />
<link rel="stylesheet" href="/assets/css/s.css" />
</noscript>
<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'" />
<noscript>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
</noscript>
<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>
</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 class="home-navbar">
<img src="/assets/images/icons/favicon.ico" class="favicon">
<span id="waves">Waves</span>
<a href="/" id="home">Home</a>
<a href="/g" id="games">Games</a>
<a href="/a" id="apps">Apps</a>
<a href="#" id="movies">Movies</a>
<a href="#" id="ai">AI</a>
<a href="#" id="settings-icon">
<i class="settings-icon fa-regular fa-gear"></i>
</a>
</div>
<div class="home-navbar">
<img src="/assets/images/icons/favicon.ico" class="favicon" alt="favicon" />
<span id="waves">Waves.</span>
<a href="/" id="home">Home</a>
<a href="/g" id="games">Games</a>
<a href="/s" id="shortcuts" style="color: #ffffff;">Shortcuts</a>
<a href="#" id="movies">Movies</a>
<a href="#" id="ai">AI</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 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="/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 class="shortcuts-grid"></div>
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<div id="overlay" class="overlay"></div>
<div id="namePrompt" class="popup">
<div class="input-container">
<label for="userName">Please enter a name so we know what to call you:</label>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" autocomplete="off" />
</div>
<button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
</div>
<div class="content apps-page">
<h1>Apps</h1>
<div class="apps-search-bar">
<input type="text" id="appSearchInput" placeholder="Search apps..." autocomplete="off" />
<span class="shortcut-indicator-4">Ctrl + S</span>
</div>
<div class="apps-grid">
</div>
</div>
<div id="overlay" class="overlay"></div>
<div id="namePrompt" class="popup">
<div class="input-container">
<label for="userName">Please enter a name so we know what to call you:</label>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" oninput="checkInput()" autocomplete="off" />
</div>
<button id="doneButton" onclick="submitName()" disabled>
<i class="fas fa-check"></i> Done
</button>
</div>
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<iframe id="cool-iframe" class="iframe"></iframe>
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script>
</body>
</div>
<iframe id="cool-iframe" class="iframe"></iframe>
<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>

View File

@ -1,101 +1,155 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves. - Games"/>
<meta property="og:description" content="A sleek and minimalist web proxy."/>
<meta property="og:image" content="/assets/images/icons/favicon.ico"/>
<meta name="theme-color" content="#ffffff"/>
<meta name="msapplication-TileColor" content="#ffffff"/>
<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="stylesheet" href="/assets/css/settings.css">
<link rel="stylesheet" href="/assets/css/toast.css">
<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="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>
<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>
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script>
</head>
<body>
<script src="/baremux/index.js"></script>
<script src="/wah/uv.bundle.js" defer></script>
<script src="/wah/cute1.js" defer></script>
<script src="/assets/js/navbar.js" defer></script>
<script src="/assets/js/load.js" defer></script>
<script src="/assets/js/eruda.js" defer></script>
<script src="/assets/js/register.js" defer></script>
<script src="/assets/js/settings.js" defer></script>
<script src="/assets/js/greetings.js" defer></script>
<script src="/assets/js/shortcuts.js" defer></script>
<script src="/assets/js/$.js" defer></script>
<script src="/assets/js/g.js" 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>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves." />
<meta property="og:description" content="A sleek and minimalist web proxy." />
<meta property="og:image" content="/assets/images/icons/favicon.ico" />
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff" />
<title>Waves.</title>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
<link rel="stylesheet" href="/assets/css/$.css" />
<link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/g.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<noscript>
<link rel="stylesheet" href="/assets/css/settings.css" />
<link rel="stylesheet" href="/assets/css/toast.css" />
<link rel="stylesheet" href="/assets/css/nprogress.css" />
<link rel="stylesheet" href="/assets/css/g.css" />
</noscript>
<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'" />
<noscript>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
</noscript>
<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>
</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 class="home-navbar">
<img src="/assets/images/icons/favicon.ico" class="favicon">
<span id="waves">Waves</span>
<a href="/" id="home">Home</a>
<a href="/g" id="games">Games</a>
<a href="/a" id="apps">Apps</a>
<a href="#" id="movies">Movies</a>
<a href="#" id="ai">AI</a>
<a href="#" id="settings-icon">
<i class="settings-icon fa-regular fa-gear"></i>
</a>
</div>
<div class="home-navbar">
<img src="/assets/images/icons/favicon.ico" class="favicon" alt="favicon" />
<span id="waves">Waves.</span>
<a href="/" id="home">Home</a>
<a href="/g" id="games" style="color: #ffffff;">Games</a>
<a href="/s" id="apps">Shortcuts</a>
<a href="#" id="movies">Movies</a>
<a href="#" id="ai">AI</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 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="/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 class="games-grid"></div>
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<div id="overlay" class="overlay"></div>
<div id="namePrompt" class="popup">
<div class="input-container">
<label for="userName">Please enter a name so we know what to call you:</label>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" autocomplete="off" />
</div>
<button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
</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 class="games-grid">
</div>
</div>
<div id="overlay" class="overlay"></div>
<div id="namePrompt" class="popup">
<div class="input-container">
<label for="userName">Please enter a name so we know what to call you:</label>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" oninput="checkInput()" autocomplete="off" />
</div>
<button id="doneButton" onclick="submitName()" disabled>
<i class="fas fa-check"></i> Done
</button>
</div>
</div>
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<iframe id="cool-iframe" class="iframe"></iframe>
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script>
</div>
</body>
</div>
<iframe id="cool-iframe" class="iframe"></iframe>
<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>

View File

@ -1,99 +1,172 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="Waves."/>
<meta property="og:description" content="A sleek and minimalist web proxy."/>
<meta property="og:image" content="/assets/images/icons/favicon.ico"/>
<meta name="theme-color" content="#ffffff"/>
<meta name="msapplication-TileColor" content="#ffffff"/>
<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="stylesheet" href="/assets/css/settings.css">
<link rel="stylesheet" href="/assets/css/toast.css">
<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">
<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>
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script>
</head>
<body>
<script src="/baremux/index.js"></script>
<script src="/wah/uv.bundle.js" defer></script>
<script src="/wah/cute1.js" defer></script>
<script src="/assets/js/navbar.js" defer></script>
<script src="/assets/js/load.js" defer></script>
<script src="/assets/js/eruda.js" defer></script>
<script src="/assets/js/register.js" defer></script>
<script src="/assets/js/settings.js" defer></script>
<script src="/assets/js/ping.js" defer></script>
<script src="/assets/js/greetings.js" defer></script>
<script src="/assets/js/shortcuts.js" defer></script>
<script src="/assets/js/$.js" defer></script>
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-white transition-bg">
<div class="absolute inset-0 overflow-hidden">
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
</div>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Waves." />
<meta property="og:description" content="A sleek and minimalist web proxy." />
<meta property="og:image" content="/assets/images/icons/favicon.ico" />
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff" />
<title>Waves.</title>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
<link rel="stylesheet" href="/assets/css/$.css" />
<link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
<noscript>
<link rel="stylesheet" href="/assets/css/settings.css" />
<link rel="stylesheet" href="/assets/css/toast.css" />
<link rel="stylesheet" href="/assets/css/nprogress.css" />
</noscript>
<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'" />
<noscript>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
</noscript>
<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>
</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 class="home-navbar">
<img src="/assets/images/icons/favicon.ico" class="favicon">
<span id="waves">Waves</span>
<a href="/" id="home">Home</a>
<a href="/g" id="games">Games</a>
<a href="/a" id="apps">Apps</a>
<a href="#" id="movies">Movies</a>
<a href="#" id="ai">AI</a>
<a href="#" id="settings-icon">
<i id="settings-icon" class="settings-icon fa-regular fa-gear"></i>
</a>
</div>
<div class="home-navbar">
<img src="/assets/images/icons/favicon.ico" class="favicon" />
<span id="waves">Waves</span>
<a href="/" id="home" style="color: #ffffff;">Home</a>
<a href="/g" id="games">Games</a>
<a href="/s" id="apps">Shortcuts</a>
<a href="#" id="movies">Movies</a>
<a href="#" id="ai">AI</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 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="/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 id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<div id="overlay" class="overlay"></div>
<div id="namePrompt" class="popup">
<div class="input-container">
<label for="userName">Please enter a name so we know what to call you:</label>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" autocomplete="off" />
</div>
<button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
</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="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
<div id="overlay" class="overlay"></div>
<div id="namePrompt" class="popup">
<div class="input-container">
<label for="userName">Please enter a name so we know what to call you:</label>
<div class="input-wrapper">
<input type="text" id="userName" placeholder="Your name" autocomplete="off">
</div>
<button id="doneButton" onclick="submitName()" disabled>
<i class="fa-regular fa-check"></i> Done
</button>
</div>
</div>
<div id="pingDisplay">Ping: Connecting...</div>
<div id="greeting"></div>
<iframe id="cool-iframe" class="iframe"></iframe>
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script>
</body>
</div>
<div id="pingDisplay"><i class="fa-regular fa-wifi"></i> Ping: Connecting...</div>
<div id="greeting"></div>
<iframe id="cool-iframe" class="iframe"></iframe>
<div id="lastest-commit">Loading latest commit</div>
<div id="copyright">
<i class="fa-regular fa-copyright"></i> 2025
<a class="hover-link" href="https://discord.gg/ire" target="_blank" rel="noopener noreferrer"><span class="copyrightname">Waves Services</span></a>.
All Rights Reserved.
</div>
<div id="discord">
<a class="hover-link" href="https://discord.gg/ire" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-discord"></i> Discord
</a>
</div>
<div id="github">
<a class="hover-link" href="https://github.com/xojw/waves" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-github"></i> Github
</a>
</div>
<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>

View File

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

View File

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

View File

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

View File

@ -32,6 +32,10 @@
display: inline-block;
}
.toast i {
margin-right: 8px;
}
.toast.show {
animation: slideIn 0.3s forwards;
}
@ -51,6 +55,21 @@
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 {
0% {
right: -300px;
@ -80,18 +99,3 @@
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",
"title": "Crazy Games",

View File

@ -13,7 +13,6 @@
<script>
var gameLoaded = false;
window.addEventListener("beforeunload", function (e) {
if (adsVisible || !gameLoaded || !lockedOccured) return null;
var confirmationMessage = "Are you sure you want to leave? ";
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
@ -86,52 +85,10 @@
},
});
</script>
<!-- MIDROLL/INTERSTITIAL VIDEO API -->
<script src="js/cpmstar.js"></script>
</head>
<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="loader">
<img class="logo" src="logo.png" />
@ -222,55 +179,6 @@
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 () {
//console.log("onfocus");
resumeCounter();
@ -283,26 +191,16 @@
};
var timeSinceRefresh = 0;
var timeAdsVisible = 0;
var counter;
var adsVisible = false;
function startCounter() {
timeSinceRefresh++;
if (adsVisible) timeAdsVisible++;
counter = setTimeout(function () {
startCounter();
}, 1000);
}
function resumeCounter() {
adsVisible = true;
}
function pauseCounter() {
adsVisible = false;
}
</script>
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="firebase/firebase-app.js"></script>

View File

@ -1,293 +1,485 @@
document.addEventListener('DOMContentLoaded', () => {
const historyStack = []
let currentIndex = -1
const refreshIcon = document.getElementById('refreshIcon')
const fullscreenIcon = document.getElementById('fullscreenIcon')
const backIcon = document.getElementById('backIcon')
const forwardIcon = document.getElementById('forwardIcon')
const iframe = document.getElementById('cool-iframe')
const erudaLoadingScreen = document.getElementById('erudaLoadingScreen')
if (!refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon || !iframe) return
const originalTitle = document.title
let loadingHidden = false
function showLoadingScreen(withToast = true, showEruda = false) {
loadingHidden = false
NProgress.start()
document.title = 'Loading... <3'
if (withToast) {
showToast(
'Consider joining our <a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">Discord</a>&nbsp;<3',
'success',
'heart'
)
}
}
function hideLoadingScreen() {
if (loadingHidden) return
loadingHidden = true
NProgress.done()
document.title = originalTitle
}
refreshIcon.addEventListener('click', () => {
refreshIcon.classList.add('spin')
if (iframe.tagName === 'IFRAME') {
const currentUrl = iframe.contentWindow.location.href
if (normalizeUrl(currentUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
addToHistory(currentUrl)
}
iframe.contentWindow.location.reload(true)
}
setTimeout(() => refreshIcon.classList.remove('spin'), 300)
})
fullscreenIcon.addEventListener('click', () => {
if (iframe.requestFullscreen) iframe.requestFullscreen()
else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen()
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen()
else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen()
})
backIcon.addEventListener('click', () => {
if (currentIndex > 0) {
currentIndex--
iframe.src = historyStack[currentIndex]
showLoadingScreen(false, false)
updateNavButtons()
updateDecodedSearchInput()
}
})
forwardIcon.addEventListener('click', () => {
if (currentIndex < historyStack.length - 1) {
currentIndex++
iframe.src = historyStack[currentIndex]
showLoadingScreen(false, false)
updateNavButtons()
updateDecodedSearchInput()
}
})
function normalizeUrl(urlStr) {
try {
const url = new URL(urlStr)
url.searchParams.delete('ia')
return url.toString()
} catch {
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 updateNavButtons() {
backIcon.disabled = currentIndex <= 0
forwardIcon.disabled = currentIndex >= historyStack.length - 1
backIcon.classList.toggle('disabled', currentIndex <= 0)
forwardIcon.classList.toggle('disabled', currentIndex >= historyStack.length - 1)
}
function updateDecodedSearchInput() {
const searchInput2 = document.getElementById('searchInputt')
if (!searchInput2) return
let url = ''
if (currentIndex >= 0 && historyStack[currentIndex]) {
url = historyStack[currentIndex]
} else if (iframe.src) {
url = iframe.src
}
searchInput2.value = decodeUrl(url)
const lockIcon = document.getElementById('lockIcon')
if (lockIcon) {
lockIcon.className = decodeUrl(url).startsWith('https://') ?
'fa-regular fa-lock' :
'fa-regular fa-lock-open'
lockIcon.style.color = ''
}
}
iframe.addEventListener('load', () => {
try {
hideLoadingScreen()
} catch {
hideLoadingScreen()
} finally {
if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none'
}
})
iframe.addEventListener('error', () => {
hideLoadingScreen()
})
iframe.addEventListener('loadstart', () => {
const navBar = document.querySelector('.navbar')
const navbarToggle = document.getElementById('navbar-toggle')
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block'
showLoadingScreen(false, false)
})
const navBar = document.querySelector('.navbar')
const topBar = document.querySelector('.topbar')
const searchInput1 = document.getElementById('searchInput')
const searchInput2 = document.getElementById('searchInputt')
const movies = document.getElementById('movies')
const ai = document.getElementById('ai')
const navbarToggle = document.getElementById('navbar-toggle')
if (navbarToggle && navBar) {
const savedNavbarState = localStorage.getItem('navbarToggled')
navbarToggle.checked = savedNavbarState === null ? true : savedNavbarState === 'true'
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none'
navbarToggle.addEventListener('change', () => {
localStorage.setItem('navbarToggled', navbarToggle.checked)
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none'
})
}
iframe.style.display = 'none'
window.addEventListener('load', hideLoadingScreen)
;[searchInput1, searchInput2].forEach(input => {
if (input) {
input.addEventListener('keyup', e => {
if (e.key === 'Enter') {
const val = input.value.trim()
if (val) handleSearch(val)
else showToast('Please enter something in the Search Bar.', 'error', 'warning')
}
})
}
})
if (movies) movies.addEventListener('click', e => {
e.preventDefault()
handleSearch('https://movies.usewaves.site/')
})
if (ai) ai.addEventListener('click', e => {
e.preventDefault()
handleSearch('https://ai.usewaves.site/')
})
function clearBackground() {
const preserved = [
document.querySelector('.navbar'),
document.getElementById('cool-iframe'),
document.querySelector('.loading-screen'),
erudaLoadingScreen
]
Array.from(document.body.children).forEach(child => {
if (!preserved.includes(child)) child.remove()
})
}
async function handleSearch(query) {
if (!query || !query.trim()) {
showToast('Please enter something in the Search Bar.', 'error', 'warning')
return
}
clearBackground()
let searchURL
if (
query.startsWith('/assets/g/') ||
query.startsWith(window.location.origin + '/assets/g/')
) {
searchURL = query
} else {
searchURL = generateSearchUrl(query)
}
if (searchInput2) searchInput2.value = searchURL
historyStack.length = 0
currentIndex = -1
showLoadingScreen(true, false)
iframe.style.display = 'block'
if (topBar) topBar.style.display = 'none'
backIcon.disabled = forwardIcon.disabled = true
let finalUrl
try {
const u = new URL(searchURL, window.location.origin)
if (u.origin === window.location.origin && u.pathname.startsWith('/assets/g/')) {
finalUrl = u.href
} else {
finalUrl = await getUrl(searchURL)
}
} catch {
finalUrl = await getUrl(searchURL)
}
iframe.src = finalUrl
iframe.onload = () => {
hideLoadingScreen()
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block'
generateSubject()
updateDecodedSearchInput()
}
iframe.onerror = () => {
hideLoadingScreen()
}
}
window.handleSearch = handleSearch
function generateSearchUrl(query) {
try {
return new URL(query).toString()
} catch {
try {
const u = new URL(`https://${query}`)
if (u.hostname.includes('.')) return u.toString()
} catch {}
}
return `https://duckduckgo.com/?q=${encodeURIComponent(query)}&ia=web`
}
function showToast(message, type = 'success', iconType = 'check') {
const toast = document.createElement('div')
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>',
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>',
heart: '<i class="fa-regular fa-heart" style="margin-right: 8px;"></i>'
}
const icon = icons[iconType] || icons.heart
toast.innerHTML = `${icon}${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.addEventListener('click', () => {
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)
}
function preloadResources(url) {
if (!url) return
try {
const link = document.createElement('link')
link.rel = 'preload'
link.href = url
link.as = 'fetch'
link.crossOrigin = 'anonymous'
document.head.appendChild(link)
} catch {}
}
function getUrl(url) {
return Promise.resolve(__uv$config.prefix + __uv$config.encodeUrl(url))
}
function generateSubject() {
const subjects = ['math', 'science', 'history', 'art', 'programming', 'philosophy']
const random = subjects[Math.floor(Math.random() * subjects.length)]
history.replaceState({}, '', '/learning?subject=' + random)
}
function decodeUrl(enc) {
try {
const o = new URL(enc, window.location.origin)
const p = (__uv$config && __uv$config.prefix) || '/wa/a/'
if (o.pathname.startsWith(p)) {
const part = o.pathname.slice(p.length)
return (__uv$config.decodeUrl ? __uv$config.decodeUrl(part) : decodeURIComponent(part))
}
} catch {}
return enc
}
window.decodeUrl = decodeUrl
window.addToHistory = addToHistory
window.updateDecodedSearchInput = updateDecodedSearchInput
window.normalizeUrl = normalizeUrl
})
window.APP = {};
const iframe = document.getElementById('cool-iframe');
const erudaLoadingScreen = document.getElementById('erudaLoadingScreen');
const searchInput1 = document.getElementById('searchInput');
const movies = document.getElementById('movies');
const ai = document.getElementById('ai');
const topBar = document.querySelector('.topbar');
const refreshIcon = document.getElementById('refreshIcon');
const fullscreenIcon = document.getElementById('fullscreenIcon');
const backIcon = document.getElementById('backIcon');
const forwardIcon = document.getElementById('forwardIcon');
const searchInput2 = document.getElementById('searchInputt');
const lockIcon = document.getElementById('lockIcon');
const navbarToggle = document.getElementById('navbar-toggle');
const navBar = document.querySelector('.navbar');
const historyStack = [];
let currentIndex = -1;
const originalTitle = document.title;
let isLoading = false;
if (!iframe || !refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon) {
return;
}
const animationStyle = document.createElement('style');
animationStyle.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; }
.spin { animation: spinAnimation 0.3s linear; }
@keyframes spinAnimation { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
`;
document.head.appendChild(animationStyle);
function showLoadingScreen(withToast = true) {
if (isLoading) return;
isLoading = true;
if (typeof NProgress !== 'undefined') NProgress.start();
if (withToast) {
showToast(
'Consider joining our <a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">Discord</a>&nbsp;<3',
'success',
'heart'
);
}
}
function hideLoadingScreen() {
if (!isLoading) return;
if (typeof NProgress !== 'undefined') NProgress.done();
document.title = originalTitle;
isLoading = false;
if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none';
}
function normalizeUrl(urlStr) {
if (!urlStr || urlStr === 'about:blank') return urlStr;
try {
const url = new URL(urlStr);
url.searchParams.delete('ia');
return url.toString();
} catch {
return urlStr;
}
}
function decodeUrl(encodedUrl) {
if (!encodedUrl) return '';
try {
const prefix = (typeof __uv$config !== 'undefined' && __uv$config.prefix) ? __uv$config.prefix : '/wa/a/';
const decodeFunction = (typeof __uv$config !== 'undefined' && __uv$config.decodeUrl) ? __uv$config.decodeUrl : decodeURIComponent;
const urlObject = new URL(encodedUrl, window.location.origin);
if (urlObject.pathname.startsWith(prefix)) {
const encodedPart = urlObject.pathname.slice(prefix.length);
return decodeFunction(encodedPart) + urlObject.search + urlObject.hash;
}
} catch {}
try {
return decodeURIComponent(encodedUrl);
} catch {
return encodedUrl;
}
}
function updateNavButtons() {
if (!backIcon || !forwardIcon) return;
const canGoBack = currentIndex > 0;
const canGoForward = currentIndex < historyStack.length - 1;
backIcon.disabled = !canGoBack;
forwardIcon.disabled = !canGoForward;
backIcon.classList.toggle('disabled', !canGoBack);
forwardIcon.classList.toggle('disabled', !canGoForward);
}
function updateDecodedSearchInput() {
if (!searchInput2) return;
let currentUrl = '';
if (currentIndex >= 0 && historyStack[currentIndex]) {
currentUrl = historyStack[currentIndex];
} else if (iframe.src && iframe.src !== 'about:blank') {
currentUrl = iframe.src;
}
const decoded = decodeUrl(currentUrl);
searchInput2.value = decoded;
if (lockIcon) {
const isSecure = decoded.startsWith('https://');
lockIcon.className = isSecure ? 'fa-regular fa-lock' : 'fa-regular fa-lock-open';
}
}
function addToHistory(url, isReplacingCurrent = false) {
if (!url || url === 'about:blank') return;
const normalizedNewUrl = normalizeUrl(url);
const currentHistoryEntry = historyStack[currentIndex];
const normalizedCurrentHistoryEntry = currentIndex >= 0 ? normalizeUrl(currentHistoryEntry) : null;
if (isReplacingCurrent && currentIndex >= 0) {
if (normalizedCurrentHistoryEntry !== normalizedNewUrl || currentHistoryEntry !== url) {
historyStack[currentIndex] = url;
} else {
return;
}
} else {
if (normalizedCurrentHistoryEntry === normalizedNewUrl && currentHistoryEntry === url) {
return;
}
if (currentIndex < historyStack.length - 1) {
historyStack.splice(currentIndex + 1);
}
historyStack.push(url);
currentIndex++;
}
updateNavButtons();
updateDecodedSearchInput();
}
function setupIframeNavigationListeners() {
try {
const iframeWindow = iframe.contentWindow;
if (!iframeWindow || iframeWindow === window || iframeWindow.location.href === 'about:blank') return;
const handleNav = (isReplace = false) => {
setTimeout(() => {
try {
const newUrlInIframe = iframeWindow.location.href;
if (newUrlInIframe === 'about:blank' && historyStack[currentIndex] === 'about:blank') return;
addToHistory(newUrlInIframe, isReplace);
} catch (e) {}
}, 0);
};
if (!iframeWindow.history.pushState.__isPatched) {
const originalPushState = iframeWindow.history.pushState;
iframeWindow.history.pushState = function(...args) {
originalPushState.apply(this, args);
handleNav(false);
};
iframeWindow.history.pushState.__isPatched = true;
}
if (!iframeWindow.history.replaceState.__isPatched) {
const originalReplaceState = iframeWindow.history.replaceState;
iframeWindow.history.replaceState = function(...args) {
originalReplaceState.apply(this, args);
handleNav(true);
};
iframeWindow.history.replaceState.__isPatched = true;
}
iframeWindow.removeEventListener('popstate', iframeWindow.__popstateHandler);
iframeWindow.__popstateHandler = () => handleNav(false);
iframeWindow.addEventListener('popstate', iframeWindow.__popstateHandler);
iframeWindow.removeEventListener('hashchange', iframeWindow.__hashchangeHandler);
iframeWindow.__hashchangeHandler = () => handleNav(false);
iframeWindow.addEventListener('hashchange', iframeWindow.__hashchangeHandler);
} catch (error) {}
}
iframe.addEventListener('loadstart', () => {
showLoadingScreen(false);
if (navbarToggle && navbarToggle.checked && navBar) {
navBar.style.display = 'block';
}
});
iframe.addEventListener('load', () => {
hideLoadingScreen();
try {
const newUrl = iframe.contentWindow ? iframe.contentWindow.location.href : iframe.src;
if (newUrl && newUrl !== 'about:blank') {
if (currentIndex === -1 || normalizeUrl(historyStack[currentIndex]) !== normalizeUrl(newUrl) || historyStack[currentIndex] !== newUrl) {
addToHistory(newUrl);
} else if (historyStack[currentIndex] !== newUrl) {
addToHistory(newUrl, true);
}
} else if (newUrl === 'about:blank' && historyStack.length > 0 && historyStack[currentIndex] !== 'about:blank') {
if (currentIndex > 0) {
const previousUrl = historyStack[currentIndex - 1];
currentIndex--;
iframe.src = previousUrl;
return;
}
}
setupIframeNavigationListeners();
if (navbarToggle && navbarToggle.checked && navBar) {
navBar.style.display = 'block';
}
} catch (error) {} finally {
updateNavButtons();
updateDecodedSearchInput();
}
});
iframe.addEventListener('error', () => {
hideLoadingScreen();
showToast('Error: Could not load page content.', 'error', 'times-circle');
updateNavButtons();
updateDecodedSearchInput();
});
function toggleButtonAnimation(button, animationClass) {
if (button) {
button.classList.add(animationClass);
setTimeout(() => button.classList.remove(animationClass), 200);
}
}
backIcon.addEventListener('click', () => {
toggleButtonAnimation(backIcon, 'button-animate-back');
if (currentIndex > 0) {
currentIndex--;
showLoadingScreen(false);
iframe.src = historyStack[currentIndex];
updateNavButtons();
updateDecodedSearchInput();
}
});
forwardIcon.addEventListener('click', () => {
toggleButtonAnimation(forwardIcon, 'button-animate-forward');
if (currentIndex < historyStack.length - 1) {
currentIndex++;
showLoadingScreen(false);
iframe.src = historyStack[currentIndex];
updateNavButtons();
updateDecodedSearchInput();
}
});
refreshIcon.addEventListener('click', () => {
if (refreshIcon) refreshIcon.classList.add('spin');
if (iframe.contentWindow) {
showLoadingScreen(false);
const currentIframeUrl = iframe.contentWindow.location.href;
if (normalizeUrl(currentIframeUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
addToHistory(currentIframeUrl);
}
iframe.contentWindow.location.reload(true);
}
if (refreshIcon) setTimeout(() => refreshIcon.classList.remove('spin'), 300);
});
fullscreenIcon.addEventListener('click', () => {
if (iframe.requestFullscreen) iframe.requestFullscreen();
else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen();
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen();
});
function generateSearchUrl(query) {
query = query.trim();
if (!query) return `https://duckduckgo.com/?q=&ia=web`;
if (/^[a-zA-Z]+:\/\//.test(query)) {
try {
new URL(query);
return query;
} catch (e) {}
}
if (/^(localhost|(\d{1,3}\.){3}\d{1,3})(:\d+)?(\/.*)?$/.test(query) || query.toLowerCase() === "localhost") {
if (!query.toLowerCase().startsWith("http:") && !query.toLowerCase().startsWith("https:")) {
return `http://${query}`;
}
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() {
const searchInput = document.getElementById('gameSearchInput');
const grid = document.querySelector('.games-grid');
let gamesData = [];
const searchInput = document.getElementById('gameSearchInput');
const grid = document.querySelector('.games-grid');
const sentinel = document.createElement('div');
let allGames = [];
let filteredGames = [];
let renderedCount = 0;
const BATCH_SIZE = 20;
fetch('/assets/data/g.json')
.then(response => response.json())
.then(data => {
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));
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) loadNextBatch();
}, { rootMargin: '500px' });
function displayGames(games) {
grid.innerHTML = '';
if (games.length === 0) {
grid.innerHTML = '<p>Zero games were found matching your search :(</p>';
return;
}
games.forEach(game => {
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', function() {
const url = `/assets/g/${game.directory}`;
window.handleSearch(url);
});
grid.appendChild(card);
});
fetch('/assets/data/g.json')
.then(res => res.json())
.then(data => {
allGames = data;
filteredGames = data;
searchInput.placeholder = `Search through ${allGames.length} Games…`;
grid.parentNode.appendChild(sentinel);
observer.observe(sentinel);
resetAndRender();
})
.catch(err => console.error(err));
searchInput.addEventListener('input', function() {
const q = this.value.toLowerCase();
filteredGames = allGames.filter(game =>
(game.name || '').toLowerCase().includes(q)
);
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() {
const storedName = localStorage.getItem('userName');
const path = window.location.pathname;
if (!storedName) {
document.getElementById('overlay').style.display = 'block';
document.getElementById('namePrompt').style.display = 'block';
@ -11,7 +12,9 @@ window.onload = function() {
});
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');
if (greetingElement) {
updateGreeting(storedName);
@ -31,15 +34,93 @@ function submitName() {
}, 300);
}
function updateGreeting(name) {
const { text, icon } = getGreeting();
const el = document.getElementById('greeting');
if (el) {
el.innerHTML = `${icon} ${text}, ${name}!`;
el.style.opacity = 1;
function getWelcomeMessage(name) {
const path = window.location.pathname;
if (path === '/g') {
return `Have fun playing games, ${name}!`;
} else if (path === '/s') {
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') {
const toast = document.createElement('div');
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>',
info: '<i class="fas fa-info-circle" 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');
progressBar.className = 'progress-bar';
toast.appendChild(progressBar);
@ -68,63 +151,3 @@ function showToast(message, type = 'success', iconType = 'wave') {
setTimeout(() => toast.remove(), 500);
}, 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") {
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) {
console.error("Error parsing message:", err);

View File

@ -1,97 +1,80 @@
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");
;(function(){
const origLog = console.log.bind(console);
document.addEventListener("DOMContentLoaded", () => {
origLog(
"%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() {
try {
if (!navigator.serviceWorker) {
console.log("%c[⚠️]%c Service Workers are not supported by this browser.", "color: orange; font-weight: bold;", "color: black;");
return;
}
const labelStyle = "background: white; color: black; font-weight: bold; padding: 2px 4px; border-radius: 2px";
const messageStyle = "background: black; color: white; padding: 2px 4px; border-radius: 2px";
["log","info","warn","error","debug"].forEach(method => {
const orig = console[method].bind(console);
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;");
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;");
registerSW();
const savedTransport = localStorage.getItem('transport') || "epoxy";
switchTransport(savedTransport);
updateTransportUI(savedTransport);
async function registerSW(){
try {
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) {
logError(error, 'An error occurred during Service Worker registration or WebSocket connection');
}
}
function switchTransport(t){
const m = { epoxy: "/epoxy/index.mjs", libcurl: "/libcurl/index.mjs" }[t];
if (m) connection.setTransport(m, [{ wisp: wispUrl }]);
}
async function ensureWebSocketConnection(url) {
return new Promise((resolve, reject) => {
console.log("%c[🌐]%c Establishing WebSocket connection...", "color: #007bff; font-weight: bold;", "color: #007bff;");
const ws = new WebSocket(url);
function updateTransportUI(t){
document.querySelector(".transport-selected").textContent = capitalizeTransport(t);
}
ws.onopen = () => {
console.log("%c[✅]%c WebSocket connection established.", "color: green; font-weight: bold;", "color: green;");
resolve(ws);
};
function capitalizeTransport(t){
return t.charAt(0).toUpperCase() + t.slice(1).toLowerCase();
}
ws.onerror = (error) => {
logError(error, 'Failed to establish WebSocket connection');
reject(error);
};
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();
});
document.addEventListener("wispUrlChanged", function(e){
currentWispUrl = e.detail;
switchTransport(localStorage.getItem("transport") || "epoxy");
});
});
})();

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() {
const settingsMenu = document.getElementById('settings-menu');
settingsMenu.innerHTML = `
<h2>Settings</h2>
<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" id="cloak-tab"><i class="fa-regular fa-user-secret"></i> Cloak</button>
<button class="tab-button" id="appearance-tab"><i class="fa-regular fa-palette"></i> Appearance</button>
<button class="tab-button" id="info-tab"><i class="fa-regular fa-info"></i> Info</button>
</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>
const settingsMenu = document.getElementById('settings-menu');
settingsMenu.innerHTML = `
<h2>Settings</h2>
<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" id="cloak-tab">
<i class="fa-regular fa-user-secret"></i> Cloak
</button>
<button class="tab-button" id="appearance-tab">
<i class="fa-regular fa-palette"></i> Appearance
</button>
<button class="tab-button" id="info-tab">
<i class="fa-regular fa-info"></i> Info
</button>
</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>
<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">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>
<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) {
try {
const parsedUrl = new URL(url);
return (parsedUrl.protocol === "wss:" || parsedUrl.protocol === "ws:") && url.endsWith('/');
} catch (_) {
return false;
}
}
const settingsIcon = document.getElementById('settings-icon');
const closeSettingsBtn = document.getElementById('close-settings');
const saveWispBtn = 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;
let isToggling = false;
function updateWispServerUrl(url) {
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();
});
navbarToggle.checked = localStorage.getItem('navbarToggled') !== 'false';
function toggleSettingsMenu() {
const icon = document.querySelector('#settings-icon i.settings-icon');
if (settingsMenu.classList.contains('open')) {
settingsMenu.classList.add('close');
icon.classList.remove('fa-solid');
icon.classList.add('fa-regular');
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 isValidUrl(url) {
try {
const p = new URL(url);
return (p.protocol === "wss:" || p.protocol === "ws:") && url.endsWith('/');
} catch (_) {
return false;
}
}
function switchTab(tabId, contentId, otherTabId1, otherContentId1, otherTabId2, otherContentId2, otherTabId3, otherContentId3) {
document.getElementById(otherContentId1).classList.remove('active');
document.getElementById(otherContentId2).classList.remove('active');
document.getElementById(otherContentId3).classList.remove('active');
document.getElementById(otherTabId1).classList.remove('active');
document.getElementById(otherTabId2).classList.remove('active');
document.getElementById(otherTabId3).classList.remove('active');
document.getElementById(contentId).classList.add('active');
document.getElementById(tabId).classList.add('active');
}
document.getElementById('proxy-tab').addEventListener('click', function() {
switchTab('proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content');
});
document.getElementById('cloak-tab').addEventListener('click', function() {
switchTab('cloak-tab', 'cloak-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content');
});
document.getElementById('appearance-tab').addEventListener('click', function() {
switchTab('appearance-tab', 'appearance-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content');
});
document.getElementById('info-tab').addEventListener('click', function() {
switchTab('info-tab', 'info-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'cloak-tab', 'cloak-content');
});
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 = `
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>
<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>
`;
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();
});
window.location.replace("https://bisd.schoology.com/home");
}
function showToast(type, message) {
const toast = document.createElement('div');
toast.className = `toast ${type} show`;
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>',
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>'
};
const icon = icons[type] || '';
toast.innerHTML = `${icon}${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" style="margin-left: 8px; font-size: 0.8em;"></i>';
closeBtn.addEventListener('click', () => {
toast.classList.remove('show');
toast.classList.add('hide');
setTimeout(() => {
toast.remove();
}, 500);
});
toast.appendChild(closeBtn);
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.remove('show');
toast.classList.add('hide');
setTimeout(() => {
toast.remove();
}, 500);
}, 3000);
}
document.getElementById("aboutblank-toggle").addEventListener("change", function() {
localStorage.setItem("aboutBlankChecked", JSON.stringify(this.checked));
if (this.checked) {
showToast('success', 'Auto About:Blank is now enabled.');
} else {
showToast('error', 'Auto 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 updateWispServerUrl(url) {
if (isValidUrl(url)) {
currentWispUrl = url;
localStorage.setItem('customWispUrl', url);
document.dispatchEvent(new CustomEvent('wispUrlChanged', {
detail: currentWispUrl
}));
showToast('success', `Wisp Server URL changed to: ${currentWispUrl}`);
} else {
currentWispUrl = defaultWispUrl;
localStorage.setItem('customWispUrl', defaultWispUrl);
document.dispatchEvent(new CustomEvent('wispUrlChanged', {
detail: currentWispUrl
}));
showToast('error', "Invalid URL. Reverting to default...");
}
}
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 () {
document.addEventListener('DOMContentLoaded', function () {
function getSearchInputs() {
return [
document.getElementById('searchInput'),
document.getElementById('searchInputt'),
document.getElementById('gameSearchInput'),
document.getElementById('appSearchInput')
].filter(Boolean);
(function(){
document.addEventListener('DOMContentLoaded', function(){
const indicators = document.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4');
const arrowIndicators = document.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2');
indicators.forEach(el => {
if (!el.dataset.original) el.dataset.original = el.innerHTML;
});
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;
}
}
function isVisible(el) {
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
if (inputs[0]) {
inputs[0].focus();
return inputs[0];
}
return null;
}
function focusFirstVisibleInput() {
const inputs = getSearchInputs();
for (const input of inputs) {
if (isVisible(input)) {
input.focus();
return;
}
}
if (inputs.length) {
inputs[0].focus();
}
let arrowMode = false;
function updateIndicatorState(){
const hasText = getSearchInputs().some(i => i.value.trim() !== '');
if (hasText === arrowMode) return;
arrowMode = hasText;
arrowIndicators.forEach(ind => {
ind.classList.remove('fadeIn');
ind.classList.add('fadeOut');
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) {
if (e.key === 'Escape') {
const inputs = getSearchInputs();
const active = document.activeElement;
if (inputs.includes(active)) {
active.blur();
e.preventDefault();
return;
}
}
function handleIndicatorAction(){
const inputs = getSearchInputs().filter(isVisible);
const active = document.activeElement;
if (inputs.includes(active) && active.value.trim()) {
triggerSubmit(active);
return;
}
const withText = inputs.find(i => i.value.trim());
if (withText) {
triggerSubmit(withText);
return;
}
focusFirstVisibleInput();
}
if (e.ctrlKey && e.key.toLowerCase() === 's') {
e.preventDefault();
focusFirstVisibleInput();
}
});
updateIndicatorState();
getSearchInputs().forEach(i => i.addEventListener('input', updateIndicatorState));
document.querySelectorAll(
'.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4'
).forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
focusFirstVisibleInput();
});
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') {
const act = document.activeElement;
if (getSearchInputs().includes(act)) {
act.blur();
e.preventDefault();
}
}
if (e.ctrlKey && e.key.toLowerCase() === 's') {
e.preventDefault();
focusFirstVisibleInput();
}
});
document.body.addEventListener('click', function (e) {
if (
e.target.classList.contains('shortcut-indicator') ||
e.target.classList.contains('shortcut-indicator-2') ||
e.target.classList.contains('shortcut-indicator-3') ||
e.target.classList.contains('shortcut-indicator-4')
) {
e.preventDefault();
focusFirstVisibleInput();
}
});
document.body.addEventListener('click', e => {
const ind = e.target.closest('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4');
if (!ind) return;
e.preventDefault();
if (ind.classList.contains('arrow-mode')) {
handleIndicatorAction();
} else {
focusFirstVisibleInput();
}
});
const coolIframe = document.getElementById('cool-iframe');
if (coolIframe) {
coolIframe.addEventListener('load', function () {
const doc = coolIframe.contentWindow.document;
doc.addEventListener('keydown', function (e) {
if (e.key === 'Escape') {
if (doc.activeElement && doc.activeElement.blur) {
doc.activeElement.blur();
e.preventDefault();
return;
}
}
if (e.ctrlKey && e.key.toLowerCase() === 's') {
e.preventDefault();
document.dispatchEvent(new KeyboardEvent('keydown', {
key: 's',
ctrlKey: true
}));
}
const coolIframe = document.getElementById('cool-iframe');
if (coolIframe){
coolIframe.addEventListener('load', () => {
const doc = coolIframe.contentWindow.document;
doc.addEventListener('keydown', innerE => {
if (innerE.key === 'Escape') {
if (doc.activeElement.blur) doc.activeElement.blur();
innerE.preventDefault();
}
if (innerE.ctrlKey && innerE.key.toLowerCase() === 's') {
innerE.preventDefault();
document.dispatchEvent(new KeyboardEvent('keydown', { key: 's', ctrlKey: true, bubbles: true }));
}
});
doc.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4')
.forEach(el => {
el.addEventListener('click', ev => {
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"
}
}
:80 {
reverse_proxy http://localhost:3000
}
EOF
separator
h