Small Update 🤍
This commit is contained in:
parent
b5a927077a
commit
cd4c462e62
140
index.mjs
140
index.mjs
|
@ -2,8 +2,8 @@ import cluster from "cluster";
|
|||
import os from "os";
|
||||
import net from "net";
|
||||
import fs from "fs";
|
||||
import { spawnSync } from "child_process";
|
||||
import path from "path";
|
||||
import { spawnSync } from "child_process";
|
||||
import express from "express";
|
||||
import { createServer } from "http";
|
||||
import compression from "compression";
|
||||
|
@ -17,23 +17,19 @@ import wisp from "wisp-server-node";
|
|||
|
||||
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 {
|
||||
}
|
||||
} catch {}
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[~] Running Surge...');
|
||||
const result = spawnSync("node", ["./others/surge.mjs"], { stdio: "inherit" });
|
||||
if (result.error) {
|
||||
console.error('[!] Surger failed:', result.error);
|
||||
process.exit(1);
|
||||
}
|
||||
if (result.error) process.exit(1);
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(surgeConfigPath, "utf-8"));
|
||||
const nodeArgs = config.nodeFlags.concat([path.resolve("index.mjs"), "--surged"]);
|
||||
|
@ -43,8 +39,7 @@ function applySurgeAndRestartIfNeeded() {
|
|||
ALREADY_SURGED: "true"
|
||||
};
|
||||
|
||||
console.log(`[~] Relaunching with Node flags: ${config.nodeFlags.join(' ')}`);
|
||||
const relaunch = spawnSync(process.execPath, nodeArgs, { stdio: 'inherit', env });
|
||||
const relaunch = spawnSync(process.execPath, nodeArgs, { stdio: "inherit", env });
|
||||
process.exit(relaunch.status || 0);
|
||||
}
|
||||
|
||||
|
@ -53,27 +48,33 @@ applySurgeAndRestartIfNeeded();
|
|||
if (global.gc) {
|
||||
setInterval(() => {
|
||||
const { heapUsed, heapTotal } = process.memoryUsage();
|
||||
if (heapTotal > 0 && heapUsed / heapTotal > 0.7) {
|
||||
global.gc();
|
||||
console.info('[~] Performed GC due to high heap usage');
|
||||
}
|
||||
}, 60_000);
|
||||
if (heapTotal > 0 && heapUsed / heapTotal > 0.7) global.gc();
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
import './others/scaler.mjs';
|
||||
import './others/warmup.mjs';
|
||||
import "./others/scaler.mjs";
|
||||
import "./others/warmup.mjs";
|
||||
|
||||
const cache = new LRUCache({
|
||||
maxSize: 1000,
|
||||
ttl: 4 * 24 * 60 * 60 * 1000,
|
||||
ttl: 345600000,
|
||||
allowStale: false,
|
||||
sizeCalculation: (value, key) => Buffer.byteLength(value) + Buffer.byteLength(key)
|
||||
});
|
||||
|
||||
const port = parseInt(process.env.PORT || "3000", 10);
|
||||
|
||||
function logInfo(msg) { console.info(`[~] ${msg}`); }
|
||||
function logSuccess(msg) { console.info(`[+] ${msg}`); }
|
||||
function logError(err) { console.error(`[!] ${err instanceof Error ? err.message : err}`); }
|
||||
function logInfo(msg) {
|
||||
console.info(`[~] ${msg}`);
|
||||
}
|
||||
|
||||
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}`));
|
||||
|
@ -81,11 +82,15 @@ process.on("unhandledRejection", reason => logError(`Unhandled Rejection: ${reas
|
|||
if (cluster.isPrimary) {
|
||||
const cpus = os.cpus().length;
|
||||
const workers = Math.max(1, cpus - 1);
|
||||
logInfo(`Master: forking ${workers} of ${cpus} cores`);
|
||||
for (let i = 0; i < workers; i++) cluster.fork();
|
||||
|
||||
cluster.on("exit", (worker, code, signal) => {
|
||||
logError(`Worker ${worker.process.pid} exited (code=${code}, signal=${signal}). Restarting...`);
|
||||
logInfo(`Master: forking ${workers} workers`);
|
||||
|
||||
for (let i = 0; i < workers; i++) {
|
||||
cluster.fork();
|
||||
}
|
||||
|
||||
cluster.on("exit", worker => {
|
||||
logError(`Worker ${worker.process.pid} exited. Restarting...`);
|
||||
cluster.fork();
|
||||
});
|
||||
|
||||
|
@ -98,12 +103,12 @@ if (cluster.isPrimary) {
|
|||
});
|
||||
|
||||
server.on("error", err => logError(`Server error: ${err}`));
|
||||
server.listen(port, () => logSuccess(`Server listening on port ${port}`));
|
||||
|
||||
server.listen(port, () => logSuccess(`Server listening on ${port}`));
|
||||
} else {
|
||||
const __dirname = process.cwd();
|
||||
const publicPath = path.join(__dirname, "public");
|
||||
const app = express();
|
||||
let latencySamples = [];
|
||||
|
||||
app.use(compression({ level: 4, memLevel: 4, threshold: 1024 }));
|
||||
|
||||
|
@ -129,27 +134,87 @@ if (cluster.isPrimary) {
|
|||
app.use("/libcurl/", express.static(libcurlPath, staticOpts));
|
||||
app.use(express.static(publicPath, staticOpts));
|
||||
app.use("/wah/", express.static(uvPath, staticOpts));
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
const sendHtml = file => (req, res) => res.sendFile(path.join(publicPath, file));
|
||||
const sendHtml = file => (_req, res) => res.sendFile(path.join(publicPath, file));
|
||||
|
||||
app.get('/', sendHtml('$.html'));
|
||||
app.get('/g', sendHtml('!.html'));
|
||||
app.get('/a', sendHtml('!!.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')));
|
||||
app.get('/resent', (_req, res) => res.sendFile(path.join(publicPath, 'resent', 'index.html')));
|
||||
|
||||
app.get('/api/info', (_req, res) => {
|
||||
try {
|
||||
const average = latencySamples.length > 0
|
||||
? 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/github-updates', async (_req, res) => {
|
||||
try {
|
||||
const ghRes = await fetch('https://api.github.com/repos/xojw/waves/commits?per_page=5', {
|
||||
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 now = Date.now();
|
||||
|
||||
const updates = commits.map(c => {
|
||||
const dateMs = new Date(c.commit.author.date).getTime();
|
||||
const diffMs = now - dateMs;
|
||||
const diffMins = Math.round(diffMs / 60000);
|
||||
const diffHours = Math.round(diffMs / 3600000);
|
||||
const ago = diffHours > 1 ? `${diffHours} hours ago` : `${diffMins} minutes ago`;
|
||||
return {
|
||||
sha: c.sha.slice(0, 7),
|
||||
message: c.commit.message.split('\n')[0],
|
||||
author: c.commit.author.name,
|
||||
date: c.commit.author.date,
|
||||
ago
|
||||
};
|
||||
});
|
||||
|
||||
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: 4 * 1024 * 1024, perMessageDeflate: false });
|
||||
const pingWSS = new WebSocket.Server({ noServer: true, maxPayload: 4194304, perMessageDeflate: false });
|
||||
|
||||
pingWSS.on("connection", (ws, req) => {
|
||||
const remote = req.socket.remoteAddress || 'unknown';
|
||||
let lat = [];
|
||||
const interval = setInterval(() => {
|
||||
if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'ping', timestamp: Date.now() }));
|
||||
}, 1000);
|
||||
|
||||
ws.on('message', msg => {
|
||||
try {
|
||||
const data = JSON.parse(msg);
|
||||
|
@ -157,14 +222,19 @@ if (cluster.isPrimary) {
|
|||
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}`); }
|
||||
} catch(e) {
|
||||
logError(`Ping error: ${e}`);
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
clearInterval(interval);
|
||||
const avg = lat.length ? (lat.reduce((a,b)=>a+b)/lat.length).toFixed(2) : 0;
|
||||
logInfo(`WS ${remote} closed. Avg latency ${avg}ms`);
|
||||
logInfo(`WS ${remote} closed. Avg: ${avg}ms`);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -178,7 +248,7 @@ if (cluster.isPrimary) {
|
|||
}
|
||||
});
|
||||
|
||||
server.on('error', err => logError(`Worker server error: ${err}`));
|
||||
server.on('error', err => logError(`Worker error: ${err}`));
|
||||
server.listen(0, () => logSuccess(`Worker ${process.pid} ready`));
|
||||
|
||||
process.on('message', (msg, conn) => {
|
||||
|
|
3340
package-lock.json
generated
3340
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
81
package.json
81
package.json
|
@ -1,44 +1,41 @@
|
|||
{
|
||||
"name": "waves",
|
||||
"version": "2.8.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",
|
||||
"lru-cache": "^11.1.0",
|
||||
"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.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": "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"
|
||||
}
|
||||
}
|
|
@ -22,17 +22,20 @@
|
|||
</head>
|
||||
<body>
|
||||
<script src="/baremux/index.js"></script>
|
||||
<script src="/assets/js/nprogress.js?v=0.2.0"></script>
|
||||
<script src="/wah/uv.bundle.js" defer></script>
|
||||
<script src="/wah/cute1.js" defer></script>
|
||||
<script src="/assets/js/navbar.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/load.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/register.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/settings.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/settings.js?v=2.8.7" defer></script>
|
||||
<script src="/assets/js/greetings.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/shortcuts.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/$.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/a.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/wv.js?v=2.8.4" 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>
|
||||
|
|
|
@ -22,17 +22,19 @@
|
|||
</head>
|
||||
<body>
|
||||
<script src="/baremux/index.js"></script>
|
||||
<script src="/assets/js/nprogress.js?v=0.2.0"></script>
|
||||
<script src="/wah/uv.bundle.js" defer></script>
|
||||
<script src="/wah/cute1.js" defer></script>
|
||||
<script src="/assets/js/navbar.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/load.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/register.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/settings.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/register.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/settings.js?v=2.8.7" defer></script>
|
||||
<script src="/assets/js/greetings.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/shortcuts.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/$.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/g.js?v=2.8.4" 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>
|
||||
|
|
225
public/$.html
225
public/$.html
|
@ -1,114 +1,119 @@
|
|||
<!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>
|
||||
<style>
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</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?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/load.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/register.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/settings.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/ping.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/greetings.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/shortcuts.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/$.js?v=2.8.4" 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="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/nprogress.css">
|
||||
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet">
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-WGJ2192JZY');
|
||||
</script>
|
||||
<script type="text/javascript" src="//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script src="/baremux/index.js"></script>
|
||||
<script src="/assets/js/nprogress.js?v=0.2.0"></script>
|
||||
<script src="/wah/uv.bundle.js" defer></script>
|
||||
<script src="/wah/cute1.js" defer></script>
|
||||
<script src="/assets/js/navbar.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/load.js?v=2.8.5" defer></script>
|
||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/register.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/settings.js?v=2.8.7" defer></script>
|
||||
<script src="/assets/js/ping.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/greetings.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/shortcuts.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/last-updated.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/$.js?v=2.8.4" defer></script>
|
||||
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
|
||||
|
||||
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
|
||||
<div class="absolute inset-0 overflow-hidden">
|
||||
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="home-navbar">
|
||||
<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="/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="glow-blob"></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 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>
|
||||
<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="/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 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 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>
|
||||
<script type="text/javascript">
|
||||
atOptions = {
|
||||
'key' : '26bce7e7832b24b139944832990cf69d',
|
||||
'format' : 'iframe',
|
||||
'height' : 300,
|
||||
'width' : 160,
|
||||
'params' : {}
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="//spaniardinformationbookworm.com/26bce7e7832b24b139944832990cf69d/invoke.js"></script>
|
||||
</body>
|
||||
<button id="doneButton" onclick="submitName()" disabled>
|
||||
<i class="fa-regular fa-check"></i> Done
|
||||
</button>
|
||||
</div>
|
||||
</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="last-updated">Loading latest update…</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</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</div>
|
||||
|
||||
<script type="text/javascript" src="//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1 +0,0 @@
|
|||
google.com, pub-7835554576835583, DIRECT, f08c47fec0942fa0
|
|
@ -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;
|
||||
|
@ -71,7 +72,6 @@ body {
|
|||
height: 35px;
|
||||
color: #818181;
|
||||
padding: 10px;
|
||||
animation: fadeIn 2s ease;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
|
@ -256,7 +256,6 @@ body {
|
|||
margin-top: 20%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: fadeIn 2s ease;
|
||||
text-align: center;
|
||||
width: 90%;
|
||||
}
|
||||
|
@ -266,25 +265,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 {
|
||||
|
@ -388,13 +384,13 @@ body {
|
|||
}
|
||||
|
||||
.hover-link {
|
||||
color: #949494;
|
||||
color: #b3b3b3;
|
||||
text-decoration: none;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-link:hover {
|
||||
color: #dadada;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#pingDisplay {
|
||||
|
@ -402,10 +398,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;
|
||||
|
@ -413,7 +408,7 @@ body {
|
|||
}
|
||||
|
||||
#pingDisplay:hover {
|
||||
color: #b6b6b6;
|
||||
color: #d3d3d3;
|
||||
}
|
||||
|
||||
.god-rays {
|
||||
|
@ -427,7 +422,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;
|
||||
|
@ -573,7 +567,6 @@ body {
|
|||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: fadeIn 2s ease;
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
cursor: default;
|
||||
|
@ -581,22 +574,94 @@ body {
|
|||
}
|
||||
|
||||
#greeting:hover {
|
||||
color: #b6b6b6;
|
||||
color: #d3d3d3;
|
||||
}
|
||||
|
||||
#namePrompt.fade-out {
|
||||
animation: fadeOutPrompt 0.3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeInFromLeft {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(-50px);
|
||||
}
|
||||
#last-updated {
|
||||
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;
|
||||
}
|
||||
|
||||
100% {
|
||||
.last-updated {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.last-updated:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@keyframes fadeSlideIn {
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
}
|
||||
|
||||
.apps-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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
1
public/assets/css/nprogress.css
Normal file
1
public/assets/css/nprogress.css
Normal 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)}}
|
|
@ -63,7 +63,7 @@
|
|||
|
||||
#close-settings:hover {
|
||||
transform: rotate(90deg);
|
||||
color: #d3d3d3;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#close-settings i {
|
||||
|
@ -91,11 +91,12 @@
|
|||
max-width: 300px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.transport-selected {
|
||||
background-color: #141414;
|
||||
border: 1px solid #ffffff1a;
|
||||
color: #e0e0e0;
|
||||
padding: 10px;
|
||||
border: 1px solid #4141411a;
|
||||
border-radius: 15px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
@ -136,8 +137,7 @@
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
.transport-options.transport-show,
|
||||
.server-options.transport-show {
|
||||
.transport-options.transport-show {
|
||||
max-height: 200px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
@ -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;
|
||||
|
|
|
@ -51,6 +51,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 +95,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;
|
||||
}
|
|
@ -235,7 +235,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
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>'
|
||||
heart: '<i class="fa-solid fa-heart" style="margin-right: 8px;"></i>'
|
||||
}
|
||||
const icon = icons[iconType] || icons.heart
|
||||
toast.innerHTML = `${icon}${message} `
|
||||
|
|
|
@ -111,10 +111,10 @@ function getGreeting() {
|
|||
const generalGreetings = [
|
||||
{ text: 'Welcome aboard', icon: '<i class="fa-regular fa-rocket"></i>' },
|
||||
{ text: 'Let’s do something great', icon: '<i class="fa-regular fa-lightbulb"></i>' },
|
||||
{ text: 'Hope you enjoy Waves', icon: '<i class="fa-regular fa-heart"></i>' },
|
||||
{ text: 'Hope you enjoy Waves', icon: '<i class="fa-solid fa-heart"></i>' },
|
||||
{ text: 'Time to explore', icon: '<i class="fa-regular fa-compass"></i>' },
|
||||
{ text: 'Let’s roll', icon: '<i class="fa-regular fa-tire"></i>' },
|
||||
{ text: 'Another great visit', icon: '<i class="fa-regular fa-thumbs-up"></i>' },
|
||||
{ text: 'Consider joining our Discord (discord.gg/ire)', icon: '<i class="fa-solid fa-smile"></i>' },
|
||||
{ text: 'The adventure continues', icon: '<i class="fa-regular fa-map"></i>' }
|
||||
];
|
||||
|
||||
|
|
13
public/assets/js/last-updated.js
Normal file
13
public/assets/js/last-updated.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/github-updates');
|
||||
const { updates } = await res.json();
|
||||
const u = updates[0];
|
||||
const commitUrl = `https://github.com/xojw/waves/commit/${u.sha}`;
|
||||
document.getElementById('last-updated').innerHTML =
|
||||
`<span class="last-updated"><i class="fa-regular fa-hammer"></i> Last updated ${u.ago}</span> ~ <a href="${commitUrl}" class="hover-link" target="_blank" rel="noopener noreferrer">${u.sha} (Github)</a>`;
|
||||
} catch {
|
||||
document.getElementById('last-update').textContent =
|
||||
'Failed to load last update';
|
||||
}
|
||||
})();
|
|
@ -1,21 +1,21 @@
|
|||
document.addEventListener('DOMContentLoaded', function () {
|
||||
NProgress.configure({ showSpinner: false });
|
||||
NProgress.start();
|
||||
});
|
||||
|
||||
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();
|
||||
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);
|
||||
});
|
||||
}
|
1
public/assets/js/nprogress.js
Normal file
1
public/assets/js/nprogress.js
Normal 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});
|
|
@ -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);
|
||||
|
|
|
@ -1,210 +1,287 @@
|
|||
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>
|
||||
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>
|
||||
</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.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.8.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/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>
|
||||
<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 {
|
||||
currentWispUrl = defaultWispUrl;
|
||||
localStorage.setItem('customWispUrl', defaultWispUrl);
|
||||
wispInput.value = defaultWispUrl;
|
||||
showToast('error', "Invalid URL. Reverting back to default...");
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
saveButton.addEventListener('click', () => {
|
||||
updateWispServerUrl(wispInput.value.trim());
|
||||
});
|
||||
settingsIcon.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
toggleSettingsMenu();
|
||||
});
|
||||
closeSettingsButton.addEventListener('click', toggleSettingsMenu);
|
||||
function isValidUrl(url) {
|
||||
try {
|
||||
const p = new URL(url);
|
||||
return (p.protocol === "wss:" || p.protocol === "ws:") && url.endsWith('/');
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSettingsMenu() {
|
||||
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'), 300);
|
||||
} else {
|
||||
settingsMenu.classList.add('open');
|
||||
icon.classList.replace('fa-regular', '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');
|
||||
});
|
||||
Array.from(transportOptions.getElementsByTagName('div')).forEach(option => {
|
||||
option.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
const selectedValue = this.textContent;
|
||||
transportSelected.textContent = selectedValue;
|
||||
localStorage.setItem('transport', selectedValue.toLowerCase());
|
||||
transportOptions.classList.remove('transport-show');
|
||||
transportSelected.classList.remove('transport-arrow-active');
|
||||
document.dispatchEvent(new Event('newTransport', { detail: selectedValue.toLowerCase() }));
|
||||
showToast('success', `Transport successfully changed to ${selectedValue}`);
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
document.getElementById('proxy-content').classList.add('active');
|
||||
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 switchTab(activeTabId, activeContentId, ...others) {
|
||||
[others[1], others[3], others[5]].forEach(id => document.getElementById(id).classList.remove('active'));
|
||||
[others[0], others[2], others[4]].forEach(id => document.getElementById(id).classList.remove('active'));
|
||||
document.getElementById(activeContentId).classList.add('active');
|
||||
document.getElementById(activeTabId).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');
|
||||
});
|
||||
document.querySelectorAll('.tab-button').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const icon = this.querySelector('i');
|
||||
if (icon.classList.contains('fa-bounce')) return;
|
||||
icon.classList.add('fa-bounce');
|
||||
setTimeout(() => icon.classList.remove('fa-bounce'), 750);
|
||||
});
|
||||
});
|
||||
navbarToggle.addEventListener('change', function() {
|
||||
showToast(this.checked ? 'success' : 'error', `Navigation Bar is now ${this.checked ? 'enabled' : '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 title = localStorage.getItem("siteTitle") || "Google.";
|
||||
const icon = localStorage.getItem("faviconURL") || "https://www.google.com/favicon.ico";
|
||||
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 = `<iframe style="height:100%;width:100%;border:none;position:fixed;top:0;right:0;left:0;bottom:0;" src="/"></iframe>`;
|
||||
window.location.replace("https://bisd.schoology.com/home");
|
||||
}
|
||||
document.getElementById("aboutblank-toggle").addEventListener("change", function() {
|
||||
localStorage.setItem("aboutBlankChecked", JSON.stringify(this.checked));
|
||||
showToast(this.checked ? 'success' : 'error', `About:Blank is now ${this.checked ? 'enabled' : 'disabled'}.`);
|
||||
runScriptIfChecked();
|
||||
});
|
||||
window.addEventListener("load", function() {
|
||||
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
|
||||
document.getElementById("aboutblank-toggle").checked = aboutBlankChecked;
|
||||
runScriptIfChecked();
|
||||
});
|
||||
function showToast(type, message) {
|
||||
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>'
|
||||
};
|
||||
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" style="margin-left:8px;font-size:0.8em;"></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);
|
||||
}
|
||||
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 () {
|
||||
showToast(this.checked ? 'success' : 'error', `Navigation Bar ${this.checked ? 'enabled' : 'disabled'}`);
|
||||
});
|
||||
|
||||
initializeInfo();
|
||||
});
|
103
public/assets/js/wv.js
Normal file
103
public/assets/js/wv.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
(async()=>{
|
||||
const storageKey = 'wv-verified';
|
||||
const verifiedTime = localStorage.getItem(storageKey);
|
||||
if(verifiedTime && Date.now() - verifiedTime < 2592000000) {
|
||||
return;
|
||||
}
|
||||
|
||||
const s=document.createElement('style');s.textContent=`
|
||||
:root{--overlay-bg:#000;--card-bg:rgba(0,0,0,0.85);--accent:#fff;--text-main:#fff;--text-secondary:rgba(255,255,255,0.7);--radius:12px;--transition:.3s ease;--dot-size:8px;--dot-gap:8px}
|
||||
#wv-check-overlay{position:fixed;inset:0;background:var(--overlay-bg);display:flex;align-items:center;justify-content:center;font-family:system-ui,sans-serif;z-index:2147483647;opacity:1;transition:opacity .4s ease-out}
|
||||
#wv-check-overlay.fade-out{opacity:0}
|
||||
#wv-check-card{background:var(--card-bg);backdrop-filter:blur(12px);border-radius:var(--radius);padding:32px 24px;width:340px;text-align:center;color:var(--text-main);transition:transform var(--transition)}
|
||||
#wv-check-card h2{margin:0 0 16px;font-size:1.6rem;display:flex;align-items:center;justify-content:center;gap:.5rem}
|
||||
#wv-progress-bar{width:0;height:6px;background:var(--accent);transition:width var(--transition);border-radius:var(--radius)}
|
||||
#wv-info{margin:12px 0 20px;font-size:.95rem;color:var(--text-secondary)}
|
||||
#wv-loading-dots{display:flex;justify-content:center;align-items:center;gap:var(--dot-gap);margin-top:5px}
|
||||
#wv-loading-dots .dot{width:var(--dot-size);height:var(--dot-size);background:var(--accent);border-radius:50%;opacity:.3;animation:windows-load 1s infinite ease-in-out}
|
||||
#wv-loading-dots .dot:nth-child(1){animation-delay:0s}#wv-loading-dots .dot:nth-child(2){animation-delay:.2s}#wv-loading-dots .dot:nth-child(3){animation-delay:.4s}#wv-loading-dots .dot:nth-child(4){animation-delay:.6s}
|
||||
@keyframes windows-load{0%,80%,100%{opacity:.3;transform:scale(1)}40%{opacity:1;transform:scale(1.4)}}
|
||||
#wv-complete{display:none;text-align:center}#wv-complete.show{display:block;animation:fade-in .4s ease-out forwards}
|
||||
#wv-complete h2{display:flex;align-items:center;justify-content:center;gap:.5rem;font-size:1.5rem;margin-bottom:8px;color:var(--accent)}
|
||||
#wv-complete p{color:var(--accent);font-size:1rem;text-align:center;margin:0 auto;width:100%}@keyframes fade-in{from{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}
|
||||
`;document.head.appendChild(s);
|
||||
|
||||
const overlay=document.createElement('div');overlay.id='wv-check-overlay';overlay.innerHTML=`
|
||||
<div id="wv-check-card">
|
||||
<h2><i class="fas fa-shield-alt"></i>Verifying Your Browser...</h2>
|
||||
<div id="wv-progress"><div id="wv-progress-bar"></div></div>
|
||||
<div id="wv-info">Starting tests...</div>
|
||||
<div id="wv-loading-dots"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="dot"></div></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=overlay.querySelector('#wv-info'), bar=overlay.querySelector('#wv-progress-bar');
|
||||
const tests=[
|
||||
async()=>({msg:'Browser Automation',pass:!navigator.webdriver}),
|
||||
async()=>{
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
return {msg:'Headless Mode',pass:!/headless|phantomjs|puppeteer|selenium/i.test(ua)};
|
||||
},
|
||||
async()=>({msg:'Language Support',pass:navigator.languages && navigator.languages.length > 0}),
|
||||
async()=>({msg:'Browser Plugins',pass:navigator.plugins.length > 0}),
|
||||
async()=>{
|
||||
try {
|
||||
const c=document.createElement('canvas');
|
||||
const gl=c.getContext('webgl')||c.getContext('experimental-webgl');
|
||||
if(!gl) return {msg:'WebGL Support',pass:false};
|
||||
const debugInfo=gl.getExtension('WEBGL_debug_renderer_info');
|
||||
const vendor=debugInfo ? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) : '';
|
||||
return {msg:'Graphics Driver',pass:!/swiftshader|lavapipe/i.test(vendor)};
|
||||
} catch(e) {
|
||||
return {msg:'WebGL Support',pass:false};
|
||||
}
|
||||
},
|
||||
async()=>({msg:'Screen Resolution',pass:screen.width >= 320 && screen.height >= 480}),
|
||||
async()=>{
|
||||
try {
|
||||
const start = performance.now();
|
||||
const buffer = new ArrayBuffer(1000000);
|
||||
const view = new Uint8Array(buffer);
|
||||
return {msg:'Performance Check',pass:performance.now() - start < 30};
|
||||
} catch(e) {
|
||||
return {msg:'Performance Check',pass:false};
|
||||
}
|
||||
},
|
||||
async()=>({msg:'Device Memory',pass:!navigator.deviceMemory || navigator.deviceMemory > 0.5}),
|
||||
async()=>{
|
||||
const mq=window.matchMedia('(pointer:fine)');
|
||||
return {msg:'Input Method',pass:mq.matches};
|
||||
}
|
||||
];
|
||||
|
||||
const failures=[];
|
||||
for(let i=0;i<tests.length;i++){
|
||||
try {
|
||||
const res=await tests[i]();
|
||||
info.textContent=`Test ${i+1}/${tests.length}: ${res.msg}`;
|
||||
if(!res.pass) failures.push(res.msg);
|
||||
bar.style.width=`${((i+1)/tests.length)*100}%`;
|
||||
await new Promise(r=>setTimeout(r,300));
|
||||
} catch(e) {
|
||||
failures.push(`Test error`);
|
||||
}
|
||||
}
|
||||
|
||||
if(failures.length===0){
|
||||
localStorage.setItem(storageKey, Date.now());
|
||||
overlay.querySelector('#wv-check-card').style.display='none';
|
||||
overlay.querySelector('#wv-complete').classList.add('show');
|
||||
setTimeout(()=>{
|
||||
overlay.classList.add('fade-out');
|
||||
setTimeout(()=>overlay.remove(),400);
|
||||
},800);
|
||||
} else {
|
||||
info.innerHTML=`Verification failed:<br>${failures.map(m=>`• ${m}`).join('<br>')}`;
|
||||
bar.style.background='red';
|
||||
overlay.querySelector('#wv-loading-dots').remove();
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user