formatting

a.k.a. "Install Prettier"
This commit is contained in:
Alyxia Sother 2022-03-04 17:53:18 +00:00
parent 18bebfb421
commit 87920505db
No known key found for this signature in database
GPG Key ID: 01E16C4E775A37E4
32 changed files with 1382 additions and 1341 deletions

1
.husky/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
_

5
.husky/pre-commit Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
npm run format
git add -A

11
.prettierignore Normal file
View 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

46
package-lock.json generated
View File

@ -1,12 +1,13 @@
{ {
"name": "ArmCord", "name": "ArmCord",
"version": "3.0.4", "version": "3.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ArmCord", "name": "ArmCord",
"version": "3.0.4", "version": "3.1.0",
"hasInstallScript": true,
"license": "OSL-3.0", "license": "OSL-3.0",
"dependencies": { "dependencies": {
"electron-context-menu": "^3.1.2", "electron-context-menu": "^3.1.2",
@ -21,6 +22,8 @@
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"electron": "^17.1.0", "electron": "^17.1.0",
"electron-builder": "^22.14.13", "electron-builder": "^22.14.13",
"husky": "^7.0.4",
"prettier": "^2.5.1",
"typescript": "^4.5.4" "typescript": "^4.5.4"
} }
}, },
@ -2020,6 +2023,21 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/husky": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
"integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
"dev": true,
"bin": {
"husky": "lib/bin.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/iconv-corefoundation": { "node_modules/iconv-corefoundation": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
@ -2724,6 +2742,18 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/prettier": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/process-nextick-args": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -5191,6 +5221,12 @@
"debug": "4" "debug": "4"
} }
}, },
"husky": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
"integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
"dev": true
},
"iconv-corefoundation": { "iconv-corefoundation": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
@ -5728,6 +5764,12 @@
"integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
"dev": true "dev": true
}, },
"prettier": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true
},
"process-nextick-args": { "process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",

View File

@ -7,7 +7,9 @@
"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", "watch": "tsc -w",
"start": "npm run build && electron ./ts-out/main.js", "start": "npm run build && electron ./ts-out/main.js",
"package": "npm run build && electron-builder" "package": "npm run build && electron-builder",
"format": "prettier --write **/*",
"postinstall": "husky install"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -25,6 +27,8 @@
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"electron": "^17.1.0", "electron": "^17.1.0",
"electron-builder": "^22.14.13", "electron-builder": "^22.14.13",
"husky": "^7.0.4",
"prettier": "^2.5.1",
"typescript": "^4.5.4" "typescript": "^4.5.4"
}, },
"dependencies": { "dependencies": {

14
prettier.config.js Normal file
View 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"
};

View File

@ -1,12 +1,12 @@
.info-3pQQBb:last-child:before { .info-3pQQBb:last-child:before {
content: "ArmCord Version: 3.1.0"!important; content: "ArmCord Version: 3.1.0" !important;
height: auto; height: auto;
line-height: 16px; line-height: 16px;
text-align: center; text-align: center;
color: var(--text-muted); color: var(--text-muted);
font-size: 12px; font-size: 12px;
text-transform: none; text-transform: none;
} }
.notice-2HEN-u { .notice-2HEN-u {
display: none; display: none;
} }

View File

@ -2,68 +2,68 @@
@import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); @import url("https://kckarnige.github.io/femboi_owo/discord-font.css");
:root { :root {
background-color: #2c2f33 !important; background-color: #2c2f33 !important;
--header-secondary: #b9bbbe !important; --header-secondary: #b9bbbe !important;
--header-primary: #fff !important; --header-primary: #fff !important;
--background-tertiary: #202225 !important; --background-tertiary: #202225 !important;
} }
body { body {
background-color: #2c2f33; background-color: #2c2f33;
color: white; color: white;
} }
p { p {
color: white; color: white;
text-align: center; text-align: center;
font-weight: 100; font-weight: 100;
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
.logo { .logo {
font-size: 0px; font-size: 0px;
text-align: center; text-align: center;
transform: translateY(-105%); transform: translateY(-105%);
} }
.logo:before { .logo:before {
content: "ARM"; content: "ARM";
color: #7289da; color: #7289da;
font-weight: normal; font-weight: normal;
font-family: Helvetica, sans-serif; font-family: Helvetica, sans-serif;
font-size: 32px; font-size: 32px;
} }
.logo:after { .logo:after {
content: "Cord"; content: "Cord";
color: #ffffff; color: #ffffff;
font-weight: normal; font-weight: normal;
font-family: Discordinated; font-family: Discordinated;
font-size: 32px; font-size: 32px;
} }
span { span {
text-align: center; text-align: center;
} }
.logo { .logo {
display: block; display: block;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
max-height: 204px; max-height: 204px;
max-width: 204px; max-width: 204px;
transform: translateY(5%); transform: translateY(5%);
} }
.container { .container {
position: fixed; position: fixed;
top: 50%; top: 50%;
left: 50%; left: 50%;
color: #fff; color: #fff;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
button#express { button#express {
margin-right: 84px; margin-right: 84px;
} }
button { button {
background-color: #7289da; background-color: #7289da;
@ -72,13 +72,13 @@ button {
padding: 4px; padding: 4px;
border-radius: 5px; border-radius: 5px;
margin-top: 5px; margin-top: 5px;
text-align: center; text-align: center;
border-style: none; border-style: none;
outline: none; outline: none;
} }
.setup-ask { .setup-ask {
font-size: 20px; font-size: 20px;
} }
button:hover { button:hover {
background-color: #687dc6; background-color: #687dc6;
@ -87,25 +87,25 @@ button:hover {
cursor: pointer; cursor: pointer;
} }
select { select {
-webkit-appearance: button; -webkit-appearance: button;
-moz-appearance: button; -moz-appearance: button;
-webkit-padding-end: 20px; -webkit-padding-end: 20px;
-moz-padding-end: 20px; -moz-padding-end: 20px;
-webkit-padding-start: 2px; -webkit-padding-start: 2px;
-moz-padding-start: 2px; -moz-padding-start: 2px;
background-color: #2c2f33; background-color: #2c2f33;
background-position: center right; background-position: center right;
background-repeat: no-repeat; background-repeat: no-repeat;
border: 1px solid #aaa; border: 1px solid #aaa;
border-radius: 2px; border-radius: 2px;
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
color: #fff; color: #fff;
font-size: inherit; font-size: inherit;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.center { .center {
text-align: center; text-align: center;
} }

View File

@ -20,95 +20,95 @@ 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/ SOFTWARE.*/
:root { :root {
--background-primary: #282b30; --background-primary: #282b30;
--background-secondary: rgba(255, 255, 255, 0.1); --background-secondary: rgba(255, 255, 255, 0.1);
--brand-experiment: #5865f2; --brand-experiment: #5865f2;
--header-primary: #fff; --header-primary: #fff;
--text-muted: #72767d; --text-muted: #72767d;
} }
@font-face { @font-face {
font-family: Whitney; font-family: Whitney;
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff");
} }
html, html,
body { body {
-webkit-app-region: drag; -webkit-app-region: drag;
overflow: hidden; overflow: hidden;
margin: 0; margin: 0;
padding: 0; padding: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: var(--background-primary); background: var(--background-primary);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
* { * {
font-family: "Whitney", sans-serif; font-family: "Whitney", sans-serif;
box-sizing: border-box; box-sizing: border-box;
-webkit-user-select: none; -webkit-user-select: none;
cursor: default; cursor: default;
} }
video { video {
width: 200px; width: 200px;
height: 150px; height: 150px;
object-fit: cover; object-fit: cover;
} }
#text-splashscreen { #text-splashscreen {
font-size: 7vw; font-size: 7vw;
text-align: center; text-align: center;
color: var(--header-primary); color: var(--header-primary);
font-weight: 400; font-weight: 400;
font-style: italic; font-style: italic;
font-size: 16px; font-size: 16px;
text-transform: uppercase; text-transform: uppercase;
width: 100%; width: 100%;
} }
#bar-container, #bar-container,
#bar-fill { #bar-fill {
width: 180px; width: 180px;
height: 8px; height: 8px;
border-radius: 4px; border-radius: 4px;
visibility: hidden; visibility: hidden;
} }
#bar-container { #bar-container {
background-color: var(--background-secondary); background-color: var(--background-secondary);
position: relative; position: relative;
margin-top: 12px; margin-top: 12px;
} }
#bar-fill { #bar-fill {
background-color: var(--brand-experiment); background-color: var(--brand-experiment);
width: 0; width: 0;
} }
#debug { #debug {
position: absolute; position: absolute;
bottom: 6px; bottom: 6px;
right: 6px; right: 6px;
text-align: right; text-align: right;
font-size: 10px; font-size: 10px;
color: var(--text-muted); color: var(--text-muted);
white-space: pre; white-space: pre;
} }

View File

