mirror of
https://github.com/smartfrigde/armcord.git
synced 2024-08-14 23:56:58 +00:00
[*] ESLint: The Lintening (#393)
* [*] ESLint: The Lintening * Missed a couple unused vals in utils * [*] Tend to DeepScan remarks * [*] sigh, remove some duplicate crap
This commit is contained in:
parent
974f90fd35
commit
a2a997df30
22 changed files with 1091 additions and 293 deletions
35
.eslintrc.yml
Normal file
35
.eslintrc.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
extends: eslint-config-dmitmel/presets/node
|
||||
env:
|
||||
browser: true
|
||||
plugins: ["prettier"]
|
||||
|
||||
settings:
|
||||
node:
|
||||
tryExtensions: [".tsx", ".ts", ".jsx", ".js", ".json", ".node"]
|
||||
|
||||
ignorePatterns: ["src/arrpc/**"]
|
||||
|
||||
rules:
|
||||
prettier/prettier:
|
||||
- error
|
||||
node/no-unsupported-features/es-syntax:
|
||||
- error
|
||||
- ignores:
|
||||
- modules
|
||||
|
||||
overrides:
|
||||
- files: "**/*.ts*"
|
||||
extends:
|
||||
- eslint-config-dmitmel/presets/typescript-addon
|
||||
parserOptions:
|
||||
project: "tsconfig.json"
|
||||
sourceType: module
|
||||
rules:
|
||||
eqeqeq: 0
|
||||
require-await: 0
|
||||
no-undefined: 0
|
||||
node/no-unsupported-features/es-syntax: 0
|
||||
"@typescript-eslint/no-dynamic-delete": 0
|
||||
"@typescript-eslint/no-explicit-any": 0
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": 0
|
||||
"@typescript-eslint/naming-convention": 0
|
10
package.json
10
package.json
|
@ -3,6 +3,9 @@
|
|||
"version": "3.2.0",
|
||||
"description": "ArmCord is a custom client designed to enhance your Discord experience while keeping everything lightweight.",
|
||||
"main": "ts-out/main.js",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css src/**/**/*.js ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/**/** ts-out/",
|
||||
"watch": "tsc -w",
|
||||
|
@ -11,6 +14,7 @@
|
|||
"package": "npm run build && electron-builder",
|
||||
"packageQuick": "npm run build && electron-builder --dir",
|
||||
"format": "prettier --write src *.json",
|
||||
"lint": "eslint src --ext .js,.jsx,.ts,.tsx --ignore-path .gitignore",
|
||||
"CIbuild": "npm run build && electron-builder --linux zip && electron-builder --windows zip && electron-builder --macos zip",
|
||||
"prepare": "git config --local core.hooksPath .hooks/"
|
||||
},
|
||||
|
@ -27,10 +31,16 @@
|
|||
"devDependencies": {
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
||||
"@typescript-eslint/parser": "^5.59.2",
|
||||
"chalk-cli": "^5.0.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
"electron": "^24.1.2",
|
||||
"electron-builder": "^23.6.0",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-dmitmel": "github:dmitmel/eslint-config-dmitmel",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
|
|
761
pnpm-lock.yaml
761
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -65,7 +65,7 @@ function disableAutogain(constraints) {
|
|||
|
||||
function patchFunction(object, name, createNewFunction) {
|
||||
if (name in object) {
|
||||
var original = object[name];
|
||||
const original = object[name];
|
||||
object[name] = createNewFunction(original);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import electron from "electron";
|
||||
import {getConfig} from "../utils";
|
||||
|
||||
const unstrictCSP = () => {
|
||||
const unstrictCSP = (): void => {
|
||||
console.log("Setting up CSP unstricter...");
|
||||
|
||||
electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, resourceType}, done) => {
|
||||
|
@ -15,7 +15,7 @@ const unstrictCSP = () => {
|
|||
responseHeaders["content-type"] = ["text/css"];
|
||||
}
|
||||
|
||||
done({responseHeaders});
|
||||
return done({responseHeaders});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as fs from "fs";
|
||||
import {app, session} from "electron";
|
||||
const userDataPath = app.getPath("userData");
|
||||
const pluginFolder = userDataPath + "/plugins/";
|
||||
const pluginFolder = `${userDataPath}/plugins`;
|
||||
if (!fs.existsSync(pluginFolder)) {
|
||||
fs.mkdirSync(pluginFolder);
|
||||
console.log("Created missing plugin folder");
|
||||
|
@ -9,9 +9,9 @@ if (!fs.existsSync(pluginFolder)) {
|
|||
app.whenReady().then(() => {
|
||||
fs.readdirSync(pluginFolder).forEach((file) => {
|
||||
try {
|
||||
const manifest = fs.readFileSync(`${userDataPath}/plugins/${file}/manifest.json`, "utf8");
|
||||
var pluginFile = JSON.parse(manifest);
|
||||
session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`);
|
||||
const manifest = fs.readFileSync(`${pluginFolder}/${file}/manifest.json`, "utf8");
|
||||
const pluginFile = JSON.parse(manifest);
|
||||
session.defaultSession.loadExtension(`${pluginFolder}/${file}`);
|
||||
console.log(`[Mod loader] Loaded ${pluginFile.name} made by ${pluginFile.author}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
|
87
src/ipc.ts
87
src/ipc.ts
|
@ -1,44 +1,42 @@
|
|||
//ipc stuff
|
||||
import {app, ipcMain, shell, desktopCapturer, nativeImage, screen} from "electron";
|
||||
import {app, desktopCapturer, ipcMain, nativeImage, shell} from "electron";
|
||||
import {mainWindow} from "./window";
|
||||
import {
|
||||
setConfigBulk,
|
||||
getVersion,
|
||||
getConfig,
|
||||
setLang,
|
||||
getLang,
|
||||
getWindowState,
|
||||
packageVersion,
|
||||
getDisplayVersion,
|
||||
getLang,
|
||||
getVersion,
|
||||
getWindowState,
|
||||
modInstallState,
|
||||
installModLoader
|
||||
packageVersion,
|
||||
setConfigBulk,
|
||||
setLang
|
||||
} from "./utils";
|
||||
import {customTitlebar} from "./main";
|
||||
import {createSettingsWindow} from "./settings/main";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
export function registerIpc() {
|
||||
ipcMain.on("get-app-path", (event, arg) => {
|
||||
export function registerIpc(): void {
|
||||
ipcMain.on("get-app-path", (event) => {
|
||||
event.reply("app-path", app.getAppPath());
|
||||
});
|
||||
ipcMain.on("setLang", (event, lang: string) => {
|
||||
ipcMain.on("setLang", (_event, lang: string) => {
|
||||
setLang(lang);
|
||||
});
|
||||
ipcMain.handle("getLang", (event, toGet: string) => {
|
||||
ipcMain.handle("getLang", (_event, toGet: string) => {
|
||||
return getLang(toGet);
|
||||
});
|
||||
ipcMain.on("open-external-link", (event, href: string) => {
|
||||
ipcMain.on("open-external-link", (_event, href: string) => {
|
||||
shell.openExternal(href);
|
||||
});
|
||||
ipcMain.on("setPing", (event, pingCount: number) => {
|
||||
ipcMain.on("setPing", (_event, pingCount: number) => {
|
||||
switch (os.platform()) {
|
||||
case "linux" ?? "macos":
|
||||
app.setBadgeCount(pingCount);
|
||||
break;
|
||||
case "win32":
|
||||
if (pingCount > 0) {
|
||||
var image = nativeImage.createFromPath(path.join(__dirname, "../", `/assets/ping.png`));
|
||||
let image = nativeImage.createFromPath(path.join(__dirname, "../", `/assets/ping.png`));
|
||||
mainWindow.setOverlayIcon(image, "badgeCount");
|
||||
} else {
|
||||
mainWindow.setOverlayIcon(null, "badgeCount");
|
||||
|
@ -46,28 +44,28 @@ export function registerIpc() {
|
|||
break;
|
||||
}
|
||||
});
|
||||
ipcMain.on("win-maximize", (event, arg) => {
|
||||
ipcMain.on("win-maximize", () => {
|
||||
mainWindow.maximize();
|
||||
});
|
||||
ipcMain.on("win-isMaximized", (event, arg) => {
|
||||
ipcMain.on("win-isMaximized", (event) => {
|
||||
event.returnValue = mainWindow.isMaximized();
|
||||
});
|
||||
ipcMain.on("win-isNormal", (event, arg) => {
|
||||
ipcMain.on("win-isNormal", (event) => {
|
||||
event.returnValue = mainWindow.isNormal();
|
||||
});
|
||||
ipcMain.on("win-minimize", (event, arg) => {
|
||||
ipcMain.on("win-minimize", () => {
|
||||
mainWindow.minimize();
|
||||
});
|
||||
ipcMain.on("win-unmaximize", (event, arg) => {
|
||||
ipcMain.on("win-unmaximize", () => {
|
||||
mainWindow.unmaximize();
|
||||
});
|
||||
ipcMain.on("win-show", (event, arg) => {
|
||||
ipcMain.on("win-show", () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
ipcMain.on("win-hide", (event, arg) => {
|
||||
ipcMain.on("win-hide", () => {
|
||||
mainWindow.hide();
|
||||
});
|
||||
ipcMain.on("win-quit", (event, arg) => {
|
||||
ipcMain.on("win-quit", () => {
|
||||
app.exit();
|
||||
});
|
||||
ipcMain.on("get-app-version", (event) => {
|
||||
|
@ -83,14 +81,19 @@ export function registerIpc() {
|
|||
event.returnValue = packageVersion;
|
||||
});
|
||||
ipcMain.on("splashEnd", async () => {
|
||||
let width = 800,
|
||||
height = 600,
|
||||
isMaximized = true,
|
||||
xValue = 0,
|
||||
yValue = 0;
|
||||
try {
|
||||
var width = (await getWindowState("width")) ?? 800;
|
||||
var height = (await getWindowState("height")) ?? 600;
|
||||
var isMaximized = (await getWindowState("isMaximized")) ?? false;
|
||||
var xValue = await getWindowState("x");
|
||||
var yValue = await getWindowState("y");
|
||||
} catch (e) {
|
||||
console.log("[Window state manager] No window state file found. Fallbacking to default values.");
|
||||
width = (await getWindowState("width")) ?? 800;
|
||||
height = (await getWindowState("height")) ?? 600;
|
||||
isMaximized = (await getWindowState("isMaximized")) ?? false;
|
||||
xValue = await getWindowState("x");
|
||||
yValue = await getWindowState("y");
|
||||
} catch (_e) {
|
||||
console.log("[Window state manager] No window state file found. Falling back to default values.");
|
||||
mainWindow.setSize(800, 600);
|
||||
}
|
||||
if (isMaximized) {
|
||||
|
@ -102,11 +105,11 @@ export function registerIpc() {
|
|||
console.log("[Window state manager] Not maximized.");
|
||||
}
|
||||
});
|
||||
ipcMain.on("restart", (event, arg) => {
|
||||
ipcMain.on("restart", () => {
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
});
|
||||
ipcMain.on("saveSettings", (event, args) => {
|
||||
ipcMain.on("saveSettings", (_event, args) => {
|
||||
setConfigBulk(args);
|
||||
});
|
||||
ipcMain.on("minimizeToTray", async (event) => {
|
||||
|
@ -115,28 +118,28 @@ export function registerIpc() {
|
|||
ipcMain.on("channel", async (event) => {
|
||||
event.returnValue = await getConfig("channel");
|
||||
});
|
||||
ipcMain.on("clientmod", async (event, arg) => {
|
||||
ipcMain.on("clientmod", async (event) => {
|
||||
event.returnValue = await getConfig("mods");
|
||||
});
|
||||
ipcMain.on("legacyCapturer", async (event, arg) => {
|
||||
ipcMain.on("legacyCapturer", async (event) => {
|
||||
event.returnValue = await getConfig("useLegacyCapturer");
|
||||
});
|
||||
ipcMain.on("trayIcon", async (event, arg) => {
|
||||
ipcMain.on("trayIcon", async (event) => {
|
||||
event.returnValue = await getConfig("trayIcon");
|
||||
});
|
||||
ipcMain.on("disableAutogain", async (event, arg) => {
|
||||
ipcMain.on("disableAutogain", async (event) => {
|
||||
event.returnValue = await getConfig("disableAutogain");
|
||||
});
|
||||
ipcMain.on("titlebar", (event, arg) => {
|
||||
ipcMain.on("titlebar", (event) => {
|
||||
event.returnValue = customTitlebar;
|
||||
});
|
||||
ipcMain.on("mobileMode", async (event, arg) => {
|
||||
ipcMain.on("mobileMode", async (event) => {
|
||||
event.returnValue = await getConfig("mobileMode");
|
||||
});
|
||||
ipcMain.on("shouldPatch", async (event, arg) => {
|
||||
ipcMain.on("shouldPatch", async (event) => {
|
||||
event.returnValue = await getConfig("automaticPatches");
|
||||
});
|
||||
ipcMain.on("openSettingsWindow", (event, arg) => {
|
||||
ipcMain.on("openSettingsWindow", () => {
|
||||
createSettingsWindow();
|
||||
});
|
||||
ipcMain.on("setting-armcordCSP", async (event) => {
|
||||
|
@ -146,5 +149,5 @@ export function registerIpc() {
|
|||
event.returnValue = false;
|
||||
}
|
||||
});
|
||||
ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => desktopCapturer.getSources(opts));
|
||||
ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (_event, opts) => desktopCapturer.getSources(opts));
|
||||
}
|
||||
|
|
34
src/main.ts
34
src/main.ts
|
@ -1,34 +1,32 @@
|
|||
// Modules to control application life and create native browser window
|
||||
import {app, BrowserWindow, crashReporter, session} from "electron";
|
||||
import {BrowserWindow, app, crashReporter, session} from "electron";
|
||||
import "v8-compile-cache";
|
||||
import {
|
||||
Settings,
|
||||
checkForDataFolder,
|
||||
getConfig,
|
||||
checkIfConfigExists,
|
||||
getConfig,
|
||||
injectElectronFlags,
|
||||
setConfig,
|
||||
installModLoader,
|
||||
getConfigLocation
|
||||
setConfig
|
||||
} from "./utils";
|
||||
import "./extensions/mods";
|
||||
import "./tray";
|
||||
import fs from "fs";
|
||||
import {createCustomWindow, createNativeWindow, createTransparentWindow, mainWindow} from "./window";
|
||||
import {createCustomWindow, createNativeWindow, createTransparentWindow} from "./window";
|
||||
import path from "path";
|
||||
export var iconPath: string;
|
||||
export var settings: any;
|
||||
export var customTitlebar: boolean;
|
||||
export var clientName: "ArmCord";
|
||||
async function args() {
|
||||
var argNum = 2;
|
||||
export let iconPath: string;
|
||||
export let settings: any;
|
||||
export let customTitlebar: boolean;
|
||||
async function args(): Promise<void> {
|
||||
let argNum = 2;
|
||||
if (process.argv[0] == "electron") argNum++;
|
||||
var args = process.argv[argNum];
|
||||
let args = process.argv[argNum];
|
||||
if (args == undefined) return;
|
||||
if (args.startsWith("--")) return; //electron flag
|
||||
if (args.includes("=")) {
|
||||
var e = args.split("=");
|
||||
await setConfig(e[0], e[1]);
|
||||
console.log("Setting " + e[0] + " to " + e[1]);
|
||||
let e = args.split("=");
|
||||
await setConfig(e[0] as keyof Settings, e[1]);
|
||||
console.log(`Setting ${e[0]} to ${e[1]}`);
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
}
|
||||
|
@ -70,7 +68,7 @@ if (!app.requestSingleInstanceLock()) {
|
|||
} else {
|
||||
iconPath = path.join(__dirname, "../", "/assets/ac_icon_transparent.png");
|
||||
}
|
||||
async function init() {
|
||||
async function init(): Promise<void> {
|
||||
switch (await getConfig("windowStyle")) {
|
||||
case "default":
|
||||
createCustomWindow();
|
||||
|
@ -93,7 +91,7 @@ if (!app.requestSingleInstanceLock()) {
|
|||
}
|
||||
await init();
|
||||
await installModLoader();
|
||||
session.fromPartition("some-partition").setPermissionRequestHandler((webContents, permission, callback) => {
|
||||
session.fromPartition("some-partition").setPermissionRequestHandler((_webContents, permission, callback) => {
|
||||
if (permission === "notifications") {
|
||||
// Approves the permissions request
|
||||
callback(true);
|
||||
|
|
16
src/menu.ts
16
src/menu.ts
|
@ -3,7 +3,7 @@ import {mainWindow} from "./window";
|
|||
import {getConfig} from "./utils";
|
||||
import {createSettingsWindow} from "./settings/main";
|
||||
|
||||
function paste(contents: any) {
|
||||
function paste(contents: any): void {
|
||||
const contentTypes = clipboard.availableFormats().toString();
|
||||
//Workaround: fix pasting the images.
|
||||
if (contentTypes.includes("image/") && contentTypes.includes("text/html")) {
|
||||
|
@ -11,7 +11,7 @@ function paste(contents: any) {
|
|||
}
|
||||
contents.paste();
|
||||
}
|
||||
export async function setMenu() {
|
||||
export async function setMenu(): Promise<void> {
|
||||
if ((await getConfig("alternativePaste")) == true) {
|
||||
mainWindow.on("focus", function () {
|
||||
console.log("[Window state manager] Focus");
|
||||
|
@ -39,7 +39,7 @@ export async function setMenu() {
|
|||
globalShortcut.unregister("CmdOrCtrl+V");
|
||||
});
|
||||
}
|
||||
var template: Electron.MenuItemConstructorOptions[] = [
|
||||
let template: Electron.MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: "ArmCord",
|
||||
submenu: [
|
||||
|
@ -48,28 +48,28 @@ export async function setMenu() {
|
|||
{
|
||||
label: "Developer tools",
|
||||
accelerator: "CmdOrCtrl+Shift+I",
|
||||
click: function () {
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Open settings",
|
||||
accelerator: "CmdOrCtrl+Shift+'",
|
||||
click: function () {
|
||||
click() {
|
||||
createSettingsWindow();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Reload",
|
||||
accelerator: "CmdOrCtrl+R",
|
||||
click: function () {
|
||||
click() {
|
||||
mainWindow.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Quit",
|
||||
accelerator: "CmdOrCtrl+Q",
|
||||
click: function () {
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ export async function setMenu() {
|
|||
{
|
||||
label: "Paste",
|
||||
accelerator: "CmdOrCtrl+V",
|
||||
click: function () {
|
||||
click() {
|
||||
paste(mainWindow.webContents);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@ interface IPCSources {
|
|||
name: string;
|
||||
thumbnail: HTMLCanvasElement;
|
||||
}
|
||||
async function getDisplayMediaSelector() {
|
||||
async function getDisplayMediaSelector(): Promise<string> {
|
||||
const sources: IPCSources[] = await desktopCapturer.getSources({
|
||||
types: ["screen", "window"]
|
||||
});
|
||||
|
@ -54,7 +54,7 @@ contextBridge.exposeInMainWorld("armcord", {
|
|||
ipcRenderer.invoke("getLang", toGet).then((result) => {
|
||||
return result;
|
||||
}),
|
||||
getDisplayMediaSelector: getDisplayMediaSelector,
|
||||
getDisplayMediaSelector,
|
||||
version: ipcRenderer.sendSync("get-app-version", "app-version"),
|
||||
mods: ipcRenderer.sendSync("clientmod"),
|
||||
packageVersion: ipcRenderer.sendSync("get-package-version", "app-version"),
|
||||
|
@ -63,9 +63,11 @@ contextBridge.exposeInMainWorld("armcord", {
|
|||
});
|
||||
let windowCallback: (arg0: object) => void;
|
||||
contextBridge.exposeInMainWorld("ArmCordRPC", {
|
||||
listen: (callback: any) => (windowCallback = callback)
|
||||
listen: (callback: any) => {
|
||||
windowCallback = callback;
|
||||
}
|
||||
});
|
||||
ipcRenderer.on("rpc", (event, data: object) => {
|
||||
ipcRenderer.on("rpc", (_event, data: object) => {
|
||||
windowCallback(data);
|
||||
});
|
||||
//to be only used inside armcord internal setup/splash etc
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//Fixed context isolation version https://github.com/getferdi/ferdi/blob/develop/src/webview/screenshare.ts
|
||||
//original https://github.com/electron/electron/issues/16513#issuecomment-602070250
|
||||
import {addStyle, addScript} from "../utils";
|
||||
import {addScript, addStyle} from "../utils";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import {ipcRenderer} from "electron";
|
||||
import {addStyle} from "../utils";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
export function injectMobileStuff() {
|
||||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
export function injectMobileStuff(): void {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const mobileCSS = path.join(__dirname, "../", "/content/css/mobile.css");
|
||||
addStyle(fs.readFileSync(mobileCSS, "utf8"));
|
||||
// TO-DO: clicking on the logo, or additional button triggers ESC button to move around the UI quicker
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
import {ipcRenderer} from "electron";
|
||||
import {injectJS} from "../utils";
|
||||
|
||||
var patchEndpoint = "https://patch.armcord.xyz/";
|
||||
var version = ipcRenderer.sendSync("get-app-version", "app-version");
|
||||
const patchEndpoint = "https://patch.armcord.xyz";
|
||||
const version = ipcRenderer.sendSync("get-app-version", "app-version");
|
||||
if (ipcRenderer.sendSync("shouldPatch")) {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
fetch(patchEndpoint + version + "/info.json", {cache: "no-store"}) //lmao
|
||||
fetch(`${patchEndpoint}/${version}/info.json`, {cache: "no-store"}) //lmao
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
if (res.patch == true) {
|
||||
console.log("Found a patch. Injecting...");
|
||||
injectJS(patchEndpoint + version + "/patch.js");
|
||||
injectJS(`${patchEndpoint}/${version}/patch.js`);
|
||||
} else {
|
||||
console.log("No patches have been found.");
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@ if (ipcRenderer.sendSync("legacyCapturer")) {
|
|||
import("./capturer");
|
||||
}
|
||||
|
||||
var version = ipcRenderer.sendSync("displayVersion");
|
||||
var channel = ipcRenderer.sendSync("channel");
|
||||
async function updateLang() {
|
||||
const version = ipcRenderer.sendSync("displayVersion");
|
||||
async function updateLang(): Promise<void> {
|
||||
if (window.location.href.indexOf("setup.html") > -1) {
|
||||
console.log("Setup, skipping lang update");
|
||||
} else {
|
||||
|
@ -32,8 +31,8 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
console.log("ArmCord " + version);
|
||||
ipcRenderer.on("themeLoader", (event, message) => {
|
||||
console.log(`ArmCord ${version}`);
|
||||
ipcRenderer.on("themeLoader", (_event, message) => {
|
||||
addStyle(message);
|
||||
});
|
||||
if (window.location.href.indexOf("splash.html") > -1) {
|
||||
|
|
|
@ -3,9 +3,9 @@ import {addStyle} from "../utils";
|
|||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import os from "os";
|
||||
export function injectTitlebar() {
|
||||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
var elem = document.createElement("div");
|
||||
export function injectTitlebar(): void {
|
||||
document.addEventListener("DOMContentLoaded", function (_event) {
|
||||
const elem = document.createElement("div");
|
||||
elem.innerHTML = `<nav class="titlebar">
|
||||
<div class="window-title" id="window-title"></div>
|
||||
<div id="window-controls-container">
|
||||
|
@ -28,9 +28,9 @@ export function injectTitlebar() {
|
|||
document.body.setAttribute("customTitlebar", "");
|
||||
document.body.setAttribute("armcord-platform", os.platform());
|
||||
|
||||
var minimize = document.getElementById("minimize");
|
||||
var maximize = document.getElementById("maximize");
|
||||
var quit = document.getElementById("quit");
|
||||
const minimize = document.getElementById("minimize");
|
||||
const maximize = document.getElementById("maximize");
|
||||
const quit = document.getElementById("quit");
|
||||
|
||||
minimize!.addEventListener("click", () => {
|
||||
ipcRenderer.send("win-minimize");
|
||||
|
@ -55,8 +55,8 @@ export function injectTitlebar() {
|
|||
});
|
||||
}
|
||||
|
||||
export function fixTitlebar() {
|
||||
var elem = document.createElement("div");
|
||||
export function fixTitlebar(): void {
|
||||
const elem = document.createElement("div");
|
||||
elem.innerHTML = `<nav class="titlebar">
|
||||
<div class="window-title" id="window-title"></div>
|
||||
<div id="window-controls-container">
|
||||
|
@ -72,9 +72,9 @@ export function fixTitlebar() {
|
|||
} else {
|
||||
document.getElementById("app-mount")!.prepend(elem);
|
||||
}
|
||||
var minimize = document.getElementById("minimize");
|
||||
var maximize = document.getElementById("maximize");
|
||||
var quit = document.getElementById("quit");
|
||||
const minimize = document.getElementById("minimize");
|
||||
const maximize = document.getElementById("maximize");
|
||||
const quit = document.getElementById("quit");
|
||||
|
||||
minimize!.addEventListener("click", () => {
|
||||
ipcRenderer.send("win-minimize");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {BrowserWindow, desktopCapturer, DesktopCapturerSource, ipcMain, session, shell} from "electron";
|
||||
import {BrowserWindow, desktopCapturer, ipcMain, session} from "electron";
|
||||
import path from "path";
|
||||
import {iconPath} from "../main";
|
||||
var capturerWindow: BrowserWindow;
|
||||
function registerCustomHandler() {
|
||||
let capturerWindow: BrowserWindow;
|
||||
function registerCustomHandler(): void {
|
||||
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
|
||||
console.log(request);
|
||||
const sources = await desktopCapturer.getSources({
|
||||
|
@ -23,11 +23,11 @@ function registerCustomHandler() {
|
|||
preload: path.join(__dirname, "preload.js")
|
||||
}
|
||||
});
|
||||
ipcMain.once("selectScreenshareSource", (event, id, name) => {
|
||||
ipcMain.once("selectScreenshareSource", (_event, id, name) => {
|
||||
//console.log(sources[id]);
|
||||
//console.log(id);
|
||||
capturerWindow.close();
|
||||
var result = {id, name, width: 9999, height: 9999};
|
||||
let result = {id, name, width: 9999, height: 9999};
|
||||
callback({video: result});
|
||||
});
|
||||
capturerWindow.loadURL(`file://${__dirname}/picker.html`);
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import {IpcMain, ipcRenderer} from "electron";
|
||||
import {ipcRenderer} from "electron";
|
||||
interface IPCSources {
|
||||
id: string;
|
||||
name: string;
|
||||
thumbnail: HTMLCanvasElement;
|
||||
}
|
||||
async function addDisplays() {
|
||||
ipcRenderer.once("getSources", (event, arg) => {
|
||||
var sources: IPCSources[] = arg;
|
||||
async function addDisplays(): Promise<void> {
|
||||
ipcRenderer.once("getSources", (_event, arg) => {
|
||||
let sources: IPCSources[] = arg;
|
||||
console.log(sources);
|
||||
const selectionElem = document.createElement("div");
|
||||
//@ts-ignore
|
||||
selectionElem.classList = ["desktop-capturer-selection"];
|
||||
selectionElem.classList.add("desktop-capturer-selection");
|
||||
selectionElem.innerHTML = `<div class="desktop-capturer-selection__scroller">
|
||||
<ul class="desktop-capturer-selection__list">
|
||||
${sources
|
||||
|
@ -39,7 +38,7 @@ async function addDisplays() {
|
|||
const id = button.getAttribute("data-id");
|
||||
const title = button.getAttribute("title");
|
||||
if (id === "${CANCEL_ID}") {
|
||||
new Error("Cancelled by user");
|
||||
throw new Error("Cancelled by user");
|
||||
} else {
|
||||
ipcRenderer.sendSync("selectScreenshareSource", id, title);
|
||||
}
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
import {BrowserWindow, shell, ipcMain, app, clipboard} from "electron";
|
||||
import {BrowserWindow, app, clipboard, ipcMain, shell} from "electron";
|
||||
import {
|
||||
checkForDataFolder,
|
||||
getConfig,
|
||||
setConfigBulk,
|
||||
Settings,
|
||||
getLang,
|
||||
getVersion,
|
||||
getConfig,
|
||||
getConfigLocation,
|
||||
getDisplayVersion,
|
||||
getLangName,
|
||||
sleep,
|
||||
getDisplayVersion
|
||||
getVersion,
|
||||
setConfigBulk,
|
||||
sleep
|
||||
} from "../utils";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
import {mainWindow} from "../window";
|
||||
import {crash} from "process";
|
||||
var settingsWindow: BrowserWindow;
|
||||
var instance: number = 0;
|
||||
let settingsWindow: BrowserWindow;
|
||||
let instance = 0;
|
||||
//checkForDataFolder();
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
const themesPath = path.join(userDataPath, "/themes/");
|
||||
const pluginsPath = path.join(userDataPath, "/plugins/");
|
||||
export function createSettingsWindow() {
|
||||
export function createSettingsWindow(): void {
|
||||
console.log("Creating a settings window.");
|
||||
instance = instance + 1;
|
||||
instance += 1;
|
||||
if (instance > 1) {
|
||||
if (settingsWindow) {
|
||||
settingsWindow.show();
|
||||
|
@ -45,11 +41,11 @@ export function createSettingsWindow() {
|
|||
preload: path.join(__dirname, "preload.js")
|
||||
}
|
||||
});
|
||||
async function settingsLoadPage() {
|
||||
async function settingsLoadPage(): Promise<void> {
|
||||
settingsWindow.loadURL(`file://${__dirname}/settings.html`);
|
||||
}
|
||||
const userDataPath = app.getPath("userData");
|
||||
const themesFolder = userDataPath + "/themes/";
|
||||
const themesFolder = `${userDataPath}/themes/`;
|
||||
if (!fs.existsSync(themesFolder)) {
|
||||
fs.mkdirSync(themesFolder);
|
||||
console.log("Created missing theme folder");
|
||||
|
@ -58,7 +54,7 @@ export function createSettingsWindow() {
|
|||
fs.readdirSync(themesFolder).forEach((file) => {
|
||||
try {
|
||||
const manifest = fs.readFileSync(`${themesFolder}/${file}/manifest.json`, "utf8");
|
||||
var themeFile = JSON.parse(manifest);
|
||||
let themeFile = JSON.parse(manifest);
|
||||
settingsWindow.webContents.send(
|
||||
"themeLoader",
|
||||
fs.readFileSync(`${themesFolder}/${file}/${themeFile.theme}`, "utf-8")
|
||||
|
@ -69,51 +65,41 @@ export function createSettingsWindow() {
|
|||
}
|
||||
});
|
||||
});
|
||||
ipcMain.on("saveSettings", (event, args: Settings) => {
|
||||
ipcMain.on("saveSettings", (_event, args: Settings) => {
|
||||
console.log(args);
|
||||
setConfigBulk(args);
|
||||
});
|
||||
ipcMain.on("openStorageFolder", async (event) => {
|
||||
ipcMain.on("openStorageFolder", async () => {
|
||||
shell.showItemInFolder(storagePath);
|
||||
await sleep(1000);
|
||||
});
|
||||
ipcMain.on("openThemesFolder", async (event) => {
|
||||
ipcMain.on("openThemesFolder", async () => {
|
||||
shell.showItemInFolder(themesPath);
|
||||
await sleep(1000);
|
||||
});
|
||||
ipcMain.on("openPluginsFolder", async (event) => {
|
||||
ipcMain.on("openPluginsFolder", async () => {
|
||||
shell.showItemInFolder(pluginsPath);
|
||||
await sleep(1000);
|
||||
});
|
||||
ipcMain.on("openCrashesFolder", async (event) => {
|
||||
shell.showItemInFolder(path.join(app.getPath("temp"), app.getName() + " Crashes"));
|
||||
ipcMain.on("openCrashesFolder", async () => {
|
||||
shell.showItemInFolder(path.join(app.getPath("temp"), `${app.getName()} Crashes`));
|
||||
await sleep(1000);
|
||||
});
|
||||
ipcMain.on("getLangName", async (event) => {
|
||||
event.returnValue = await getLangName();
|
||||
});
|
||||
ipcMain.on("crash", async (event) => {
|
||||
ipcMain.on("crash", async () => {
|
||||
process.crash();
|
||||
});
|
||||
ipcMain.handle("getSetting", (event, toGet: string) => {
|
||||
ipcMain.handle("getSetting", (_event, toGet: keyof Settings) => {
|
||||
return getConfig(toGet);
|
||||
});
|
||||
ipcMain.on("copyDebugInfo", (event) => {
|
||||
ipcMain.on("copyDebugInfo", () => {
|
||||
let settingsFileContent = fs.readFileSync(getConfigLocation(), "utf-8");
|
||||
clipboard.writeText(
|
||||
"**OS:** " +
|
||||
os.platform() +
|
||||
" " +
|
||||
os.version() +
|
||||
"\n**Architecture:** " +
|
||||
os.arch() +
|
||||
"\n**ArmCord version:** " +
|
||||
getVersion() +
|
||||
"\n**Electron version:** " +
|
||||
process.versions.electron +
|
||||
"\n`" +
|
||||
settingsFileContent +
|
||||
"`"
|
||||
`**OS:** ${os.platform()} ${os.version()}\n**Architecture:** ${os.arch()}\n**ArmCord version:** ${getVersion()}\n**Electron version:** ${
|
||||
process.versions.electron
|
||||
}\n\`${settingsFileContent}\``
|
||||
);
|
||||
});
|
||||
settingsWindow.webContents.setWindowOpenHandler(({url}) => {
|
||||
|
@ -121,7 +107,7 @@ export function createSettingsWindow() {
|
|||
return {action: "deny"};
|
||||
});
|
||||
settingsLoadPage();
|
||||
settingsWindow.on("close", (event: Event) => {
|
||||
settingsWindow.on("close", () => {
|
||||
ipcMain.removeHandler("getSetting");
|
||||
ipcMain.removeAllListeners("saveSettings");
|
||||
instance = 0;
|
||||
|
|
|
@ -16,6 +16,6 @@ contextBridge.exposeInMainWorld("settings", {
|
|||
crash: () => ipcRenderer.send("crash")
|
||||
});
|
||||
|
||||
ipcRenderer.on("themeLoader", (event, message) => {
|
||||
ipcRenderer.on("themeLoader", (_event, message) => {
|
||||
addStyle(message);
|
||||
});
|
||||
|
|
36
src/tray.ts
36
src/tray.ts
|
@ -1,13 +1,13 @@
|
|||
import * as fs from "fs";
|
||||
import {app, Menu, Tray, nativeImage} from "electron";
|
||||
import {Menu, Tray, app, nativeImage} from "electron";
|
||||
import {createInviteWindow, mainWindow} from "./window";
|
||||
import {getConfig, getConfigLocation, setWindowState, getDisplayVersion} from "./utils";
|
||||
import {getConfig, getConfigLocation, getDisplayVersion, setWindowState} from "./utils";
|
||||
import * as path from "path";
|
||||
import {createSettingsWindow} from "./settings/main";
|
||||
export let tray: any = null;
|
||||
app.whenReady().then(async () => {
|
||||
let finishedSetup = await getConfig("doneSetup");
|
||||
var trayIcon = (await getConfig("trayIcon")) ?? "ac_plug_colored";
|
||||
let trayIcon = (await getConfig("trayIcon")) ?? "ac_plug_colored";
|
||||
let trayPath = nativeImage.createFromPath(path.join(__dirname, "../", `/assets/${trayIcon}.png`));
|
||||
let trayVerIcon;
|
||||
trayVerIcon = function () {
|
||||
|
@ -18,14 +18,15 @@ app.whenReady().then(async () => {
|
|||
} else if (process.platform == "linux") {
|
||||
return trayPath.resize({height: 24});
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
if (process.platform == "darwin" && trayPath.getSize().height > 22) trayPath = trayPath.resize({height: 22});
|
||||
|
||||
let clientName = (await getConfig("clientName")) ?? "ArmCord";
|
||||
if ((await getConfig("windowStyle")) == "basic") {
|
||||
var clientName = (await getConfig("clientName")) ?? "ArmCord";
|
||||
tray = new Tray(trayPath);
|
||||
const contextMenu = function () {
|
||||
function contextMenu(): Electron.Menu {
|
||||
if (finishedSetup == false) {
|
||||
return Menu.buildFromTemplate([
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ app.whenReady().then(async () => {
|
|||
},
|
||||
{
|
||||
label: `Quit ${clientName}`,
|
||||
click: async function () {
|
||||
async click() {
|
||||
fs.unlink(await getConfigLocation(), (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
|
@ -48,17 +49,17 @@ app.whenReady().then(async () => {
|
|||
return Menu.buildFromTemplate([
|
||||
{
|
||||
label: `Open ${clientName}`,
|
||||
click: function () {
|
||||
click() {
|
||||
mainWindow.show();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: `Quit ${clientName}`,
|
||||
click: function () {
|
||||
click() {
|
||||
let [width, height] = mainWindow.getSize();
|
||||
setWindowState({
|
||||
width: width,
|
||||
height: height,
|
||||
width,
|
||||
height,
|
||||
isMaximized: mainWindow.isMaximized(),
|
||||
x: mainWindow.getPosition()[0],
|
||||
y: mainWindow.getPosition()[1]
|
||||
|
@ -68,12 +69,11 @@ app.whenReady().then(async () => {
|
|||
}
|
||||
]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tray.setToolTip(clientName);
|
||||
tray.setContextMenu(contextMenu);
|
||||
} else {
|
||||
var clientName = (await getConfig("clientName")) ?? "ArmCord";
|
||||
tray = new Tray(trayPath);
|
||||
if (finishedSetup == false) {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
|
@ -83,7 +83,7 @@ app.whenReady().then(async () => {
|
|||
},
|
||||
{
|
||||
label: `Quit ${clientName}`,
|
||||
click: async function () {
|
||||
async click() {
|
||||
fs.unlink(await getConfigLocation(), (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
|
@ -97,7 +97,7 @@ app.whenReady().then(async () => {
|
|||
} else {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: `${clientName} ` + getDisplayVersion(),
|
||||
label: `${clientName} ${getDisplayVersion()}`,
|
||||
icon: trayVerIcon(),
|
||||
enabled: false
|
||||
},
|
||||
|
@ -106,19 +106,19 @@ app.whenReady().then(async () => {
|
|||
},
|
||||
{
|
||||
label: `Open ${clientName}`,
|
||||
click: function () {
|
||||
click() {
|
||||
mainWindow.show();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Open Settings",
|
||||
click: function () {
|
||||
click() {
|
||||
createSettingsWindow();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Support Discord Server",
|
||||
click: function () {
|
||||
click() {
|
||||
createInviteWindow("TnhxcqynZ2");
|
||||
}
|
||||
},
|
||||
|
@ -127,7 +127,7 @@ app.whenReady().then(async () => {
|
|||
},
|
||||
{
|
||||
label: `Quit ${clientName}`,
|
||||
click: function () {
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
|
|
137
src/utils.ts
137
src/utils.ts
|
@ -1,31 +1,31 @@
|
|||
import * as fs from "fs";
|
||||
import {app, dialog, Rectangle} from "electron";
|
||||
import {app, dialog} from "electron";
|
||||
import path from "path";
|
||||
import fetch from "cross-fetch";
|
||||
import extract from "extract-zip";
|
||||
import util from "util";
|
||||
const streamPipeline = util.promisify(require("stream").pipeline);
|
||||
export var firstRun: boolean;
|
||||
export var contentPath: string;
|
||||
export var transparency: boolean;
|
||||
export let firstRun: boolean;
|
||||
export let contentPath: string;
|
||||
export let transparency: boolean;
|
||||
//utility functions that are used all over the codebase or just too obscure to be put in the file used in
|
||||
export function addStyle(styleString: string) {
|
||||
export function addStyle(styleString: string): void {
|
||||
const style = document.createElement("style");
|
||||
style.textContent = styleString;
|
||||
document.head.append(style);
|
||||
}
|
||||
|
||||
export function addScript(scriptString: string) {
|
||||
var script = document.createElement("script");
|
||||
export function addScript(scriptString: string): void {
|
||||
let script = document.createElement("script");
|
||||
script.textContent = scriptString;
|
||||
document.body.append(script);
|
||||
}
|
||||
|
||||
export async function sleep(ms: number) {
|
||||
export async function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export async function checkIfConfigIsBroken() {
|
||||
export async function checkIfConfigIsBroken(): Promise<void> {
|
||||
if ((await getConfig("0")) == "d") {
|
||||
console.log("Detected a corrupted config");
|
||||
setup();
|
||||
|
@ -36,7 +36,7 @@ export async function checkIfConfigIsBroken() {
|
|||
}
|
||||
}
|
||||
|
||||
export function setup() {
|
||||
export function setup(): void {
|
||||
console.log("Setting up temporary ArmCord settings.");
|
||||
const defaults: Settings = {
|
||||
windowStyle: "default",
|
||||
|
@ -55,7 +55,9 @@ export function setup() {
|
|||
useLegacyCapturer: false,
|
||||
mobileMode: false,
|
||||
trayIcon: "default",
|
||||
doneSetup: false
|
||||
doneSetup: false,
|
||||
clientName: "ArmCord",
|
||||
customIcon: path.join(__dirname, "../", "/assets/ac_icon_transparent.png")
|
||||
};
|
||||
setConfigBulk({
|
||||
...defaults
|
||||
|
@ -63,12 +65,12 @@ export function setup() {
|
|||
}
|
||||
|
||||
//Get the version value from the "package.json" file
|
||||
export var packageVersion = require("../package.json").version;
|
||||
export const packageVersion = require("../package.json").version;
|
||||
|
||||
export function getVersion() {
|
||||
export function getVersion(): string {
|
||||
return packageVersion;
|
||||
}
|
||||
export function getDisplayVersion() {
|
||||
export function getDisplayVersion(): string {
|
||||
//Checks if the app version # has 4 sections (3.1.0.0) instead of 3 (3.1.0) / Shitty way to check if Kernel Mod is installed
|
||||
if ((app.getVersion() == packageVersion) == false) {
|
||||
if ((app.getVersion() == process.versions.electron) == true) {
|
||||
|
@ -80,7 +82,7 @@ export function getDisplayVersion() {
|
|||
return packageVersion;
|
||||
}
|
||||
}
|
||||
export async function injectJS(inject: string) {
|
||||
export async function injectJS(inject: string): Promise<void> {
|
||||
const js = await (await fetch(`${inject}`)).text();
|
||||
|
||||
const el = document.createElement("script");
|
||||
|
@ -89,7 +91,7 @@ export async function injectJS(inject: string) {
|
|||
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
export async function injectElectronFlags() {
|
||||
export async function injectElectronFlags(): Promise<void> {
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2022 GooseNest
|
||||
|
@ -135,43 +137,43 @@ export async function injectElectronFlags() {
|
|||
});
|
||||
}
|
||||
}
|
||||
export async function setLang(language: string) {
|
||||
const langConfigFile = path.join(app.getPath("userData"), "/storage/") + "lang.json";
|
||||
export async function setLang(language: string): Promise<void> {
|
||||
const langConfigFile = `${path.join(app.getPath("userData"), "/storage/")}lang.json`;
|
||||
if (!fs.existsSync(langConfigFile)) {
|
||||
fs.writeFileSync(langConfigFile, "{}", "utf-8");
|
||||
}
|
||||
let rawdata = fs.readFileSync(langConfigFile, "utf-8");
|
||||
let parsed = JSON.parse(rawdata);
|
||||
parsed["lang"] = language;
|
||||
parsed.lang = language;
|
||||
let toSave = JSON.stringify(parsed, null, 4);
|
||||
fs.writeFileSync(langConfigFile, toSave, "utf-8");
|
||||
}
|
||||
var language: string;
|
||||
export async function getLang(object: string) {
|
||||
let language: string;
|
||||
export async function getLang(object: string): Promise<string> {
|
||||
if (language == undefined) {
|
||||
try {
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
const langConfigFile = storagePath + "lang.json";
|
||||
const langConfigFile = `${storagePath}lang.json`;
|
||||
let rawdata = fs.readFileSync(langConfigFile, "utf-8");
|
||||
let parsed = JSON.parse(rawdata);
|
||||
language = parsed["lang"];
|
||||
} catch (e) {
|
||||
language = parsed.lang;
|
||||
} catch (_e) {
|
||||
console.log("Language config file doesn't exist. Fallback to English.");
|
||||
language = "en-US";
|
||||
}
|
||||
}
|
||||
if (language.length == 2) {
|
||||
language = language + "-" + language.toUpperCase();
|
||||
language = `${language}-${language.toUpperCase()}`;
|
||||
}
|
||||
var langPath = path.join(__dirname, "../", "/assets/lang/" + language + ".json");
|
||||
let langPath = path.join(__dirname, "../", `/assets/lang/${language}.json`);
|
||||
if (!fs.existsSync(langPath)) {
|
||||
langPath = path.join(__dirname, "../", "/assets/lang/en-US.json");
|
||||
}
|
||||
let rawdata = fs.readFileSync(langPath, "utf-8");
|
||||
let parsed = JSON.parse(rawdata);
|
||||
if (parsed[object] == undefined) {
|
||||
console.log(object + " is undefined in " + language);
|
||||
console.log(`${object} is undefined in ${language}`);
|
||||
langPath = path.join(__dirname, "../", "/assets/lang/en-US.json");
|
||||
rawdata = fs.readFileSync(langPath, "utf-8");
|
||||
parsed = JSON.parse(rawdata);
|
||||
|
@ -180,22 +182,22 @@ export async function getLang(object: string) {
|
|||
return parsed[object];
|
||||
}
|
||||
}
|
||||
export async function getLangName() {
|
||||
export async function getLangName(): Promise<string> {
|
||||
if (language == undefined) {
|
||||
try {
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
const langConfigFile = storagePath + "lang.json";
|
||||
const langConfigFile = `${storagePath}lang.json`;
|
||||
let rawdata = fs.readFileSync(langConfigFile, "utf-8");
|
||||
let parsed = JSON.parse(rawdata);
|
||||
language = parsed["lang"];
|
||||
} catch (e) {
|
||||
language = parsed.lang;
|
||||
} catch (_e) {
|
||||
console.log("Language config file doesn't exist. Fallback to English.");
|
||||
language = "en-US";
|
||||
}
|
||||
}
|
||||
if (language.length == 2) {
|
||||
language = language + "-" + language.toUpperCase();
|
||||
language = `${language}-${language.toUpperCase()}`;
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
@ -207,26 +209,26 @@ export interface WindowState {
|
|||
y: number;
|
||||
isMaximized: boolean;
|
||||
}
|
||||
export async function setWindowState(object: WindowState) {
|
||||
export async function setWindowState(object: WindowState): Promise<void> {
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
const saveFile = storagePath + "window.json";
|
||||
const saveFile = `${storagePath}window.json`;
|
||||
let toSave = JSON.stringify(object, null, 4);
|
||||
fs.writeFileSync(saveFile, toSave, "utf-8");
|
||||
}
|
||||
export async function getWindowState(object: string) {
|
||||
export async function getWindowState<K extends keyof WindowState>(object: K): Promise<WindowState[K]> {
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
const settingsFile = storagePath + "window.json";
|
||||
const settingsFile = `${storagePath}window.json`;
|
||||
let rawdata = fs.readFileSync(settingsFile, "utf-8");
|
||||
let returndata = JSON.parse(rawdata);
|
||||
console.log(returndata);
|
||||
console.log("[Window state manager] " + returndata);
|
||||
console.log(`[Window state manager] ${returndata}`);
|
||||
return returndata[object];
|
||||
}
|
||||
//ArmCord Settings/Storage manager
|
||||
|
||||
export function checkForDataFolder() {
|
||||
export function checkForDataFolder(): void {
|
||||
const dataPath = path.join(path.dirname(app.getPath("exe")), "armcord-data");
|
||||
if (fs.existsSync(dataPath) && fs.statSync(dataPath).isDirectory()) {
|
||||
console.log("Found armcord-data folder. Running in portable mode.");
|
||||
|
@ -235,6 +237,14 @@ export function checkForDataFolder() {
|
|||
}
|
||||
|
||||
export interface Settings {
|
||||
// Referenced for detecting a broken config.
|
||||
"0"?: string;
|
||||
// Referenced once for disabling mod updating.
|
||||
noBundleUpdates?: boolean;
|
||||
// Only used for external url warning dialog.
|
||||
ignoreProtocolWarning?: boolean;
|
||||
customIcon: string;
|
||||
|
||||
windowStyle: string;
|
||||
channel: string;
|
||||
armcordCSP: boolean;
|
||||
|
@ -252,33 +262,34 @@ export interface Settings {
|
|||
disableAutogain: boolean;
|
||||
trayIcon: string;
|
||||
doneSetup: boolean;
|
||||
clientName: string;
|
||||
}
|
||||
export function getConfigLocation() {
|
||||
export function getConfigLocation(): string {
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
return storagePath + "settings.json";
|
||||
return `${storagePath}settings.json`;
|
||||
}
|
||||
export async function getConfig(object: string) {
|
||||
export async function getConfig<K extends keyof Settings>(object: K): Promise<Settings[K]> {
|
||||
let rawdata = fs.readFileSync(getConfigLocation(), "utf-8");
|
||||
let returndata = JSON.parse(rawdata);
|
||||
console.log("[Config manager] " + object + ": " + returndata[object]);
|
||||
console.log(`[Config manager] ${object}: ${returndata[object]}`);
|
||||
return returndata[object];
|
||||
}
|
||||
export async function setConfig(object: string, toSet: any) {
|
||||
export async function setConfig<K extends keyof Settings>(object: K, toSet: Settings[K]): Promise<void> {
|
||||
let rawdata = fs.readFileSync(getConfigLocation(), "utf-8");
|
||||
let parsed = JSON.parse(rawdata);
|
||||
parsed[object] = toSet;
|
||||
let toSave = JSON.stringify(parsed, null, 4);
|
||||
fs.writeFileSync(getConfigLocation(), toSave, "utf-8");
|
||||
}
|
||||
export async function setConfigBulk(object: Settings) {
|
||||
export async function setConfigBulk(object: Settings): Promise<void> {
|
||||
let toSave = JSON.stringify(object, null, 4);
|
||||
fs.writeFileSync(getConfigLocation(), toSave, "utf-8");
|
||||
}
|
||||
export async function checkIfConfigExists() {
|
||||
export async function checkIfConfigExists(): Promise<void> {
|
||||
const userDataPath = app.getPath("userData");
|
||||
const storagePath = path.join(userDataPath, "/storage/");
|
||||
const settingsFile = storagePath + "settings.json";
|
||||
const settingsFile = `${storagePath}settings.json`;
|
||||
|
||||
if (!fs.existsSync(settingsFile)) {
|
||||
if (!fs.existsSync(storagePath)) {
|
||||
|
@ -288,27 +299,25 @@ export async function checkIfConfigExists() {
|
|||
console.log("First run of the ArmCord. Starting setup.");
|
||||
setup();
|
||||
firstRun = true;
|
||||
} else {
|
||||
if ((await getConfig("doneSetup")) == false) {
|
||||
} else if ((await getConfig("doneSetup")) == false) {
|
||||
console.log("First run of the ArmCord. Starting setup.");
|
||||
setup();
|
||||
firstRun = true;
|
||||
} else {
|
||||
console.log("ArmCord has been run before. Skipping setup.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mods
|
||||
async function updateModBundle() {
|
||||
async function updateModBundle(): Promise<void> {
|
||||
if ((await getConfig("noBundleUpdates")) == undefined ?? false) {
|
||||
try {
|
||||
console.log("Downloading mod bundle");
|
||||
const distFolder = app.getPath("userData") + "/plugins/loader/dist/";
|
||||
const distFolder = `${app.getPath("userData")}/plugins/loader/dist/`;
|
||||
while (!fs.existsSync(distFolder)) {
|
||||
//waiting
|
||||
}
|
||||
var name: string = await getConfig("mods");
|
||||
let name: string = await getConfig("mods");
|
||||
const clientMods = {
|
||||
vencord: "https://github.com/Vendicated/Vencord/releases/download/devbuild/browser.js",
|
||||
cordwood: "https://raw.githubusercontent.com/Cordwood/builds/master/index.js",
|
||||
|
@ -319,10 +328,10 @@ async function updateModBundle() {
|
|||
cordwood: "https://armcord.xyz/placeholder.css",
|
||||
shelter: "https://armcord.xyz/placeholder.css"
|
||||
};
|
||||
var bundle: string = await (await fetch(clientMods[name as keyof typeof clientMods])).text();
|
||||
fs.writeFileSync(distFolder + "bundle.js", bundle, "utf-8");
|
||||
var css: string = await (await fetch(clientModsCss[name as keyof typeof clientModsCss])).text();
|
||||
fs.writeFileSync(distFolder + "bundle.css", css, "utf-8");
|
||||
let bundle: string = await (await fetch(clientMods[name as keyof typeof clientMods])).text();
|
||||
fs.writeFileSync(`${distFolder}bundle.js`, bundle, "utf-8");
|
||||
let css: string = await (await fetch(clientModsCss[name as keyof typeof clientModsCss])).text();
|
||||
fs.writeFileSync(`${distFolder}bundle.css`, css, "utf-8");
|
||||
} catch (e) {
|
||||
console.log("[Mod loader] Failed to install mods");
|
||||
console.error(e);
|
||||
|
@ -336,25 +345,25 @@ async function updateModBundle() {
|
|||
}
|
||||
}
|
||||
|
||||
export var modInstallState: string;
|
||||
export async function installModLoader() {
|
||||
export let modInstallState: string;
|
||||
export async function installModLoader(): Promise<void> {
|
||||
if ((await getConfig("mods")) == "none") {
|
||||
modInstallState = "none";
|
||||
fs.rmSync(app.getPath("userData") + "/plugins/loader", {recursive: true, force: true});
|
||||
fs.rmSync(`${app.getPath("userData")}/plugins/loader`, {recursive: true, force: true});
|
||||
import("./extensions/plugin");
|
||||
console.log("[Mod loader] Skipping");
|
||||
} else {
|
||||
const pluginFolder = app.getPath("userData") + "/plugins/";
|
||||
if (!fs.existsSync(pluginFolder + "loader") || !fs.existsSync(pluginFolder + "loader/dist/" + "bundle.css")) {
|
||||
const pluginFolder = `${app.getPath("userData")}/plugins/`;
|
||||
if (!fs.existsSync(`${pluginFolder}loader`) || !fs.existsSync(`${pluginFolder}loader/dist/bundle.css`)) {
|
||||
try {
|
||||
fs.rmSync(app.getPath("userData") + "/plugins/loader", {recursive: true, force: true});
|
||||
fs.rmSync(`${app.getPath("userData")}/plugins/loader`, {recursive: true, force: true});
|
||||
modInstallState = "installing";
|
||||
var zipPath = app.getPath("temp") + "/" + "loader.zip";
|
||||
let zipPath = `${app.getPath("temp")}/loader.zip`;
|
||||
if (!fs.existsSync(pluginFolder)) {
|
||||
fs.mkdirSync(pluginFolder);
|
||||
console.log("[Mod loader] Created missing plugin folder");
|
||||
}
|
||||
var loaderZip = await fetch("https://armcord.xyz/loader.zip");
|
||||
let loaderZip = await fetch("https://armcord.xyz/loader.zip");
|
||||
if (!loaderZip.ok) throw new Error(`unexpected response ${loaderZip.statusText}`);
|
||||
await streamPipeline(loaderZip.body, fs.createWriteStream(zipPath));
|
||||
await extract(zipPath, {dir: path.join(app.getPath("userData"), "plugins")});
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
// I had to add most of the window creation code here to split both into seperete functions
|
||||
// WHY? Because I can't use the same code for both due to annoying bug with value `frame` not responding to variables
|
||||
// I'm sorry for this mess but I'm not sure how to fix it.
|
||||
import {BrowserWindow, shell, app, dialog, nativeImage} from "electron";
|
||||
import {BrowserWindow, app, dialog, nativeImage, shell} from "electron";
|
||||
import path from "path";
|
||||
import {
|
||||
checkIfConfigIsBroken,
|
||||
contentPath,
|
||||
firstRun,
|
||||
getConfig,
|
||||
contentPath,
|
||||
modInstallState,
|
||||
setConfig,
|
||||
setLang,
|
||||
setWindowState,
|
||||
transparency,
|
||||
sleep,
|
||||
modInstallState
|
||||
transparency
|
||||
} from "./utils";
|
||||
import {registerIpc} from "./ipc";
|
||||
import {setMenu} from "./menu";
|
||||
|
@ -26,13 +26,13 @@ import {iconPath} from "./main";
|
|||
export let mainWindow: BrowserWindow;
|
||||
export let inviteWindow: BrowserWindow;
|
||||
|
||||
var osType = os.type();
|
||||
let osType = os.type();
|
||||
contextMenu({
|
||||
showSaveImageAs: true,
|
||||
showCopyImageAddress: true,
|
||||
showSearchWithGoogle: false,
|
||||
showSearchWithDuckDuckGo: false,
|
||||
prepend: (defaultActions, parameters, browserWindow) => [
|
||||
prepend: (_defaultActions, parameters) => [
|
||||
{
|
||||
label: "Search with Google",
|
||||
// Only show it when right-clicking text
|
||||
|
@ -51,7 +51,7 @@ contextMenu({
|
|||
}
|
||||
]
|
||||
});
|
||||
async function doAfterDefiningTheWindow() {
|
||||
async function doAfterDefiningTheWindow(): Promise<void> {
|
||||
if (await getConfig("startMinimized")) {
|
||||
mainWindow.hide();
|
||||
} else {
|
||||
|
@ -66,7 +66,7 @@ async function doAfterDefiningTheWindow() {
|
|||
}
|
||||
});
|
||||
}
|
||||
var ignoreProtocolWarning = await getConfig("ignoreProtocolWarning");
|
||||
let ignoreProtocolWarning = await getConfig("ignoreProtocolWarning");
|
||||
await checkIfConfigIsBroken();
|
||||
registerIpc();
|
||||
if (await getConfig("mobileMode")) {
|
||||
|
@ -75,11 +75,11 @@ async function doAfterDefiningTheWindow() {
|
|||
} else {
|
||||
// A little sloppy but it works :p
|
||||
if (osType == "Windows_NT") {
|
||||
osType = "Windows " + os.release().split(".")[0] + " (" + os.release() + ")";
|
||||
osType = `Windows ${os.release().split(".")[0]} (${os.release()})`;
|
||||
}
|
||||
mainWindow.webContents.userAgent = `Mozilla/5.0 (X11; ${osType} ${os.arch()}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36`; //fake useragent for screenshare to work
|
||||
}
|
||||
app.on("second-instance", (event, commandLine, workingDirectory, additionalData) => {
|
||||
app.on("second-instance", (_event, _commandLine, _workingDirectory, additionalData) => {
|
||||
// Print out data received from the second instance.
|
||||
console.log(additionalData);
|
||||
|
||||
|
@ -102,8 +102,7 @@ async function doAfterDefiningTheWindow() {
|
|||
return {action: "allow"};
|
||||
if (url.startsWith("https:") || url.startsWith("http:") || url.startsWith("mailto:")) {
|
||||
shell.openExternal(url);
|
||||
} else {
|
||||
if (ignoreProtocolWarning) {
|
||||
} else if (ignoreProtocolWarning) {
|
||||
shell.openExternal(url);
|
||||
} else {
|
||||
const options = {
|
||||
|
@ -128,12 +127,9 @@ async function doAfterDefiningTheWindow() {
|
|||
}
|
||||
if (response == 0) {
|
||||
shell.openExternal(url);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return {action: "deny"};
|
||||
});
|
||||
if ((await getConfig("useLegacyCapturer")) == false) {
|
||||
|
@ -147,8 +143,8 @@ async function doAfterDefiningTheWindow() {
|
|||
);
|
||||
|
||||
if ((await getConfig("trayIcon")) == "default" || (await getConfig("dynamicIcon"))) {
|
||||
mainWindow.webContents.on("page-favicon-updated", async (event) => {
|
||||
var faviconBase64 = await mainWindow.webContents.executeJavaScript(`
|
||||
mainWindow.webContents.on("page-favicon-updated", async () => {
|
||||
let faviconBase64 = await mainWindow.webContents.executeJavaScript(`
|
||||
var getFavicon = function(){
|
||||
var favicon = undefined;
|
||||
var nodeList = document.getElementsByTagName("link");
|
||||
|
@ -163,7 +159,7 @@ async function doAfterDefiningTheWindow() {
|
|||
}
|
||||
getFavicon()
|
||||
`);
|
||||
var buf = new Buffer(faviconBase64.replace(/^data:image\/\w+;base64,/, ""), "base64");
|
||||
let buf = Buffer.from(faviconBase64.replace(/^data:image\/\w+;base64,/, ""), "base64");
|
||||
fs.writeFileSync(path.join(app.getPath("temp"), "/", "tray.png"), buf, "utf-8");
|
||||
let trayPath = nativeImage.createFromPath(path.join(app.getPath("temp"), "/", "tray.png"));
|
||||
if (process.platform === "darwin" && trayPath.getSize().height > 22)
|
||||
|
@ -178,7 +174,7 @@ async function doAfterDefiningTheWindow() {
|
|||
});
|
||||
}
|
||||
const userDataPath = app.getPath("userData");
|
||||
const themesFolder = userDataPath + "/themes/";
|
||||
const themesFolder = `${userDataPath}/themes/`;
|
||||
if (!fs.existsSync(themesFolder)) {
|
||||
fs.mkdirSync(themesFolder);
|
||||
console.log("Created missing theme folder");
|
||||
|
@ -187,7 +183,7 @@ async function doAfterDefiningTheWindow() {
|
|||
fs.readdirSync(themesFolder).forEach((file) => {
|
||||
try {
|
||||
const manifest = fs.readFileSync(`${themesFolder}/${file}/manifest.json`, "utf8");
|
||||
var themeFile = JSON.parse(manifest);
|
||||
let themeFile = JSON.parse(manifest);
|
||||
mainWindow.webContents.send(
|
||||
"themeLoader",
|
||||
fs.readFileSync(`${themesFolder}/${file}/${themeFile.theme}`, "utf-8")
|
||||
|
@ -202,8 +198,8 @@ async function doAfterDefiningTheWindow() {
|
|||
mainWindow.on("close", async (e) => {
|
||||
let [width, height] = mainWindow.getSize();
|
||||
await setWindowState({
|
||||
width: width,
|
||||
height: height,
|
||||
width,
|
||||
height,
|
||||
isMaximized: mainWindow.isMaximized(),
|
||||
x: mainWindow.getPosition()[0],
|
||||
y: mainWindow.getPosition()[1]
|
||||
|
@ -232,12 +228,11 @@ async function doAfterDefiningTheWindow() {
|
|||
});
|
||||
console.log(contentPath);
|
||||
if ((await getConfig("inviteWebsocket")) == true) {
|
||||
//@ts-ignore
|
||||
require("arrpc");
|
||||
//await startServer();
|
||||
}
|
||||
if (firstRun) {
|
||||
await setLang(Intl.DateTimeFormat().resolvedOptions().locale);
|
||||
await setLang(new Intl.DateTimeFormat().resolvedOptions().locale);
|
||||
mainWindow.setSize(390, 470);
|
||||
await mainWindow.loadFile(path.join(__dirname, "/content/setup.html"));
|
||||
let trayPath = nativeImage.createFromPath(path.join(__dirname, "../", `/assets/ac_plug_colored.png`));
|
||||
|
@ -245,6 +240,8 @@ async function doAfterDefiningTheWindow() {
|
|||
if (process.platform === "win32" && trayPath.getSize().height > 32) trayPath = trayPath.resize({height: 32});
|
||||
tray.setImage(trayPath);
|
||||
} else if ((await getConfig("skipSplash")) == true) {
|
||||
// It's modified elsewhere.
|
||||
// eslint-disable-next-line no-unmodified-loop-condition
|
||||
while (modInstallState == "installing") {
|
||||
await sleep(1000);
|
||||
}
|
||||
|
@ -277,7 +274,7 @@ async function doAfterDefiningTheWindow() {
|
|||
mainWindow.show();
|
||||
}
|
||||
}
|
||||
export function createCustomWindow() {
|
||||
export function createCustomWindow(): void {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 300,
|
||||
height: 350,
|
||||
|
@ -296,7 +293,7 @@ export function createCustomWindow() {
|
|||
});
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
export function createNativeWindow() {
|
||||
export function createNativeWindow(): void {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 300,
|
||||
height: 350,
|
||||
|
@ -315,7 +312,7 @@ export function createNativeWindow() {
|
|||
});
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
export function createTransparentWindow() {
|
||||
export function createTransparentWindow(): void {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 300,
|
||||
height: 350,
|
||||
|
@ -334,7 +331,7 @@ export function createTransparentWindow() {
|
|||
});
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
export function createInviteWindow(code: string) {
|
||||
export function createInviteWindow(code: string): void {
|
||||
inviteWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
@ -348,7 +345,7 @@ export function createInviteWindow(code: string) {
|
|||
spellcheck: true
|
||||
}
|
||||
});
|
||||
var formInviteURL = `https://discord.com/invite/${code}`;
|
||||
let formInviteURL = `https://discord.com/invite/${code}`;
|
||||
inviteWindow.webContents.session.webRequest.onBeforeRequest((details, callback) => {
|
||||
if (details.url.includes("ws://")) return callback({cancel: true});
|
||||
return callback({});
|
||||
|
|
Loading…
Reference in a new issue