├── .github └── sources │ └── branding.png ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── app.json ├── index.mjs ├── package-lock.json ├── package.json ├── render.yaml ├── services ├── .DS_Store ├── dynamic │ ├── dynamic.client.js │ ├── dynamic.client.js.map │ ├── dynamic.config.js │ ├── dynamic.handler.js │ ├── dynamic.handler.js.map │ ├── dynamic.html.js │ ├── dynamic.html.js.map │ ├── dynamic.worker.js │ └── dynamic.worker.js.map └── uv │ ├── sw.js │ ├── uv.bundle.js │ ├── uv.bundle.js.map │ ├── uv.client.js │ ├── uv.client.js.map │ ├── uv.config.js │ ├── uv.handler.js │ ├── uv.handler.js.map │ ├── uv.sw.js │ └── uv.sw.js.map ├── static ├── assets │ ├── apps.json │ ├── black.png │ ├── blue.png │ ├── cog.png │ ├── favicon.ico │ ├── game.png │ ├── globedark.png │ ├── green.png │ ├── icons │ │ ├── 1.webp │ │ ├── 1v1-lol.webp │ │ ├── 2048.webp │ │ ├── 2D-Rocket-League.webp │ │ ├── 3slices.webp │ │ ├── 60-second-burger-run.webp │ │ ├── 8ball.webp │ │ ├── ADR.webp │ │ ├── BFM.webp │ │ ├── BP.webp │ │ ├── C2048.webp │ │ ├── DOOM.webp │ │ ├── FNAF2.webp │ │ ├── FNAF3.webp │ │ ├── FNAFWeb.webp │ │ ├── N64.webp │ │ ├── NGON.webp │ │ ├── OR.webp │ │ ├── PS2.webp │ │ ├── SF.webp │ │ ├── SMB.webp │ │ ├── SVI.webp │ │ ├── W3Schools.webp │ │ ├── aa.webp │ │ ├── acww.webp │ │ ├── addictinggames.webp │ │ ├── adventure-capitalist.webp │ │ ├── agario.webp │ │ ├── ageofwar.webp │ │ ├── akinator.webp │ │ ├── amazon-luna.webp │ │ ├── amazon.webp │ │ ├── android.webp │ │ ├── antwario.webp │ │ ├── apex.webp │ │ ├── aptoide.webp │ │ ├── arrasio.webp │ │ ├── bakeria.webp │ │ ├── banditrip.webp │ │ ├── basket-bros.webp │ │ ├── basketball-legends.webp │ │ ├── basketball-stars.webp │ │ ├── biggiecheese.webp │ │ ├── bigtowertinysquare.webp │ │ ├── bitlife.webp │ │ ├── bloonstd.webp │ │ ├── bloonstd2.webp │ │ ├── bloxd-io.webp │ │ ├── book2.webp │ │ ├── br.webp │ │ ├── braintest.webp │ │ ├── braintest2.webp │ │ ├── braintest3.webp │ │ ├── btd4.webp │ │ ├── buckshotroulette.webp │ │ ├── build-now.webp │ │ ├── burritobison.webp │ │ ├── buzzfeed.webp │ │ ├── candybox.webp │ │ ├── candyjump.webp │ │ ├── canva.webp │ │ ├── cat-ninja.webp │ │ ├── celeste.webp │ │ ├── characterai.webp │ │ ├── chatgpt.webp │ │ ├── chess.webp │ │ ├── clickerheros.webp │ │ ├── cluster-rush.webp │ │ ├── cookieclicker.webp │ │ ├── cookierunkingdom.webp │ │ ├── coolmath.webp │ │ ├── cr.webp │ │ ├── crazy.webp │ │ ├── cryzen.webp │ │ ├── cs16.webp │ │ ├── csgoparkour.webp │ │ ├── cupcakeria.webp │ │ ├── custom.webp │ │ ├── db.webp │ │ ├── deadshot.webp │ │ ├── deal-or-no-deal.webp │ │ ├── deeeepio.webp │ │ ├── deepest-sword.webp │ │ ├── default-g.webp │ │ ├── diep.webp │ │ ├── digdigio.webp │ │ ├── discord.webp │ │ ├── dl4.webp │ │ ├── dm.webp │ │ ├── doge-miner-1.webp │ │ ├── doodlejump.webp │ │ ├── doom2.webp │ │ ├── dreader.webp │ │ ├── drift-hunters.webp │ │ ├── ds.webp │ │ ├── duckduckgo.webp │ │ ├── ducklife.webp │ │ ├── dynast-io.webp │ │ ├── earntodie2012part2.webp │ │ ├── easports-fcmobile24.webp │ │ ├── easports-ufc.webp │ │ ├── espn.webp │ │ ├── evadesio.webp │ │ ├── evio.webp │ │ ├── fallout2.webp │ │ ├── fancypantsadventures.webp │ │ ├── fancypantsadventures2.webp │ │ ├── feedvid.webp │ │ ├── fifa.webp │ │ ├── fireboyandwatergirlcrystaltemple.webp │ │ ├── fireboyandwatergirlelements.webp │ │ ├── fireboyandwatergirlfairytales.webp │ │ ├── fireboyandwatergirlforesttemple.webp │ │ ├── fireboyandwatergirllighttemple.webp │ │ ├── firefox.webp │ │ ├── flixhq.webp │ │ ├── florr.webp │ │ ├── fmhy.webp │ │ ├── fnf.webp │ │ ├── fortnite.webp │ │ ├── freefire.webp │ │ ├── garticphone.webp │ │ ├── gba.webp │ │ ├── gc2.webp │ │ ├── geforce-now.webp │ │ ├── gemini.webp │ │ ├── genshinimpact.webp │ │ ├── getaway.webp │ │ ├── gidd.webp │ │ ├── github.webp │ │ ├── gladihoppers.webp │ │ ├── gmail.webp │ │ ├── goal.webp │ │ ├── golden-eye-007.webp │ │ ├── google.webp │ │ ├── googlebaseball.webp │ │ ├── googlefeud.webp │ │ ├── gswitch.webp │ │ ├── gswitch2.webp │ │ ├── gswitch3.webp │ │ ├── guilded.webp │ │ ├── gunspin.webp │ │ ├── half-life.webp │ │ ├── happywheels.webp │ │ ├── hbo.webp │ │ ├── hd.webp │ │ ├── heartgold.webp │ │ ├── helixjump.webp │ │ ├── hexarena.webp │ │ ├── hole.webp │ │ ├── hordes.webp │ │ ├── hw.webp │ │ ├── idlebreakout.webp │ │ ├── idlestartup.webp │ │ ├── insta.webp │ │ ├── interactive-buddy.webp │ │ ├── isleward.webp │ │ ├── itch.webp │ │ ├── iv.webp │ │ ├── jacksmith.webp │ │ ├── jellymario.webp │ │ ├── jetpackjoyride.webp │ │ ├── johnnyupgrade.webp │ │ ├── just-fall-lol.webp │ │ ├── kiomet.webp │ │ ├── kirby.webp │ │ ├── kirka.webp │ │ ├── krunker.webp │ │ ├── learntofly3.webp │ │ ├── lofi.webp │ │ ├── lordz.webp │ │ ├── lostgamerio.webp │ │ ├── louie1.webp │ │ ├── louie2.webp │ │ ├── lp.webp │ │ ├── ltf_idle.webp │ │ ├── madalinmultiplayer.webp │ │ ├── madalinstuntcars2.webp │ │ ├── madalinstuntcars3.webp │ │ ├── maddennfl24.webp │ │ ├── marblesgarden.webp │ │ ├── mario-kart-64.webp │ │ ├── masked-forces.webp │ │ ├── mc.webp │ │ ├── melonplayground.webp │ │ ├── mergefruit.webp │ │ ├── messenger.webp │ │ ├── mk48io.webp │ │ ├── mlb.webp │ │ ├── mm.webp │ │ ├── mobsinc.webp │ │ ├── moo.webp │ │ ├── mope-io.webp │ │ ├── mortal-kombat-4.webp │ │ ├── movie-web.webp │ │ ├── mrmine.webp │ │ ├── mx3m-spooky.webp │ │ ├── mx3m-winter.webp │ │ ├── mx3m.webp │ │ ├── na.webp │ │ ├── narrowone.webp │ │ ├── nba.webp │ │ ├── nealfun.webp │ │ ├── newgrounds.webp │ │ ├── nfl.webp │ │ ├── ng.webp │ │ ├── nguidle.webp │ │ ├── ninja-cat.webp │ │ ├── now-gg.webp │ │ ├── osm.webp │ │ ├── outlook.webp │ │ ├── ovo.webp │ │ ├── papa-louie-3.webp │ │ ├── papasburgeria.webp │ │ ├── papascheeseria.webp │ │ ├── papasfreezeria.webp │ │ ├── papaspancakeria.webp │ │ ├── papasscooperia.webp │ │ ├── papassushiria.webp │ │ ├── papaswingeria.webp │ │ ├── paper-mario-64.webp │ │ ├── paperio.webp │ │ ├── paramount.webp │ │ ├── parkourblock3d.webp │ │ ├── pinterest.webp │ │ ├── pix.webp │ │ ├── pixel-shooter.webp │ │ ├── pizza-tower.webp │ │ ├── pizzeria.webp │ │ ├── pl.webp │ │ ├── poki.webp │ │ ├── powerline.webp │ │ ├── pranx.webp │ │ ├── precision.webp │ │ ├── proton.webp │ │ ├── ptr.webp │ │ ├── r6.webp │ │ ├── rainbowobby.webp │ │ ├── rainbowtower.webp │ │ ├── redball1.webp │ │ ├── redball2.webp │ │ ├── redball4.webp │ │ ├── redball4vol2.webp │ │ ├── redball4vol3.webp │ │ ├── request.webp │ │ ├── retro.webp │ │ ├── riddle-school.webp │ │ ├── roblox.webp │ │ ├── rocketbotroyale.webp │ │ ├── rocketpult.webp │ │ ├── rooftop.webp │ │ ├── rooftopsnipers2.webp │ │ ├── rs2.webp │ │ ├── rs3.webp │ │ ├── rs4.webp │ │ ├── rs5.webp │ │ ├── run3.webp │ │ ├── sand.webp │ │ ├── sandboxels.webp │ │ ├── sandtrix.webp │ │ ├── saulrun.webp │ │ ├── scratch-among-us.webp │ │ ├── scratch.webp │ │ ├── shapezio.webp │ │ ├── shell-shockers.webp │ │ ├── showdown.webp │ │ ├── shuttle.webp │ │ ├── skribblio.webp │ │ ├── slither.webp │ │ ├── slope.webp │ │ ├── sm63.webp │ │ ├── sm64.webp │ │ ├── smashkarts.webp │ │ ├── snake.webp │ │ ├── snap.webp │ │ ├── snorlax.webp │ │ ├── snowball.webp │ │ ├── snowrider3d.webp │ │ ├── solarsmash.webp │ │ ├── soundcloud.webp │ │ ├── spaceplan.webp │ │ ├── spotify.webp │ │ ├── ssf1.webp │ │ ├── stabfish.webp │ │ ├── starblastio.webp │ │ ├── steam.webp │ │ ├── stickman-archero-fight.webp │ │ ├── stickmanhook.webp │ │ ├── stompedio.webp │ │ ├── stumble-guys.webp │ │ ├── sugarsugar.webp │ │ ├── super-smash-bros-64.webp │ │ ├── supplychainlogo.webp │ │ ├── swordbattle.webp │ │ ├── tamingio.webp │ │ ├── tanuki.webp │ │ ├── telegram.webp │ │ ├── temple-run-2.webp │ │ ├── templeofboom.webp │ │ ├── temu.webp │ │ ├── territorialio.webp │ │ ├── tetrio.webp │ │ ├── the-simpsons-game.webp │ │ ├── theimpossiblequiz.webp │ │ ├── thelast-io.webp │ │ ├── thereisnogame.webp │ │ ├── thisissand.webp │ │ ├── tiktok.webp │ │ ├── timeshooter2.webp │ │ ├── tinyfishing.webp │ │ ├── tocabocahairsalon4.webp │ │ ├── tocakitchen2.webp │ │ ├── tocalifeworld.webp │ │ ├── tpg.webp │ │ ├── trello.webp │ │ ├── trex-run-3D.webp │ │ ├── tribalsio.webp │ │ ├── tubejumpers.webp │ │ ├── tumblr.webp │ │ ├── tunnelrush.webp │ │ ├── tunnelrush2.webp │ │ ├── twistedcookingmama.webp │ │ ├── twitch.webp │ │ ├── twitter.webp │ │ ├── tyranio.webp │ │ ├── venge.webp │ │ ├── vercel.webp │ │ ├── vex3.webp │ │ ├── vex4.webp │ │ ├── vex5.webp │ │ ├── vex6.webp │ │ ├── vex7.webp │ │ ├── voxiom.webp │ │ ├── vscode.webp │ │ ├── wattpad.webp │ │ ├── webretro.webp │ │ ├── whatsapp.webp │ │ ├── wiki.webp │ │ ├── windows96.webp │ │ ├── wingsio.webp │ │ ├── worldbox.webp │ │ ├── wrassling.webp │ │ ├── y8.webp │ │ ├── yohoho.webp │ │ ├── youtube.webp │ │ ├── zombs-io.webp │ │ └── zombs-royale.webp │ ├── orange.png │ ├── purple.png │ ├── red.png │ ├── themes.json │ └── themes │ │ ├── cappuccino.css │ │ ├── frappe.css │ │ ├── grey.css │ │ ├── m.css │ │ ├── macchiato.css │ │ ├── mocha.css │ │ └── moon.css ├── index.html ├── index.js ├── m.html ├── m.js ├── particles.js ├── sw.js ├── tabsys.js └── themesys.js └── vercel.json /.github/sources/branding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbyssServices/Abyss-Web/938df88b94cca98a560cd6b1e64209789050b694/.github/sources/branding.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js 2 | node_modules/ 3 | npm-debug.log 4 | yarn-error.log 5 | 6 | # Dependency directories 7 | /.pnp 8 | .pnp.js 9 | 10 | # Optional npm cache directory 11 | .npm 12 | 13 | # ESLint 14 | /.eslintcache 15 | 16 | # IDE 17 | .idea/ 18 | .vscode/ 19 | *.sublime-project 20 | *.sublime-workspace 21 | 22 | # Logs 23 | logs 24 | *.log 25 | 26 | # Build output 27 | /dist 28 | /build 29 | 30 | # Environment variables 31 | .env 32 | .env.local 33 | .env.development.local 34 | .env.test.local 35 | .env.production.local 36 | 37 | # Testing 38 | /coverage 39 | 40 | # Editor directories and files 41 | .editorconfig 42 | .eslintignore 43 | .eslintrc 44 | .jshintrc 45 | .prettierignore 46 | .prettierrc 47 | 48 | # code-alt's extensions 49 | .history/ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:bookworm-slim 2 | ENV NODE_ENV=production 3 | 4 | WORKDIR /app 5 | 6 | COPY ["package.json", "./"] 7 | 8 | RUN npm install 9 | 10 | COPY . . 11 | 12 | CMD [ "node", "index.js" ] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Abyss is an advanced proxy service that provides modern unblocking for all users who use it.

