mirror of
https://github.com/smartfrigde/armcord.git
synced 2024-08-14 23:56:58 +00:00
Compare commits
13 commits
a48258da45
...
53fd78dc4b
Author | SHA1 | Date | |
---|---|---|---|
|
53fd78dc4b | ||
|
1be3275375 | ||
|
2f01b26339 | ||
|
46f91276c2 | ||
|
87920505db | ||
|
18bebfb421 | ||
|
7ed9f1bef2 | ||
|
bab60a4f1b | ||
|
2a736fb9e0 | ||
|
c98b6016ca | ||
|
fcdb247601 | ||
|
ead7e62d39 | ||
|
f7711034c5 |
36 changed files with 2044 additions and 1026 deletions
37
.github/workflows/build.yml
vendored
37
.github/workflows/build.yml
vendored
|
@ -1,37 +0,0 @@
|
|||
name: Build/release
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node.js, NPM and Yarn
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Build/release Electron app
|
||||
uses: samuelmeuli/action-electron-builder@v1
|
||||
with:
|
||||
# GitHub token, automatically provided to the action
|
||||
# (No need to define this secret in the repo settings)
|
||||
github_token: ${{ secrets.github_token }}
|
||||
# skip npm run build as there's no script like that
|
||||
skip_build: false
|
||||
# If the commit is tagged with a version (e.g. "v1.0.0"),
|
||||
# release the app after building
|
||||
release: ${{ startsWith(github.ref, 'refs/tags/v') }} #disabled for now as it caused problems (nvm)
|
||||
- name: Archive production builds
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: dist folder
|
||||
path: dist/**
|
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
_
|
5
.husky/pre-commit
Executable file
5
.husky/pre-commit
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname $0)/_/husky.sh"
|
||||
|
||||
npm run format
|
||||
git add -A
|
11
.prettierignore
Normal file
11
.prettierignore
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Some prettier-specific files so it doesn't die.
|
||||
**/*.png
|
||||
**/*.ico
|
||||
LICENSE
|
||||
.gitignore
|
||||
|
||||
node_modules
|
||||
out/
|
||||
dist
|
||||
ts-out/
|
||||
ts-out
|
|
@ -32,8 +32,8 @@
|
|||
|
||||
# How to run/install it?
|
||||
### Recommended:
|
||||
Check releases tab for precompiled packages for Linux, Windows and ~~Mac OS~~ (Mac OS is broken see [#48](https://github.com/ArmCord/ArmCord/issues/48)).
|
||||
|
||||
Check releases tab for precompiled packages for Linux, Windows and ~~Mac OS~~ (Mac OS is broken see [#48](https://github.com/ArmCord/ArmCord/issues/48)). Alternatively use our Sourceforge mirror.
|
||||
<a href="https://sourceforge.net/projects/armcord/files/latest/download"><img alt="Download ArmCord" src="https://a.fsdn.com/con/app/sf-download-button" width=276 height=48 srcset="https://a.fsdn.com/con/app/sf-download-button?button_size=2x 2x"></a>
|
||||
### AUR Package
|
||||
Armcord is also available on the Arch User Repository (AUR) [here](https://aur.archlinux.org/packages/armcord-bin/).
|
||||
|
||||
|
|
671
package-lock.json
generated
671
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -1,13 +1,15 @@
|
|||
{
|
||||
"name": "ArmCord",
|
||||
"version": "3.0.4",
|
||||
"version": "3.1.0",
|
||||
"description": "ArmCord is a custom client designed to enhance your Discord experience while keeping everything lightweight.",
|
||||
"main": "ts-out/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc && copyfiles -u 1 src/**/*.html src/**/*.css ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/** ts-out/",
|
||||
"build": "tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/** ts-out/",
|
||||
"watch": "tsc -w",
|
||||
"start": "npm run build && electron ./ts-out/main.js",
|
||||
"package": "npm run build && electron-builder"
|
||||
"package": "npm run build && electron-builder",
|
||||
"format": "prettier --write src/**/*",
|
||||
"postinstall": "husky install"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -23,12 +25,17 @@
|
|||
"@types/electron-json-storage": "^4.5.0",
|
||||
"@types/node": "^14.18.2",
|
||||
"copyfiles": "^2.4.1",
|
||||
"electron": "^16.0.7",
|
||||
"electron-builder": "^22.14.5",
|
||||
"electron": "^17.1.0",
|
||||
"electron-builder": "^22.14.13",
|
||||
"husky": "^7.0.4",
|
||||
"prettier": "^2.5.1",
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"electron-context-menu": "^3.1.2",
|
||||
"electron-json-storage": "^4.5.0",
|
||||
"electron-tabs": "^0.15.0",
|
||||
"glasstron": "^0.1.1",
|
||||
"v8-compile-cache": "^2.3.0"
|
||||
},
|
||||
"build": {
|
||||
|
|
14
prettier.config.js
Normal file
14
prettier.config.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
module.exports = {
|
||||
printWidth: 120,
|
||||
tabWidth: 4,
|
||||
useTabs: false,
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
quoteProps: "as-needed",
|
||||
jsxSingleQuote: false,
|
||||
trailingComma: "none",
|
||||
bracketSpacing: false,
|
||||
jsxBracketSameLine: false,
|
||||
arrowParens: "always",
|
||||
endOfLine: "auto"
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
.info-1sUqUG:last-child:before {
|
||||
content: "ArmCord Version: 3.1.0"!important;
|
||||
.info-3pQQBb:last-child:before {
|
||||
content: "ArmCord Version: 3.1.0" !important;
|
||||
height: auto;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
|
|
53
src/content/css/tabs.css
Normal file
53
src/content/css/tabs.css
Normal file
|
@ -0,0 +1,53 @@
|
|||
@import url("https://kckarnige.github.io/femboi_owo/discord-font.css");
|
||||
:root {
|
||||
--window-buttons: var(--header-secondary);
|
||||
--cord-color: var(--header-primary);
|
||||
--armcord-color: #7289da;
|
||||
--titlebar-color: var(--background-tertiary);
|
||||
}
|
||||
.tabs {
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
zoom: 1;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
clear: both;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background-color: #202225;
|
||||
-webkit-app-region: drag;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.tabs #tabs-controls-container {
|
||||
float: left;
|
||||
width: 150px;
|
||||
height: 100%;
|
||||
line-height: 30px;
|
||||
background-color: #202225;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
.tabs-buttons {
|
||||
color: white;
|
||||
background-color: inherit;
|
||||
float: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
font-size: 20px;
|
||||
}
|
||||
.tabs-buttons:hover {
|
||||
background-color: #4e515a;
|
||||
}
|
||||
.withFrame-haYltI {
|
||||
height: 30px !important;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
@import url("https://kckarnige.github.io/femboi_owo/discord-font.css");
|
||||
@import url("https://armcord.smartfridge.space/logofont.css");
|
||||
:root {
|
||||
--window-buttons: var(--header-secondary);
|
||||
--cord-color: var(--header-primary);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<h1>settings, really cool</h1>
|
|
@ -1,10 +1,8 @@
|
|||
<!--- This is awful and should be replaced in later versions. Possibly based of current settings as of 3.1.0 version. If you have time please PR a better setup screen. --->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css" />
|
||||
<meta charset="UTF-8" />
|
||||
<title>ArmCord Setup</title>
|
||||
<style>
|
||||
|
@ -22,7 +20,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
function fade(element) {
|
||||
var op = 1; // initial opacity
|
||||
var timer = setInterval(function () {
|
||||
|
@ -42,12 +39,20 @@
|
|||
} else {
|
||||
console.log("Starting ArmCord Setup...");
|
||||
document.getElementById("express").addEventListener("click", function () {
|
||||
window.armcordinternal.saveSettings(true, "stable", true, "cumcord");
|
||||
window.armcordinternal.saveSettings({
|
||||
windowStyle: "default",
|
||||
channel: "stable",
|
||||
armcordCSP: true,
|
||||
minimizeToTray: true,
|
||||
automaticPatches: false,
|
||||
mods: "cumcord",
|
||||
blurType: "acrylic"
|
||||
});
|
||||
fade(document.getElementById("setup"));
|
||||
setTimeout(function () {
|
||||
window.armcordinternal.restart()
|
||||
window.armcordinternal.restart();
|
||||
}, 5000);
|
||||
})
|
||||
});
|
||||
document.getElementById("full").addEventListener("click", function () {
|
||||
document.getElementById("setup").innerHTML = `
|
||||
<p class="text-center setup-ask">Choose your Discord channel/instance:</p>
|
||||
|
@ -68,9 +73,7 @@
|
|||
</div>
|
||||
<button id="next" class="center">Next</button>
|
||||
`;
|
||||
document
|
||||
.getElementById("next")
|
||||
.addEventListener("click", function () {
|
||||
document.getElementById("next").addEventListener("click", function () {
|
||||
var branch = document.getElementById("channel").value;
|
||||
var csp = document.getElementById("csp").value;
|
||||
if (csp === "true") {
|
||||
|
@ -86,22 +89,35 @@
|
|||
<p>Why not all of them? Having many client mods at the same time can cause issues. If you really want to do it though, check our documentation ;)</p>
|
||||
<button id="next" class="center">Next</button>
|
||||
`;
|
||||
document
|
||||
.getElementById("next")
|
||||
.addEventListener("click", function () {
|
||||
document.getElementById("next").addEventListener("click", function () {
|
||||
var mod = document.getElementById("mod").value;
|
||||
window.armcordinternal.saveSettings(true, branch, true, mod);
|
||||
window.armcordinternal.saveSettings({
|
||||
windowStyle: "default",
|
||||
channel: branch,
|
||||
armcordCSP: true,
|
||||
minimizeToTray: true,
|
||||
automaticPatches: false,
|
||||
mods: mod,
|
||||
blurType: "acrylic"
|
||||
});
|
||||
fade(document.getElementById("setup"));
|
||||
setTimeout(function () {
|
||||
window.armcordinternal.restart();
|
||||
}, 5000);
|
||||
});
|
||||
} else {
|
||||
//saveSettings(customTitlebarSetting: boolean, channelSetting: string, armcordCSPSetting: boolean, modsSetting: string)
|
||||
window.armcordinternal.saveSettings(true, branch, true, "none");
|
||||
window.armcordinternal.saveSettings({
|
||||
windowStyle: "default",
|
||||
channel: branch,
|
||||
armcordCSP: true,
|
||||
minimizeToTray: true,
|
||||
automaticPatches: false,
|
||||
mods: "none",
|
||||
blurType: "acrylic"
|
||||
});
|
||||
fade(document.getElementById("setup"));
|
||||
setTimeout(function () {
|
||||
window.armcordinternal.restart()
|
||||
window.armcordinternal.restart();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -11,10 +11,7 @@
|
|||
<body>
|
||||
<div class="container">
|
||||
<video autoplay loop class="logo" id="splashscreen-armcord">
|
||||
<source
|
||||
src="https://armcord.smartfridge.space/discord_loading.webm"
|
||||
type="video/webm"
|
||||
/>
|
||||
<source src="https://armcord.smartfridge.space/discord_loading.webm" type="video/webm" />
|
||||
</video>
|
||||
<p id="text-splashscreen"></p>
|
||||
</div>
|
||||
|
@ -22,8 +19,7 @@
|
|||
<script>
|
||||
const text = document.getElementById("text-splashscreen");
|
||||
if (window.navigator.onLine === false) {
|
||||
text.innerHTML =
|
||||
"You appear to be offline. Please connect to the internet and try again.";
|
||||
text.innerHTML = "You appear to be offline. Please connect to the internet and try again.";
|
||||
} else {
|
||||
text.innerHTML = "Starting ArmCord...";
|
||||
fetch("https://armcord.smartfridge.space/latest.json")
|
||||
|
@ -35,10 +31,9 @@
|
|||
elem.src = "https://armcord.smartfridge.space/update.webp";
|
||||
document.body.prepend(elem);
|
||||
document.getElementById("splashscreen-armcord").remove();
|
||||
text.innerHTML =
|
||||
"A new version of ArmCord is available. Please update to the latest version.";
|
||||
text.innerHTML = "A new version of ArmCord is available. Please update to the latest version.";
|
||||
} else {
|
||||
console.log("ArmCord is up to date.")
|
||||
console.log("ArmCord is up to date.");
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -12,8 +12,8 @@ import electron from "electron";
|
|||
import * as storage from "electron-json-storage";
|
||||
const otherMods = {
|
||||
generic: {
|
||||
electronProxy: require("util").types.isProxy(electron), // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
|
||||
},
|
||||
electronProxy: require("util").types.isProxy(electron) // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
|
||||
}
|
||||
};
|
||||
|
||||
const unstrictCSP = () => {
|
||||
|
@ -27,11 +27,10 @@ const unstrictCSP = () => {
|
|||
"https://api.goosemod.com/inject.js",
|
||||
"https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js",
|
||||
"https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js",
|
||||
"https://raw.githubusercontent.com/FlickerMod/dist/main/build.js",
|
||||
"https://raw.githubusercontent.com/FlickerMod/dist/main/build.js"
|
||||
];
|
||||
|
||||
electron.session.defaultSession.webRequest.onHeadersReceived(
|
||||
({ responseHeaders, url }, done) => {
|
||||
electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, url}, done) => {
|
||||
let csp = responseHeaders!["content-security-policy"];
|
||||
|
||||
if (otherMods.generic.electronProxy) {
|
||||
|
@ -53,17 +52,14 @@ const unstrictCSP = () => {
|
|||
responseHeaders!["access-control-allow-origin"] = ["*"];
|
||||
}
|
||||
|
||||
done({ responseHeaders });
|
||||
}
|
||||
);
|
||||
done({responseHeaders});
|
||||
});
|
||||
};
|
||||
storage.get("settings", function (error, data: any) {
|
||||
if (error) throw error;
|
||||
if (data.armcordCSP) {
|
||||
unstrictCSP();
|
||||
} else {
|
||||
console.log(
|
||||
"ArmCord CSP is disabled. The CSP should be managed by third-party plugin."
|
||||
);
|
||||
console.log("ArmCord CSP is disabled. The CSP should be managed by third-party plugin.");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
import * as fs from 'fs';
|
||||
import { app, session } from 'electron';
|
||||
import * as fs from "fs";
|
||||
import {app, session} from "electron";
|
||||
const userDataPath = app.getPath("userData");
|
||||
const pluginFolder = userDataPath + "/plugins/";
|
||||
if (!fs.existsSync(pluginFolder)) {
|
||||
fs.mkdirSync(pluginFolder);
|
||||
console.log("Created missing plugin folder");
|
||||
}
|
||||
}
|
||||
app.whenReady().then(() => {
|
||||
fs.readdirSync(pluginFolder).forEach((file) => {
|
||||
try {
|
||||
const manifest = fs.readFileSync(
|
||||
`${userDataPath}/plugins/${file}/manifest.json`,
|
||||
"utf8"
|
||||
);
|
||||
const manifest = fs.readFileSync(`${userDataPath}/plugins/${file}/manifest.json`, "utf8");
|
||||
var pluginFile = JSON.parse(manifest);
|
||||
session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`);
|
||||
console.log(
|
||||
`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`,
|
||||
"color:red"
|
||||
);
|
||||
console.log(`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, "color:red");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
|
37
src/ipc.ts
37
src/ipc.ts
|
@ -1,13 +1,16 @@
|
|||
//ipc stuff
|
||||
import { app, ipcMain, shell, desktopCapturer } from "electron";
|
||||
import { mainWindow } from "./window";
|
||||
import { saveSettings, getVersion } from "./utils";
|
||||
import { settings, customTitlebar } from "./main";
|
||||
import { createSettingsWindow } from "./settings/main";
|
||||
import {app, ipcMain, shell, desktopCapturer} from "electron";
|
||||
import {createTabsGuest, mainWindow} from "./window";
|
||||
import {saveSettings, getVersion} from "./utils";
|
||||
import {settings, customTitlebar, tabs} from "./main";
|
||||
import {createSettingsWindow} from "./settings/main";
|
||||
export function registerIpc() {
|
||||
ipcMain.on("get-app-path", (event, arg) => {
|
||||
event.reply("app-path", app.getAppPath());
|
||||
});
|
||||
ipcMain.on("openTab", (event, number: number) => {
|
||||
createTabsGuest(number);
|
||||
});
|
||||
ipcMain.on("open-external-link", (event, href: string) => {
|
||||
shell.openExternal(href);
|
||||
});
|
||||
|
@ -29,6 +32,9 @@ export function registerIpc() {
|
|||
ipcMain.on("win-hide", (event, arg) => {
|
||||
mainWindow.hide();
|
||||
});
|
||||
ipcMain.on("win-quit", (event, arg) => {
|
||||
app.exit();
|
||||
});
|
||||
ipcMain.on("get-app-version", (event) => {
|
||||
event.returnValue = getVersion();
|
||||
});
|
||||
|
@ -39,10 +45,12 @@ export function registerIpc() {
|
|||
app.relaunch();
|
||||
app.exit();
|
||||
});
|
||||
|
||||
ipcMain.on("saveSettings", (event, ...args) => {
|
||||
//@ts-ignore
|
||||
saveSettings(...args);
|
||||
ipcMain.on("saveSettings", (event, args) => {
|
||||
saveSettings(args);
|
||||
});
|
||||
ipcMain.on("minimizeToTray", (event) => {
|
||||
console.log(settings.minimizeToTray);
|
||||
event.returnValue = settings.minimizeToTray;
|
||||
});
|
||||
ipcMain.on("channel", (event) => {
|
||||
event.returnValue = settings.channel;
|
||||
|
@ -53,6 +61,12 @@ export function registerIpc() {
|
|||
ipcMain.on("titlebar", (event, arg) => {
|
||||
event.returnValue = customTitlebar;
|
||||
});
|
||||
ipcMain.on("tabs", (event, arg) => {
|
||||
event.returnValue = tabs;
|
||||
});
|
||||
ipcMain.on("shouldPatch", (event, arg) => {
|
||||
event.returnValue = settings.automaticPatches;
|
||||
});
|
||||
ipcMain.on("openSettingsWindow", (event, arg) => {
|
||||
createSettingsWindow();
|
||||
});
|
||||
|
@ -63,8 +77,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));
|
||||
}
|
||||
|
|
80
src/main.ts
80
src/main.ts
|
@ -1,22 +1,26 @@
|
|||
// Modules to control application life and create native browser window
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
session,
|
||||
} from "electron";
|
||||
import {app, BrowserWindow, session} from "electron";
|
||||
import * as path from "path";
|
||||
import "v8-compile-cache";
|
||||
import * as storage from "electron-json-storage";
|
||||
import { getConfigUnsafe, setup } from "./utils";
|
||||
import {getConfigUnsafe, setup} from "./utils";
|
||||
import "./extensions/mods";
|
||||
import "./extensions/plugin";
|
||||
import "./tray";
|
||||
import { mainWindow, createCustomWindow, createNativeWindow } from "./window";
|
||||
import {mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost} from "./window";
|
||||
import "./shortcuts";
|
||||
export var contentPath: string;
|
||||
var channel: string;
|
||||
export var settings: any;
|
||||
export var customTitlebar: boolean;
|
||||
export var tabs: boolean;
|
||||
async function appendSwitch() {
|
||||
if ((await getConfigUnsafe("windowStyle")) == "glasstron") {
|
||||
console.log("Enabling transparency visuals.");
|
||||
app.commandLine.appendSwitch("enable-transparent-visuals");
|
||||
}
|
||||
}
|
||||
appendSwitch();
|
||||
storage.has("settings", function (error, hasKey) {
|
||||
if (error) throw error;
|
||||
|
||||
|
@ -42,23 +46,35 @@ storage.get("settings", function (error, data: any) {
|
|||
settings = data;
|
||||
});
|
||||
app.whenReady().then(async () => {
|
||||
if (await getConfigUnsafe("customTitlebar") == true) {
|
||||
console.log("Creating custom titlebar window.");
|
||||
customTitlebar = true;
|
||||
switch (await getConfigUnsafe("windowStyle")) {
|
||||
case "default":
|
||||
createCustomWindow();
|
||||
} else if (await getConfigUnsafe("customTitlebar") == "setup") {
|
||||
//rare case of setup window
|
||||
console.log("Creating setup window.");
|
||||
customTitlebar = true;
|
||||
createCustomWindow();
|
||||
} else {
|
||||
console.log("Creating native titlebar window.");
|
||||
customTitlebar = false;
|
||||
break;
|
||||
case "native":
|
||||
createNativeWindow();
|
||||
break;
|
||||
case "glasstron":
|
||||
setTimeout(
|
||||
createGlasstronWindow,
|
||||
process.platform == "linux" ? 1000 : 0
|
||||
// Electron has a bug on linux where it
|
||||
// won't initialize properly when using
|
||||
// transparency. To work around that, it
|
||||
// is necessary to delay the window
|
||||
// spawn function.
|
||||
);
|
||||
break;
|
||||
case "tabs":
|
||||
createTabsHost();
|
||||
tabs = true;
|
||||
break;
|
||||
default:
|
||||
createCustomWindow();
|
||||
customTitlebar = true;
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
@ -68,19 +84,21 @@ app.whenReady().then(async () => {
|
|||
callback(true);
|
||||
}
|
||||
});
|
||||
mainWindow.webContents.session.webRequest.onBeforeRequest(
|
||||
(details, callback) => {
|
||||
if (/api\/v\d\/science$/g.test(details.url))
|
||||
return callback({ cancel: true });
|
||||
return callback({});
|
||||
}
|
||||
);
|
||||
app.on("activate", function () {
|
||||
app.on("activate", async function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0)
|
||||
if (!settings.customTitlebar) {
|
||||
createNativeWindow();
|
||||
} else {
|
||||
switch (await getConfigUnsafe("windowStyle")) {
|
||||
case "default":
|
||||
createCustomWindow();
|
||||
break;
|
||||
case "native":
|
||||
createNativeWindow();
|
||||
break;
|
||||
case "glasstron":
|
||||
createGlasstronWindow();
|
||||
break;
|
||||
default:
|
||||
createCustomWindow();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
import { contextBridge, ipcRenderer } from "electron";
|
||||
import { getDisplayMediaSelector } from "./capturer";
|
||||
import { injectTitlebar } from "./titlebar";
|
||||
import {contextBridge, ipcRenderer} from "electron";
|
||||
import {getDisplayMediaSelector} from "./capturer";
|
||||
import {injectTitlebar} from "./titlebar";
|
||||
|
||||
contextBridge.exposeInMainWorld("armcord", {
|
||||
window: {
|
||||
show: () => ipcRenderer.send("win-show"),
|
||||
hide: () => ipcRenderer.send("win-hide"),
|
||||
minimize: () => ipcRenderer.send("win-minimize"),
|
||||
maximize: () => ipcRenderer.send("win-maximize"),
|
||||
maximize: () => ipcRenderer.send("win-maximize")
|
||||
},
|
||||
titlebar: {
|
||||
injectTitlebar: () => injectTitlebar(),
|
||||
isTitlebar: ipcRenderer.sendSync("titlebar"),
|
||||
isTitlebar: ipcRenderer.sendSync("titlebar")
|
||||
},
|
||||
electron: process.versions.electron,
|
||||
channel: ipcRenderer.sendSync("channel"),
|
||||
openTab: (number: number) => ipcRenderer.sendSync("openTab", number),
|
||||
version: ipcRenderer.sendSync("get-app-version", "app-version"),
|
||||
getDisplayMediaSelector: getDisplayMediaSelector,
|
||||
openSettingsWindow: () => ipcRenderer.send("openSettingsWindow"),
|
||||
openSettingsWindow: () => ipcRenderer.send("openSettingsWindow")
|
||||
});
|
||||
//to be only used inside armcord internal setup/splash etc
|
||||
if (
|
||||
window.location.href.indexOf("splash.html") > -1 ||
|
||||
window.location.href.indexOf("setup.html") > -1
|
||||
) {
|
||||
if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) {
|
||||
contextBridge.exposeInMainWorld("armcordinternal", {
|
||||
restart: () => ipcRenderer.send("restart"),
|
||||
saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args),
|
||||
splashEnd: () => ipcRenderer.send("splashEnd"),
|
||||
splashEnd: () => ipcRenderer.send("splashEnd")
|
||||
});
|
||||
}
|
|
@ -1,28 +1,36 @@
|
|||
//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 { desktopCapturer } from 'electron';
|
||||
import {addStyle, addScript} from '../utils';
|
||||
import {ipcRenderer} from "electron";
|
||||
import {addStyle, addScript} from "../utils";
|
||||
const desktopCapturer = {
|
||||
getSources: (opts: any) => ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts)
|
||||
};
|
||||
const CANCEL_ID = "desktop-capturer-selection__cancel";
|
||||
|
||||
const CANCEL_ID = 'desktop-capturer-selection__cancel';
|
||||
interface IPCSources {
|
||||
id: string;
|
||||
name: string;
|
||||
thumbnail: HTMLCanvasElement;
|
||||
}
|
||||
|
||||
export async function getDisplayMediaSelector() {
|
||||
const sources = await desktopCapturer.getSources({
|
||||
types: ['screen', 'window'],
|
||||
const sources: IPCSources[] = await desktopCapturer.getSources({
|
||||
types: ["screen", "window"]
|
||||
});
|
||||
return `<div class="desktop-capturer-selection__scroller">
|
||||
<ul class="desktop-capturer-selection__list">
|
||||
${sources
|
||||
.map(
|
||||
({ id, name, thumbnail }) => `
|
||||
({id, name, thumbnail}) => `
|
||||
<li class="desktop-capturer-selection__item">
|
||||
<button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}">
|
||||
<img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" />
|
||||
<span class="desktop-capturer-selection__name">${name}</span>
|
||||
</button>
|
||||
</li>
|
||||
`,
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
.join("")}
|
||||
<li class="desktop-capturer-selection__item">
|
||||
<button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel">
|
||||
<span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span>
|
||||
|
@ -145,9 +153,8 @@ window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve
|
|||
});
|
||||
`;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
addScript(screenShareJS);
|
||||
addStyle(screenShareCSS);
|
||||
console.log("Capturer injected.")
|
||||
console.log("Capturer injected.");
|
||||
});
|
||||
|
||||
|
|
22
src/preload/patch.ts
Normal file
22
src/preload/patch.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// What does this do?
|
||||
// In case of faulty update of ArmCord we can quickly push an update to the user and possibly try to fix it
|
||||
// This is completely optional and is disabled by default in settings
|
||||
import {ipcRenderer} from "electron";
|
||||
import {injectJS} from "../utils";
|
||||
|
||||
var patchEndpoint = "https://patch.armcord.xyz/";
|
||||
var 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
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
if (res.patch == true) {
|
||||
console.log("Found a patch. Injecting...");
|
||||
injectJS(patchEndpoint + version + "/patch.js");
|
||||
} else {
|
||||
console.log("No patches have been found.");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
import "./bridge";
|
||||
import "./capturer";
|
||||
import "./patch";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { injectTitlebar } from "./titlebar";
|
||||
import { sleep, addStyle } from "../utils";
|
||||
import { ipcRenderer } from "electron";
|
||||
|
||||
import {injectTitlebar} from "./titlebar";
|
||||
import {sleep, addStyle, injectJS} from "../utils";
|
||||
import {ipcRenderer} from "electron";
|
||||
import {injectTabs} from "./tabs";
|
||||
declare global {
|
||||
interface Window {
|
||||
armcord: any;
|
||||
|
@ -13,19 +14,9 @@ declare global {
|
|||
}
|
||||
const clientMods = {
|
||||
goosemod: "https://api.goosemod.com/inject.js",
|
||||
cumcord:
|
||||
"https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js",
|
||||
flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js",
|
||||
cumcord: "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js",
|
||||
flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js"
|
||||
};
|
||||
async function injectJS(inject: string) {
|
||||
const js = await (await fetch(`${inject}`)).text();
|
||||
|
||||
const el = document.createElement("script");
|
||||
|
||||
el.appendChild(document.createTextNode(js));
|
||||
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
|
||||
console.log("ArmCord");
|
||||
if (window.location.href.indexOf("splash.html") > -1) {
|
||||
|
@ -34,6 +25,9 @@ if (window.location.href.indexOf("splash.html") > -1) {
|
|||
if (ipcRenderer.sendSync("titlebar")) {
|
||||
injectTitlebar();
|
||||
}
|
||||
if (ipcRenderer.sendSync("tabs")) {
|
||||
injectTabs();
|
||||
}
|
||||
sleep(5000).then(() => {
|
||||
const cssPath = path.join(__dirname, "../", "/content/css/discord.css");
|
||||
addStyle(fs.readFileSync(cssPath, "utf8"));
|
||||
|
|
26
src/preload/tabs.ts
Normal file
26
src/preload/tabs.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import {addStyle} from "../utils";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
export function injectTabs() {
|
||||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
var elem = document.createElement("div");
|
||||
elem.innerHTML = `<nav class="tabs">
|
||||
<div id="tabs-controls-container">
|
||||
<button class="tabs-buttons" onclick="armcord.openTab(1)">1</button>
|
||||
<button class="tabs-buttons" onclick="armcord.openTab(2)">2</button>
|
||||
<button class="tabs-buttons" onclick="armcord.openTab(3)">3</button>
|
||||
<button class="tabs-buttons" onclick="armcord.openTab(4)">4</button>
|
||||
<button class="tabs-buttons" onclick="armcord.openTab(5)">5</button>
|
||||
<p class="experimental">Experimental</p>
|
||||
</div>
|
||||
</nav>`;
|
||||
elem.classList.add("withFrame-haYltI");
|
||||
if (document.getElementById("app-mount") == null) {
|
||||
document.body.appendChild(elem);
|
||||
} else {
|
||||
document.getElementById("app-mount")!.prepend(elem);
|
||||
}
|
||||
const cssPath = path.join(__dirname, "../", "/content/css/tabs.css");
|
||||
addStyle(fs.readFileSync(cssPath, "utf8"));
|
||||
});
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { ipcRenderer } from "electron";
|
||||
import { addStyle } from "../utils";
|
||||
import {ipcRenderer} from "electron";
|
||||
import {addStyle} from "../utils";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
export function injectTitlebar() {
|
||||
|
@ -39,7 +39,11 @@ export function injectTitlebar() {
|
|||
});
|
||||
|
||||
quit!.addEventListener("click", () => {
|
||||
if (ipcRenderer.sendSync("minimizeToTray") === true) {
|
||||
ipcRenderer.send("win-hide");
|
||||
} else if (ipcRenderer.sendSync("minimizeToTray") === false) {
|
||||
ipcRenderer.send("win-quit");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,25 +1,46 @@
|
|||
import { BrowserWindow, shell } from "electron";
|
||||
import {BrowserWindow, shell, ipcMain} from "electron";
|
||||
import * as storage from "electron-json-storage";
|
||||
import {getConfigUnsafe, saveSettings, Settings} from "../utils";
|
||||
import path from "path";
|
||||
|
||||
var settingsWindow;
|
||||
var settings: any;
|
||||
var isAlreadyCreated: boolean = false;
|
||||
storage.get("settings", function (error, data: any) {
|
||||
if (error) throw error;
|
||||
console.log(data);
|
||||
settings = data;
|
||||
});
|
||||
var settingsWindow: BrowserWindow;
|
||||
export function createSettingsWindow() {
|
||||
if (isAlreadyCreated) {
|
||||
settingsWindow.show();
|
||||
} else {
|
||||
settingsWindow = new BrowserWindow({
|
||||
width: 500,
|
||||
height: 600,
|
||||
height: 500,
|
||||
title: "ArmCord Settings",
|
||||
darkTheme: true,
|
||||
icon: path.join(__dirname, "/assets/icon_transparent.png"),
|
||||
frame: false,
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload/preload.js"),
|
||||
},
|
||||
preload: path.join(__dirname, "preload.js")
|
||||
}
|
||||
});
|
||||
|
||||
settingsWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
ipcMain.on("saveSettings", (event, args: Settings) => {
|
||||
console.log(args);
|
||||
saveSettings(args);
|
||||
});
|
||||
ipcMain.handle("getSetting", (event, toGet: string) => {
|
||||
return getConfigUnsafe(toGet);
|
||||
});
|
||||
settingsWindow.webContents.setWindowOpenHandler(({url}) => {
|
||||
shell.openExternal(url);
|
||||
return { action: "deny" };
|
||||
return {action: "deny"};
|
||||
});
|
||||
|
||||
settingsWindow.loadFile("settings.html");
|
||||
settingsWindow.loadURL(`file://${__dirname}/settings.html`);
|
||||
settingsWindow.on("close", async (e) => {
|
||||
e.preventDefault();
|
||||
settingsWindow.hide();
|
||||
});
|
||||
isAlreadyCreated = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
console.log("test")
|
||||
import {contextBridge, ipcRenderer} from "electron";
|
||||
console.log("ArmCord Settings");
|
||||
contextBridge.exposeInMainWorld("settings", {
|
||||
save: (...args: any) => ipcRenderer.send("saveSettings", ...args),
|
||||
get: (toGet: string) =>
|
||||
ipcRenderer.invoke("getSetting", toGet).then((result) => {
|
||||
return result;
|
||||
}) //jank but works
|
||||
});
|
||||
|
|
176
src/settings/settings.css
Normal file
176
src/settings/settings.css
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*MIT License
|
||||
|
||||
Copyright (c) 2021 GooseMod
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.*/
|
||||
:root {
|
||||
--background-primary: #282b30;
|
||||
--background-secondary: rgba(255, 255, 255, 0.1);
|
||||
--brand-experiment: #5865f2;
|
||||
--header-primary: #fff;
|
||||
--text-muted: #72767d;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Whitney;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff");
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin: 2%;
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: "Whitney", sans-serif;
|
||||
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
}
|
||||
.left {
|
||||
float: right;
|
||||
vertical-align: right !important;
|
||||
}
|
||||
.switch {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.header {
|
||||
color: white;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
/*buttons*/
|
||||
button {
|
||||
background-color: #7289da;
|
||||
font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #ffffff;
|
||||
padding: 4px;
|
||||
border-radius: 5px;
|
||||
margin-top: 5px;
|
||||
|
||||
text-align: center;
|
||||
border-style: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #687dc6;
|
||||
border-style: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tgl {
|
||||
display: none;
|
||||
}
|
||||
.tgl,
|
||||
.tgl:after,
|
||||
.tgl:before,
|
||||
.tgl *,
|
||||
.tgl *:after,
|
||||
.tgl *:before,
|
||||
.tgl + .tgl-btn {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.tgl::-moz-selection,
|
||||
.tgl:after::-moz-selection,
|
||||
.tgl:before::-moz-selection,
|
||||
.tgl *::-moz-selection,
|
||||
.tgl *:after::-moz-selection,
|
||||
.tgl *:before::-moz-selection,
|
||||
.tgl + .tgl-btn::-moz-selection {
|
||||
background: none;
|
||||
}
|
||||
.tgl::selection,
|
||||
.tgl:after::selection,
|
||||
.tgl:before::selection,
|
||||
.tgl *::selection,
|
||||
.tgl *:after::selection,
|
||||
.tgl *:before::selection,
|
||||
.tgl + .tgl-btn::selection {
|
||||
background: none;
|
||||
}
|
||||
.tgl + .tgl-btn {
|
||||
outline: 0;
|
||||
display: block;
|
||||
width: 4em;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.tgl + .tgl-btn:after,
|
||||
.tgl + .tgl-btn:before {
|
||||
position: relative;
|
||||
display: block;
|
||||
content: "";
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
.tgl + .tgl-btn:after {
|
||||
left: 0;
|
||||
}
|
||||
.tgl + .tgl-btn:before {
|
||||
display: none;
|
||||
}
|
||||
.tgl:checked + .tgl-btn:after {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.tgl-light + .tgl-btn {
|
||||
background: #5c5757;
|
||||
border-radius: 2em;
|
||||
padding: 2px;
|
||||
transition: all 0.4s ease;
|
||||
}
|
||||
.tgl-light + .tgl-btn:after {
|
||||
border-radius: 50%;
|
||||
background: rgb(255, 255, 255);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.tgl-light:checked + .tgl-btn {
|
||||
background: #47ca5a;
|
||||
}
|
||||
select {
|
||||
-webkit-appearance: button;
|
||||
-moz-appearance: button;
|
||||
background-color: #2c2f33;
|
||||
background-position: center right;
|
||||
background-repeat: no-repeat;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
color: #fff;
|
||||
font-size: 1.2em;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
92
src/settings/settings.html
Normal file
92
src/settings/settings.html
Normal file
|
@ -0,0 +1,92 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>ArmCord Settings</title>
|
||||
<style>
|
||||
@import url("settings.css");
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="switch">
|
||||
<select name="theme" id="theme" class="left">
|
||||
<option value="default">Default</option>
|
||||
<option value="native">Native</option>
|
||||
<option value="glasstron">Glasstron (experimental)</option>
|
||||
<option value="tabs">Tabs (experimental)</option>
|
||||
</select>
|
||||
<p class="header">ArmCord theme:</p>
|
||||
</div>
|
||||
<br />
|
||||
<div class="switch">
|
||||
<label class="header">ArmCord CSP</label>
|
||||
<input class="tgl tgl-light left" id="csp" type="checkbox" />
|
||||
<label class="tgl-btn left" for="csp"></label>
|
||||
</div>
|
||||
<br />
|
||||
<div class="switch">
|
||||
<label class="header">Minimize to tray</label>
|
||||
<input class="tgl tgl-light left" id="tray" type="checkbox" />
|
||||
<label class="tgl-btn left" for="tray"></label>
|
||||
</div>
|
||||
<br />
|
||||
<div class="switch">
|
||||
<label class="header">Automatic Patches</label>
|
||||
<input class="tgl tgl-light left" id="patches" type="checkbox" />
|
||||
<label class="tgl-btn left" for="patches"></label>
|
||||
</div>
|
||||
<div class="switch">
|
||||
<select name="channel" id="channel" class="left">
|
||||
<option value="stable">Stable</option>
|
||||
<option value="canary">Canary</option>
|
||||
<option value="ptb">PTB</option>
|
||||
<option value="foss">Fosscord</option>
|
||||
</select>
|
||||
<p class="header">Discord channel:</p>
|
||||
</div>
|
||||
<div class="switch">
|
||||
<select name="mod" id="mod" class="left">
|
||||
<option value="cumcord">Cumcord</option>
|
||||
<option value="goosemod">GooseMod</option>
|
||||
<option value="flicker">Flicker</option>
|
||||
</select>
|
||||
<p class="header">Client mod:</p>
|
||||
</div>
|
||||
<div class="switch">
|
||||
<select name="blurType" id="blurType" class="left">
|
||||
<option value="acrylic">Acrylic</option>
|
||||
<option value="blurbehind">Blur Behind</option>
|
||||
<option value="transparent">Transparent</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
<p class="header">Glasstron blur type:</p>
|
||||
</div>
|
||||
<button id="save" class="center">Save settings</button>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
async function loadSettings() {
|
||||
document.getElementById("csp").checked = await settings.get("armcordCSP");
|
||||
document.getElementById("tray").checked = await settings.get("minimizeToTray");
|
||||
document.getElementById("patches").value = await settings.get("automaticPatches");
|
||||
document.getElementById("mod").value = await settings.get("mods");
|
||||
document.getElementById("channel").value = await settings.get("channel");
|
||||
document.getElementById("theme").value = await settings.get("windowStyle");
|
||||
document.getElementById("blurType").value = await settings.get("blurType");
|
||||
}
|
||||
loadSettings();
|
||||
document.getElementById("save").addEventListener("click", function () {
|
||||
//function saveSettings(windowStyle: string, channelSetting: string, armcordCSPSetting: boolean, minimizeToTray: boolean, automaticPatches: boolean,modsSetting: string, blurType: string)
|
||||
settings.save(
|
||||
document.getElementById("theme").value,
|
||||
document.getElementById("channel").value,
|
||||
document.getElementById("csp").checked,
|
||||
document.getElementById("tray").checked,
|
||||
document.getElementById("patches").checked,
|
||||
document.getElementById("mod").value,
|
||||
document.getElementById("blurType").value
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -1,11 +1,11 @@
|
|||
import { app } from "electron";
|
||||
import {mainWindow} from './window';
|
||||
import {app} from "electron";
|
||||
import {mainWindow} from "./window";
|
||||
//https://github.com/electron/electron/issues/1334#issuecomment-716080005
|
||||
// TO-DO add more
|
||||
app.on("web-contents-created", (webContentsCreatedEvent, webContents) => {
|
||||
webContents.on("before-input-event", (beforeInputEvent, input) => {
|
||||
// console.log('Main console::', input)
|
||||
const { code, alt, control, shift, meta } = input;
|
||||
const {code, alt, control, shift, meta} = input;
|
||||
// Shortcut: toggle devTools
|
||||
if (shift && control && !alt && !meta && code === "KeyI") {
|
||||
mainWindow.webContents.toggleDevTools();
|
||||
|
|
31
src/tray.ts
31
src/tray.ts
|
@ -1,31 +1,38 @@
|
|||
import { app, Menu, Tray } from 'electron';
|
||||
import {mainWindow} from './window';
|
||||
import * as path from 'path'
|
||||
let tray = null
|
||||
import {app, Menu, Tray} from "electron";
|
||||
import {mainWindow} from "./window";
|
||||
import * as path from "path";
|
||||
import {createSettingsWindow} from "./settings/main";
|
||||
let tray = null;
|
||||
app.whenReady().then(() => {
|
||||
tray = new Tray(path.join(__dirname, "../", "/assets/ac_plug.png"))
|
||||
tray = new Tray(path.join(__dirname, "../", "/assets/ac_plug.png"));
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: "Open ArmCord",
|
||||
click: function () {
|
||||
mainWindow.show();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Open Settings",
|
||||
click: function () {
|
||||
createSettingsWindow();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Support Discord Server",
|
||||
click: function () {
|
||||
mainWindow.show();
|
||||
mainWindow.loadURL("https://discord.gg/F25bc4RYDt");
|
||||
},
|
||||
mainWindow.loadURL("https://discord.gg/TnhxcqynZ2");
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Quit ArmCord",
|
||||
click: function () {
|
||||
app.quit();
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
tray.setToolTip('ArmCord ' + process.env.npm_package_version)
|
||||
tray.setContextMenu(contextMenu)
|
||||
})
|
||||
tray.setToolTip("ArmCord " + app.getVersion());
|
||||
tray.setContextMenu(contextMenu);
|
||||
});
|
||||
|
|
70
src/types/glasstron.d.ts
vendored
Normal file
70
src/types/glasstron.d.ts
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
declare module "glasstron" {
|
||||
export class BrowserWindow extends Electron.BrowserWindow {
|
||||
getBlur(): Promise<boolean>;
|
||||
setBlur(value: boolean): Promise<boolean>;
|
||||
blurType: WindowsBlurType;
|
||||
setVibrancy(vibrancy: MacOSVibrancy): void;
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export function init(): void;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export function update(
|
||||
window: Electron.BrowserWindow,
|
||||
values: {
|
||||
windows?: {
|
||||
blurType: WindowsBlurType;
|
||||
};
|
||||
macos?: {
|
||||
vibrancy: MacOSVibrancy;
|
||||
};
|
||||
linux?: {
|
||||
requestBlur: boolean;
|
||||
};
|
||||
}
|
||||
): void;
|
||||
export class Hacks {
|
||||
static injectOnElectron(): void;
|
||||
static delayReadyEvent(): void;
|
||||
}
|
||||
export type WindowsBlurType = "acrylic" | "blurbehind" | "transparent" | "none";
|
||||
export type MacOSVibrancy =
|
||||
| (
|
||||
| "appearance-based"
|
||||
| "light"
|
||||
| "dark"
|
||||
| "titlebar"
|
||||
| "selection"
|
||||
| "menu"
|
||||
| "popover"
|
||||
| "sidebar"
|
||||
| "medium-light"
|
||||
| "ultra-dark"
|
||||
| "header"
|
||||
| "sheet"
|
||||
| "window"
|
||||
| "hud"
|
||||
| "fullscreen-ui"
|
||||
| "tooltip"
|
||||
| "content"
|
||||
| "under-window"
|
||||
| "under-page"
|
||||
)
|
||||
| null;
|
||||
}
|
||||
|
||||
declare module "glasstron/src/utils" {
|
||||
class Utils {
|
||||
static getSavePath(): string;
|
||||
static copyToPath(innerFile: string, outerFilename?: string, flags?: number): void;
|
||||
static removeFromPath(filename: string): void;
|
||||
static isInPath(filename: string): boolean;
|
||||
static getPlatform(): any;
|
||||
static parseKeyValString(string: string, keyvalSeparator?: string, pairSeparator?: string): any;
|
||||
static makeKeyValString(object: any, keyvalSeparator?: string, pairSeparator?: string): string;
|
||||
}
|
||||
export = Utils;
|
||||
}
|
67
src/utils.ts
67
src/utils.ts
|
@ -1,6 +1,6 @@
|
|||
import * as storage from "electron-json-storage";
|
||||
import * as fs from "fs";
|
||||
import { app } from "electron";
|
||||
import {app} from "electron";
|
||||
import path from "path";
|
||||
export var firstRun: boolean;
|
||||
|
||||
|
@ -16,40 +16,56 @@ export function addScript(scriptString: string) {
|
|||
script.textContent = scriptString;
|
||||
document.body.append(script);
|
||||
}
|
||||
|
||||
export async function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export async function checkIfConfigIsNew() {
|
||||
if ((await getConfigUnsafe("automaticPatches")) == undefined) {
|
||||
firstRun = true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
windowStyle: string;
|
||||
channel: string;
|
||||
armcordCSP: boolean;
|
||||
minimizeToTray: boolean;
|
||||
automaticPatches: boolean;
|
||||
mods: string;
|
||||
blurType: string;
|
||||
}
|
||||
export function setup() {
|
||||
console.log("Setting up ArmCord settings.");
|
||||
console.log("Setting up temporary ArmCord settings.");
|
||||
const defaults: Settings = {
|
||||
windowStyle: "default",
|
||||
channel: "stable",
|
||||
armcordCSP: true,
|
||||
minimizeToTray: true,
|
||||
automaticPatches: false,
|
||||
mods: "cumcord",
|
||||
blurType: "acrylic"
|
||||
};
|
||||
storage.set(
|
||||
"settings",
|
||||
{
|
||||
customTitlebar: true,
|
||||
channel: "stable",
|
||||
doneSetup: true,
|
||||
armcordCSP: true,
|
||||
mods: "cumcord",
|
||||
...defaults,
|
||||
doneSetup: false
|
||||
},
|
||||
function (error) {
|
||||
if (error) throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
export async function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
export function saveSettings(
|
||||
customTitlebarSetting: boolean,
|
||||
channelSetting: string,
|
||||
armcordCSPSetting: boolean,
|
||||
modsSetting: string
|
||||
) {
|
||||
|
||||
export function saveSettings(settings: Settings) {
|
||||
console.log("Setting up ArmCord settings.");
|
||||
storage.set(
|
||||
"settings",
|
||||
{
|
||||
customTitlebar: customTitlebarSetting,
|
||||
channel: channelSetting,
|
||||
doneSetup: true,
|
||||
armcordCSP: armcordCSPSetting,
|
||||
mods: modsSetting,
|
||||
...settings,
|
||||
doneSetup: true
|
||||
},
|
||||
function (error) {
|
||||
if (error) throw error;
|
||||
|
@ -74,3 +90,12 @@ export function getVersion() {
|
|||
//to-do better way of doing this
|
||||
return "3.1.0";
|
||||
}
|
||||
export async function injectJS(inject: string) {
|
||||
const js = await (await fetch(`${inject}`)).text();
|
||||
|
||||
const el = document.createElement("script");
|
||||
|
||||
el.appendChild(document.createTextNode(js));
|
||||
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
|
|
133
src/window.ts
133
src/window.ts
|
@ -2,22 +2,45 @@
|
|||
// 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 } from "electron";
|
||||
import {BrowserWindow, shell, app, ipcMain} from "electron";
|
||||
import path from "path";
|
||||
import { contentPath } from "./main";
|
||||
import { firstRun } from "./utils";
|
||||
import { registerIpc } from "./ipc";
|
||||
import {contentPath} from "./main";
|
||||
import {checkIfConfigIsNew, firstRun, getConfigUnsafe} from "./utils";
|
||||
import {registerIpc} from "./ipc";
|
||||
import contextMenu from "electron-context-menu";
|
||||
export let mainWindow: BrowserWindow;
|
||||
import * as glasstron from "glasstron";
|
||||
|
||||
let guestWindows: BrowserWindow[] = [];
|
||||
contextMenu({
|
||||
showSaveImageAs: true,
|
||||
showCopyImageAddress: true,
|
||||
showSearchWithGoogle: true
|
||||
});
|
||||
|
||||
function doAfterDefiningTheWindow() {
|
||||
checkIfConfigIsNew();
|
||||
registerIpc();
|
||||
mainWindow.webContents.userAgent =
|
||||
"Mozilla/5.0 (X11; Linux x86) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"; //fake useragent for screenshare to work
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work
|
||||
mainWindow.webContents.setWindowOpenHandler(({url}) => {
|
||||
shell.openExternal(url);
|
||||
return { action: "deny" };
|
||||
return {action: "deny"};
|
||||
});
|
||||
mainWindow.webContents.session.webRequest.onBeforeRequest((details, callback) => {
|
||||
if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true});
|
||||
return callback({});
|
||||
});
|
||||
mainWindow.on("close", async (e) => {
|
||||
if (await getConfigUnsafe("minimizeToTray")) {
|
||||
e.preventDefault();
|
||||
mainWindow.hide();
|
||||
} else if (!(await getConfigUnsafe("minimizeToTray"))) {
|
||||
e.preventDefault();
|
||||
app.exit();
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
console.log(contentPath);
|
||||
try {
|
||||
mainWindow.loadFile(contentPath);
|
||||
|
@ -52,7 +75,8 @@ export function createCustomWindow() {
|
|||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload/preload.js"),
|
||||
},
|
||||
spellcheck: true
|
||||
}
|
||||
});
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
|
@ -67,7 +91,96 @@ export function createNativeWindow() {
|
|||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload/preload.js"),
|
||||
},
|
||||
spellcheck: true
|
||||
}
|
||||
});
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
export function createGlasstronWindow() {
|
||||
mainWindow = new glasstron.BrowserWindow({
|
||||
width: 300,
|
||||
height: 350,
|
||||
title: "ArmCord",
|
||||
darkTheme: true,
|
||||
icon: path.join(__dirname, "/assets/icon_transparent.png"),
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload/preload.js"),
|
||||
spellcheck: true
|
||||
}
|
||||
});
|
||||
|
||||
//@ts-expect-error
|
||||
mainWindow.blurType = getConfigUnsafe("blurType");
|
||||
//@ts-expect-error
|
||||
mainWindow.setBlur(true);
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
export function createTabsHost() {
|
||||
guestWindows[1] = mainWindow;
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 300,
|
||||
height: 350,
|
||||
title: "ArmCord",
|
||||
darkTheme: true,
|
||||
icon: path.join(__dirname, "/assets/icon_transparent.png"),
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload/preload.js")
|
||||
}
|
||||
});
|
||||
doAfterDefiningTheWindow();
|
||||
}
|
||||
export function createTabsGuest(number: number) {
|
||||
console.log(guestWindows);
|
||||
if (guestWindows[number] !== undefined || null) {
|
||||
try {
|
||||
console.log("Showing Guest Window " + number);
|
||||
mainWindow.hide();
|
||||
guestWindows[number].show();
|
||||
mainWindow = guestWindows[number];
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
} else {
|
||||
console.log("Creating Guest Window " + number);
|
||||
mainWindow.hide();
|
||||
|
||||
guestWindows[number] = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
title: "ArmCord Guest Window " + number,
|
||||
darkTheme: true,
|
||||
icon: path.join(__dirname, "/assets/icon_transparent.png"),
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "preload/preload.js")
|
||||
}
|
||||
});
|
||||
|
||||
mainWindow = guestWindows[number];
|
||||
ipcMain.on("tab" + number, (event) => {
|
||||
event.returnValue = true; //return true so we know the tab exists
|
||||
});
|
||||
|
||||
guestWindows[number].webContents.userAgent =
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"; //fake useragent for screenshare to work
|
||||
|
||||
guestWindows[number].webContents.setWindowOpenHandler(({url}) => {
|
||||
shell.openExternal(url);
|
||||
return {action: "deny"};
|
||||
});
|
||||
|
||||
guestWindows[number].webContents.session.webRequest.onBeforeRequest(
|
||||
(details: {url: string}, callback: (arg0: {cancel?: boolean}) => any) => {
|
||||
if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true});
|
||||
return callback({});
|
||||
}
|
||||
);
|
||||
|
||||
guestWindows[number].loadURL("https://discord.com/app");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
"declaration": false, // Exports declaration files in addition, used for exporting a module.
|
||||
"declarationMap": false, // Allows the user to go to the source file when hitting a go-to-implementation key like F12 in VSCode for example.
|
||||
//"declarationDir": "typings", // declarationDir allows you to separate the compiled code from the declaration files, used in conjunction with package.json's "types" property.
|
||||
|
||||
// Web Compatibility //
|
||||
"target": "ES2020", // ES2017 supports async/await, reducing the amount of compiled code, especially for async-heavy projects. ES2020 is from the Node 14 base (https://github.com/tsconfig/bases/blob/master/bases/node14.json)
|
||||
"downlevelIteration": false, // This flag adds extra support when targeting ES3, but adds extra bloat otherwise.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue