Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"webpack-dev-server": "^5.2.4"
},
"dependencies": {
"@mercuryworkshop/scramjet": "^1.1.0"
"@mercuryworkshop/scramjet": "^1.1.0",
"idb": "^8.0.3"
}
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<script src="https://unpkg.com/@mercuryworkshop/bare-mux@2.1.9/dist/index.js"></script>
<script src="https://unpkg.com/@titaniumnetwork-dev/ultraviolet@3.2.8/dist/uv.bundle.js"></script>
<script src="https://cdn.jsdelivr.net/gh/luminsdk/script@latest/lumin.min.js"></script>
<script src="https://unpkg.com/@mercuryworkshop/scramjet@1.1.0/dist/scramjet.all.js"></script>
<script
defer
src="https://cdn.jsdelivr.net/npm/libcurl.js@0.7.1/libcurl.js"
Expand Down
42 changes: 35 additions & 7 deletions src/app/TabManager.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
import { Tab } from "./types";
import { homeDataURL } from "../components/StartPage";
import { PREFIX } from "./constants";
import { PREFIX, CURRENT_PROXY } from "./constants";
import { normalizeUrl } from "./utils";
import { checkLarp } from "./EasterEgg";
import logo from "../assets/logo.png";
import { openDB } from "idb";
import { sj } from "../index";

const dbPromise = openDB('SettingsDB', 1, {
upgrade(db) {
db.createObjectStore('settings');
},
});
const db = await dbPromise;
async function proxyFind() {
return await db.get('settings', 'deployable.proxy');
}

let tabs: Tab[] = [];
let activeTab: Tab | null = null;
let sjFrame;
let frame;

export function getTabs() { return tabs; }
export function getActiveTab() { return activeTab; }
export function setActiveTab(tab: Tab | null) { activeTab = tab; }