@ -1,53 +1,53 @@
@import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); @import url("https://kckarnige.github.io/femboi_owo/discord-font.css");
:root { :root {
--window-buttons: var(--header-secondary); --window-buttons: var(--header-secondary);
--cord-color: var(--header-primary); --cord-color: var(--header-primary);
--armcord-color: #7289da; --armcord-color: #7289da;
--titlebar-color: var(--background-tertiary); --titlebar-color: var(--background-tertiary);
} }
.tabs { .tabs {
display: block; display: block;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
flex-shrink: 0; flex-shrink: 0;
overflow: hidden; overflow: hidden;
zoom: 1; zoom: 1;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
clear: both; clear: both;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
background-color: #202225; background-color: #202225;
-webkit-app-region: drag; -webkit-app-region: drag;
width: 100%; width: 100%;
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
position: fixed; position: fixed;
z-index: 99999; z-index: 99999;
} }
.tabs #tabs-controls-container { .tabs #tabs-controls-container {
float: left; float: left;
width: 150px; width: 150px;
height: 100%; height: 100%;
line-height: 30px; line-height: 30px;
background-color: #202225; background-color: #202225;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }
.tabs-buttons { .tabs-buttons {
color: white; color: white;
background-color: inherit; background-color: inherit;
float: left; float: left;
border: none; border: none;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
transition: 0.3s; transition: 0.3s;
font-size: 20px; font-size: 20px;
} }
.tabs-buttons:hover { .tabs-buttons:hover {
background-color: #4e515a; background-color: #4e515a;
} }
.withFrame-haYltI { .withFrame-haYltI {
height: 30px !important; height: 30px !important;
} }

View File

@ -1,108 +1,108 @@
@import url("https://armcord.smartfridge.space/logofont.css"); @import url("https://armcord.smartfridge.space/logofont.css");
:root { :root {
--window-buttons: var(--header-secondary); --window-buttons: var(--header-secondary);
--cord-color: var(--header-primary); --cord-color: var(--header-primary);
--armcord-color: #7289da; --armcord-color: #7289da;
--titlebar-color: var(--background-tertiary); --titlebar-color: var(--background-tertiary);
} }
.titlebar { .titlebar {
display: block; display: block;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
flex-shrink: 0; flex-shrink: 0;
overflow: hidden; overflow: hidden;
zoom: 1; zoom: 1;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
clear: both; clear: both;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
background-color: #202225; background-color: #202225;
-webkit-app-region: drag; -webkit-app-region: drag;
width: 100%; width: 100%;
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
position: fixed; position: fixed;
z-index: 99999; z-index: 99999;
} }
.titlebar #window-title { .titlebar #window-title {
width: 30%; width: 30%;
height: 100%; height: 100%;
line-height: 30px; line-height: 30px;
float: left; float: left;
padding: 0 0 0 1em; padding: 0 0 0 1em;
} }
.titlebar #window-controls-container { .titlebar #window-controls-container {
float: right; float: right;
width: 150px; width: 150px;
height: 100%; height: 100%;
line-height: 30px; line-height: 30px;
background-color: #202225; background-color: #202225;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }
.titlebar #window-controls-container #minimize, .titlebar #window-controls-container #minimize,
.titlebar #window-controls-container #maximize, .titlebar #window-controls-container #maximize,
.titlebar #window-controls-container #quit { .titlebar #window-controls-container #quit {
float: left; float: left;
height: 100%; height: 100%;
width: 33%; width: 33%;
text-align: center; text-align: center;
color: #f7f7f7; color: #f7f7f7;
cursor: default; cursor: default;
} }
.titlebar #window-controls-container #minimize:hover { .titlebar #window-controls-container #minimize:hover {
background-color: #99aab5; background-color: #99aab5;
} }
.titlebar #window-controls-container #maximize:hover { .titlebar #window-controls-container #maximize:hover {
background-color: #99aab5; background-color: #99aab5;
} }
.titlebar #window-controls-container #quit:hover { .titlebar #window-controls-container #quit:hover {
background-color: #f04747; background-color: #f04747;
} }
.titlebar #window-controls-container #quit { .titlebar #window-controls-container #quit {
background-color: #f7f7f7; background-color: #f7f7f7;
-webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E")
no-repeat 50% 50%; no-repeat 50% 50%;
mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E")
no-repeat 50% 50%; no-repeat 50% 50%;
} }
.titlebar #window-controls-container #minimize { .titlebar #window-controls-container #minimize {
background-color: #f7f7f7; background-color: #f7f7f7;
-webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E")
no-repeat 50% 50%; no-repeat 50% 50%;
mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E")
no-repeat 50% 50%; no-repeat 50% 50%;
} }
.titlebar #window-controls-container #maximize { .titlebar #window-controls-container #maximize {
background-color: #f7f7f7; background-color: #f7f7f7;
-webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E")
no-repeat 50% 50%; no-repeat 50% 50%;
mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E")
no-repeat 50% 50%; no-repeat 50% 50%;
} }
.window-title:after { .window-title:after {
content: "Cord"; content: "Cord";
color: var(--cord-color) !important; color: var(--cord-color) !important;
font-weight: normal; font-weight: normal;
font-size: 14px; font-size: 14px;
font-family: Discordinated; font-family: Discordinated;
} }
.window-title:before { .window-title:before {
content: "ARM"; content: "ARM";
color: var(--armcord-color); color: var(--armcord-color);
font-weight: normal; font-weight: normal;
font-size: 14px; font-size: 14px;
font-family: Helvetica, sans-serif; font-family: Helvetica, sans-serif;
} }
.window-title { .window-title {
font-size: 0px !important; font-size: 0px !important;
margin-left: initial !important; margin-left: initial !important;
transform: translate(10px, 0px); transform: translate(10px, 0px);
} }
.withFrame-haYltI { .withFrame-haYltI {
height: 30px !important; height: 30px !important;
} }

View File

@ -1,64 +1,60 @@
<!--- 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. ---> <!--- 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> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<link <link rel="stylesheet" href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css" />
rel="stylesheet" <meta charset="UTF-8" />
href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css" <title>ArmCord Setup</title>
/> <style>
<meta charset="UTF-8" /> @import url("css/setup.css");
<title>ArmCord Setup</title> </style>
<style> </head>
@import url("css/setup.css");
</style>
</head>
<body> <body>
<div class="container"> <div class="container">
<h1 class="logo"></h1> <h1 class="logo"></h1>
<div id="setup"> <div id="setup">
<p>Select what kind of setup you want to perform:</p> <p>Select what kind of setup you want to perform:</p>
<button id="express" class="center">Express setup</button> <button id="express" class="center">Express setup</button>
<button id="full" class="center">Full setup</button> <button id="full" class="center">Full setup</button>
</div> </div>
</div> </div>
<script> <script>
function fade(element) {
var op = 1; // initial opacity
var timer = setInterval(function () {
if (op <= 0.1) {
clearInterval(timer);
element.style.display = "none";
}
element.style.opacity = op;
element.style.filter = "alpha(opacity=" + op * 100 + ")";
op -= op * 0.1;
}, 50);
}
function fade(element) { if (window.navigator.onLine === false) {
var op = 1; // initial opacity document.getElementById("setup").innerHTML =
var timer = setInterval(function () { "You appear to be offline. Please connect to the internet and restart ArmCord Setup.";
if (op <= 0.1) { } else {
clearInterval(timer); console.log("Starting ArmCord Setup...");
element.style.display = "none"; document.getElementById("express").addEventListener("click", function () {
} window.armcordinternal.saveSettings({
element.style.opacity = op; windowStyle: "default",
element.style.filter = "alpha(opacity=" + op * 100 + ")"; channel: "stable",
op -= op * 0.1; armcordCSP: true,
}, 50); minimizeToTray: true,
} automaticPatches: false,
mods: "cumcord",
if (window.navigator.onLine === false) { blurType: "acrylic"
document.getElementById("setup").innerHTML = });
"You appear to be offline. Please connect to the internet and restart ArmCord Setup."; fade(document.getElementById("setup"));
} else { setTimeout(function () {
console.log("Starting ArmCord Setup..."); window.armcordinternal.restart();
document.getElementById("express").addEventListener("click", function () { }, 5000);
window.armcordinternal.saveSettings({ });
windowStyle: "default", document.getElementById("full").addEventListener("click", function () {
channel: "stable", document.getElementById("setup").innerHTML = `
armcordCSP: true,
minimizeToTray: true,
automaticPatches: false,
mods: "cumcord",
blurType: "acrylic"
})
fade(document.getElementById("setup"));
setTimeout(function () {
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> <p class="text-center setup-ask">Choose your Discord channel/instance:</p>
<div class="center"> <div class="center">
<select name="channel" id="channel" class="dropdown-button"> <select name="channel" id="channel" class="dropdown-button">
@ -77,13 +73,11 @@
</div> </div>
<button id="next" class="center">Next</button> <button id="next" class="center">Next</button>
`; `;
document document.getElementById("next").addEventListener("click", function () {
.getElementById("next") var branch = document.getElementById("channel").value;
.addEventListener("click", function () { var csp = document.getElementById("csp").value;
var branch = document.getElementById("channel").value; if (csp === "true") {
var csp = document.getElementById("csp").value; document.getElementById("setup").innerHTML = `
if (csp === "true") {
document.getElementById("setup").innerHTML = `
<p class="text-center setup-ask">Select a client mod you want to install:</p> <p class="text-center setup-ask">Select a client mod you want to install:</p>
<div class="center"> <div class="center">
<select name="mod" id="mod" class="dropdown-button"> <select name="mod" id="mod" class="dropdown-button">
@ -95,42 +89,40 @@
<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> <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> <button id="next" class="center">Next</button>
`; `;
document document.getElementById("next").addEventListener("click", function () {
.getElementById("next") var mod = document.getElementById("mod").value;
.addEventListener("click", function () { window.armcordinternal.saveSettings({
var mod = document.getElementById("mod").value; windowStyle: "default",
window.armcordinternal.saveSettings({ channel: branch,
windowStyle: "default", armcordCSP: true,
channel: branch, minimizeToTray: true,
armcordCSP: true, automaticPatches: false,
minimizeToTray: true, mods: mod,
automaticPatches: false, blurType: "acrylic"
mods: mod, });
blurType: "acrylic" fade(document.getElementById("setup"));
}) setTimeout(function () {
fade(document.getElementById("setup")); window.armcordinternal.restart();
setTimeout(function () { }, 5000);
window.armcordinternal.restart(); });
}, 5000); } else {
}); window.armcordinternal.saveSettings({
} else { windowStyle: "default",
window.armcordinternal.saveSettings({ channel: branch,
windowStyle: "default", armcordCSP: true,
channel: branch, minimizeToTray: true,
armcordCSP: true, automaticPatches: false,
minimizeToTray: true, mods: "none",
automaticPatches: false, blurType: "acrylic"
mods: "none", });
blurType: "acrylic" fade(document.getElementById("setup"));
}) setTimeout(function () {
fade(document.getElementById("setup")); window.armcordinternal.restart();
setTimeout(function () { }, 5000);
window.armcordinternal.restart() }
}, 5000); });
} });
}); }
}); </script>
} </body>
</script>
</body>
</html> </html>

View File

@ -1,68 +1,63 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>ArmCord</title> <title>ArmCord</title>
<style> <style>
@import url("css/splash.css"); @import url("css/splash.css");
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<video autoplay loop class="logo" id="splashscreen-armcord"> <video autoplay loop class="logo" id="splashscreen-armcord">
<source <source src="https://armcord.smartfridge.space/discord_loading.webm" type="video/webm" />
src="https://armcord.smartfridge.space/discord_loading.webm" </video>
type="video/webm" <p id="text-splashscreen"></p>
/> </div>
</video> </body>
<p id="text-splashscreen"></p> <script>
</div> const text = document.getElementById("text-splashscreen");
</body> if (window.navigator.onLine === false) {
<script> text.innerHTML = "You appear to be offline. Please connect to the internet and try again.";
const text = document.getElementById("text-splashscreen"); } else {
if (window.navigator.onLine === false) { text.innerHTML = "Starting ArmCord...";
text.innerHTML = fetch("https://armcord.smartfridge.space/latest.json")
"You appear to be offline. Please connect to the internet and try again."; .then((response) => response.json())
} else { .then((data) => {
text.innerHTML = "Starting ArmCord..."; if (data.version !== window.armcord.version) {
fetch("https://armcord.smartfridge.space/latest.json") var elem = document.createElement("img");
.then((response) => response.json()) elem.classList.add("logo");
.then((data) => { elem.src = "https://armcord.smartfridge.space/update.webp";
if (data.version !== window.armcord.version) { document.body.prepend(elem);
var elem = document.createElement("img"); document.getElementById("splashscreen-armcord").remove();
elem.classList.add("logo"); text.innerHTML = "A new version of ArmCord is available. Please update to the latest version.";
elem.src = "https://armcord.smartfridge.space/update.webp"; } else {
document.body.prepend(elem); console.log("ArmCord is up to date.");
document.getElementById("splashscreen-armcord").remove(); }
text.innerHTML = });
"A new version of ArmCord is available. Please update to the latest version."; setTimeout(() => {
} else { window.armcordinternal.splashEnd();
console.log("ArmCord is up to date.") switch (window.armcord.channel) {
} case "stable":
}); window.location.replace("https://discord.com/app");
setTimeout(() => { break;
window.armcordinternal.splashEnd(); case "canary":
switch (window.armcord.channel) { window.location.replace("https://canary.discord.com/app");
case "stable": break;
window.location.replace("https://discord.com/app"); case "ptb":
break; window.location.replace("https://ptb.discord.com/app");
case "canary": break;
window.location.replace("https://canary.discord.com/app"); case "foss":
break; window.location.replace("https://dev.fosscord.com/app");
case "ptb": break;
window.location.replace("https://ptb.discord.com/app"); case undefined:
break; window.location.replace("https://discord.com/app");
case "foss": break;
window.location.replace("https://dev.fosscord.com/app"); default:
break; window.location.replace("https://discord.com/app");
case undefined: }
window.location.replace("https://discord.com/app"); }, 5000);
break; }
default: </script>
window.location.replace("https://discord.com/app");
}
}, 5000);
}
</script>
</html> </html>

View File

@ -11,59 +11,55 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
import electron from "electron"; import electron from "electron";
import * as storage from "electron-json-storage"; import * as storage from "electron-json-storage";
const otherMods = { const otherMods = {
generic: { 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 = () => { const unstrictCSP = () => {
console.log("Setting up CSP unstricter..."); console.log("Setting up CSP unstricter...");
const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"]; const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"];
const corsAllowUrls = [ const corsAllowUrls = [
"https://github.com/GooseMod/GooseMod/releases/download/dev/index.js", "https://github.com/GooseMod/GooseMod/releases/download/dev/index.js",
"https://github-releases.githubusercontent.com/", "https://github-releases.githubusercontent.com/",
"https://api.goosemod.com/inject.js", "https://api.goosemod.com/inject.js",
"https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.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/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( electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, url}, done) => {
({ responseHeaders, url }, done) => { let csp = responseHeaders!["content-security-policy"];
let csp = responseHeaders!["content-security-policy"];
if (otherMods.generic.electronProxy) { if (otherMods.generic.electronProxy) {
// Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods
delete responseHeaders!["content-security-policy"]; delete responseHeaders!["content-security-policy"];
csp = []; csp = [];
}
if (csp) {
for (let p of cspAllowAll) {
csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs
} }
// Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?) if (csp) {
csp[0] = csp[0].replace(/'nonce-.*?' /, ""); for (let p of cspAllowAll) {
} csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs
}
if (corsAllowUrls.some((x) => url.startsWith(x))) { // Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?)
responseHeaders!["access-control-allow-origin"] = ["*"]; csp[0] = csp[0].replace(/'nonce-.*?' /, "");
} }
done({ responseHeaders }); if (corsAllowUrls.some((x) => url.startsWith(x))) {
} responseHeaders!["access-control-allow-origin"] = ["*"];
); }
done({responseHeaders});
});
}; };
storage.get("settings", function (error, data: any) { storage.get("settings", function (error, data: any) {
if (error) throw error; if (error) throw error;
if (data.armcordCSP) { if (data.armcordCSP) {
unstrictCSP(); unstrictCSP();
} else { } else {
console.log( console.log("ArmCord CSP is disabled. The CSP should be managed by third-party plugin.");
"ArmCord CSP is disabled. The CSP should be managed by third-party plugin." }
);
}
}); });

View File

@ -1,26 +1,20 @@
import * as fs from 'fs'; import * as fs from "fs";
import { app, session } from 'electron'; import {app, session} from "electron";
const userDataPath = app.getPath("userData"); const userDataPath = app.getPath("userData");
const pluginFolder = userDataPath + "/plugins/"; const pluginFolder = userDataPath + "/plugins/";
if (!fs.existsSync(pluginFolder)) { if (!fs.existsSync(pluginFolder)) {
fs.mkdirSync(pluginFolder); fs.mkdirSync(pluginFolder);
console.log("Created missing plugin folder"); console.log("Created missing plugin folder");
} }
app.whenReady().then(() => { app.whenReady().then(() => {
fs.readdirSync(pluginFolder).forEach((file) => { fs.readdirSync(pluginFolder).forEach((file) => {
try { try {
const manifest = fs.readFileSync( const manifest = fs.readFileSync(`${userDataPath}/plugins/${file}/manifest.json`, "utf8");
`${userDataPath}/plugins/${file}/manifest.json`, var pluginFile = JSON.parse(manifest);
"utf8" session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`);
); console.log(`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, "color:red");
var pluginFile = JSON.parse(manifest); } catch (err) {
session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); console.error(err);
console.log( }
`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, });
"color:red"
);
} catch (err) {
console.error(err);
}
});
}); });

View File

