summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2024-02-04 13:37:54 +0100
committerRaindropsSys <raindrops@equestria.dev>2024-02-04 13:37:54 +0100
commite5e5aa2c92ce7694449c19b94dd2af0f41e93e3f (patch)
tree3ff3ebfd00400d5b5108368566d719194c3f6f5a
parent01a027a0a189389188eac692b309c21d690cd582 (diff)
downloadchatroom-e5e5aa2c92ce7694449c19b94dd2af0f41e93e3f.tar.gz
chatroom-e5e5aa2c92ce7694449c19b94dd2af0f41e93e3f.tar.bz2
chatroom-e5e5aa2c92ce7694449c19b94dd2af0f41e93e3f.zip
Updated 4 files, added 2 files and deleted bot.zip (automated)
-rw-r--r--bot.zipbin11173720 -> 0 bytes
-rwxr-xr-xbuild.js14
-rw-r--r--client/home.html62
-rw-r--r--client/icons/newtab.svg20
-rw-r--r--client/index.html140
-rwxr-xr-xclient/main.js996
-rw-r--r--launcher/client/index.html90
7 files changed, 869 insertions, 453 deletions
diff --git a/bot.zip b/bot.zip
deleted file mode 100644
index 3b1635c..0000000
--- a/bot.zip
+++ /dev/null
Binary files differ
diff --git a/build.js b/build.js
index b509ba5..9a3551d 100755
--- a/build.js
+++ b/build.js
@@ -40,6 +40,16 @@ function scandir(path) {
let list = scandir("./client");
let pack = [];
+function processFile(item) {
+ if (item.endsWith("main.js")) {
+ let data = fs.readFileSync(item).toString();
+ data = data.replace(/\/\/ --- >START< @BUILDNUMBER@ >START< --- \/\/\n((.|\n)*)\n\/\/ --- >FINAL< @BUILDNUMBER@ >FINAL< --- \/\/\n\n/gm, "// --- >START< @BUILDNUMBER@ >START< --- //\nconst buildNumber = \"" + new Date().toISOString().split("T")[0] + "\";\n// --- >FINAL< @BUILDNUMBER@ >FINAL< --- //\n\n");
+ return Buffer.from(data);
+ } else {
+ return fs.readFileSync(item);
+ }
+}
+
for (let item of list) {
if (fs.lstatSync(item).isDirectory()) {
pack.push({
@@ -51,8 +61,8 @@ for (let item of list) {
pack.push({
type: "file",
name: item,
- content: zlib.brotliCompressSync(fs.readFileSync(item)).toString("base64"),
- hash: crypto.createHash("sha256").update(fs.readFileSync(item)).digest("base64")
+ content: zlib.brotliCompressSync(processFile(item)).toString("base64"),
+ hash: crypto.createHash("sha256").update(processFile(item)).digest("base64")
});
}
}
diff --git a/client/home.html b/client/home.html
new file mode 100644
index 0000000..617a042
--- /dev/null
+++ b/client/home.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>New Tab</title>
+ <link rel="icon" href="./icons/newtab.svg">
+ <link href="./bs.css" rel="stylesheet">
+ <script src="./bs.js"></script>
+ <style>
+ @media (prefers-color-scheme: dark) {
+ main {
+ filter: invert(1) hue-rotate(180deg);
+ background-color: #ddd !important;
+ }
+ }
+ </style>
+</head>
+<body>
+ <main style="background-color: #eee; position: fixed; inset: 0; overflow: auto;">
+ <div style="margin-left: auto; margin-right: auto; width: max-content; margin-top: 50px;">
+ <img src="./icon.png" style="filter: invert(1) hue-rotate(180deg); width: 96px; vertical-align: middle;">
+ <span style="vertical-align: middle; margin-left: 20px; font-size: 36px;">Chatroom</span>
+ </div>
+ <form action="https://duckduckgo.com">
+ <input type="text" name="q" class="form-control" placeholder="Search the web without being tracked" style="margin-top: 50px; width: 50%; margin-left: auto; margin-right: auto;">
+ </form>
+
+ <div class="container" style="margin-top: 50px; margin-bottom: 50px;">
+ <hr style="margin-bottom: 30px;">
+
+ <h3>What's new in Chatroom?</h3>
+
+ <h5>Chatroom 2.6.0</h5>
+ <ul>
+ <li>Fixed a bug that was causing some buttons to be hidden below the window controls on Windows</li>
+ <li>Fixed a bug that was causing the window controls on Windows to show up in light theme even when dark theme is on</li>
+ <li>Fixed a bug that was causing an error message to show up when pressing Ctrl/Cmd+W on Chrome Dev Tools</li>
+ <li>Introduced a new launcher experience</li>
+ <li>Improved dark theme support introduced in version 2.5.0</li>
+ <li>Fixed a bug where some websites would show a broken tab icon</li>
+ <li>Made the tab bar shrink, so you can open a lot more tabs at once (about 30 with the default window size)</li>
+ <li>Added a new home page, replacing the DuckDuckGo homepage</li>
+ <li>Added a confirmation dialog when closing Chatroom</li>
+ <li>A basic right click menu has been added, giving you the option to (for example) open links in new tabs</li>
+ </ul>
+
+ <h5>Chatroom 2.5.1</h5>
+ <ul>
+ <li>Fixed a bug that prevented accessing the chat</li>
+ </ul>
+
+ <h5>Chatroom 2.5.0</h5>
+ <ul>
+ <li>Added dark theme support</li>
+ <li>Added an option to turn the built-in ad blocker on or off</li>
+ <li>Fixed a bug that was making it possible to scroll the main browser UI</li>
+ <li>Added new modern icons</li>
+ </ul>
+ </div>
+ </main>
+</body>
+</html> \ No newline at end of file
diff --git a/client/icons/newtab.svg b/client/icons/newtab.svg
new file mode 100644
index 0000000..bb30c5f
--- /dev/null
+++ b/client/icons/newtab.svg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 256 256" style="enable-background:new 0 0 256 256;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#1ABCB900;}
+ .st1{fill:#000000;}
+</style>
+<path class="st0" d="M218.63,256H37.37C16.73,256,0,239.27,0,218.63V37.37C0,16.73,16.73,0,37.37,0h181.26
+ C239.27,0,256,16.73,256,37.37v181.26C256,239.27,239.27,256,218.63,256z"/>
+<path class="st1" d="M66.51,186.68c-3.75-2.02-6.68-4.84-8.77-8.44c-2.09-3.61-3.14-7.51-3.14-11.69v-45.47l-22.73-12.55
+ c-2.04-1.14-3.53-2.56-4.45-4.27c-0.93-1.71-1.39-3.6-1.39-5.69c0-2.02,0.46-3.92,1.39-5.71c0.93-1.79,2.41-3.27,4.45-4.47
+ l78.81-43.09c1.73-1.01,3.52-1.73,5.36-2.17s3.74-0.65,5.68-0.65c1.94,0,3.83,0.22,5.68,0.65c1.84,0.43,3.63,1.15,5.36,2.17
+ l91.37,49.8c1.86,0.95,3.29,2.32,4.32,4.13c1.02,1.8,1.53,3.75,1.53,5.83v61.06c0,3.18-1.12,5.88-3.36,8.12
+ c-2.24,2.24-4.94,3.36-8.12,3.36c-3.18,0-5.88-1.12-8.12-3.36c-2.24-2.24-3.36-4.94-3.36-8.12v-55.21l-18.19,10.18v45.47
+ c0,4.19-1.05,8.08-3.14,11.69c-2.09,3.61-5.02,6.42-8.77,8.44l-44.17,24.03c-1.73,1.01-3.52,1.73-5.36,2.17
+ c-1.84,0.43-3.74,0.65-5.68,0.65c-1.94,0-3.83-0.22-5.68-0.65c-1.84-0.43-3.63-1.15-5.36-2.17L66.51,186.68z M121.72,131.25
+ l60.63-32.91l-60.63-32.69L61.31,98.34L121.72,131.25z M121.72,190.36l44.17-23.82v-33.56l-33.13,18.4c-1.73,1.01-3.5,1.73-5.3,2.17
+ c-1.8,0.43-3.72,0.65-5.74,0.65c-2.02,0-3.93-0.22-5.74-0.65s-3.57-1.15-5.3-2.17l-33.13-18.4v33.56L121.72,190.36z"/>
+</svg>
diff --git a/client/index.html b/client/index.html
index 0e59212..d95083f 100644
--- a/client/index.html
+++ b/client/index.html
@@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<title>Chatroom Workspace</title>
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
+ <link href="./bs.css" rel="stylesheet">
+ <script src="./bs.js"></script>
<style>
* {
-webkit-user-drag: none;
@@ -63,6 +63,10 @@
filter: invert(1) hue-rotate(180deg);
}
+ #changelog {
+ filter: invert(1) hue-rotate(180deg);
+ }
+
.nav-link.active {
background-color: #ddd !important;
border-bottom: none !important;
@@ -71,16 +75,51 @@
img:not([src$=".svg"]) {
filter: invert(1) hue-rotate(180deg);
}
+
+ #windows, body {
+ background-color: #111111;
+ }
+
+ webview {
+ background-color: #111;
+ }
+ }
+
+ .small-1 .tab-text {
+ width: 100px !important;
+ }
+
+ .small-2 .tab-text {
+ width: 50px !important;
+ }
+
+ .small-3 .tab-text {
+ opacity: 0 !important;
+ width: 7px !important;
+ }
+
+ .small-4 .tab-text, .small-4 .tab-close {
+ display: none !important;
+ }
+
+ .small-5 .nav-link {
+ padding: 0.5rem !important;
+ }
+
+ .small-6 .nav-link img {
+ width: 16px !important;
+ height: 24px !important;
+ padding: 4px 0 !important;
}
</style>
</head>
-<body style="overflow-y: hidden;">
+<body style="overflow: hidden;">
<ul id="tabs" class="nav nav-tabs" style="background-color: #eee; -webkit-app-region: drag;"></ul>
<script>
if (process.platform === "darwin") {
document.getElementById("tabs").style.paddingLeft = "86px";
} else {
- document.getElementById("tabs").style.paddingRight = "96px";
+ document.getElementById("tabs").style.paddingRight = "140px";
}
</script>
<div id="windows" style="display: flex;"></div>
@@ -122,7 +161,7 @@
document.getElementById("tabs").innerHTML = `<div style="display: grid; grid-template-columns: 1fr max-content; width: 100%;"><span>` + window.tabs.map((i, j) => `
<li class="nav-item ${i.chat ? 'pinned' : ''}" style="width: max-content; display: inline-block;">
- <a class="nav-link ${j === window.activeTab ? 'active' : ''}" aria-current="page" href="#" onclick="if (event.target.classList.contains('nav-link')) switchToTab(${j});"><img style="width: 24px; height: 24px; pointer-events: none;" alt="" src="${i.icon}"><span class="tab-text" onclick="switchToTab(${j});" style="vertical-align: middle; margin-left: 5px; width: 171px; display: inline-block; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis">${i.name}</span><span class="tab-close" style="display: inline-block;" onclick="event.preventDefault(); closeTab(${j});"><img alt="" src="./icons/dismiss.svg"></span></a>
+ <a class="nav-link ${j === window.activeTab ? 'active' : ''}" aria-current="page" href="#" onclick="if (event.target.classList.contains('nav-link')) switchToTab(${j});"><img onerror="event.target.src = './icons/placeholder.svg';" style="width: 24px; height: 24px; pointer-events: none;" alt="" src="${i.icon}"><span class="tab-text" onclick="switchToTab(${j});" style="vertical-align: middle; margin-left: 5px; width: 171px; display: inline-block; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis">${i.name}</span><span class="tab-close" style="display: inline-block;" onclick="event.preventDefault(); closeTab(${j});"><img alt="" src="./icons/dismiss.svg"></span></a>
</li>
`).join("") + `<li class="nav-item" style="width: max-content; display: inline-block;">
<a class="nav-link" aria-current="page" href="#" onclick="openHome();"><img alt="" src="./icons/new.svg"></a>
@@ -130,6 +169,68 @@
<a class="nav-link" aria-current="page" href="#" onclick="toggleProtection();"><img id="ad-protection-img" alt="" src="./icons/${window.protectionEnabled ? 'shield-on' : 'shield-off'}.svg"></a>
</li></span></div>`;
if (tabs[window.activeTab]) document.title = tabs[window.activeTab].name + " · Chatroom Workspace";
+
+ secureTabHeight();
+ }
+
+ let lastTabHeightUpdateCount = tabs.length;
+
+ function secureTabHeight(force) {
+ let first = false;
+ let i = 0;
+
+ while ((!first || document.getElementById("tabs").clientHeight > 43) && i < 10) {
+ if (document.getElementById("tabs").clientHeight > 43 && !document.getElementById("tabs").classList.contains("small-1")) {
+ document.getElementById("tabs").classList.add("small-1");
+ } else if (document.getElementById("tabs").clientHeight > 43 && !document.getElementById("tabs").classList.contains("small-2")) {
+ document.getElementById("tabs").classList.add("small-1");
+ document.getElementById("tabs").classList.add("small-2");
+ } else if (document.getElementById("tabs").clientHeight > 43 && !document.getElementById("tabs").classList.contains("small-3")) {
+ document.getElementById("tabs").classList.add("small-1");
+ document.getElementById("tabs").classList.add("small-2");
+ document.getElementById("tabs").classList.add("small-3");
+ } else if (document.getElementById("tabs").clientHeight > 43 && !document.getElementById("tabs").classList.contains("small-4")) {
+ document.getElementById("tabs").classList.add("small-1");
+ document.getElementById("tabs").classList.add("small-2");
+ document.getElementById("tabs").classList.add("small-3");
+ document.getElementById("tabs").classList.add("small-4");
+ } else if (document.getElementById("tabs").clientHeight > 43 && !document.getElementById("tabs").classList.contains("small-5")) {
+ document.getElementById("tabs").classList.add("small-1");
+ document.getElementById("tabs").classList.add("small-2");
+ document.getElementById("tabs").classList.add("small-3");
+ document.getElementById("tabs").classList.add("small-4");
+ document.getElementById("tabs").classList.add("small-5");
+ } else if (document.getElementById("tabs").clientHeight > 43 && !document.getElementById("tabs").classList.contains("small-6")) {
+ document.getElementById("tabs").classList.add("small-1");
+ document.getElementById("tabs").classList.add("small-2");
+ document.getElementById("tabs").classList.add("small-3");
+ document.getElementById("tabs").classList.add("small-4");
+ document.getElementById("tabs").classList.add("small-5");
+ document.getElementById("tabs").classList.add("small-6");
+ } else {
+ if (force || tabs.length < lastTabHeightUpdateCount) {
+ document.getElementById("tabs").classList.remove("small-1");
+ document.getElementById("tabs").classList.remove("small-2");
+ document.getElementById("tabs").classList.remove("small-3");
+ document.getElementById("tabs").classList.remove("small-4");
+ document.getElementById("tabs").classList.remove("small-5");
+ document.getElementById("tabs").classList.remove("small-6");
+ }
+ }
+
+ first = true;
+ i++;
+ }
+
+ if (i >= 10) {
+ closeTab(tabs.length - 1);
+ }
+
+ lastTabHeightUpdateCount = tabs.length;
+ }
+
+ window.onresize = () => {
+ secureTabHeight(true);
}
function reloadWebview(force) {
@@ -152,19 +253,20 @@
}
function resetURL(id) {
- if (document.getElementById("wv-item-" + id + "-inner").getURL() === "https://start.duckduckgo.com/") {
+ if (document.getElementById("wv-item-" + id + "-inner").getURL().startsWith("file://") && document.getElementById("wv-item-" + id + "-inner").getURL().endsWith("/home.html")) {
document.getElementById("wv-item-" + id + "-bar-address").value = "";
} else {
document.getElementById("wv-item-" + id + "-bar-address").value = document.getElementById("wv-item-" + id + "-inner").getURL();
}
}
- function openTab(url) {
+ function openTab(url, focusSearchBar) {
let container = document.createElement("div");
let webview = document.createElement("webview");
+
let tab = {
icon: "./icons/placeholder.svg",
- name: "Unnamed tab",
+ name: "New Tab",
url,
webview: container,
id: crypto.randomUUID(),
@@ -200,6 +302,12 @@
webview.id = "wv-item-" + tab.id + "-inner";
container.id = "wv-item-" + tab.id;
container.classList.add("wv-container");
+ webview.addEventListener('devtools-open-url', (e) => {
+ openTab(e.url);
+ });
+ webview.addEventListener('close', () => {
+ closeTab(tabs.map((i, j) => [i, j]).filter(i => i[0].id === tab.id)[0][1]);
+ });
webview.addEventListener('page-title-updated', (e) => {
if (webview.getURL().startsWith("https://school.equestria.dev/")) {
tab.name = "Chat";
@@ -209,6 +317,9 @@
refreshTabBar();
});
+ webview.addEventListener('context-menu', (e) => {
+ ipcRenderer.send('menu', e.params);
+ });
webview.addEventListener('page-favicon-updated', (e) => {
if (webview.getURL().startsWith("https://school.equestria.dev/")) {
tab.icon = "./icons/chat.svg";
@@ -242,6 +353,7 @@
document.getElementById('wv-item-' + tab.id + '-bar-address').onkeydown = (e) => {
if (e.code === "Return" || e.code === "Enter") {
loadURL(tab.id);
+ document.getElementById('wv-item-' + tab.id + '-bar-address').blur();
}
}
@@ -249,6 +361,10 @@
refreshTabBar();
switchToTab(tabs.length - 1);
+
+ if (focusSearchBar) {
+ document.getElementById("wv-item-" + tab.id + "-bar-address").focus();
+ }
}
function switchToTab(id) {
@@ -274,7 +390,7 @@
}
function openHome() {
- openTab("https://start.duckduckgo.com");
+ openTab("./home.html", true);
}
function closeTab(id) {
@@ -335,8 +451,10 @@
}
}
- openTab("https://school.equestria.dev");
- openHome();
+ window.onload = () => {
+ openTab("https://school.equestria.dev");
+ openHome();
+ }
</script>
</body>
</html> \ No newline at end of file
diff --git a/client/main.js b/client/main.js
index 0586b46..000d903 100755
--- a/client/main.js
+++ b/client/main.js
@@ -1,407 +1,591 @@
-const { app, BrowserWindow, webContents, globalShortcut, ipcMain, session, dialog, MenuItem, Menu, desktopCapturer, clipboard, nativeImage } = require('electron');
-const path = require('path');
-const os = require("os");
-const {appendFileSync, writeFileSync, existsSync, unlinkSync} = require("fs");
-const fs = require("fs");
-
-try {
- if (!app.getAppPath().endsWith("/launcher/client")) writeFileSync(app.getAppPath() + "/index.html", `
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <title>Chatroom</title>
- <style>
- #loader-circle-1, #loader-circle-2, #loader-circle-3 {
- animation-name: opacity;
- animation-timing-function: linear;
- animation-duration: 1.2s;
- animation-fill-mode: forwards;
- animation-iteration-count: infinite;
- }
-
- #loader-circle-2 {
- animation-delay: .25s;
- }
-
- #loader-circle-3 {
- animation-delay: .5s;
- }
-
- @keyframes opacity {
- 0% {
- opacity: 0;
- }
- 50% {
- opacity: 1;
- }
- 100% {
- opacity: 0;
- }
- }
- </style>
- <script>
- const { ipcRenderer } = require('electron');
-
- ipcRenderer.on('local', (_, data) => {
- loadApp(data);
- });
-
- ipcRenderer.on('download', (_) => {
- download();
- });
-
- function download() {
- document.getElementById("status").innerText = "Downloading application... 0%";
-
- const axios = require('./node_modules/axios/dist/node/axios.cjs');
- const fs = require("fs");
- const zlib = require("zlib");
- const crypto = require("crypto");
-
- let tempDir = require('@electron/remote').app.getPath('userData') + "/Chatroom";
- if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true });
- fs.mkdirSync(tempDir);
-
- function downloadClient() {
- return new Promise(async (res) => {
- const response = await axios({
- url: "http://51.68.173.117:21938/update/client.lctpk?_" + require('crypto').randomBytes(64).toString("hex"),
- method: 'GET',
- responseType: 'blob',
- onDownloadProgress: (event) => {
- document.getElementById("status").innerText = "Downloading application... " + Math.round(((event.loaded / event.total) / 2) * 100) + "%";
- }
- });
-
- document.getElementById("status").innerText = "Extracting...";
-
- res(JSON.parse(zlib.brotliDecompressSync(Buffer.from(await response.data.arrayBuffer())).toString()).map(i => {
- if (i['content']) i['content'] = zlib.brotliDecompressSync(Buffer.from(i['content'], "base64"));
- if (i['hash']) i['hash'] = crypto.createHash("sha256").update(i['content']).digest("base64") === i['hash'];
- return i;
- }));
- });
- }
-
- (async () => {
- let _client = await downloadClient();
- let files = [..._client];
-
- document.getElementById("status").innerText = "Installing application... 0%";
- let total = files.length;
- let index = 0;
-
- for (let file of files) {
- if (file.type === "file" && !file.hash) {
- alert("Unable to continue: file " + file.name + " is corrupted");
- window.close();
- }
-
- if (file.type === "file") {
- fs.writeFileSync(tempDir + "/" + file.name, file.content);
- } else {
- if (!fs.existsSync(tempDir + "/" + file.name)) fs.mkdirSync(tempDir + "/" + file.name);
- }
-
- index++;
- document.getElementById("status").innerText = "Installing application... " + Math.round((index / total) * 100) + "%";
- }
-
- document.getElementById("status").innerText = "Starting...";
-
- loadApp(tempDir + "/client");
- })();
- }
-
- function loadApp(path) {
- ipcRenderer.send("start", path);
- }
-
- //alert("Automatic updates could work on this system! Please click on OK and tell Raindrops.");
- </script>
-</head>
-<body style="margin: 0; user-select: none;">
- <div style="position: fixed; inset: 0; z-index: 9999; -webkit-app-region: drag;"></div>
-
- <div style="position: fixed; inset: 0; z-index: 999; display: flex; align-items: center; justify-content: center; text-align: center;">
- <div>
- <svg style="opacity: .25;" id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.96 171.05">
- <defs>
- <style>
- .cls-1 {
- fill: #fff;
- }
- </style>
- </defs>
- <path class="cls-1" d="M40.49,144.2c-3.75-2.02-6.68-4.84-8.77-8.44-2.09-3.61-3.14-7.51-3.14-11.69v-45.47l-22.73-12.55c-2.04-1.14-3.53-2.56-4.45-4.27-.93-1.71-1.39-3.6-1.39-5.69s.46-3.92,1.39-5.71c.93-1.79,2.41-3.27,4.45-4.47L84.66,2.81c1.73-1.01,3.52-1.73,5.36-2.17s3.74-.65,5.68-.65,3.83,.22,5.68,.65,3.63,1.15,5.36,2.17l91.37,49.8c1.86,.95,3.29,2.32,4.32,4.13,1.02,1.8,1.53,3.75,1.53,5.83v61.06c0,3.18-1.12,5.88-3.36,8.12s-4.94,3.36-8.12,3.36-5.88-1.12-8.12-3.36c-2.24-2.24-3.36-4.94-3.36-8.12v-55.21l-18.19,10.18v45.47c0,4.19-1.05,8.08-3.14,11.69-2.09,3.61-5.02,6.42-8.77,8.44l-44.17,24.03c-1.73,1.01-3.52,1.73-5.36,2.17-1.84,.43-3.74,.65-5.68,.65s-3.83-.22-5.68-.65c-1.84-.43-3.63-1.15-5.36-2.17l-44.17-24.03Zm55.21-55.43l60.63-32.91L95.7,23.17,35.29,55.86l60.41,32.91Zm0,59.11l44.17-23.82v-33.56l-33.13,18.4c-1.73,1.01-3.5,1.73-5.3,2.17-1.8,.43-3.72,.65-5.74,.65s-3.93-.22-5.74-.65-3.57-1.15-5.3-2.17l-33.13-18.4v33.56l44.17,23.82Z"/>
- </svg>
- <br>
- <p style="color: white; opacity: .25; font-family: system-ui, -apple-system, sans-serif;" id="status">Starting...</p>
- </div>
- </div>
-</body>
-</html>
-`);
-} catch (e) {
- console.error(e);
-}
-
-const { ElectronBlocker } = require('@cliqz/adblocker-electron');
-const { fetch } = require('cross-fetch');
-
-ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => {
- global.blocker = blocker;
-});
-
-ipcMain.on('enable-protection', () => {
- let waiter = setInterval(() => {
- if (global.blocker) {
- clearInterval(waiter);
- try { global.blocker.enableBlockingInSession(session.defaultSession); } catch (e) {
- console.error(e);
- }
- }
- });
-});
-
-ipcMain.on('disable-protection', () => {
- let waiter = setInterval(() => {
- if (global.blocker) {
- clearInterval(waiter);
- try { global.blocker.disableBlockingInSession(session.defaultSession); } catch (e) {
- console.error(e);
- }
- }
- });
-});
-
-session.defaultSession.setUserAgent(session.defaultSession.getUserAgent().replace(/(.*)( Electron\/(.*) )/gm, "$1 ") + " Chatroom/1.0.0");
-
-let localchatDataRoot = (os.platform() === "win32" ? os.homedir() + "/AppData/Roaming" : (os.platform() === "darwin" ? os.homedir() + "/Library/Application Support" : os.homedir())) + (os.platform() === "darwin" ? "/ChatroomWorkspace" : "/.chatroom-workspace");
-
-if (!fs.existsSync(localchatDataRoot)) fs.mkdirSync(localchatDataRoot);
-if (!fs.existsSync(localchatDataRoot + "/session")) fs.mkdirSync(localchatDataRoot + "/session");
-if (!fs.existsSync(localchatDataRoot + "/data")) fs.mkdirSync(localchatDataRoot + "/data");
-if (!fs.existsSync(localchatDataRoot + "/logs")) fs.mkdirSync(localchatDataRoot + "/logs");
-
-app.setPath("userData", localchatDataRoot + "/data");
-app.setPath("sessionData", localchatDataRoot + "/session");
-app.setAppLogsPath(localchatDataRoot + "/logs");
-
-if (require('os').platform() !== "darwin" && require('os').platform() !== "win32" && require('os').platform() !== "linux") return;
-global.windows = [];
-
-if (!global._localchatPath) {
- global.nextGenChatroom = true;
- global._localchatPath = __dirname;
-}
-
-const createWindow = () => {
- app.setPath("userData", localchatDataRoot);
- app.setPath("sessionData", localchatDataRoot + "/session");
- app.setAppLogsPath(localchatDataRoot + "/logs");
-
- global.mainWindow = new BrowserWindow({
- width: 1280,
- minWidth: 300,
- height: 720,
- minHeight: 300,
- titleBarStyle: "hidden",
- titleBarOverlay: {
- color: "#eeeeee",
- symbolColor: "#222222",
- height: 43
- },
- trafficLightPosition: {
- x: 15,
- y: 15
- },
- icon: require('os').platform() === "darwin" ? "./icon.icns" : (require('os').platform() === "linux" ? "./icon.png" : "./icon.ico"),
- show: false,
- fullscreenable: false,
- autoHideMenuBar: true,
- webPreferences: {
- nodeIntegration: true,
- contextIsolation: false,
- additionalArguments: "--user-data-dir=\"" + localchatDataRoot + "/client" + "\"",
- webviewTag: true
- }
- });
-
- if (global.nextGenChatroom) {
- mainWindow.loadFile(global._localchatPath + "/index.html");
- } else {
- mainWindow.loadFile(global._localchatPath + "/block.html");
- }
-
- let menu = Menu.buildFromTemplate([
- ...(process.platform === "darwin" ? [
- {
- role: "appMenu",
- }
- ] : []),
- {
- type: "submenu",
- label: "File",
- submenu: [
- {
- label: "New Tab",
- click: (_, win) => {
- win.webContents.executeJavaScript('window.openHome();');
- },
- accelerator: "CmdOrCtrl+T"
- },
- {
- label: "Switch to Next Tab",
- click: (_, win) => {
- win.webContents.executeJavaScript('window.switchRight();');
- },
- accelerator: "Ctrl+Tab"
- },
- {
- label: "Switch to Previous Tab",
- click: (_, win) => {
- win.webContents.executeJavaScript('window.switchLeft();');
- },
- accelerator: "Ctrl+Shift+Tab"
- },
- {
- label: "Close Tab",
- click: (_, win) => {
- win.webContents.executeJavaScript('window.closeCurrentTab();');
- },
- accelerator: "CmdOrCtrl+W"
- }
- ]
- },
- {
- role: "editMenu"
- },
- {
- type: "submenu",
- label: "View",
- submenu: [
- {
- label: "Host",
- submenu: [
- {
- role: "reload",
- label: "Reload",
- accelerator: "CmdOrCtrl+Alt+R"
- },
- {
- role: "forceReload",
- label: "Force Reload",
- accelerator: "CmdOrCtrl+Shift+Alt+R"
- },
- {
- role: "toggleDevTools",
- label: "Toggle Developer Tools",
- accelerator: "CmdOrCtrl+Alt+Shift+I"
- }
- ]
- },
- {
- label: "Renderer",
- submenu: [
- {
- label: "Reload",
- accelerator: "CmdOrCtrl+R",
- click: () => {
- mainWindow.webContents.executeJavaScript('window.reloadWebview(false);');
- }
- },
- {
- label: "Force Reload",
- accelerator: "CmdOrCtrl+Shift+R",
- click: () => {
- mainWindow.webContents.executeJavaScript('window.reloadWebview(true);');
- }
- },
- {
- label: "Toggle Developer Tools",
- accelerator: "CmdOrCtrl+Alt+I",
- click: () => {
- mainWindow.webContents.executeJavaScript('window.openDevTools();');
- }
- }
- ]
- },
- {
- type: "separator"
- },
- {
- role: "resetZoom"
- },
- {
- role: "zoomIn"
- },
- {
- role: "zoomOut"
- },
- {
- type: "separator"
- },
- {
- role: "togglefullscreen"
- }
- ]
- },
- {
- role: "windowMenu"
- }
- ]);
-
- mainWindow.setMenu(menu);
- Menu.setApplicationMenu(menu);
-
- mainWindow.webContents.setWindowOpenHandler(() => {
- return {
- action: "deny"
- }
- });
-
- windows.push(mainWindow);
- if (os.platform() === "win32") mainWindow.setContentProtection(true);
-
- ipcMain.on('setupIcon', (e, id, index) => {
- webContents.fromId(id).on('page-favicon-updated', (e, icons) => {
- mainWindow.send("favicon", {
- index,
- icons
- });
- })
- });
-
- mainWindow.once('ready-to-show', () => {
- mainWindow.show();
- try { loaderWindow.close(); } catch (e) {}
- });
-}
-
-app.whenReady().then(() => {
- globalShortcut.register('Alt+CommandOrControl+C', () => {
- for (let window of windows) {
- try {
- if (!window.isVisible()) {
- window.show();
- if (process.platform === "darwin") app.dock.show();
- } else {
- window.hide();
- if (process.platform === "darwin") app.dock.hide();
- }
- } catch (e) {}
- }
- });
-
- createWindow();
-
- app.on('activate', () => {
- if (BrowserWindow.getAllWindows().length === 0) createWindow();
- });
-});
-
-app.on('window-all-closed', () => {
- if (process.platform !== 'darwin' || !global.nextGenChatroom) app.quit();
+// --- >START< @BUILDNUMBER@ >START< --- //
+const buildNumber = "main";
+// --- >FINAL< @BUILDNUMBER@ >FINAL< --- //
+
+const version = "2.6.0";
+
+const { app, BrowserWindow, webContents, globalShortcut, nativeTheme, ipcMain, session, dialog, MenuItem, Menu, desktopCapturer, clipboard, nativeImage } = require('electron');
+const path = require('path');
+const os = require("os");
+const {appendFileSync, writeFileSync, existsSync, unlinkSync} = require("fs");
+const fs = require("fs");
+
+app.setName("Chatroom");
+app.setAboutPanelOptions({
+ applicationName: "Chatroom",
+ applicationVersion: version,
+ copyright: "Copyright © 2023-" + new Date().getFullYear() + " Equestria.dev. Released under the MIT License.",
+ version: buildNumber
+});
+
+try {
+ if (!app.getAppPath().endsWith("/launcher/client")) writeFileSync(app.getAppPath() + "/index.html", `
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Chatroom</title>
+ <style>
+ @keyframes loaded-1 {
+ 0% {
+ background-color: #111111;
+ }
+
+ 100% {
+ background-color: #1ABCB9;
+ }
+ }
+
+ @keyframes loaded-2 {
+ 0% {
+ opacity: .3;
+ filter: drop-shadow(0 0 0 transparent);
+ }
+
+ 100% {
+ opacity: 1;
+ filter: drop-shadow(0 0 15px rgba(0, 0, 0, .5));
+ }
+ }
+
+ body.loaded {
+ animation-name: loaded-1;
+ animation-duration: .5s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ animation-play-state: running;
+ animation-timing-function: ease-in-out;
+ }
+
+ body.loaded #ic {
+ animation-name: loaded-2;
+ animation-duration: .5s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ animation-play-state: running;
+ animation-timing-function: ease-in-out;
+ }
+ </style>
+ <script>
+ const { ipcRenderer } = require('electron');
+
+ ipcRenderer.on('local', (_, data) => {
+ download(data);
+ });
+
+ ipcRenderer.on('download', (_) => {
+ download(null);
+ });
+
+ function download(data) {
+ const axios = require('./node_modules/axios/dist/node/axios.cjs');
+ const fs = require("fs");
+ const zlib = require("zlib");
+ const crypto = require("crypto");
+
+ let tempDir = require('@electron/remote').app.getPath('userData') + "/Chatroom";
+ if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true });
+ fs.mkdirSync(tempDir);
+
+ function downloadClient() {
+ document.getElementById("progress-outer").style.display = "";
+
+ return new Promise(async (res) => {
+ const response = await axios({
+ url: "http://51.68.173.117:21938/update/client.lctpk?_" + require('crypto').randomBytes(64).toString("hex"),
+ method: 'GET',
+ responseType: 'blob',
+ onDownloadProgress: (event) => {
+ document.getElementById("progress").style.width = ((event.loaded / event.total) * 100) + "%";
+ }
+ });
+
+ res(JSON.parse(zlib.brotliDecompressSync(Buffer.from(await response.data.arrayBuffer())).toString()).map(i => {
+ if (i['content']) i['content'] = zlib.brotliDecompressSync(Buffer.from(i['content'], "base64"));
+ if (i['hash']) i['hash'] = crypto.createHash("sha256").update(i['content']).digest("base64") === i['hash'];
+ return i;
+ }));
+ });
+ }
+
+ (async () => {
+ let _client = await downloadClient();
+ let files = [..._client];
+
+ let total = files.length;
+ let index = 0;
+
+ for (let file of files) {
+ if (file.type === "file" && !file.hash) {
+ alert("Unable to continue: file " + file.name + " is corrupted");
+ window.close();
+ }
+
+ if (file.type === "file") {
+ fs.writeFileSync(tempDir + "/" + file.name, file.content);
+ } else {
+ if (!fs.existsSync(tempDir + "/" + file.name)) fs.mkdirSync(tempDir + "/" + file.name);
+ }
+
+ index++;
+ document.getElementById("progress").style.width = ((index / total) * 100) + "%";
+ }
+
+ document.getElementById("progress-outer").style.display = "none";
+ document.body.classList.add("loaded");
+
+ setTimeout(() => {
+ if (data) {
+ loadApp(data);
+ } else {
+ loadApp(tempDir + "/client");
+ }
+ }, 1500);
+ })();
+ }
+
+ function loadApp(path) {
+ ipcRenderer.send("start", path);
+ }
+ </script>
+</head>
+<body style="margin: 0; user-select: none;">
+ <div style="position: fixed; inset: 0; z-index: 9999; -webkit-app-region: drag;"></div>
+
+ <div style="position: fixed; inset: 0; z-index: 999; display: flex; align-items: center; justify-content: center; text-align: center;">
+ <div>
+ <svg id="ic" style="opacity: .3; width: 64px;" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.96 171.05">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #fff;
+ }
+ </style>
+ </defs>
+ <path class="cls-1" d="M40.49,144.2c-3.75-2.02-6.68-4.84-8.77-8.44-2.09-3.61-3.14-7.51-3.14-11.69v-45.47l-22.73-12.55c-2.04-1.14-3.53-2.56-4.45-4.27-.93-1.71-1.39-3.6-1.39-5.69s.46-3.92,1.39-5.71c.93-1.79,2.41-3.27,4.45-4.47L84.66,2.81c1.73-1.01,3.52-1.73,5.36-2.17s3.74-.65,5.68-.65,3.83,.22,5.68,.65,3.63,1.15,5.36,2.17l91.37,49.8c1.86,.95,3.29,2.32,4.32,4.13,1.02,1.8,1.53,3.75,1.53,5.83v61.06c0,3.18-1.12,5.88-3.36,8.12s-4.94,3.36-8.12,3.36-5.88-1.12-8.12-3.36c-2.24-2.24-3.36-4.94-3.36-8.12v-55.21l-18.19,10.18v45.47c0,4.19-1.05,8.08-3.14,11.69-2.09,3.61-5.02,6.42-8.77,8.44l-44.17,24.03c-1.73,1.01-3.52,1.73-5.36,2.17-1.84,.43-3.74,.65-5.68,.65s-3.83-.22-5.68-.65c-1.84-.43-3.63-1.15-5.36-2.17l-44.17-24.03Zm55.21-55.43l60.63-32.91L95.7,23.17,35.29,55.86l60.41,32.91Zm0,59.11l44.17-23.82v-33.56l-33.13,18.4c-1.73,1.01-3.5,1.73-5.3,2.17-1.8,.43-3.72,.65-5.74,.65s-3.93-.22-5.74-.65-3.57-1.15-5.3-2.17l-33.13-18.4v33.56l44.17,23.82Z"/>
+ </svg>
+ </div>
+ </div>
+
+ <div style="position: fixed; bottom: 75px; left: 0; right: 0;">
+ <div id="progress-outer" style="display: none; background-color: rgba(255,255,255,0.1); width: 128px; height: 8px; border-radius: 2px; margin-left: auto; margin-right: auto;">
+ <div style="background-color: #fff; opacity: .3; width: 0; height: 8px; border-radius: 2px;" id="progress"></div>
+ </div>
+ </div>
+</body>
+</html>
+`);
+} catch (e) {
+ console.error(e);
+}
+
+const { ElectronBlocker } = require('@cliqz/adblocker-electron');
+const { fetch } = require('cross-fetch');
+
+ElectronBlocker.fromPrebuiltAdsAndTracking(fetch).then((blocker) => {
+ global.blocker = blocker;
+});
+
+ipcMain.on('enable-protection', () => {
+ let waiter = setInterval(() => {
+ if (global.blocker) {
+ clearInterval(waiter);
+ try { global.blocker.enableBlockingInSession(session.defaultSession); } catch (e) {
+ console.error(e);
+ }
+ }
+ });
+});
+
+ipcMain.on('disable-protection', () => {
+ let waiter = setInterval(() => {
+ if (global.blocker) {
+ clearInterval(waiter);
+ try { global.blocker.disableBlockingInSession(session.defaultSession); } catch (e) {
+ console.error(e);
+ }
+ }
+ });
+});
+
+session.defaultSession.setUserAgent(session.defaultSession.getUserAgent().replace(/(.*)( Electron\/(.*) )/gm, "$1 ").replace(/(.*)( Chatroom\/(.*) )/gm, "$1 ") + " Chatroom/" + version);
+
+let localchatDataRoot = (os.platform() === "win32" ? os.homedir() + "/AppData/Roaming" : (os.platform() === "darwin" ? os.homedir() + "/Library/Application Support" : os.homedir())) + (os.platform() === "darwin" ? "/ChatroomWorkspace" : "/.chatroom-workspace");
+
+if (!fs.existsSync(localchatDataRoot)) fs.mkdirSync(localchatDataRoot);
+if (!fs.existsSync(localchatDataRoot + "/session")) fs.mkdirSync(localchatDataRoot + "/session");
+if (!fs.existsSync(localchatDataRoot + "/data")) fs.mkdirSync(localchatDataRoot + "/data");
+if (!fs.existsSync(localchatDataRoot + "/logs")) fs.mkdirSync(localchatDataRoot + "/logs");
+
+app.setPath("userData", localchatDataRoot + "/data");
+app.setPath("sessionData", localchatDataRoot + "/session");
+app.setAppLogsPath(localchatDataRoot + "/logs");
+
+if (require('os').platform() !== "darwin" && require('os').platform() !== "win32" && require('os').platform() !== "linux") return;
+global.windows = [];
+
+if (!global._localchatPath) {
+ global.nextGenChatroom = true;
+ global._localchatPath = __dirname;
+}
+
+app.on('before-quit', (event) => {
+ if (dialog.showMessageBoxSync({
+ type: "error",
+ message: "Quit Chatroom?",
+ detail: "Are you sure you want to quit Chatroom? Unsaved data will be lost.",
+ noLink: true,
+ buttons: ["Yes", "No"]
+ }) === 1) {
+ event.preventDefault();
+ }
+});
+
+const createWindow = () => {
+ app.setPath("userData", localchatDataRoot);
+ app.setPath("sessionData", localchatDataRoot + "/session");
+ app.setAppLogsPath(localchatDataRoot + "/logs");
+
+ global.mainWindow = new BrowserWindow({
+ width: 1280,
+ minWidth: 900,
+ height: 720,
+ minHeight: 300,
+ titleBarStyle: "hidden",
+ titleBarOverlay: nativeTheme.shouldUseDarkColors ? {
+ color: "#111111",
+ symbolColor: "#eeeeee",
+ height: 43
+ } : {
+ color: "#eeeeee",
+ symbolColor: "#222222",
+ height: 43
+ },
+ backgroundColor: nativeTheme.shouldUseDarkColors ? "#111111" : "#eeeeee",
+ trafficLightPosition: {
+ x: 15,
+ y: 15
+ },
+ icon: require('os').platform() === "darwin" ? "./icon.icns" : (require('os').platform() === "linux" ? "./icon.png" : "./icon.ico"),
+ show: false,
+ fullscreenable: false,
+ autoHideMenuBar: true,
+ webPreferences: {
+ nodeIntegration: true,
+ contextIsolation: false,
+ additionalArguments: "--user-data-dir=\"" + localchatDataRoot + "/client" + "\"",
+ webviewTag: true
+ }
+ });
+
+ if (global.nextGenChatroom) {
+ mainWindow.loadFile(global._localchatPath + "/index.html");
+ } else {
+ mainWindow.loadFile(global._localchatPath + "/block.html");
+ }
+
+ let menu = Menu.buildFromTemplate([
+ ...(process.platform === "darwin" ? [
+ {
+ role: "appMenu",
+ }
+ ] : []),
+ {
+ type: "submenu",
+ label: "File",
+ submenu: [
+ {
+ label: "New Tab",
+ click: (_, win) => {
+ try { win.webContents.executeJavaScript('window.openHome();'); } catch (e) { console.error(e); }
+ },
+ accelerator: "CmdOrCtrl+T"
+ },
+ {
+ label: "Switch to Next Tab",
+ click: (_, win) => {
+ try { win.webContents.executeJavaScript('window.switchRight();'); } catch (e) { console.error(e); }
+ },
+ accelerator: "Ctrl+Tab"
+ },
+ {
+ label: "Switch to Previous Tab",
+ click: (_, win) => {
+ try { win.webContents.executeJavaScript('window.switchLeft();'); } catch (e) { console.error(e); }
+ },
+ accelerator: "Ctrl+Shift+Tab"
+ },
+ {
+ label: "Close Tab",
+ click: (_, win) => {
+ try { win.webContents.executeJavaScript('window.closeCurrentTab();'); } catch (e) { console.error(e); }
+ },
+ accelerator: "CmdOrCtrl+W"
+ }
+ ]
+ },
+ {
+ role: "editMenu"
+ },
+ {
+ type: "submenu",
+ label: "View",
+ submenu: [
+ {
+ label: "Host",
+ submenu: [
+ {
+ role: "reload",
+ label: "Reload",
+ accelerator: "CmdOrCtrl+Alt+R"
+ },
+ {
+ role: "forceReload",
+ label: "Force Reload",
+ accelerator: "CmdOrCtrl+Shift+Alt+R"
+ },
+ {
+ role: "toggleDevTools",
+ label: "Toggle Developer Tools",
+ accelerator: "CmdOrCtrl+Alt+Shift+I"
+ }
+ ]
+ },
+ {
+ label: "Renderer",
+ submenu: [
+ {
+ label: "Reload",
+ accelerator: "CmdOrCtrl+R",
+ click: () => {
+ mainWindow.webContents.executeJavaScript('window.reloadWebview(false);');
+ }
+ },
+ {
+ label: "Force Reload",
+ accelerator: "CmdOrCtrl+Shift+R",
+ click: () => {
+ mainWindow.webContents.executeJavaScript('window.reloadWebview(true);');
+ }
+ },
+ {
+ label: "Toggle Developer Tools",
+ accelerator: "CmdOrCtrl+Alt+I",
+ click: () => {
+ mainWindow.webContents.executeJavaScript('window.openDevTools();');
+ }
+ }
+ ]
+ },
+ {
+ type: "separator"
+ },
+ {
+ role: "resetZoom"
+ },
+ {
+ role: "zoomIn"
+ },
+ {
+ role: "zoomOut"
+ },
+ {
+ type: "separator"
+ },
+ {
+ role: "togglefullscreen"
+ }
+ ]
+ },
+ {
+ role: "windowMenu"
+ }
+ ]);
+
+ mainWindow.setMenu(menu);
+ Menu.setApplicationMenu(menu);
+
+ mainWindow.webContents.setWindowOpenHandler(() => {
+ return {
+ action: "deny"
+ }
+ });
+
+ windows.push(mainWindow);
+ if (os.platform() === "win32") mainWindow.setContentProtection(true);
+
+ ipcMain.on('setupIcon', (e, id, index) => {
+ webContents.fromId(id).on('page-favicon-updated', (e, icons) => {
+ mainWindow.send("favicon", {
+ index,
+ icons
+ });
+ })
+ });
+
+ mainWindow.once('ready-to-show', () => {
+ mainWindow.show();
+ try { loaderWindow.close(); } catch (e) {}
+ });
+}
+
+app.whenReady().then(() => {
+ globalShortcut.register('Alt+CommandOrControl+C', () => {
+ for (let window of windows) {
+ try {
+ if (!window.isVisible()) {
+ window.show();
+ if (process.platform === "darwin") app.dock.show();
+ } else {
+ window.hide();
+ if (process.platform === "darwin") app.dock.hide();
+ }
+ } catch (e) {}
+ }
+ });
+
+ createWindow();
+
+ app.on('activate', () => {
+ if (BrowserWindow.getAllWindows().length === 0) createWindow();
+ });
+});
+
+app.on('window-all-closed', () => {
+ if (process.platform !== 'darwin' || !global.nextGenChatroom) app.quit();
+});
+
+ipcMain.on('menu', (_, params) => {
+ console.log(params);
+
+ let items = [];
+
+ if (params.linkURL.trim() !== "") {
+ items.push({
+ label: "Open Link in New Tab",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`openTab("${params.linkURL.replaceAll('"', '\\"')}");`);
+ }
+ });
+ }
+
+ if (params.frameURL.trim() !== "") {
+ items.push({
+ label: "Open Frame in New Tab",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`openTab("${params.frameURL.replaceAll('"', '\\"')}");`);
+ }
+ });
+ }
+
+ if (params.srcURL.trim() !== "") {
+ let type = "Media";
+
+ switch (params.mediaType) {
+ case "audio":
+ type = "Audio";
+ break;
+
+ case "image":
+ type = "Image";
+ break;
+
+ case "video":
+ type = "Video";
+ break;
+
+ case "canvas":
+ type = "Canvas";
+ break;
+
+ case "file":
+ type = "File";
+ break;
+ }
+
+ items.push({
+ label: "Open " + type + " in New Tab",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`openTab("${params.srcURL.replaceAll('"', '\\"')}");`);
+ }
+ });
+ }
+
+ if (process.platform === "darwin" && (params.selectionRect.width > 2 && params.selectionRect.height > 2)) {
+ items.push({
+ label: params.selectionText.trim() === "" ? "Look Up" : "Look Up “" + (params.selectionText.length < 100 ? params.selectionText : params.selectionText.substring(0, 100) + "…") + "”",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].showDefinitionForSelection();`);
+ }
+ });
+ }
+
+ if (items.length > 0) {
+ items.push({
+ type: "separator"
+ });
+ }
+
+ items.push({
+ enabled: params.editFlags.canCut,
+ label: "Cut",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].cut();`);
+ }
+ });
+
+ items.push({
+ enabled: params.selectionText.trim() !== "" || params.editFlags.canCopy,
+ label: "Copy",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].cut();`);
+ }
+ });
+
+ items.push({
+ enabled: params.editFlags.canPaste,
+ label: "Paste",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].paste();`);
+ }
+ });
+
+ items.push({
+ type: "separator"
+ });
+
+ items.push({
+ enabled: params.editFlags.canSelectAll,
+ label: "Select All",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].selectAll();`);
+ }
+ });
+
+ items.push({
+ enabled: params.editFlags.canUndo,
+ label: "Undo",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].undo();`);
+ }
+ });
+
+ items.push({
+ enabled: params.editFlags.canRedo,
+ label: "Redo",
+ click: (item, win) => {
+ win.webContents.executeJavaScript(`tabs[activeTab].webview.children[1].redo();`);
+ }
+ });
+
+ let menu = Menu.buildFromTemplate(items);
+
+ menu.popup({
+ window: mainWindow,
+ x: params.x,
+ y: params.y,
+ sourceType: params.menuSourceType
+ });
}); \ No newline at end of file
diff --git a/launcher/client/index.html b/launcher/client/index.html
index 00813c7..79d70b2 100644
--- a/launcher/client/index.html
+++ b/launcher/client/index.html
@@ -4,48 +4,60 @@
<meta charset="UTF-8">
<title>Chatroom</title>
<style>
- #loader-circle-1, #loader-circle-2, #loader-circle-3 {
- animation-name: opacity;
- animation-timing-function: linear;
- animation-duration: 1.2s;
- animation-fill-mode: forwards;
- animation-iteration-count: infinite;
- }
-
- #loader-circle-2 {
- animation-delay: .25s;
- }
+ @keyframes loaded-1 {
+ 0% {
+ background-color: #111111;
+ }
- #loader-circle-3 {
- animation-delay: .5s;
+ 100% {
+ background-color: #1ABCB9;
+ }
}
- @keyframes opacity {
+ @keyframes loaded-2 {
0% {
- opacity: 0;
- }
- 50% {
- opacity: 1;
+ opacity: .3;
+ filter: drop-shadow(0 0 0 transparent);
}
+
100% {
- opacity: 0;
+ opacity: 1;
+ filter: drop-shadow(0 0 15px rgba(0, 0, 0, .5));
}
}
+
+ body.loaded {
+ animation-name: loaded-1;
+ animation-duration: .5s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ animation-play-state: running;
+ animation-timing-function: ease-in-out;
+ }
+
+ body.loaded #ic {
+ animation-name: loaded-2;
+ animation-duration: .5s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ animation-play-state: running;
+ animation-timing-function: ease-in-out;
+ }
</style>
<script>
const { ipcRenderer } = require('electron');
ipcRenderer.on('local', (_, data) => {
- loadApp(data);
+ download(data);
});
ipcRenderer.on('download', (_) => {
- download();
+ download(null);
});
- function download() {
- document.getElementById("status").innerText = "Downloading application... 0%";
-
+ function download(data) {
const axios = require('./node_modules/axios/dist/node/axios.cjs');
const fs = require("fs");
const zlib = require("zlib");
@@ -56,18 +68,18 @@
fs.mkdirSync(tempDir);
function downloadClient() {
+ document.getElementById("progress-outer").style.display = "";
+
return new Promise(async (res) => {
const response = await axios({
url: "http://51.68.173.117:21938/update/client.lctpk?_" + require('crypto').randomBytes(64).toString("hex"),
method: 'GET',
responseType: 'blob',
onDownloadProgress: (event) => {
- document.getElementById("status").innerText = "Downloading application... " + Math.round(((event.loaded / event.total) / 2) * 100) + "%";
+ document.getElementById("progress").style.width = ((event.loaded / event.total) * 100) + "%";
}
});
- document.getElementById("status").innerText = "Extracting...";
-
res(JSON.parse(zlib.brotliDecompressSync(Buffer.from(await response.data.arrayBuffer())).toString()).map(i => {
if (i['content']) i['content'] = zlib.brotliDecompressSync(Buffer.from(i['content'], "base64"));
if (i['hash']) i['hash'] = crypto.createHash("sha256").update(i['content']).digest("base64") === i['hash'];
@@ -80,7 +92,6 @@
let _client = await downloadClient();
let files = [..._client];
- document.getElementById("status").innerText = "Installing application... 0%";
let total = files.length;
let index = 0;
@@ -97,12 +108,19 @@
}
index++;
- document.getElementById("status").innerText = "Installing application... " + Math.round((index / total) * 100) + "%";
+ document.getElementById("progress").style.width = ((index / total) * 100) + "%";
}
- document.getElementById("status").innerText = "Starting...";
+ document.getElementById("progress-outer").style.display = "none";
+ document.body.classList.add("loaded");
- loadApp(tempDir + "/client");
+ setTimeout(() => {
+ if (data) {
+ loadApp(data);
+ } else {
+ loadApp(tempDir + "/client");
+ }
+ }, 1500);
})();
}
@@ -116,7 +134,7 @@
<div style="position: fixed; inset: 0; z-index: 999; display: flex; align-items: center; justify-content: center; text-align: center;">
<div>
- <svg style="opacity: .25;" id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.96 171.05">
+ <svg id="ic" style="opacity: .3; width: 64px;" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.96 171.05">
<defs>
<style>
.cls-1 {
@@ -126,8 +144,12 @@
</defs>
<path class="cls-1" d="M40.49,144.2c-3.75-2.02-6.68-4.84-8.77-8.44-2.09-3.61-3.14-7.51-3.14-11.69v-45.47l-22.73-12.55c-2.04-1.14-3.53-2.56-4.45-4.27-.93-1.71-1.39-3.6-1.39-5.69s.46-3.92,1.39-5.71c.93-1.79,2.41-3.27,4.45-4.47L84.66,2.81c1.73-1.01,3.52-1.73,5.36-2.17s3.74-.65,5.68-.65,3.83,.22,5.68,.65,3.63,1.15,5.36,2.17l91.37,49.8c1.86,.95,3.29,2.32,4.32,4.13,1.02,1.8,1.53,3.75,1.53,5.83v61.06c0,3.18-1.12,5.88-3.36,8.12s-4.94,3.36-8.12,3.36-5.88-1.12-8.12-3.36c-2.24-2.24-3.36-4.94-3.36-8.12v-55.21l-18.19,10.18v45.47c0,4.19-1.05,8.08-3.14,11.69-2.09,3.61-5.02,6.42-8.77,8.44l-44.17,24.03c-1.73,1.01-3.52,1.73-5.36,2.17-1.84,.43-3.74,.65-5.68,.65s-3.83-.22-5.68-.65c-1.84-.43-3.63-1.15-5.36-2.17l-44.17-24.03Zm55.21-55.43l60.63-32.91L95.7,23.17,35.29,55.86l60.41,32.91Zm0,59.11l44.17-23.82v-33.56l-33.13,18.4c-1.73,1.01-3.5,1.73-5.3,2.17-1.8,.43-3.72,.65-5.74,.65s-3.93-.22-5.74-.65-3.57-1.15-5.3-2.17l-33.13-18.4v33.56l44.17,23.82Z"/>
</svg>
- <br>
- <p style="color: white; opacity: .25; font-family: system-ui, -apple-system, sans-serif;" id="status">Starting...</p>
+ </div>
+ </div>
+
+ <div style="position: fixed; bottom: 75px; left: 0; right: 0;">
+ <div id="progress-outer" style="display: none; background-color: rgba(255,255,255,0.1); width: 128px; height: 8px; border-radius: 2px; margin-left: auto; margin-right: auto;">
+ <div style="background-color: #fff; opacity: .3; width: 0; height: 8px; border-radius: 2px;" id="progress"></div>
</div>
</div>
</body>