export function createTab(url: string = homeDataURL) {
export async function createTab(url: string = homeDataURL) {
const framesContainer = document.getElementById("frames-container") as HTMLDivElement;
const tabBar = document.getElementById("tab-bar") as HTMLDivElement;
const newTabBtn = document.getElementById("new-tab-btn") as HTMLButtonElement;
const urlBar = document.getElementById("url-bar") as HTMLInputElement;

const id = Math.random().toString(36).substring(2, 11);
const frame = document.createElement("iframe");
const sjFrame = sj.createFrame();
const frame = sjFrame.frame;
frame.className = "proxy-frame";
frame.id = `frame-${id}`;
framesContainer.appendChild(frame);
Expand All @@ -42,6 +57,7 @@ export function createTab(url: string = homeDataURL) {
historyIndex: -1,
frame,
tabElement,
sjFrame
};

tabs.push(tab);
Expand Down Expand Up @@ -74,9 +90,13 @@ export function createTab(url: string = homeDataURL) {
const encodedUrl = frameHref.substring(
frameHref.indexOf(PREFIX) + PREFIX.length,
);
const decodedUrl = (window as any).Ultraviolet.codec.xor.decode(
encodedUrl,
);
let decodedUrl;
if (CURRENT_PROXY === "choice-scram") {
const decodedUrl = decodeURIComponent(encodedUrl);
}
else {
const decodedUrl = (window as any).Ultraviolet.codec.xor.decode(encodedUrl);
}
if (decodedUrl && normalizeUrl(decodedUrl) !== normalizeUrl(tab.url)) {
tab.url = decodedUrl;
if (activeTab === tab) urlBar.value = decodedUrl;
Expand Down Expand Up @@ -158,7 +178,15 @@ export function loadTab(
tab.frame.src = homeDataURL;
} else {
if (activeTab === tab) urlBar.value = url;
const encodedUrl = (window as any).Ultraviolet.codec.xor.encode(url);
let encodedUrl: string;
// console.log(CURRENT_PROXY);
if (CURRENT_PROXY === "choice-scram") {
encodedUrl = encodeURIComponent(url);
}
else {
encodedUrl = (window as any).Ultraviolet.codec.xor.encode(url);
}
// console.log(encodedUrl);
tab.frame.src = PREFIX + encodedUrl;
checkLarp(url);
}
Expand Down
8 changes: 6 additions & 2 deletions src/app/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export const BASE = new URL("./", location.href).pathname;
export const PREFIX = BASE + "uv/service/";
import { proxyFind } from "./utils"
export const CURRENT_PROXY = await proxyFind();
export const BASE = new URL("./", location.href).pathname;
export const PREFIX = CURRENT_PROXY === "choice-scram"
? BASE + "scramjet/"
: BASE + "uv/service/";
export const DEFAULT_WISP = "wss://anura.pro/";
export const WISP_STORAGE_KEY = "deployable.wispServer";
1 change: 1 addition & 0 deletions src/app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface Tab {
historyIndex: number;
frame: HTMLIFrameElement;
tabElement: HTMLElement;
sjFrame: any;
}
11 changes: 11 additions & 0 deletions src/app/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DEFAULT_WISP, WISP_STORAGE_KEY } from "./constants";
import { openDB } from "idb";

export const getWispServer = () =>
localStorage.getItem(WISP_STORAGE_KEY) || DEFAULT_WISP;
Expand All @@ -13,3 +14,13 @@ export const normalizeUrl = (u: string) => {
return u;
}
};

export const proxyFind = async () => {
const dbPromise = openDB('SettingsDB', 1, {
upgrade(db) {
db.createObjectStore('settings');
},
});
const db = await dbPromise;
return await db.get('settings', 'deployable.proxy');
}
8 changes: 8 additions & 0 deletions src/components/UI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export function initUI(app: HTMLElement) {
<p class="settings-hint">WebSocket URL used for the proxy transport.</p>
</div>

<div class="settings-section">
<label for="proxy-choice">Proxy</label>
<div class="choice-actions">
<button id="choice-uv">Ultraviolet</button><button id="choice-scram">Scramjet</button>
</div>
<p class="settings-hint">Scramjet is newer and is still maintained. There are few reasons to choose Ultraviolet.</p>
</div>

<div class="settings-section">
<label>Data Management</label>
<div class="data-actions">
Expand Down
3 changes: 2 additions & 1 deletion src/games/GamesManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,5 @@ export async function loadGames(query = "", category = "", page = 1) {
} finally {
gamesLoader.style.display = "none";
}
}
}

7 changes: 4 additions & 3 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ declare module "*.svg";
declare module "*.woff2";
declare module "*.woff";

declare const $scramjetLoadController: () => any;
declare const BareMuxConnection: any;
declare const sj: any;
declare const $scramjetLoadController: any;
declare const $scramjetLoadClient: () => any;
declare const $scramjetLoadWorker: () => any;
declare const $scramjetVersion: any;
declare const Lumin: any;

declare const LibcurlTransport: any;
declare const LibcurlTransport: any;
78 changes: 76 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import { initUI } from "./components/UI";
import { createTab, getActiveTab, loadTab } from "./app/TabManager";
import { loadGames, getGamesState } from "./games/GamesManager";
import { exportData, importData } from "./app/SettingsManager";
import { openDB } from 'idb';

export let sj: any = null;

let bareMuxConnection: any = null;

async function applyTransport(wispUrl: string) {
if (!bareMuxConnection) return;
await bareMuxConnection.setTransport(
"https://unpkg.com/@mercuryworkshop/libcurl-transport@1/dist/index.mjs",
"https://unpkg.com/@mercuryworkshop/libcurl-transport@1.5.2/dist/index.mjs",
[
{
websocket: wispUrl,
Expand All @@ -23,16 +26,49 @@ async function applyTransport(wispUrl: string) {
}

async function init() {
await navigator.serviceWorker.register("pingas.js"); // change *this*
await navigator.serviceWorker.register("pingas.js", {scope: "/"}); // change *this*
await navigator.serviceWorker.ready;

bareMuxConnection = new (window as any).BareMux.BareMuxConnection(
BASE + "bare-mux-worker.js",
);

await applyTransport(getWispServer());
const { ScramjetController } = $scramjetLoadController();

sj = new ScramjetController({
prefix: BASE + "scramjet/",
files: {
wasm: "https://unpkg.com/@mercuryworkshop/scramjet@1.1.0/dist/scramjet.wasm.wasm",
all: "https://unpkg.com/@mercuryworkshop/scramjet@1.1.0/dist/scramjet.all.js",
sync: "https://unpkg.com/@mercuryworkshop/scramjet@1.1.0/dist/scramjet.sync.js"
},
codec: {
encode: (url: any) => encodeURIComponent(url),
decode: (url: any) => decodeURIComponent(url),
}
});
sj.init();
}

const dbPromise = openDB('SettingsDB', 1, {
upgrade(db) {
db.createObjectStore('settings');
},
});

async function loadProxyChoice() {
const db = await dbPromise;
const savedProxy = await db.get('settings', 'deployable.proxy');

if (savedProxy) {
const btn = document.getElementById(savedProxy);
if (btn) btn.classList.add('selected');
}
}

loadProxyChoice();

const app = document.getElementById("app");

if (app) {
Expand Down Expand Up @@ -123,19 +159,22 @@ if (app) {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
loadGames(gamesSearch.value);
return;
}, 400);
};

prevPageBtn.onclick = () => {
const { currentPage, selectedCategory } = getGamesState();
if (currentPage > 1)
loadGames(gamesSearch.value, selectedCategory, currentPage - 1);
// return;
};

nextPageBtn.onclick = () => {
const { currentPage, totalPages, selectedCategory } = getGamesState();
if (currentPage < totalPages)
loadGames(gamesSearch.value, selectedCategory, currentPage + 1);
// return;
};

const wispInput = document.getElementById(
Expand Down Expand Up @@ -171,6 +210,15 @@ if (app) {
const settingsOverlay = document.getElementById(
"settings-overlay",
) as HTMLDivElement;
const choiceScram = document.getElementById(
"choice-scram"
) as HTMLButtonElement;
const choiceUv = document.getElementById(
"choice-uv"
) as HTMLButtonElement;
const choiceBtns = document.querySelectorAll(
'.choice-actions button'
) as NodeListOf<HTMLButtonElement>;

settingsBtn.onclick = () => {
wispInput.value = getWispServer();
Expand All @@ -184,6 +232,13 @@ if (app) {
setWispServer(value);
await applyTransport(value);
settingsOverlay.style.display = "none";
const activeBtn = document.querySelector('.choice-actions button.selected') as HTMLButtonElement | null;
if (activeBtn) {
const db = await dbPromise;
await db.put('settings', activeBtn.id, 'deployable.proxy');
console.log('Settings saved to IndexedDB: deployable.proxy:' + activeBtn.id);
}
window.location.reload();
};
settingsReset.onclick = () => (wispInput.value = DEFAULT_WISP);
settingsOverlay.onclick = (e) => {
Expand All @@ -204,6 +259,25 @@ if (app) {
}
};

async function initProxySelection() {
const db = await dbPromise;
const storedProxyId = await db.get('settings', 'deployable.proxy');

choiceBtns.forEach((btn) => {
const shouldSelect = storedProxyId ? btn.id === storedProxyId : btn.id === 'choice-uv';

if (shouldSelect) {
btn.classList.add('selected');
}

btn.addEventListener('click', () => {
choiceBtns.forEach((b) => b.classList.remove('selected'));
btn.classList.add('selected');
});
});
}
initProxySelection();

exportBtn.onclick = exportData;
importBtn.onclick = () => importInput.click();
importInput.onchange = (e) => {
Expand Down
32 changes: 32 additions & 0 deletions src/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,38 @@ body {
margin: 0;
}

.choice-actions {
display: flex;
gap: 10px;
}

.choice-actions button {
flex: 1;
padding: 10px;
background: #1a1a1a;
border: 1px solid #333;
border-radius: 8px;
color: #fff;
cursor: pointer;
font-size: 13px;
transition: all 0.2s ease;
}

.choice-actions button:hover {
background: #222;
border-color: #444;
}

.choice-actions button.selected {
background: #2563eb;
border-color: #2563eb;
color: #fff;
}

.choice-actions button.selected:hover {
background: #1d4ed8;
}

.data-actions {
display: flex;
gap: 10px;
Expand Down
Loading
Loading