@ -1,83 +1,81 @@
//ipc stuff //ipc stuff
import { app, ipcMain, shell, desktopCapturer } from "electron"; import {app, ipcMain, shell, desktopCapturer} from "electron";
import { createTabsGuest, mainWindow } from "./window"; import {createTabsGuest, mainWindow} from "./window";
import { saveSettings, getVersion } from "./utils"; import {saveSettings, getVersion} from "./utils";
import { settings, customTitlebar, tabs } from "./main"; import {settings, customTitlebar, tabs} from "./main";
import { createSettingsWindow } from "./settings/main"; import {createSettingsWindow} from "./settings/main";
export function registerIpc() { export function registerIpc() {
ipcMain.on("get-app-path", (event, arg) => { ipcMain.on("get-app-path", (event, arg) => {
event.reply("app-path", app.getAppPath()); event.reply("app-path", app.getAppPath());
}); });
ipcMain.on("openTab", (event, number: number) => { ipcMain.on("openTab", (event, number: number) => {
createTabsGuest(number); createTabsGuest(number);
}); });
ipcMain.on("open-external-link", (event, href: string) => { ipcMain.on("open-external-link", (event, href: string) => {
shell.openExternal(href); shell.openExternal(href);
}); });
ipcMain.on("win-maximize", (event, arg) => { ipcMain.on("win-maximize", (event, arg) => {
mainWindow.maximize(); mainWindow.maximize();
}); });
ipcMain.on("win-isMaximized", (event, arg) => { ipcMain.on("win-isMaximized", (event, arg) => {
event.returnValue = mainWindow.isMaximized(); event.returnValue = mainWindow.isMaximized();
}); });
ipcMain.on("win-minimize", (event, arg) => { ipcMain.on("win-minimize", (event, arg) => {
mainWindow.minimize(); mainWindow.minimize();
}); });
ipcMain.on("win-unmaximize", (event, arg) => { ipcMain.on("win-unmaximize", (event, arg) => {
mainWindow.unmaximize(); mainWindow.unmaximize();
}); });
ipcMain.on("win-show", (event, arg) => { ipcMain.on("win-show", (event, arg) => {
mainWindow.show(); mainWindow.show();
}); });
ipcMain.on("win-hide", (event, arg) => { ipcMain.on("win-hide", (event, arg) => {
mainWindow.hide(); mainWindow.hide();
}); });
ipcMain.on("win-quit", (event, arg) => { ipcMain.on("win-quit", (event, arg) => {
app.exit(); app.exit();
}); });
ipcMain.on("get-app-version", (event) => { ipcMain.on("get-app-version", (event) => {
event.returnValue = getVersion(); event.returnValue = getVersion();
}); });
ipcMain.on("splashEnd", (event, arg) => { ipcMain.on("splashEnd", (event, arg) => {
mainWindow.setSize(800, 600); mainWindow.setSize(800, 600);
}); });
ipcMain.on("restart", (event, arg) => { ipcMain.on("restart", (event, arg) => {
app.relaunch(); app.relaunch();
app.exit(); app.exit();
}); });
ipcMain.on("saveSettings", (event, args) => { ipcMain.on("saveSettings", (event, args) => {
saveSettings(args); saveSettings(args);
}); });
ipcMain.on("minimizeToTray", (event) => { ipcMain.on("minimizeToTray", (event) => {
console.log(settings.minimizeToTray); console.log(settings.minimizeToTray);
event.returnValue = settings.minimizeToTray; event.returnValue = settings.minimizeToTray;
}); });
ipcMain.on("channel", (event) => { ipcMain.on("channel", (event) => {
event.returnValue = settings.channel; event.returnValue = settings.channel;
}); });
ipcMain.on("clientmod", (event, arg) => { ipcMain.on("clientmod", (event, arg) => {
event.returnValue = settings.mods; event.returnValue = settings.mods;
}); });
ipcMain.on("titlebar", (event, arg) => { ipcMain.on("titlebar", (event, arg) => {
event.returnValue = customTitlebar; event.returnValue = customTitlebar;
}); });
ipcMain.on("tabs", (event, arg) => { ipcMain.on("tabs", (event, arg) => {
event.returnValue = tabs; event.returnValue = tabs;
}); });
ipcMain.on("shouldPatch", (event, arg) => { ipcMain.on("shouldPatch", (event, arg) => {
event.returnValue = settings.automaticPatches; event.returnValue = settings.automaticPatches;
}); });
ipcMain.on("openSettingsWindow", (event, arg) => { ipcMain.on("openSettingsWindow", (event, arg) => {
createSettingsWindow(); createSettingsWindow();
}); });
ipcMain.on("setting-armcordCSP", (event) => { ipcMain.on("setting-armcordCSP", (event) => {
if (settings.armcordCSP) { if (settings.armcordCSP) {
event.returnValue = true; event.returnValue = true;
} else { } else {
event.returnValue = false; event.returnValue = false;
} }
}); });
ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => desktopCapturer.getSources(opts));
desktopCapturer.getSources(opts)
);
} }

View File

@ -1,114 +1,108 @@
// Modules to control application life and create native browser window // Modules to control application life and create native browser window
import { import {app, BrowserWindow, session} from "electron";
app,
BrowserWindow,
session,
} from "electron";
import * as path from "path"; import * as path from "path";
import "v8-compile-cache"; import "v8-compile-cache";
import * as storage from "electron-json-storage"; import * as storage from "electron-json-storage";
import { getConfigUnsafe, setup } from "./utils"; import {getConfigUnsafe, setup} from "./utils";
import "./extensions/mods"; import "./extensions/mods";
import "./extensions/plugin"; import "./extensions/plugin";
import "./tray"; import "./tray";
import { mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost } from "./window"; import {mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost} from "./window";
import "./shortcuts"; import "./shortcuts";
export var contentPath: string; export var contentPath: string;
var channel: string; var channel: string;
export var settings: any; export var settings: any;
export var customTitlebar: boolean; export var customTitlebar: boolean;
export var tabs: boolean; export var tabs: boolean;
async function appendSwitch(){ async function appendSwitch() {
if (await getConfigUnsafe("windowStyle") == "glasstron") { if ((await getConfigUnsafe("windowStyle")) == "glasstron") {
console.log("Enabling transparency visuals."); console.log("Enabling transparency visuals.");
app.commandLine.appendSwitch("enable-transparent-visuals"); app.commandLine.appendSwitch("enable-transparent-visuals");
} }
} }
appendSwitch(); appendSwitch();
storage.has("settings", function (error, hasKey) { storage.has("settings", function (error, hasKey) {
if (error) throw error; if (error) throw error;
if (!hasKey) { if (!hasKey) {
console.log("First run of the ArmCord. Starting setup."); console.log("First run of the ArmCord. Starting setup.");
setup(); setup();
contentPath = path.join(__dirname, "/content/setup.html"); contentPath = path.join(__dirname, "/content/setup.html");
if (!contentPath.includes("ts-out")) { if (!contentPath.includes("ts-out")) {
contentPath = path.join(__dirname, "/ts-out/content/setup.html"); contentPath = path.join(__dirname, "/ts-out/content/setup.html");
} }
} else { } else {
console.log("ArmCord has been run before. Skipping setup."); console.log("ArmCord has been run before. Skipping setup.");
contentPath = path.join(__dirname, "/content/splash.html"); contentPath = path.join(__dirname, "/content/splash.html");
if (!contentPath.includes("ts-out")) { if (!contentPath.includes("ts-out")) {
contentPath = path.join(__dirname, "/ts-out/content/splash.html"); contentPath = path.join(__dirname, "/ts-out/content/splash.html");
} }
} }
}); });
storage.get("settings", function (error, data: any) { storage.get("settings", function (error, data: any) {
if (error) throw error; if (error) throw error;
console.log(data); console.log(data);
channel = data.channel; channel = data.channel;
settings = data; settings = data;
}); });
app.whenReady().then(async () => { app.whenReady().then(async () => {
switch (await getConfigUnsafe("windowStyle")) { switch (await getConfigUnsafe("windowStyle")) {
case "default":
createCustomWindow();
customTitlebar = true;
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) => {
if (permission === "notifications") {
// Approves the permissions request
callback(true);
}
if (permission === "media") {
// Approves the permissions request
callback(true);
}
});
app.on("activate", async function () {
if (BrowserWindow.getAllWindows().length === 0)
switch (await getConfigUnsafe("windowStyle")) {
case "default": case "default":
createCustomWindow(); createCustomWindow();
break; customTitlebar = true;
break;
case "native": case "native":
createNativeWindow(); createNativeWindow();
break; break;
case "glasstron": case "glasstron":
createGlasstronWindow(); setTimeout(
break; 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: default:
createCustomWindow(); createCustomWindow();
break; customTitlebar = true;
} break;
}); }
session.fromPartition("some-partition").setPermissionRequestHandler((webContents, permission, callback) => {
if (permission === "notifications") {
// Approves the permissions request
callback(true);
}
if (permission === "media") {
// Approves the permissions request
callback(true);
}
});
app.on("activate", async function () {
if (BrowserWindow.getAllWindows().length === 0)
switch (await getConfigUnsafe("windowStyle")) {
case "default":
createCustomWindow();
break;
case "native":
createNativeWindow();
break;
case "glasstron":
createGlasstronWindow();
break;
default:
createCustomWindow();
break;
}
});
}); });
app.on("window-all-closed", function () { app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit(); if (process.platform !== "darwin") app.quit();
}); });

View File

@ -1,33 +1,30 @@
import { contextBridge, ipcRenderer } from "electron"; import {contextBridge, ipcRenderer} from "electron";
import { getDisplayMediaSelector } from "./capturer"; import {getDisplayMediaSelector} from "./capturer";
import { injectTitlebar } from "./titlebar"; import {injectTitlebar} from "./titlebar";
contextBridge.exposeInMainWorld("armcord", { contextBridge.exposeInMainWorld("armcord", {
window: { window: {
show: () => ipcRenderer.send("win-show"), show: () => ipcRenderer.send("win-show"),
hide: () => ipcRenderer.send("win-hide"), hide: () => ipcRenderer.send("win-hide"),
minimize: () => ipcRenderer.send("win-minimize"), minimize: () => ipcRenderer.send("win-minimize"),
maximize: () => ipcRenderer.send("win-maximize"), maximize: () => ipcRenderer.send("win-maximize")
}, },
titlebar: { titlebar: {
injectTitlebar: () => injectTitlebar(), injectTitlebar: () => injectTitlebar(),
isTitlebar: ipcRenderer.sendSync("titlebar"), isTitlebar: ipcRenderer.sendSync("titlebar")
}, },
electron: process.versions.electron, electron: process.versions.electron,
channel: ipcRenderer.sendSync("channel"), channel: ipcRenderer.sendSync("channel"),
openTab: (number: number) => ipcRenderer.sendSync("openTab", number), openTab: (number: number) => ipcRenderer.sendSync("openTab", number),
version: ipcRenderer.sendSync("get-app-version", "app-version"), version: ipcRenderer.sendSync("get-app-version", "app-version"),
getDisplayMediaSelector: getDisplayMediaSelector, getDisplayMediaSelector: getDisplayMediaSelector,
openSettingsWindow: () => ipcRenderer.send("openSettingsWindow"), openSettingsWindow: () => ipcRenderer.send("openSettingsWindow")
}); });
//to be only used inside armcord internal setup/splash etc //to be only used inside armcord internal setup/splash etc
if ( if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) {
window.location.href.indexOf("splash.html") > -1 || contextBridge.exposeInMainWorld("armcordinternal", {
window.location.href.indexOf("setup.html") > -1 restart: () => ipcRenderer.send("restart"),
) { saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args),
contextBridge.exposeInMainWorld("armcordinternal", { splashEnd: () => ipcRenderer.send("splashEnd")
restart: () => ipcRenderer.send("restart"), });
saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args), }
splashEnd: () => ipcRenderer.send("splashEnd"),
});
}