4 |
5 | 6 | ![inpreview](https://cdn.paxton.rip/B0TnxDf0no00/direct.png) 7 | 8 | > [!IMPORTANT] 9 | > If you fork this project, consider giving it a star in the original repository! 10 | 11 | **Join Our [Discord Community](https://discord.gg/goabyss) for support, more links, and an active community!** 12 | 13 | ## Features 14 | 15 | - About:Blank Cloaking 16 | - https://play.geforcenow.com 17 | - https://pc.shadow.tech/login 18 | - Tab Cloaking 19 | - Wide collection of apps & games 20 | - Clean, Easy to use UI 21 | - Inspect Element 22 | - Various Themes 23 | - Built-in Tab System 24 | - Now.gg Support 25 | - Fast Speeds 26 | 27 | ## Deployment 28 | 29 | > [!IMPORTANT] 30 | > You **cannot** deploy to static web hosts, including Netlify, Cloudflare Pages, and GitHub Pages. 31 | 32 | ### Server Deployment 33 | 34 | You must run these commands on your server: 35 | `git clone https://github.com/AbyssServices/Abyss-Web` 36 | `cd Abyss-Web` 37 | `npm install` 38 | `npm start` 39 | 40 | ### Updating 41 | 42 | `cd Abyss-Web` 43 | `git pull --force --allow-unrelated-histories` 44 | 45 | Deploy to Heroku 46 | Deploy to Vercel 47 | 48 | #### What happened to Replit Deployment? 49 | 50 | As of January 1st, 2024, Replit is [no longer free](https://blog.replit.com/hosting-changes). Try GitHub Codespaces instead. 51 | 52 | ### GitHub Codespaces 53 | 54 | 1. Create a GitHub account if you haven't already. 55 | 2. Click "Code" (green button) and then "Create Codespace on main." 56 | 3. In the terminal at the bottom, paste `pnpm i && pnpm start`. 57 | 4. Respond to the application popup by clicking "Make public." 58 | > [!IMPORTANT] 59 | > Make sure you click the "Make public." button, or the proxy won't function properly. 60 | 5. Access the deployed website from the ports tab. 61 | 6. For subsequent uses in the same codespace, just run `pnpm start` 62 | 63 | ### Solution for if there is no popup. 64 | 65 | 1. Run `pnpm i`, and before `pnpm start`, prepend `PORT=8080`, replacing 8080 with another port. For example, `PORT=6969 pnpm start`. 66 | 3. Go to the ports tab, Click Forward A Port, And type the port number. 67 | 4. Right-click Visibility and set Port Visibility to Public. 68 | 69 | > [!NOTE] 70 | > We are committed to making Abyss easy and personalized however, as of now we need your support in making it ad-free. Consider keeping ads so Abyss can run freely or contribute by being a supporter. 71 | 72 | ## Report Issues 73 | 74 | If you encounter problems, open an issue on GitHub, and we'll address it promptly. 75 | 76 | > [!TIP] 77 | > If you're having trouble, don't hesitate to reach out to us on [Discord](https://discord.gg/goabyss) for personalized support. 78 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "edu", 3 | "description": "?", 4 | "repository": "https://github.com/AbyssServices/Abyss-Web", 5 | "keywords": ["school", "math"], 6 | "image": "heroku/nodejs" 7 | } 8 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | import { createBareServer } from "@tomphttp/bare-server-node"; 2 | // const createBareServer = bareServerNode.createBareServer; 3 | import express from "express"; 4 | import http from "http"; 5 | import { dirname, join } from "path"; 6 | import { hostname } from "node:os"; 7 | import { fileURLToPath } from "url"; 8 | import compression from 'compression'; 9 | import chalk from 'chalk'; 10 | import 'dotenv/config' 11 | 12 | 13 | let port = parseInt(process.env.PORT || ""); 14 | 15 | if (isNaN(port)) port = 8080; 16 | 17 | const bare = createBareServer("/bare/"); 18 | const app = express(); 19 | 20 | const __filename = fileURLToPath(import.meta.url); 21 | const __dirname = dirname(__filename); 22 | 23 | app.use(compression()); 24 | app.use(express.static(__dirname + "/static/")); 25 | app.use("/class/", express.static(__dirname + "/services/uv/")); 26 | app.use("/work/", express.static(__dirname + "/services/dynamic/")); 27 | 28 | app.use((req, res) => { 29 | res.status(404); 30 | res.send( 31 | `

404 :(

The page you are looking for might have been removed or does not exist. If you opened Abyss inside of Abyss, this page will also show up.

Open a new tab to continue.

` 32 | ); 33 | }); 34 | 35 | const server = http.createServer(); 36 | 37 | server.on('error', (err) => { 38 | console.error(`ERROR: ${err}`); 39 | }); 40 | 41 | server.on("request", (req, res) => { 42 | if (bare.shouldRoute(req)) { 43 | bare.routeRequest(req, res); 44 | } else { 45 | app(req, res); 46 | } 47 | }); 48 | 49 | server.on("upgrade", (req, socket, head) => { 50 | if (bare.shouldRoute(req)) { 51 | bare.routeUpgrade(req, socket, head); 52 | } else { 53 | socket.end(); 54 | } 55 | }); 56 | 57 | server.on("listening", () => { 58 | const address = server.address(); 59 | console.log(chalk.green("ABYSS: Abyss Web started.")); 60 | console.log("Listening on:"); 61 | console.log(`\thttp://localhost:${address.port}`); 62 | console.log(`\thttp://${hostname()}:${address.port}`); 63 | console.log( 64 | `\thttp://${ 65 | address.family === "IPv6" ? `[${address.address}]` : address.address 66 | }:${address.port}` 67 | ); 68 | }); 69 | 70 | process.on("SIGINT", shutdown); 71 | process.on("SIGTERM", shutdown); 72 | 73 | function shutdown() { 74 | console.log("SIGTERM signal received: closing HTTP server"); 75 | server.close(); 76 | bare.close(); 77 | process.exit(0); 78 | } 79 | 80 | server.listen({ 81 | port, 82 | }); 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "abyss", 3 | "version": "6.0.0", 4 | "description": "", 5 | "main": "index.mjs", 6 | "scripts": { 7 | "start": "node index.mjs" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "LGPL-2.0-only", 12 | "dependencies": { 13 | "@nebula-services/ultraviolet": "^1.0.1-1.patch.7", 14 | "@tomphttp/bare-server-node": "^2.0.1", 15 | "chalk": "^5.3.0", 16 | "compression": "^1.7.4", 17 | "dotenv": "^16.3.1", 18 | "eruda": "^3.0.1", 19 | "express": "^4.18.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /render.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | - type: web 3 | name: edu 4 | env: docker 5 | plan: free 6 | -------------------------------------------------------------------------------- /services/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbyssServices/Abyss-Web/938df88b94cca98a560cd6b1e64209789050b694/services/.DS_Store -------------------------------------------------------------------------------- /services/dynamic/dynamic.config.js: -------------------------------------------------------------------------------- 1 | // See documentation for more information 2 | 3 | self.__dynamic$config = { 4 | prefix: '/classes/english/', 5 | encoding: 'xor', 6 | mode: 'production', 7 | logLevel: 0, 8 | bare: { 9 | version: 2, 10 | path: '/bare/', 11 | }, 12 | tab: { 13 | title: null, 14 | icon: null, 15 | ua: null, 16 | }, 17 | assets: { 18 | prefix: '/work/', 19 | files: { 20 | handler: 'dynamic.handler.js', 21 | client: 'dynamic.client.js', 22 | worker: 'dynamic.worker.js', 23 | config: 'dynamic.config.js', 24 | inject: null, 25 | } 26 | }, 27 | block: [ 28 | 29 | ] 30 | }; 31 | -------------------------------------------------------------------------------- /services/uv/sw.js: -------------------------------------------------------------------------------- 1 | /*global UVServiceWorker,__uv$config*/ 2 | /* 3 | * Stock service worker script. 4 | * Users can provide their own sw.js if they need to extend the functionality of the service worker. 5 | * Ideally, this will be registered under the scope in uv.config.js so it will not need to be modified. 6 | * However, if a user changes the location of uv.bundle.js/uv.config.js or sw.js is not relative to them, they will need to modify this script locally. 7 | */ 8 | importScripts('uv.bundle.js'); 9 | importScripts('uv.config.js'); 10 | importScripts(__uv$config.sw || 'uv.sw.js'); 11 | 12 | const sw = new UVServiceWorker(); 13 | 14 | self.addEventListener('fetch', (event) => event.respondWith(sw.fetch(event))); 15 | -------------------------------------------------------------------------------- /services/uv/uv.config.js: -------------------------------------------------------------------------------- 1 | /*global Ultraviolet*/ 2 | self.__uv$config = { 3 | prefix: '/classes/math/', 4 | bare: '/bare/', 5 | encodeUrl: Ultraviolet.codec.xor.encode, 6 | decodeUrl: Ultraviolet.codec.xor.decode, 7 | handler: '/class/uv.handler.js', 8 | client: '/class/uv.client.js', 9 | bundle: '/class/uv.bundle.js', 10 | config: '/class/uv.config.js', 11 | sw: '/class/uv.sw.js', 12 | }; 13 | -------------------------------------------------------------------------------- /services/uv/uv.sw.js: -------------------------------------------------------------------------------- 1 | (()=>{var p=self.Ultraviolet,x=["cross-origin-embedder-policy","cross-origin-opener-policy","cross-origin-resource-policy","content-security-policy","content-security-policy-report-only","expect-ct","feature-policy","origin-isolation","strict-transport-security","upgrade-insecure-requests","x-content-type-options","x-download-options","x-frame-options","x-permitted-cross-domain-policies","x-powered-by","x-xss-protection"],w=["GET","HEAD"],b=class extends p.EventEmitter{constructor(t=__uv$config){super(),t.bare||(t.bare="/bare/"),t.prefix||(t.prefix="/service/"),this.config=t;let i=(Array.isArray(t.bare)?t.bare:[t.bare]).map(e=>new URL(e,location).toString());this.address=i[~~(Math.random()*i.length)],this.bareClient=new p.BareClient(this.address)}async fetch({request:t}){let i;try{if(!t.url.startsWith(location.origin+this.config.prefix))return await fetch(t);let e=new p(this.config,this.address);typeof this.config.construct=="function"&&this.config.construct(e,"service");let a=await e.cookie.db();e.meta.origin=location.origin,e.meta.base=e.meta.url=new URL(e.sourceUrl(t.url));let r=new g(t,this,e,w.includes(t.method.toUpperCase())?null:await t.blob());if(e.meta.url.protocol==="blob:"&&(r.blob=!0,r.base=r.url=new URL(r.url.pathname)),t.referrer&&t.referrer.startsWith(location.origin)){let n=new URL(e.sourceUrl(t.referrer));(r.headers.origin||e.meta.url.origin!==n.origin&&t.mode==="cors")&&(r.headers.origin=n.origin),r.headers.referer=n.href}let l=await e.cookie.getCookies(a)||[],c=e.cookie.serialize(l,e.meta,!1);r.headers["user-agent"]=navigator.userAgent,c&&(r.headers.cookie=c);let f=new m(r,null,null);if(this.emit("request",f),f.intercepted)return f.returnValue;i=r.blob?"blob:"+location.origin+r.url.pathname:r.url;let h=await this.bareClient.fetch(i,{headers:r.headers,method:r.method,body:r.body,credentials:r.credentials,mode:location.origin!==r.address.origin?"cors":r.mode,cache:r.cache,redirect:r.redirect,proxyIp:this.config.proxyIp,proxyPort:this.config.proxyPort}),s=new y(r,h),d=new m(s,null,null);if(this.emit("beforemod",d),d.intercepted)return d.returnValue;for(let n of x)s.headers[n]&&delete s.headers[n];if(s.headers.location&&(s.headers.location=e.rewriteUrl(s.headers.location)),t.destination==="document"){let n=s.headers["content-disposition"];if(!/\s*?((inline|attachment);\s*?)filename=/i.test(n)){let u=/^\s*?attachment/i.test(n)?"attachment":"inline",[v]=new URL(h.finalURL).pathname.split("/").slice(-1);s.headers["content-disposition"]=`${u}; filename=${JSON.stringify(v)}`}}if(s.headers["set-cookie"]&&(Promise.resolve(e.cookie.setCookies(s.headers["set-cookie"],a,e.meta)).then(()=>{self.clients.matchAll().then(function(n){n.forEach(function(u){u.postMessage({msg:"updateCookies",url:e.meta.url.href})})})}),delete s.headers["set-cookie"]),s.body)switch(t.destination){case"script":case"worker":{let n=[e.bundleScript,e.clientScript,e.configScript,e.handlerScript].map(u=>JSON.stringify(u)).join(",");s.body=`if (!self.__uv && self.importScripts) { ${e.createJsInject(this.address,this.bareClient.manfiest,e.cookie.serialize(l,e.meta,!0),t.referrer)} importScripts(${n}); } 2 | `,s.body+=e.js.rewrite(await h.text())}break;case"style":s.body=e.rewriteCSS(await h.text());break;case"iframe":case"document":S(e.meta.url,s.headers["content-type"]||"")&&(s.body=e.rewriteHtml(await h.text(),{document:!0,injectHead:e.createHtmlInject(e.handlerScript,e.bundleScript,e.clientScript,e.configScript,this.address,this.bareClient.manfiest,e.cookie.serialize(l,e.meta,!0),t.referrer)}))}return r.headers.accept==="text/event-stream"&&(s.headers["content-type"]="text/event-stream"),crossOriginIsolated&&(s.headers["Cross-Origin-Embedder-Policy"]="require-corp"),this.emit("response",d),d.intercepted?d.returnValue:new Response(s.body,{headers:s.headers,status:s.status,statusText:s.statusText})}catch(e){return["document","iframe"].includes(t.destination)?(console.error(e),O(e,i,this.address)):new Response(void 0,{status:500})}}static Ultraviolet=p};self.UVServiceWorker=b;var y=class{constructor(t,i){this.request=t,this.raw=i,this.ultraviolet=t.ultraviolet,this.headers={};for(let e in i.rawHeaders)this.headers[e.toLowerCase()]=i.rawHeaders[e];this.status=i.status,this.statusText=i.statusText,this.body=i.body}get url(){return this.request.url}get base(){return this.request.base}set base(t){this.request.base=t}},g=class{constructor(t,i,e,a=null){this.ultraviolet=e,this.request=t,this.headers=Object.fromEntries(t.headers.entries()),this.method=t.method,this.address=i.address,this.body=a||null,this.cache=t.cache,this.redirect=t.redirect,this.credentials="omit",this.mode=t.mode==="cors"?t.mode:"same-origin",this.blob=!1}get url(){return this.ultraviolet.meta.url}set url(t){this.ultraviolet.meta.url=t}get base(){return this.ultraviolet.meta.base}set base(t){this.ultraviolet.meta.base=t}};function S(o,t=""){return(p.mime.contentType(t||o.pathname)||"text/html").split(";")[0]==="text/html"}var m=class{#e;#t;constructor(t={},i=null,e=null){this.#e=!1,this.#t=null,this.data=t,this.target=i,this.that=e}get intercepted(){return this.#e}get returnValue(){return this.#t}respondWith(t){this.#t=t,this.#e=!0}};function C(o,t){let i=new URL(o),e=`remoteHostname.textContent = ${JSON.stringify(i.hostname)};bareServer.href = ${JSON.stringify(t)};uvHostname.textContent = ${JSON.stringify(location.hostname)};reload.addEventListener("click", () => location.reload());uvVersion.textContent = ${JSON.stringify("1.0.11.patch.7")};`;return`Error

This site can\u2019t be reached


\u2019s server IP address could not be found.

Try:


Ultraviolet v

19 | 20 | 21 | 22 | 23 | 24 |
25 |

abyss

26 |

discord.gg/goabyss

27 | 28 |
29 | 30 | -------------------------------------------------------------------------------- /static/m.js: -------------------------------------------------------------------------------- 1 | var particlesConfig = {"particles":{"number":{"value":67,"density":{"enable":true,"value_area":800}},"color":{"value":"#ffffff"},"shape":{"type":"circle","stroke":{"width":1,"color":"#000000"},"polygon":{"nb_sides":5},"image":{"src":"img/github.svg","width":100,"height":100}},"opacity":{"value":1,"random":false,"anim":{"enable":false,"speed":1,"opacity_min":0.1,"sync":false}},"size":{"value":14,"random":true,"anim":{"enable":false,"speed":40,"size_min":0.1,"sync":false}},"line_linked":{"enable":false,"distance":150,"color":"#ffffff","opacity":0.4,"width":1},"move":{"enable":true,"speed":1.5,"direction":"none","random":true,"straight":false,"out_mode":"out","bounce":false,"attract":{"enable":false,"rotateX":600,"rotateY":1200}}},"interactivity":{"detect_on":"canvas","events":{"onhover":{"enable":false,"mode":"repulse"},"onclick":{"enable":false,"mode":"push"},"resize":true},"modes":{"grab":{"distance":400,"line_linked":{"opacity":1}},"bubble":{"distance":400,"size":40,"duration":2,"opacity":8,"speed":3},"repulse":{"distance":200,"duration":0.4},"push":{"particles_nb":4},"remove":{"particles_nb":2}}},"retina_detect":true} 2 | particlesJS("particles-js", particlesConfig) 3 | const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); 4 | if (!isMobile) { 5 | window.location.href = "/"; 6 | } 7 | function go(url) { 8 | if (!/^(https?:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,30}/i.test(url)) { 9 | url = 'https://www.google.com/search?q=' + url; 10 | } else if (!/^(https?:\/\/)/.test(url)) { 11 | url = "https://" + url; 12 | } 13 | window.location.href = '/classes/math/' + __uv$config.encodeUrl(url); 14 | } 15 | 16 | async function worker() { 17 | return await navigator.serviceWorker.register("/sw.js", { 18 | scope: "/classes", 19 | }); 20 | } 21 | 22 | document.addEventListener("DOMContentLoaded", async function () { 23 | await worker(); 24 | workerLoaded = true; 25 | }); 26 | -------------------------------------------------------------------------------- /static/sw.js: -------------------------------------------------------------------------------- 1 | importScripts("/work/dynamic.config.js"); 2 | importScripts("/work/dynamic.worker.js"); 3 | importScripts("/class/uv.bundle.js"); 4 | importScripts("/class/uv.config.js"); 5 | importScripts("/class/uv.sw.js"); // override because the support for UV is complete dogshit 6 | 7 | const uv = new UVServiceWorker(); 8 | const dynamic = new Dynamic(); 9 | 10 | self.dynamic = dynamic; 11 | 12 | self.addEventListener("fetch", (event) => { 13 | event.respondWith( 14 | (async function () { 15 | if (await dynamic.route(event)) { 16 | return await dynamic.fetch(event); 17 | } 18 | 19 | if (event.request.url.startsWith(location.origin + "/classes/math/")) { 20 | return await uv.fetch(event); 21 | } 22 | 23 | return await fetch(event.request); 24 | })() 25 | ); 26 | }); 27 | 28 | -------------------------------------------------------------------------------- /static/tabsys.js: -------------------------------------------------------------------------------- 1 | // OP TAB SYSTEM V2.2.0 2 | 3 | // LICENSE: 4 | /* 5 | 6 | Copyright (c) 2023 Code-Alt 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | */ 27 | 28 | // DOCS: 29 | 30 | // here are some prerequisites: 31 | // you must have a tab container, a btn container, a tab template, and a btn template, and a search bar. 32 | // btw this might be hard to set up, set up your own classes and CSS until you find it satisfactory. 33 | 34 | // new TabSystem() - Initializes the TabSystem class, used for holding all the information about the tab system, and it's functions. 35 | // TabSystem.addTab(tab) - Adds a tab to the tab system. Returns the tab. 36 | // TabSystem.getTabTemplate() - Returns the tab template. 37 | // TabSystem.getBtnTemplate() - Returns the tab button template. 38 | // TabSystem.createTabBtn(id) - Creates a tab button with the specified id. Returns the tab button. 39 | // TabSystem.createTabFrame(id) - Creates a tab frame with the specified id. Returns the tab frame. 40 | // TabSystem.setActiveTab(tab) - Sets the active tab to the specified tab. 41 | // TabSystem.getActiveTab() - Returns the active tab. 42 | // TabSystem.getTabs() - Returns all tabs. 43 | // TabSystem.getTabCount() - Returns the amount of tabs. 44 | // TabSystem.genRanId() - Generates a random id. Returns the id. 45 | // TabSystem.deleteTab(tab, force) - Deletes the specified tab. If force is true, it will delete the tab even if it's the last tab. 46 | // TabSystem.deleteTabs(tabs, force) - Deletes the specified tabs. If force is true, it will delete the tabs even if it's the last tab. 47 | // TabSystem.deleteAllTabs() - Deletes all tabs. 48 | // TabSystem.deleteAllTabsExcept(tab) - Deletes all tabs except the specified tab. 49 | // TabSystem.deleteAllTabsExceptThese(tabs) - Deletes all tabs except the specified tabs. 50 | // new Tab() - Initializes the Tab class, used for holding all the information about the tab frame and the button used to activate it. 51 | // Tab.getConnectedElement() - Returns the connected element. 52 | // Tab.getTabElement() - Returns the tab element. 53 | // Tab.setTabElement(tabElement) - Sets the tab element. 54 | // Tab.setConnectedElement(connectedElement) - Sets the connected element. 55 | 56 | var dp = "Starting Page"; 57 | var conf = {}; 58 | var mainTS; 59 | var _OPTabSys_callbacks = { 60 | tabChange: [], 61 | tabAdd: [], 62 | tabDelete: [], 63 | }; 64 | 65 | class TabSystem { 66 | constructor(object) { 67 | this.config = { 68 | tabContainer: 69 | object.tabContainer || document.getElementById("tabContainer"), 70 | tabTemplate: object.tabTemplate || document.getElementById("tabTemplate"), 71 | btnTemplate: object.btnTemplate || document.getElementById("btnTemplate"), 72 | tabBtnContainer: 73 | object.tabBtnContainer || document.getElementById("tabBtnContainer"), 74 | URLBar: object.URLBar || document.getElementById("adrbar"), 75 | defaultPlaceholder: object.defaultPlaceholder || "Starting Page", 76 | closePlaceholder: object.closePlaceholder || "No tab open", 77 | tabActiveClass: object.tabActiveClass || "op-tabs-active", 78 | }; 79 | conf = this.config; 80 | dp = this.config.defaultPlaceholder; 81 | this.tabs = []; 82 | this.tabCount = 0; 83 | this.activeTab = null; 84 | this.config.tabTemplate.style.display = "none"; 85 | this.config.btnTemplate.style.display = "none"; 86 | mainTS = this; 87 | } 88 | 89 | on(event, callback) { 90 | switch (event) { 91 | case "tabChange": 92 | if (_OPTabSys_callbacks == null) _OPTabSys_callbacks = {}; 93 | if (_OPTabSys_callbacks.tabChange == null) 94 | _OPTabSys_callbacks.tabChange = []; 95 | _OPTabSys_callbacks.tabChange.push(callback); 96 | break; 97 | case "tabAdd": 98 | if (_OPTabSys_callbacks == null) _OPTabSys_callbacks = {}; 99 | if (_OPTabSys_callbacks.tabAdd == null) _OPTabSys_callbacks.tabAdd = []; 100 | _OPTabSys_callbacks.tabAdd.push(callback); 101 | break; 102 | case "tabDelete": 103 | if (_OPTabSys_callbacks == null) _OPTabSys_callbacks = {}; 104 | if (_OPTabSys_callbacks.tabDelete == null) 105 | _OPTabSys_callbacks.tabDelete = []; 106 | _OPTabSys_callbacks.tabDelete.push(callback); 107 | break; 108 | default: 109 | return console.error("Invalid event!"); 110 | } 111 | } 112 | 113 | addTab(tab) { 114 | this.tabs.push(tab); 115 | this.tabCount++; 116 | if (_OPTabSys_callbacks != null) { 117 | if (_OPTabSys_callbacks.tabAdd != null) { 118 | for (var i = 0; i < _OPTabSys_callbacks.tabAdd.length; i++) { 119 | _OPTabSys_callbacks.tabAdd[i](tab); 120 | } 121 | } 122 | } 123 | return tab; 124 | } 125 | 126 | getTabTemplate() { 127 | return this.config.tabTemplate; 128 | } 129 | 130 | getBtnTemplate() { 131 | return this.config.btnTemplate; 132 | } 133 | 134 | createTabBtn(id) { 135 | const btn = this.getBtnTemplate().cloneNode(true); 136 | if (id == null) id = ""; 137 | btn.id = id; 138 | btn.style = btn.style.toString().replace(/display:( )*none(;){0,1}/g, ""); 139 | this.config.tabBtnContainer.appendChild(btn); 140 | btn.style.width = "0px"; 141 | btn.style.opacity = "0"; 142 | setTimeout(() => { 143 | btn.style.width = "235px"; 144 | btn.style.opacity = "1"; 145 | }, 0); 146 | return btn; 147 | } 148 | 149 | createTabFrame(id) { 150 | const frame = this.getTabTemplate().cloneNode(true); 151 | if (id == null) id = ""; 152 | frame.id = id; 153 | frame.style.display = "none"; 154 | this.config.tabContainer.appendChild(frame); 155 | return frame; 156 | } 157 | 158 | setActiveTab(tab) { 159 | if (_OPTabSys_callbacks != null) { 160 | if (_OPTabSys_callbacks.tabChange != null) { 161 | for (var i = 0; i < _OPTabSys_callbacks.tabChange.length; i++) { 162 | _OPTabSys_callbacks.tabChange[i](tab); 163 | } 164 | } 165 | } 166 | if (!this.tabs.includes(tab) && tab != null) { 167 | this.addTab(tab); 168 | } 169 | if (this.activeTab != null) { 170 | this.activeTab.getConnectedElement().classList.remove(this.config.tabActiveClass); 171 | this.activeTab.setSearchBarContent(this.config.URLBar.value); 172 | this.activeTab.setPlaceholder(this.config.URLBar.placeholder); 173 | } 174 | this.config.URLBar.value = ""; 175 | if (tab != null && tab.getSearchBarContent()) { 176 | this.config.URLBar.value = tab.getSearchBarContent(); 177 | } 178 | this.activeTab = tab; 179 | if (tab != null && this.activeTab.getPlaceholder()) { 180 | this.config.URLBar.placeholder = this.activeTab.getPlaceholder(); 181 | } 182 | if (this.activeTab == null) { 183 | this.config.URLBar.placeholder = this.config.closePlaceholder; 184 | } 185 | for (var t = 0; t < this.tabs.length; t++) { 186 | if (this.tabs[t] == tab && tab != null) { 187 | if (this.tabs[t].tabElement != null) { 188 | this.tabs[t].tabElement.style.display = "initial"; 189 | } 190 | if (this.tabs[t].connectedElement != null) { 191 | this.tabs[t].connectedElement.classList.add(this.config.tabActiveClass); 192 | } 193 | } else { 194 | if (this.tabs[t].tabElement != null && tab != null) { 195 | this.tabs[t].tabElement.style.display = "none"; 196 | } 197 | if (this.tabs[t].connectedElement != null && tab != null) { 198 | this.tabs[t].connectedElement.classList.remove(this.config.tabActiveClass); 199 | } 200 | } 201 | } 202 | } 203 | 204 | getActiveTab() { 205 | return this.activeTab; 206 | } 207 | 208 | getTabs() { 209 | return this.tabs; 210 | } 211 | 212 | getTabCount() { 213 | return this.tabCount; 214 | } 215 | 216 | genRanId() { 217 | return Date.now() + Math.floor(Math.random() * 1000000000); 218 | } 219 | 220 | deleteTab(tab, force) { 221 | for (var i = 0; i < this.tabs.length; i++) { 222 | if (this.tabs[i] == tab) { 223 | if (this.tabs[i] == this.activeTab) { 224 | if (this.tabs[i - 1] != null) { 225 | this.setActiveTab(this.tabs[i - 1]); 226 | } else if (this.tabs[i + 1] != null) { 227 | this.setActiveTab(this.tabs[i + 1]); 228 | } else { 229 | if (force != true) { 230 | return alert("You can't delete the last tab!"); 231 | } else { 232 | this.setActiveTab(null); 233 | } 234 | } 235 | } 236 | this.tabs[i].connectedElement.remove(); 237 | this.tabs[i].tabElement.remove(); 238 | this.tabs.splice(i, 1); 239 | this.tabCount--; 240 | if (_OPTabSys_callbacks != null) { 241 | if (_OPTabSys_callbacks.tabDelete != null) { 242 | for (var tC = 0; tC < _OPTabSys_callbacks.tabDelete.length; tC++) { 243 | _OPTabSys_callbacks.tabDelete[tC](this.activeTab); 244 | } 245 | } 246 | } 247 | break; 248 | } 249 | } 250 | } 251 | 252 | deleteTabs(tabs) { 253 | const tabsToDelete = tabs.slice(); 254 | for (let i = 0; i < tabsToDelete.length; i++) { 255 | const tab = tabsToDelete[i]; 256 | if (tab === this.activeTab) { 257 | if (this.tabs[i - 1]) { 258 | this.setActiveTab(this.tabs[i - 1]); 259 | } else if (this.tabs[i + 1]) { 260 | this.setActiveTab(this.tabs[i + 1]); 261 | } else { 262 | this.setActiveTab(null); 263 | } 264 | } 265 | tab.connectedElement.remove(); 266 | tab.tabElement.remove(); 267 | this.tabs.splice(this.tabs.indexOf(tab), 1); 268 | this.tabCount--; 269 | } 270 | if (_OPTabSys_callbacks?.tabDelete) { 271 | _OPTabSys_callbacks.tabDelete.forEach((callback) => 272 | callback(this.activeTab) 273 | ); 274 | } 275 | } 276 | 277 | deleteAllTabs() { 278 | this.deleteTabs(this.tabs); 279 | } 280 | 281 | deleteAllTabsExcept(tab) { 282 | const tabsToDelete = this.tabs.slice(); 283 | tabsToDelete.splice(tabsToDelete.indexOf(tab), 1); 284 | this.deleteTabs(tabsToDelete); 285 | } 286 | 287 | deleteAllTabsExceptThese(tabs) { 288 | const tabsToDelete = this.tabs.slice(); 289 | tabsToDelete.forEach((tab) => { 290 | if (tabs.includes(tab)) { 291 | tabsToDelete.splice(tabsToDelete.indexOf(tab), 1); 292 | } 293 | }); 294 | this.deleteTabs(tabsToDelete); 295 | } 296 | 297 | getConfig() { 298 | return this.config; 299 | } 300 | } 301 | 302 | class Tab { 303 | constructor(connectedElement, tabFrame, searchBarContent, placeholder) { 304 | this.connectedElement = 305 | connectedElement || mainTS.createTabBtn(mainTS.genRanId()); 306 | this.tabElement = tabFrame || mainTS.createTabFrame(mainTS.genRanId()); 307 | if (searchBarContent == null) searchBarContent = ""; 308 | this.searchBarContent = searchBarContent; 309 | if (placeholder == null) placeholder = dp; 310 | this.placeholder = placeholder; 311 | this.connectedElement.addEventListener("click", () => { 312 | if (window.tryClose) { 313 | this.connectedElement.style.width="0px"; 314 | this.connectedElement.style.opacity="0"; 315 | window.setTimeout(() => { 316 | mainTS.deleteTab(this, window.allowForce); 317 | window.tryClose = false; 318 | }, 200); 319 | return; 320 | } 321 | mainTS.setActiveTab(this); 322 | }); 323 | } 324 | 325 | getConnectedElement() { 326 | return this.connectedElement; 327 | } 328 | 329 | getTabElement() { 330 | return this.tabElement; 331 | } 332 | 333 | setSearchBarContent(searchBarContent) { 334 | this.searchBarContent = searchBarContent; 335 | } 336 | 337 | getSearchBarContent() { 338 | return this.searchBarContent; 339 | } 340 | 341 | findFirstIFrame() { 342 | return this.tabElement.querySelector("iframe"); 343 | } 344 | 345 | hasIFrame() { 346 | if (this.findIFrame() != null) { 347 | return true; 348 | } else { 349 | return false; 350 | } 351 | } 352 | 353 | setPlaceholder(placeholder) { 354 | this.placeholder = placeholder; 355 | } 356 | 357 | getPlaceholder() { 358 | return this.placeholder; 359 | } 360 | } 361 | 362 | window.TabSystem = TabSystem; 363 | window.Tab = Tab; 364 | window.allowForce = true; 365 | -------------------------------------------------------------------------------- /static/themesys.js: -------------------------------------------------------------------------------- 1 | class ThemeSystem { 2 | constructor() { 3 | this.config = {}; // is there even a need for this 4 | this.themes = []; 5 | this.themeCount = 0; 6 | this.activeTheme = null; 7 | this.lastTheme = null; 8 | } 9 | 10 | getThemeFromName(name) { 11 | for (let i = 0; i < this.themes.length; i++) { 12 | if (this.themes[i].getName() == name) { 13 | return this.themes[i]; 14 | } 15 | } 16 | } 17 | 18 | addTheme(theme) { 19 | for (let i = 0; i < this.themes.length; i++) { 20 | if (this.themes[i].getName() == theme.getName()) { 21 | console.error( 22 | "A theme with the name " + theme.getName() + " already exists!" 23 | ); 24 | return; 25 | } 26 | } 27 | if (this.lastTheme != theme) { 28 | this.themes.push(theme); 29 | this.themeCount++; 30 | } 31 | return theme; 32 | } 33 | 34 | setActiveTheme(theme) { 35 | if (this.activeTheme != null) { 36 | this.activeTheme.disable(); 37 | } 38 | this.activeTheme = theme; 39 | this.activeTheme.apply(); 40 | } 41 | 42 | getActiveTheme() { 43 | return this.activeTheme; 44 | } 45 | 46 | getThemes() { 47 | return this.themes; 48 | } 49 | 50 | getThemeCount() { 51 | return this.themeCount; 52 | } 53 | 54 | genRanId() { 55 | return ( 56 | Math.random().toString(36).substring(2, 15) + 57 | Math.random().toString(36).substring(2, 15) 58 | ); 59 | } 60 | 61 | deleteTheme(theme) { 62 | if (this.themeCount > 1 || force == true) { 63 | for (let i = 0; i < this.themes.length; i++) { 64 | if (this.themes[i].id == theme.id) { 65 | this.themes.splice(i, 1); 66 | this.themeCount--; 67 | if (this.activeTheme.id == theme.id) { 68 | this.setActiveTheme(this.themes[0]); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | deleteThemes(themes) { 76 | if (this.themeCount > 1) { 77 | for (let i = 0; i < themes.length; i++) { 78 | this.deleteTheme(themes[i]); 79 | } 80 | } 81 | } 82 | 83 | genCSS(css) { 84 | var style = document.createElement("style"); 85 | style.innerHTML = css; 86 | style.disabled = true; 87 | document.head.appendChild(style); 88 | return style; 89 | } 90 | 91 | genCSSFile(url, enabled) { 92 | for (let i = 0; i < this.themes.length; i++) { 93 | if ( 94 | this.themes[i].getCSSElem() && 95 | this.themes[i].getCSSElem().href == url 96 | ) { 97 | console.error("A theme with the url " + url + " already exists!"); 98 | return; 99 | } 100 | } 101 | var link = document.createElement("link"); 102 | link.rel = "stylesheet"; 103 | link.href = url; 104 | document.head.appendChild(link); 105 | link.disabled = true; 106 | if (enabled) link.disabled = false; 107 | return link; 108 | } 109 | 110 | getConfig() { 111 | return this.config; 112 | } 113 | } 114 | 115 | class Theme { 116 | constructor(elem, name) { 117 | if (typeof elem == "object") { 118 | this.csselem = elem; 119 | } else { 120 | this.url = elem; 121 | } 122 | this.store = elem; 123 | this.name = name; 124 | // check for a duplicate theme 125 | for (let i = 0; i < tHs.getThemes().length; i++) { 126 | if (tHs.getThemes()[i].getName() == this.name) { 127 | console.error( 128 | "A theme with the name " + this.name + " already exists!" 129 | ); 130 | delete this; 131 | return; 132 | } 133 | } 134 | } 135 | 136 | apply() { 137 | if (typeof this.store == "object") { 138 | this.csselem.disabled = false; 139 | } else { 140 | this.csselem = tHs.genCSSFile(this.url, true); 141 | } 142 | } 143 | 144 | disable() { 145 | if (typeof this.store == "object") { 146 | this.csselem.disabled = true; 147 | } else { 148 | this.csselem.remove(); 149 | this.csselem = null; 150 | } 151 | } 152 | 153 | setName(name) { 154 | this.name = name; 155 | } 156 | 157 | getName() { 158 | return this.name; 159 | } 160 | 161 | getURL() { 162 | return this.url; 163 | } 164 | 165 | setURL(url) { 166 | this.url = url; 167 | } 168 | 169 | getCSSElem() { 170 | return this.csselem; 171 | } 172 | 173 | setCSSElem(elem) { 174 | this.csselem = elem; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "builds": [ 3 | { 4 | "src": "index.mjs", 5 | "use": "@vercel/node" 6 | } 7 | ], 8 | "routes": [ 9 | { 10 | "src": "/(.*)", 11 | "dest": "index.mjs" 12 | } 13 | ] 14 | } 15 | --------------------------------------------------------------------------------