View File

@ -1,37 +1,36 @@
//Fixed context isolation version https://github.com/getferdi/ferdi/blob/develop/src/webview/screenshare.ts //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 //original https://github.com/electron/electron/issues/16513#issuecomment-602070250
import { ipcRenderer } from 'electron'; import {ipcRenderer} from "electron";
import {addStyle, addScript} from '../utils'; import {addStyle, addScript} from "../utils";
const desktopCapturer = { const desktopCapturer = {
getSources: (opts: any) => getSources: (opts: any) => ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts)
ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts),
}; };
const CANCEL_ID = 'desktop-capturer-selection__cancel'; const CANCEL_ID = "desktop-capturer-selection__cancel";
interface IPCSources { interface IPCSources {
id: string; id: string;
name: string; name: string;
thumbnail: HTMLCanvasElement; thumbnail: HTMLCanvasElement;
} }
export async function getDisplayMediaSelector() { export async function getDisplayMediaSelector() {
const sources: IPCSources[] = await desktopCapturer.getSources({ const sources: IPCSources[] = await desktopCapturer.getSources({
types: ['screen', 'window'], types: ["screen", "window"]
}); });
return `<div class="desktop-capturer-selection__scroller"> return `<div class="desktop-capturer-selection__scroller">
<ul class="desktop-capturer-selection__list"> <ul class="desktop-capturer-selection__list">
${sources ${sources
.map( .map(
({ id, name, thumbnail }) => ` ({id, name, thumbnail}) => `
<li class="desktop-capturer-selection__item"> <li class="desktop-capturer-selection__item">
<button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}">
<img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" />
<span class="desktop-capturer-selection__name">${name}</span> <span class="desktop-capturer-selection__name">${name}</span>
</button> </button>
</li> </li>
`, `
) )
.join('')} .join("")}
<li class="desktop-capturer-selection__item"> <li class="desktop-capturer-selection__item">
<button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel"> <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> <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span>
@ -154,9 +153,8 @@ window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve
}); });
`; `;
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
addScript(screenShareJS); addScript(screenShareJS);
addStyle(screenShareCSS); addStyle(screenShareCSS);
console.log("Capturer injected.") console.log("Capturer injected.");
}); });

View File

@ -1,22 +1,22 @@
// What does this do? // 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 // 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 // This is completely optional and is disabled by default in settings
import { ipcRenderer } from "electron"; import {ipcRenderer} from "electron";
import { injectJS } from "../utils"; import {injectJS} from "../utils";
var patchEndpoint = "https://patch.armcord.xyz/"; var patchEndpoint = "https://patch.armcord.xyz/";
var version = ipcRenderer.sendSync("get-app-version", "app-version"); var version = ipcRenderer.sendSync("get-app-version", "app-version");
if (ipcRenderer.sendSync("shouldPatch")) { if (ipcRenderer.sendSync("shouldPatch")) {
document.addEventListener("DOMContentLoaded", function () { 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) => res.json())
.then((res) => { .then((res) => {
if (res.patch == true) { if (res.patch == true) {
console.log("Found a patch. Injecting..."); console.log("Found a patch. Injecting...");
injectJS(patchEndpoint + version + "/patch.js"); injectJS(patchEndpoint + version + "/patch.js");
} else { } else {
console.log("No patches have been found.") console.log("No patches have been found.");
} }
}); });
}); });
} }

View File

@ -1,51 +1,50 @@
import "./bridge"; import "./bridge";
import "./capturer"; import "./capturer";
import "./patch" import "./patch";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { injectTitlebar } from "./titlebar"; import {injectTitlebar} from "./titlebar";
import { sleep, addStyle, injectJS } from "../utils"; import {sleep, addStyle, injectJS} from "../utils";
import { ipcRenderer } from "electron"; import {ipcRenderer} from "electron";
import { injectTabs } from "./tabs"; import {injectTabs} from "./tabs";
declare global { declare global {
interface Window { interface Window {
armcord: any; armcord: any;
} }
} }
const clientMods = { const clientMods = {
goosemod: "https://api.goosemod.com/inject.js", goosemod: "https://api.goosemod.com/inject.js",
cumcord: cumcord: "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js",
"https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js"
flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js",
}; };
console.log("ArmCord"); console.log("ArmCord");
if (window.location.href.indexOf("splash.html") > -1) { if (window.location.href.indexOf("splash.html") > -1) {
console.log("Skipping titlebar injection and client mod injection."); console.log("Skipping titlebar injection and client mod injection.");
} else { } else {
if (ipcRenderer.sendSync("titlebar")) { if (ipcRenderer.sendSync("titlebar")) {
injectTitlebar(); injectTitlebar();
}
if (ipcRenderer.sendSync("tabs")) {
injectTabs();
}
sleep(5000).then(() => {
const cssPath = path.join(__dirname, "../", "/content/css/discord.css");
addStyle(fs.readFileSync(cssPath, "utf8"));
switch (ipcRenderer.sendSync("clientmod")) {
case "goosemod":
injectJS(clientMods.goosemod);
console.log("Loading GooseMod...");
break;
case "cumcord":
injectJS(clientMods.cumcord);
console.log("Loading Cumcord...");
break;
case "flicker":
injectJS(clientMods.flicker);
console.log("Loading FlickerMod...");
break;
} }
}); if (ipcRenderer.sendSync("tabs")) {
injectTabs();
}
sleep(5000).then(() => {
const cssPath = path.join(__dirname, "../", "/content/css/discord.css");
addStyle(fs.readFileSync(cssPath, "utf8"));
switch (ipcRenderer.sendSync("clientmod")) {
case "goosemod":
injectJS(clientMods.goosemod);
console.log("Loading GooseMod...");
break;
case "cumcord":
injectJS(clientMods.cumcord);
console.log("Loading Cumcord...");
break;
case "flicker":
injectJS(clientMods.flicker);
console.log("Loading FlickerMod...");
break;
}
});
} }

View File

@ -1,10 +1,10 @@
import { addStyle } from "../utils"; import {addStyle} from "../utils";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
export function injectTabs() { export function injectTabs() {
document.addEventListener("DOMContentLoaded", function (event) { document.addEventListener("DOMContentLoaded", function (event) {
var elem = document.createElement("div"); var elem = document.createElement("div");
elem.innerHTML = `<nav class="tabs"> elem.innerHTML = `<nav class="tabs">
<div id="tabs-controls-container"> <div id="tabs-controls-container">
<button class="tabs-buttons" onclick="armcord.openTab(1)">1</button> <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(2)">2</button>
@ -14,12 +14,13 @@ export function injectTabs() {
<p class="experimental">Experimental</p> <p class="experimental">Experimental</p>
</div> </div>
</nav>`; </nav>`;
elem.classList.add("withFrame-haYltI"); elem.classList.add("withFrame-haYltI");
if (document.getElementById("app-mount") == null) { if (document.getElementById("app-mount") == null) {
document.body.appendChild(elem); document.body.appendChild(elem);
} else { } else {
document.getElementById("app-mount")!.prepend(elem); document.getElementById("app-mount")!.prepend(elem);
} }
const cssPath = path.join(__dirname, "../", "/content/css/tabs.css"); const cssPath = path.join(__dirname, "../", "/content/css/tabs.css");
addStyle(fs.readFileSync(cssPath, "utf8")); addStyle(fs.readFileSync(cssPath, "utf8"));
})} });
}

View File

@ -1,11 +1,11 @@
import { ipcRenderer } from "electron"; import {ipcRenderer} from "electron";
import { addStyle } from "../utils"; import {addStyle} from "../utils";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
export function injectTitlebar() { export function injectTitlebar() {
document.addEventListener("DOMContentLoaded", function (event) { document.addEventListener("DOMContentLoaded", function (event) {
var elem = document.createElement("div"); var elem = document.createElement("div");
elem.innerHTML = `<nav class="titlebar"> elem.innerHTML = `<nav class="titlebar">
<div class="window-title" id="window-title"></div> <div class="window-title" id="window-title"></div>
<div id="window-controls-container"> <div id="window-controls-container">
<div id="minimize"></div> <div id="minimize"></div>
@ -13,40 +13,40 @@ export function injectTitlebar() {
<div id="quit"></div> <div id="quit"></div>
</div> </div>
</nav>`; </nav>`;
elem.classList.add("withFrame-haYltI"); elem.classList.add("withFrame-haYltI");
if (document.getElementById("app-mount") == null) { if (document.getElementById("app-mount") == null) {
document.body.appendChild(elem); document.body.appendChild(elem);
} else { } else {
document.getElementById("app-mount")!.prepend(elem); document.getElementById("app-mount")!.prepend(elem);
} }
const cssPath = path.join(__dirname, "../", "/content/css/titlebar.css"); const cssPath = path.join(__dirname, "../", "/content/css/titlebar.css");
addStyle(fs.readFileSync(cssPath, "utf8")); addStyle(fs.readFileSync(cssPath, "utf8"));
var minimize = document.getElementById("minimize"); var minimize = document.getElementById("minimize");
var maximize = document.getElementById("maximize"); var maximize = document.getElementById("maximize");
var quit = document.getElementById("quit"); var quit = document.getElementById("quit");
minimize!.addEventListener("click", () => { minimize!.addEventListener("click", () => {
ipcRenderer.send("win-minimize"); ipcRenderer.send("win-minimize");
});
maximize!.addEventListener("click", () => {
if (ipcRenderer.sendSync("win-isMaximized") == true) {
ipcRenderer.send("win-unmaximize");
} else {
ipcRenderer.send("win-maximize");
}
});
quit!.addEventListener("click", () => {
if (ipcRenderer.sendSync("minimizeToTray") === true) {
ipcRenderer.send("win-hide");
} else if (ipcRenderer.sendSync("minimizeToTray") === false) {
ipcRenderer.send("win-quit");
}
});
}); });
maximize!.addEventListener("click", () => {
if (ipcRenderer.sendSync("win-isMaximized") == true) {
ipcRenderer.send("win-unmaximize");
} else {
ipcRenderer.send("win-maximize");
}
});
quit!.addEventListener("click", () => {
if (ipcRenderer.sendSync("minimizeToTray") === true) {
ipcRenderer.send("win-hide");
} else if (ipcRenderer.sendSync("minimizeToTray") === false) {
ipcRenderer.send("win-quit");
}
});
});
} }
export function removeTitlebar() { export function removeTitlebar() {
document.querySelector("#titlebar")!.remove(); document.querySelector("#titlebar")!.remove();
} }

View File

@ -1,46 +1,46 @@
import { BrowserWindow, shell, ipcMain } from "electron"; import {BrowserWindow, shell, ipcMain} from "electron";
import * as storage from "electron-json-storage"; import * as storage from "electron-json-storage";
import {getConfigUnsafe, saveSettings, Settings} from "../utils"; import {getConfigUnsafe, saveSettings, Settings} from "../utils";
import path from "path"; import path from "path";
var settings:any; var settings: any;
var isAlreadyCreated:boolean = false; var isAlreadyCreated: boolean = false;
storage.get("settings", function (error, data: any) { storage.get("settings", function (error, data: any) {
if (error) throw error; if (error) throw error;
console.log(data); console.log(data);
settings = data; settings = data;
}); });
var settingsWindow:BrowserWindow; var settingsWindow: BrowserWindow;
export function createSettingsWindow() { export function createSettingsWindow() {
if (isAlreadyCreated) { if (isAlreadyCreated) {
settingsWindow.show(); settingsWindow.show();
} else { } else {
settingsWindow = new BrowserWindow({ settingsWindow = new BrowserWindow({
width: 500, width: 500,
height: 500, height: 500,
title: "ArmCord Settings", title: "ArmCord Settings",
darkTheme: true, darkTheme: true,
frame: true, frame: true,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "preload.js"), preload: path.join(__dirname, "preload.js")
}, }
}); });
ipcMain.on("saveSettings", (event, args: Settings) => { ipcMain.on("saveSettings", (event, args: Settings) => {
console.log(args); console.log(args);
saveSettings(args); saveSettings(args);
}); });
ipcMain.handle("getSetting", (event, toGet: string) => { ipcMain.handle("getSetting", (event, toGet: string) => {
return getConfigUnsafe(toGet); return getConfigUnsafe(toGet);
}); });
settingsWindow.webContents.setWindowOpenHandler(({ url }) => { settingsWindow.webContents.setWindowOpenHandler(({url}) => {
shell.openExternal(url); shell.openExternal(url);
return { action: "deny" }; return {action: "deny"};
}); });
settingsWindow.loadURL(`file://${__dirname}/settings.html`); settingsWindow.loadURL(`file://${__dirname}/settings.html`);
settingsWindow.on("close", async (e) => { settingsWindow.on("close", async (e) => {
e.preventDefault() e.preventDefault();
settingsWindow.hide() settingsWindow.hide();
}); });
isAlreadyCreated = true; isAlreadyCreated = true;
} }
} }

View File

@ -1,6 +1,9 @@
import {contextBridge, ipcRenderer} from "electron"; import {contextBridge, ipcRenderer} from "electron";
console.log("ArmCord Settings") console.log("ArmCord Settings");
contextBridge.exposeInMainWorld("settings", { contextBridge.exposeInMainWorld("settings", {
save: (...args: any) => ipcRenderer.send("saveSettings", ...args), save: (...args: any) => ipcRenderer.send("saveSettings", ...args),
get: (toGet: string) => ipcRenderer.invoke('getSetting', toGet).then((result) => {return result}) //jank but works get: (toGet: string) =>
}); ipcRenderer.invoke("getSetting", toGet).then((result) => {
return result;
}) //jank but works
});

View File

@ -20,49 +20,49 @@ 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/ SOFTWARE.*/
:root { :root {
--background-primary: #282b30; --background-primary: #282b30;
--background-secondary: rgba(255, 255, 255, 0.1); --background-secondary: rgba(255, 255, 255, 0.1);
--brand-experiment: #5865f2; --brand-experiment: #5865f2;
--header-primary: #fff; --header-primary: #fff;
--text-muted: #72767d; --text-muted: #72767d;
} }
@font-face { @font-face {
font-family: Whitney; font-family: Whitney;
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff");
} }
html, html,
body { body {
overflow: hidden; overflow: hidden;
margin: 0; margin: 0;
padding: 0; padding: 0;
margin: 2%; margin: 2%;
background: var(--background-primary); background: var(--background-primary);
} }
* { * {
font-family: "Whitney", sans-serif; font-family: "Whitney", sans-serif;
box-sizing: border-box; box-sizing: border-box;
cursor: default; cursor: default;
} }
.left { .left {
float:right; float: right;
vertical-align: right!important; vertical-align: right !important;
} }
.switch { .switch {
vertical-align: middle; vertical-align: middle;
} }
.header { .header {
color: white; color: white;
font-size: 1.5em; font-size: 1.5em;
} }
.center { .center {
text-align: center; text-align: center;
} }
/*buttons*/ /*buttons*/
button { button {
@ -72,7 +72,7 @@ button {
padding: 4px; padding: 4px;
border-radius: 5px; border-radius: 5px;
margin-top: 5px; margin-top: 5px;
text-align: center; text-align: center;
border-style: none; border-style: none;
outline: none; outline: none;
@ -85,73 +85,92 @@ button:hover {
cursor: pointer; cursor: pointer;
} }
.tgl { .tgl {
display: none; display: none;
} }
.tgl, .tgl:after, .tgl:before, .tgl *, .tgl *:after, .tgl *:before, .tgl + .tgl-btn { .tgl,
box-sizing: border-box; .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 { .tgl::-moz-selection,
background: none; .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 { .tgl::selection,
background: none; .tgl:after::selection,
.tgl:before::selection,
.tgl *::selection,
.tgl *:after::selection,
.tgl *:before::selection,
.tgl + .tgl-btn::selection {
background: none;
} }
.tgl + .tgl-btn { .tgl + .tgl-btn {
outline: 0; outline: 0;
display: block; display: block;
width: 4em; width: 4em;
height: 2em; height: 2em;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
.tgl + .tgl-btn:after, .tgl + .tgl-btn:before { .tgl + .tgl-btn:after,
position: relative; .tgl + .tgl-btn:before {
display: block; position: relative;
content: ""; display: block;
width: 50%; content: "";
height: 100%; width: 50%;
height: 100%;
} }
.tgl + .tgl-btn:after { .tgl + .tgl-btn:after {
left: 0; left: 0;
} }
.tgl + .tgl-btn:before { .tgl + .tgl-btn:before {
display: none; display: none;
} }
.tgl:checked + .tgl-btn:after { .tgl:checked + .tgl-btn:after {
left: 50%; left: 50%;
} }
.tgl-light + .tgl-btn { .tgl-light + .tgl-btn {
background: #5c5757; background: #5c5757;
border-radius: 2em; border-radius: 2em;
padding: 2px; padding: 2px;
transition: all 0.4s ease; transition: all 0.4s ease;
} }
.tgl-light + .tgl-btn:after { .tgl-light + .tgl-btn:after {
border-radius: 50%; border-radius: 50%;
background: rgb(255, 255, 255); background: rgb(255, 255, 255);
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.tgl-light:checked + .tgl-btn { .tgl-light:checked + .tgl-btn {
background: #47ca5a; background: #47ca5a;
} }
select { select {
-webkit-appearance: button; -webkit-appearance: button;
-moz-appearance: button; -moz-appearance: button;
background-color: #2c2f33; background-color: #2c2f33;
background-position: center right; background-position: center right;
background-repeat: no-repeat; background-repeat: no-repeat;
border: 1px solid #aaa; border: 1px solid #aaa;
border-radius: 2px; border-radius: 2px;
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
color: #fff; color: #fff;
font-size: 1.2em; font-size: 1.2em;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }

View File

@ -1,88 +1,92 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8" />
<title>ArmCord Settings</title>
<style>
@import url("settings.css");
</style>
</head>
<head> <body>
<meta charset="UTF-8" /> <div class="switch">
<title>ArmCord Settings</title> <select name="theme" id="theme" class="left">
<style> <option value="default">Default</option>
@import url("settings.css"); <option value="native">Native</option>
</style> <option value="glasstron">Glasstron (experimental)</option>
</head> <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>
<body> <script>
async function loadSettings() {
<div class="switch"> document.getElementById("csp").checked = await settings.get("armcordCSP");
<select name="theme" id="theme" class="left"> document.getElementById("tray").checked = await settings.get("minimizeToTray");
<option value="default">Default</option> document.getElementById("patches").value = await settings.get("automaticPatches");
<option value="native">Native</option> document.getElementById("mod").value = await settings.get("mods");
<option value="glasstron">Glasstron (experimental)</option> document.getElementById("channel").value = await settings.get("channel");
<option value="tabs">Tabs (experimental)</option> document.getElementById("theme").value = await settings.get("windowStyle");
</select> document.getElementById("blurType").value = await settings.get("blurType");
<p class="header">ArmCord theme:</p> }
</div> loadSettings();
</br> document.getElementById("save").addEventListener("click", function () {
<div class="switch"> //function saveSettings(windowStyle: string, channelSetting: string, armcordCSPSetting: boolean, minimizeToTray: boolean, automaticPatches: boolean,modsSetting: string, blurType: string)
<label class="header">ArmCord CSP</label> settings.save(
<input class="tgl tgl-light left" id="csp" type="checkbox" /> document.getElementById("theme").value,
<label class="tgl-btn left" for="csp"></label> document.getElementById("channel").value,
</div> document.getElementById("csp").checked,
</br> document.getElementById("tray").checked,
<div class="switch"> document.getElementById("patches").checked,
<label class="header">Minimize to tray</label> document.getElementById("mod").value,
<input class="tgl tgl-light left" id="tray" type="checkbox" /> document.getElementById("blurType").value
<label class="tgl-btn left" for="tray"></label> );
</div> });
</br> </script>
<div class="switch"> </html>
<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>

View File

@ -1,18 +1,18 @@
import { app } from "electron"; import {app} from "electron";
import {mainWindow} from './window'; import {mainWindow} from "./window";
//https://github.com/electron/electron/issues/1334#issuecomment-716080005 //https://github.com/electron/electron/issues/1334#issuecomment-716080005
// TO-DO add more // TO-DO add more
app.on("web-contents-created", (webContentsCreatedEvent, webContents) => { app.on("web-contents-created", (webContentsCreatedEvent, webContents) => {
webContents.on("before-input-event", (beforeInputEvent, input) => { webContents.on("before-input-event", (beforeInputEvent, input) => {
// console.log('Main console::', input) // console.log('Main console::', input)
const { code, alt, control, shift, meta } = input; const {code, alt, control, shift, meta} = input;
// Shortcut: toggle devTools // Shortcut: toggle devTools
if (shift && control && !alt && !meta && code === "KeyI") { if (shift && control && !alt && !meta && code === "KeyI") {
mainWindow.webContents.toggleDevTools(); mainWindow.webContents.toggleDevTools();
} }
// Shortcut: window reload // Shortcut: window reload
if (shift && control && !alt && !meta && code === "KeyR") { if (shift && control && !alt && !meta && code === "KeyR") {
mainWindow.reload(); mainWindow.reload();
} }
}); });
}); });

View File

@ -1,38 +1,38 @@
import { app, Menu, Tray } from 'electron'; import {app, Menu, Tray} from "electron";
import {mainWindow} from './window'; import {mainWindow} from "./window";
import * as path from 'path' import * as path from "path";
import { createSettingsWindow } from './settings/main'; import {createSettingsWindow} from "./settings/main";
let tray = null let tray = null;
app.whenReady().then(() => { 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([ const contextMenu = Menu.buildFromTemplate([
{ {
label: "Open ArmCord", label: "Open ArmCord",
click: function () { click: function () {
mainWindow.show(); mainWindow.show();
}, }
}, },
{ {
label: "Open Settings", label: "Open Settings",
click: function () { click: function () {
createSettingsWindow(); createSettingsWindow();
}, }
}, },
{ {
label: "Support Discord Server", label: "Support Discord Server",
click: function () { click: function () {
mainWindow.show(); mainWindow.show();
mainWindow.loadURL("https://discord.gg/pZtWQBFjk6"); mainWindow.loadURL("https://discord.gg/pZtWQBFjk6");
}, }
}, },
{ {
label: "Quit ArmCord", label: "Quit ArmCord",
click: function () { click: function () {
app.quit(); app.quit();
}, }
}, }
]); ]);
tray.setToolTip('ArmCord ' + app.getVersion()) tray.setToolTip("ArmCord " + app.getVersion());
tray.setContextMenu(contextMenu) tray.setContextMenu(contextMenu);
}) });

View File

@ -1,86 +1,70 @@
declare module "glasstron" { declare module "glasstron" {
export class BrowserWindow extends Electron.BrowserWindow { export class BrowserWindow extends Electron.BrowserWindow {
getBlur(): Promise<boolean>; getBlur(): Promise<boolean>;
setBlur(value: boolean): 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; blurType: WindowsBlurType;
}; setVibrancy(vibrancy: MacOSVibrancy): void;
macos?: {
vibrancy: MacOSVibrancy;
};
linux?: {
requestBlur: boolean;
};
} }
): void; /**
export class Hacks { * @deprecated
static injectOnElectron(): void; */
static delayReadyEvent(): void; export function init(): void;
} /**
export type WindowsBlurType = * @deprecated
| "acrylic" */
| "blurbehind" export function update(
| "transparent" window: Electron.BrowserWindow,
| "none"; values: {
export type MacOSVibrancy = windows?: {
| ( blurType: WindowsBlurType;
| "appearance-based" };
| "light" macos?: {
| "dark" vibrancy: MacOSVibrancy;
| "titlebar" };
| "selection" linux?: {
| "menu" requestBlur: boolean;
| "popover" };
| "sidebar" }
| "medium-light" ): void;
| "ultra-dark" export class Hacks {
| "header" static injectOnElectron(): void;
| "sheet" static delayReadyEvent(): void;
| "window" }
| "hud" export type WindowsBlurType = "acrylic" | "blurbehind" | "transparent" | "none";
| "fullscreen-ui" export type MacOSVibrancy =
| "tooltip" | (
| "content" | "appearance-based"
| "under-window" | "light"
| "under-page" | "dark"
) | "titlebar"
| null; | "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" { declare module "glasstron/src/utils" {
class Utils { class Utils {
static getSavePath(): string; static getSavePath(): string;
static copyToPath( static copyToPath(innerFile: string, outerFilename?: string, flags?: number): void;
innerFile: string, static removeFromPath(filename: string): void;
outerFilename?: string, static isInPath(filename: string): boolean;
flags?: number static getPlatform(): any;
): void; static parseKeyValString(string: string, keyvalSeparator?: string, pairSeparator?: string): any;
static removeFromPath(filename: string): void; static makeKeyValString(object: any, keyvalSeparator?: string, pairSeparator?: string): string;
static isInPath(filename: string): boolean; }
static getPlatform(): any; export = Utils;
static parseKeyValString(
string: string,
keyvalSeparator?: string,
pairSeparator?: string
): any;
static makeKeyValString(
object: any,
keyvalSeparator?: string,
pairSeparator?: string
): string;
}
export = Utils;
} }

View File

@ -1,103 +1,101 @@
import * as storage from "electron-json-storage"; import * as storage from "electron-json-storage";
import * as fs from "fs"; import * as fs from "fs";
import { app } from "electron"; import {app} from "electron";
import path from "path"; import path from "path";
export var firstRun: boolean; export var firstRun: boolean;
//utillity functions that are used all over the codebase or just too obscure to be put in the file used in //utillity 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) {
const style = document.createElement("style"); const style = document.createElement("style");
style.textContent = styleString; style.textContent = styleString;
document.head.append(style); document.head.append(style);
} }
export function addScript(scriptString: string) { export function addScript(scriptString: string) {
var script = document.createElement("script"); var script = document.createElement("script");
script.textContent = scriptString; script.textContent = scriptString;
document.body.append(script); document.body.append(script);
} }
export async function sleep(ms: number) { export async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
export async function checkIfConfigIsNew() { export async function checkIfConfigIsNew() {
if (await getConfigUnsafe("automaticPatches") == undefined) { if ((await getConfigUnsafe("automaticPatches")) == undefined) {
firstRun = true; firstRun = true;
} }
} }
export interface Settings { export interface Settings {
windowStyle: string, windowStyle: string;
channel: string, channel: string;
armcordCSP: boolean, armcordCSP: boolean;
minimizeToTray: boolean, minimizeToTray: boolean;
automaticPatches: boolean, automaticPatches: boolean;
mods: string, mods: string;
blurType: string blurType: string;
} }
export function setup() { export function setup() {
console.log("Setting up temporary ArmCord settings."); console.log("Setting up temporary ArmCord settings.");
const defaults: Settings = { const defaults: Settings = {
windowStyle: "default", windowStyle: "default",
channel: "stable", channel: "stable",
armcordCSP: true, armcordCSP: true,
minimizeToTray: true, minimizeToTray: true,
automaticPatches: false, automaticPatches: false,
mods: "cumcord", mods: "cumcord",
blurType: "acrylic", blurType: "acrylic"
} };
storage.set( storage.set(
"settings", "settings",
{ {
...defaults, ...defaults,
doneSetup: true, doneSetup: true
}, },
function (error) { function (error) {
if (error) throw error; if (error) throw error;
} }
); );
} }
export function saveSettings( export function saveSettings(settings: Settings) {
settings: Settings console.log("Setting up ArmCord settings.");
) { storage.set(
console.log("Setting up ArmCord settings."); "settings",
storage.set( {
"settings", ...settings,
{ doneSetup: true
...settings, },
doneSetup: true function (error) {
}, if (error) throw error;
function (error) { }
if (error) throw error; );
}
);
} }
export async function getConfigUnsafe(object: string) { export async function getConfigUnsafe(object: string) {
try { try {
const userDataPath = app.getPath("userData"); const userDataPath = app.getPath("userData");
const storagePath = path.join(userDataPath, "/storage/"); const storagePath = path.join(userDataPath, "/storage/");
let rawdata = fs.readFileSync(storagePath + "settings.json", "utf-8"); let rawdata = fs.readFileSync(storagePath + "settings.json", "utf-8");
let returndata = JSON.parse(rawdata); let returndata = JSON.parse(rawdata);
console.log(returndata[object]); console.log(returndata[object]);
return returndata[object]; return returndata[object];
} catch (e) { } catch (e) {
console.log("Config probably doesn't exist yet. Returning setup value."); console.log("Config probably doesn't exist yet. Returning setup value.");
firstRun = true; firstRun = true;
return "setup"; return "setup";
} }
} }
export function getVersion() { export function getVersion() {
//to-do better way of doing this //to-do better way of doing this
return "3.1.0"; return "3.1.0";
} }
export async function injectJS(inject: string) { export async function injectJS(inject: string) {
const js = await (await fetch(`${inject}`)).text(); const js = await (await fetch(`${inject}`)).text();
const el = document.createElement("script"); const el = document.createElement("script");
el.appendChild(document.createTextNode(js)); el.appendChild(document.createTextNode(js));
document.body.appendChild(el); document.body.appendChild(el);
} }

View File

@ -2,193 +2,185 @@
// I had to add most of the window creation code here to split both into seperete functions // 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 // 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. // I'm sorry for this mess but I'm not sure how to fix it.
import { BrowserWindow, shell, app, ipcMain } from "electron"; import {BrowserWindow, shell, app, ipcMain} from "electron";
import path from "path"; import path from "path";
import { contentPath } from "./main"; import {contentPath} from "./main";
import { checkIfConfigIsNew, firstRun, getConfigUnsafe } from "./utils"; import {checkIfConfigIsNew, firstRun, getConfigUnsafe} from "./utils";
import { registerIpc } from "./ipc"; import {registerIpc} from "./ipc";
import contextMenu from "electron-context-menu"; import contextMenu from "electron-context-menu";
export let mainWindow: BrowserWindow; export let mainWindow: BrowserWindow;
import * as glasstron from "glasstron"; import * as glasstron from "glasstron";
let guestWindows: BrowserWindow [] = []; let guestWindows: BrowserWindow[] = [];
contextMenu({ contextMenu({
showSaveImageAs: true, showSaveImageAs: true,
showCopyImageAddress: true, showCopyImageAddress: true,
showSearchWithGoogle: true, showSearchWithGoogle: true
}); });
function doAfterDefiningTheWindow() { function doAfterDefiningTheWindow() {
checkIfConfigIsNew(); checkIfConfigIsNew();
registerIpc(); registerIpc();
mainWindow.webContents.userAgent = mainWindow.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 "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 }) => { mainWindow.webContents.setWindowOpenHandler(({url}) => {
shell.openExternal(url); shell.openExternal(url);
return { action: "deny" }; return {action: "deny"};
}); });
mainWindow.webContents.session.webRequest.onBeforeRequest( mainWindow.webContents.session.webRequest.onBeforeRequest((details, callback) => {
(details, callback) => { if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true});
if (/api\/v\d\/science$/g.test(details.url)) return callback({});
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);
} catch (e) {
console.log(
"Major error detected while starting up. User is most likely on Windows platform. Fallback to alternative startup."
);
console.log(process.platform);
if (process.platform === "win32") {
if (firstRun) {
mainWindow.loadURL(`file://${__dirname}/content/setup.html`);
} else {
mainWindow.loadURL(`file://${__dirname}/content/splash.html`);
}
} else {
if (firstRun) {
mainWindow.loadURL(`file://${__dirname}/ts-out/content/setup.html`);
} else {
mainWindow.loadURL(`file://${__dirname}/ts-out/content/splash.html`);
}
}
} }
);
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);
} catch (e) {
console.log(
"Major error detected while starting up. User is most likely on Windows platform. Fallback to alternative startup."
);
console.log(process.platform);
if (process.platform === "win32") {
if (firstRun) {
mainWindow.loadURL(`file://${__dirname}/content/setup.html`);
} else {
mainWindow.loadURL(`file://${__dirname}/content/splash.html`);
}
} else {
if (firstRun) {
mainWindow.loadURL(`file://${__dirname}/ts-out/content/setup.html`);
} else {
mainWindow.loadURL(`file://${__dirname}/ts-out/content/splash.html`);
}
}
}
} }
export function createCustomWindow() { export function createCustomWindow() {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 300, width: 300,
height: 350, height: 350,
title: "ArmCord", title: "ArmCord",
darkTheme: true, darkTheme: true,
icon: path.join(__dirname, "/assets/icon_transparent.png"), icon: path.join(__dirname, "/assets/icon_transparent.png"),
frame: false, frame: false,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "preload/preload.js"), preload: path.join(__dirname, "preload/preload.js"),
spellcheck: true, spellcheck: true
}, }
}); });
doAfterDefiningTheWindow(); doAfterDefiningTheWindow();
} }
export function createNativeWindow() { export function createNativeWindow() {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 300, width: 300,
height: 350, height: 350,
title: "ArmCord", title: "ArmCord",
darkTheme: true, darkTheme: true,
icon: path.join(__dirname, "/assets/icon_transparent.png"), icon: path.join(__dirname, "/assets/icon_transparent.png"),
frame: true, frame: true,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "preload/preload.js"), preload: path.join(__dirname, "preload/preload.js"),
spellcheck: true, spellcheck: true
}, }
}); });
doAfterDefiningTheWindow(); doAfterDefiningTheWindow();
} }
export function createGlasstronWindow() { export function createGlasstronWindow() {
mainWindow = new glasstron.BrowserWindow({ mainWindow = new glasstron.BrowserWindow({
width: 300, width: 300,
height: 350, height: 350,
title: "ArmCord", title: "ArmCord",
darkTheme: true, darkTheme: true,
icon: path.join(__dirname, "/assets/icon_transparent.png"), icon: path.join(__dirname, "/assets/icon_transparent.png"),
frame: true, frame: true,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "preload/preload.js"), preload: path.join(__dirname, "preload/preload.js"),
spellcheck: true, spellcheck: true
}, }
}); });
//@ts-expect-error //@ts-expect-error
mainWindow.blurType = getConfigUnsafe("blurType"); mainWindow.blurType = getConfigUnsafe("blurType");
//@ts-expect-error //@ts-expect-error
mainWindow.setBlur(true); mainWindow.setBlur(true);
doAfterDefiningTheWindow(); doAfterDefiningTheWindow();
} }
export function createTabsHost() { export function createTabsHost() {
guestWindows[1] = mainWindow; guestWindows[1] = mainWindow;
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 300, width: 300,
height: 350, height: 350,
title: "ArmCord", title: "ArmCord",
darkTheme: true, darkTheme: true,
icon: path.join(__dirname, "/assets/icon_transparent.png"), icon: path.join(__dirname, "/assets/icon_transparent.png"),
frame: true, frame: true,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "preload/preload.js"), preload: path.join(__dirname, "preload/preload.js")
}, }
}); });
doAfterDefiningTheWindow(); doAfterDefiningTheWindow();
} }
export function createTabsGuest(number: number) { export function createTabsGuest(number: number) {
console.log(guestWindows) console.log(guestWindows);
if (guestWindows[number] !== undefined || null) { if (guestWindows[number] !== undefined || null) {
try { try {
console.log("Showing Guest Window " + number); console.log("Showing Guest Window " + number);
mainWindow.hide() mainWindow.hide();
guestWindows[number].show(); guestWindows[number].show();
mainWindow = guestWindows[number]; mainWindow = guestWindows[number];
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
} else { } else {
console.log("Creating Guest Window " + number); console.log("Creating Guest Window " + number);
mainWindow.hide(); mainWindow.hide();
guestWindows[number] = new BrowserWindow({ guestWindows[number] = new BrowserWindow({
width: 800, width: 800,
height: 600, height: 600,
title: "ArmCord Guest Window " + number, title: "ArmCord Guest Window " + number,
darkTheme: true, darkTheme: true,
icon: path.join(__dirname, "/assets/icon_transparent.png"), icon: path.join(__dirname, "/assets/icon_transparent.png"),
frame: true, frame: true,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "preload/preload.js"), preload: path.join(__dirname, "preload/preload.js")
}, }
}); });
mainWindow = guestWindows[number]; mainWindow = guestWindows[number];
ipcMain.on("tab" + number, (event) => { ipcMain.on("tab" + number, (event) => {
event.returnValue = true; //return true so we know the tab exists event.returnValue = true; //return true so we know the tab exists
}); });
guestWindows[number].webContents.userAgent = 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 "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 }) => { guestWindows[number].webContents.setWindowOpenHandler(({url}) => {
shell.openExternal(url); shell.openExternal(url);
return { action: "deny" }; return {action: "deny"};
}); });
guestWindows[number].webContents.session.webRequest.onBeforeRequest( guestWindows[number].webContents.session.webRequest.onBeforeRequest(
( (details: {url: string}, callback: (arg0: {cancel?: boolean}) => any) => {
details: { url: string }, if (/api\/v\d\/science$/g.test(details.url)) return callback({cancel: true});
callback: (arg0: { cancel?: boolean }) => any return callback({});
) => { }
if (/api\/v\d\/science$/g.test(details.url)) );
return callback({ cancel: true });
return callback({}); guestWindows[number].loadURL("https://discord.com/app");
} }
); }
guestWindows[number].loadURL("https://discord.com/app");
}
}