Compare commits

...

18 commits

Author SHA1 Message Date
smartfridge
e6df2b0ecf Make invite socket use arrpc 2022-11-22 15:34:24 +01:00
smartfridge
d7a318d5c3 Update arrpc to 2.2.0 2022-11-22 15:03:54 +01:00
smartfridge
afa83c782d Add mod bundle update skip 2022-11-21 16:25:11 +01:00
Ven
a4968e7529
Make clicking notifications focus ArmCord (#262) 2022-11-21 06:50:45 +01:00
Ven
ed775cbf31
Fix npm format script (#261) 2022-11-21 06:50:21 +01:00
Ven
c5ce910940
Fix csp (Vencord QuickCss & dynamic imports) (#260) 2022-11-21 06:50:09 +01:00
Ven
bea251634c
yeet husky (#259) 2022-11-20 21:05:40 +01:00
Ven
fbeffdb166
Add missing BrowserWindow import; bump deps (#258) 2022-11-20 20:46:37 +01:00
smartfridge
17c05fedd3
Fix dev tools 2022-11-20 19:25:34 +01:00
smartfridge
ddac01ee8f Update arRPC 2022-11-20 13:48:07 +01:00
smartfridge
beaa993e39
Create .npmrc 2022-11-20 00:42:07 +01:00
smartfridge
598ac2eb2f
Delete .npmrc 2022-11-20 00:41:44 +01:00
CanadaHonk
235015bd24
Rename Invite Websocket setting to Rich Presence (#257) 2022-11-19 23:53:11 +01:00
smartfridge
35b86b92e3 Update pnpm lock 2022-11-19 23:30:51 +01:00
smartfridge
ac806fffb7 Dependencies fix 2022-11-19 23:29:12 +01:00
smartfridge
3b571f2322 [skip ci] Remove log.txt 2022-11-19 23:16:47 +01:00
smartfridge
a0e0f6a516 Add experimental arrpc 2022-11-19 23:15:05 +01:00
smartfridge
0bd294480d Add Windows ARM64 dev build 2022-11-19 20:26:13 +01:00
36 changed files with 1809 additions and 527 deletions

View file

@ -113,11 +113,44 @@ jobs:
with:
name: ArmCordWindows.zip
path: dist/ArmCord-3.1.0-win.zip
build-windowsOnARM:
runs-on: windows-latest
steps:
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Checkout code
uses: actions/checkout@v2
- name: Set architecture
run: set npm_config_arch=arm64
- uses: pnpm/action-setup@v2 # Install pnpm using packageManager key in package.json
- name: Install Node dependencies
run: pnpm install -g cargo-cp-artifact && pnpm install
- name: Install Electron-Builder
run: pnpm install -g electron-builder
- name: Replace the version number
run: (Get-Content src/utils.ts) -replace "\d\.\d\.\d", "DEV" | Out-File src/utils.ts
- name: Build
run: npm run build && electron-builder --windows zip --arm64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: ArmCordWindowsArm64.zip
path: dist\ArmCord-3.1.0-arm64-win.zip
release:
runs-on: ubuntu-latest
needs: [build-linux, build-mac, build-windows]
needs: [build-linux, build-mac, build-windows, build-windowsOnARM]
steps:
- name: Checkout code
@ -142,6 +175,10 @@ jobs:
with:
name: ArmCordLinuxArm64.zip
path: linux
- uses: actions/download-artifact@v2
with:
name: ArmCordWindowsArm64.zip
path: windows
- name: Get some values needed for the release
id: vars
@ -171,3 +208,4 @@ jobs:
linux/ArmCord-3.1.0-arm64.zip
macos/ArmCord-3.1.0-mac.zip
windows/ArmCord-3.1.0-win.zip
windows/ArmCord-3.1.0-arm64-win.zip

View file

@ -1,38 +0,0 @@
name: Windows on ARM
on:
push:
branches:
- dev
jobs:
build-windowsOnARM:
runs-on: windows-latest
steps:
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Checkout code
uses: actions/checkout@v2
- name: Install pnpm
run: npm i -g pnpm && pnpm setup
- name: Set architecture
run: set npm_config_arch=arm64
- name: Install Node dependencies
run: pnpm install -g cargo-cp-artifact && pnpm install
- name: Install Electron-Builder
run: pnpm install -g electron-builder
- name: Build
run: npm run build && electron-builder --windows --arm64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Delete unpacked builds
run: Remove-Item -LiteralPath ".\dist\win-unpacked" -Force -Recurse
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: ArmCordWindows
path: dist/

View file

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

1
.husky/.gitignore vendored
View file

@ -1 +0,0 @@
_

View file

@ -1,3 +1,3 @@
node-linker=hoisted
public-hoist-pattern=*
shamefully-hoist=true
shamefully-hoist=true

13
.vscode/launch.json vendored
View file

@ -9,14 +9,9 @@
"request": "launch",
"name": "Debug ArmCord via NPM",
"runtimeExecutable": "npm",
"runtimeArgs": [
"start",
"debug",
],
"runtimeArgs": ["start", "debug"],
"port": 9229,
"skipFiles": [
"<node_internals>/**"
]
},
"skipFiles": ["<node_internals>/**"]
}
]
}
}

View file

@ -13,7 +13,7 @@
- **Various mods built in**
Enjoy Cumcord, GooseMod, Flicker, and their many features, or have a more vanilla experience, it's your choice!
Enjoy Vencord, Shelter and their many features, or have a more vanilla experience, it's your choice!
- **Made for Privacy™**

View file

@ -32,8 +32,8 @@
"settings-channel-desc3": "this is alpha test release of Discord. By using it you gain access to the newest\n features and fixes.",
"settings-channel-desc4": "public test build. Receives features earlier than stable but is a bit older than Canary.",
"settings-channel-desc5": "unofficial instance of Discord that takes you back to 2016! Only client mod\n available to run alongside with it is Cordwood. It's run by community, so you take all the risk by\n using it.",
"settings-invitewebsocket": "Invite Websocket",
"settings-invitewebsocket-desc": "When enabled ArmCord will support Discord.gg links which means that if you open an invite link in your\n browser, ArmCord will automatically accept the invite. Can be unresponsive at times.",
"settings-invitewebsocket": "Rich Presence (Experimental)",
"settings-invitewebsocket-desc": "Uses <a target=\"_blank\" href=\"https://github.com/OpenAsar/arrpc\">arRPC</a> to support Discord RPC (Rich Presence) with local programs on your machine. Work in progress.",
"settings-altPaste": "Alternative Paste",
"settings-altPaste-desc": "If you're on Gnome on Linux or just simply can't paste images copied from other messages, then this is\n for you. This enables alternative module for pasting images. Only enable this when you're experiencing\n issues.",
"settings-mod": "Client mod",

572
log.txt Normal file
View file

@ -0,0 +1,572 @@
> ArmCord@3.1.0 start
> npm run build && electron ./ts-out/main.js
> ArmCord@3.1.0 build
> tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css src/**/**/*.js ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/**/** ts-out/
[Config manager] doneSetup: undefined
[Config manager] performanceMode: none
ArmCord has been run before. Skipping setup.
No performance modes set
[Config manager] windowStyle: default
[Config manager] armcordCSP: true
[Config manager] doneSetup: undefined
[Config manager] customIcon: undefined
Setting up CSP unstricter...
[Config manager] mods: vencord
[Config manager] trayIcon: default
[Config manager] windowStyle: default
[Config manager] windowStyle: default
[Config manager] ignoreProtocolWarning: undefined
[Config manager] clientName: undefined
[Config manager] 0: undefined
[Config manager] mods: vencord
[Config manager] noBundleUpdates: undefined
[Config manager] mobileMode: false
Downloading mod bundle
[Config manager] mods: vencord
[Config manager] trayIcon: default
[Mod loader] Loaded ArmCord Mod Loader made by Vendicated
[Config manager] alternativePaste: false
undefined
[Config manager] inviteWebsocket: true
[Config manager] skipSplash: undefined
[arRPC] arRPC v1.1.0-beta ArmCord
[arRPC > ipc] checking /run/user/1000/discord-ipc-0
[arRPC > bridge] listening on 1337
[arRPC > ipc] checked if socket is available: true
[arRPC > ipc] listening at /run/user/1000/discord-ipc-0
[arRPC > websocket] trying port 6463
[arRPC > websocket] listening on 6463
[Config manager] channel: stable
[Config manager] mods: vencord
[Config manager] automaticPatches: false
[Config manager] channel: stable
[Window state manager] width: 1920
[Window state manager] height: 1048
[Window state manager] isMaximized: true
[Config manager] channel: stable
[Config manager] mods: vencord
[Config manager] automaticPatches: false
[Config manager] channel: stable
[Config manager] mobileMode: false
[arRPC > ipc] new connection!
[arRPC > ipc] handshake: { v: 1, client_id: '383226320970055681' }
[arRPC > ipc] sending { cmd: 'DISPATCH', evt: 'READY', data: { v: 1 } }
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '4d2717f7-8fae-4339-222a-800a0e43f023'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'ed60da61-58bc-4e12-0fc3-c628a710cf7d'
}
[arRPC > bridge] fetched app info for 383226320970055681 {
id: '383226320970055681',
name: 'Visual Studio Code',
icon: 'bc45e1c85351ce0bafcb9245b3762e75',
description: '',
summary: '',
type: null,
cover_image: 'f1794a9f863d86c4a80aa51c3738fe58',
hook: true,
verify_key: 'd9fda69a8c8a9168d7fc41738822738eb31a4975a261d3172835df3595203f99',
flags: 0,
assets: [
{ id: '565944082250334228', type: 1, name: 'applescript' },
{ id: '565944082258722817', type: 1, name: 'arduino' },
{ id: '565944082266849297', type: 1, name: 'cshtml' },
{ id: '565944082271305778', type: 1, name: 'ahk' },
{ id: '565944082317312000', type: 1, name: 'assembly' },
{ id: '565944082321637386', type: 1, name: 'android' },
{ id: '565944082329763843', type: 1, name: 'csharp' },
{ id: '565944082384551955', type: 1, name: 'cmake' },
{ id: '565944082392940584', type: 1, name: 'autoit' },
{ id: '565944082401198090', type: 1, name: 'c' },
{ id: '565944082409455626', type: 1, name: 'angular' },
{ id: '565944082417975296', type: 1, name: 'asp' },
{ id: '565944082501861376', type: 1, name: 'appveyor' },
{ id: '565944082506055681', type: 1, name: 'crystal' },
{ id: '565944082510249984', type: 1, name: 'cpp' },
{ id: '565944082522963968', type: 1, name: 'cargo' },
{ id: '565944082573295616', type: 1, name: 'cssmap' },
{ id: '565944082585878538', type: 1, name: 'css' },
{ id: '565944082816565284', type: 1, name: 'bower' },
{ id: '565944082833342465', type: 1, name: 'clojure' },
{ id: '565944082858377220', type: 1, name: 'circleci' },
{ id: '565944082992726027', type: 1, name: 'as' },
{ id: '565944083021955093', type: 1, name: 'coffee' },
{ id: '565944083088932884', type: 1, name: 'bat' },
{ id: '565944083441516564', type: 1, name: 'brainfuck' },
{ id: '565944476732882948', type: 1, name: 'dart' },
{ id: '565944476829351967', type: 1, name: 'elixir' },
{ id: '565944476879683585', type: 1, name: 'eslint' },
{ id: '565944477068296243', type: 1, name: 'haskell' },
{ id: '565944477076684801', type: 1, name: 'go' },
{ id: '565944477085073418', type: 1, name: 'dm' },
{ id: '565944477122822179', type: 1, name: 'flowconfig' },
{ id: '565944477152444416', type: 1, name: 'fsharp' },
{ id: '565944477202645033', type: 1, name: 'erlang' },
{ id: '565944477215358986', type: 1, name: 'gemfile' },
{ id: '565944477232136192', type: 1, name: 'd' },
{ id: '565944477232136202', type: 1, name: 'git' },
{ id: '565944477278142465', type: 1, name: 'haxe' },
{ id: '565944477286531072', type: 1, name: 'graphql' },
{ id: '565944477328343040', type: 1, name: 'docker' },
{ id: '565944477336993822', type: 1, name: 'firebase' },
{ id: '565944477340926001', type: 1, name: 'editorconfig' },
{ id: '565944477647241228', type: 1, name: 'delphi' },
{ id: '565944477684989977', type: 1, name: 'handlebars' },
{ id: '565944477752098836', type: 1, name: 'gulp' },
{ id: '565944477961814016', type: 1, name: 'cuda' },
{ id: '565944478142169089', type: 1, name: 'gatsbyjs' },
{ id: '565944478418993152', type: 1, name: 'gradle' },
{ id: '565944478549016577', type: 1, name: 'env' },
{ id: '565944478557274142', type: 1, name: 'ejs' },
{ id: '565944478792155136', type: 1, name: 'elm' },
{ id: '565944479194808320', type: 1, name: 'gruntfile' },
{ id: '565944799245369386', type: 1, name: 'makefile' },
{ id: '565944799312740364', type: 1, name: 'less' },
{ id: '565944799446827009', type: 1, name: 'julia' },
{ id: '565944799450890240', type: 1, name: 'jar' },
{ id: '565944799455346703', type: 1, name: 'html' },
{ id: '565944799459278879', type: 1, name: 'jsmap' },
{ id: '565944799492964353', type: 1, name: 'kotlin' },
{ id: '565944799538970634', type: 1, name: 'heroku' },
{ id: '565944799576719366', type: 1, name: 'js' },
{ id: '565944799618662400', type: 1, name: 'livescript' },
{ id: '565944799707004929', type: 1, name: 'log' },
{ id: '565944799761268737', type: 1, name: 'json' },
{ id: '565944799761268766', type: 1, name: 'jest' },
{ id: '565944799996411914', type: 1, name: 'http' },
{ id: '565944800021446707', type: 1, name: 'java' },
{ id: '565944800021577729', type: 1, name: 'lisp' },
{ id: '565944800105332777', type: 1, name: 'lua' },
{ id: '565944802462531603', type: 1, name: 'jsx' },
{ id: '565945077252489228', type: 1, name: 'nim' },
{ id: '565945077260746763', type: 1, name: 'pascal' },
{ id: '565945077277655043', type: 1, name: 'perl' },
{ id: '565945077323792386', type: 1, name: 'postcss' },
{ id: '565945077348958236', type: 1, name: 'marko' },
{ id: '565945077411741717', type: 1, name: 'prisma' },
{ id: '565945077487108099', type: 1, name: 'nodemon' },
{ id: '565945077491433494', type: 1, name: 'markdown' },
{ id: '565945077524987927', type: 1, name: 'markdownx' },
{ id: '565945077554479114', type: 1, name: 'manifest' },
{ id: '565945077575319552', type: 1, name: 'pawn' },
{ id: '565945077583839243', type: 1, name: 'npm' },
{ id: '565945077625651200', type: 1, name: 'pug' },
{ id: '565945077642559498', type: 1, name: 'ocaml' },
{ id: '565945077709406209', type: 1, name: 'prettier' },
{ id: '565945078166716458', type: 1, name: 'powershell' },
{ id: '565945078359785494', type: 1, name: 'objc' },
{ id: '565945078833741834', type: 1, name: 'php' },
{ id: '565945350532104193', type: 1, name: 'tex' },
{ id: '565945350641418270', type: 1, name: 'reasonml' },
{ id: '565945350645481492', type: 1, name: 'python' },
{ id: '565945350670647298', type: 1, name: 'swift' },
{ id: '565945350695813133', type: 1, name: 'scala' },
{ id: '565945350766985216', type: 1, name: 'svg' },
{ id: '565945350771441676', type: 1, name: 'rust' },
{ id: '565945350792151064', type: 1, name: 'toml' },
{ id: '565945350838419490', type: 1, name: 'sql' },
{ id: '565945350846939145', type: 1, name: 'text' },
{ id: '565945350851002389', type: 1, name: 'shell' },
{ id: '565945350897008640', type: 1, name: 'scss' },
... 50 more items
]
}
[arRPC > bridge] fetched app info for 383226320970055681 {
id: '383226320970055681',
name: 'Visual Studio Code',
icon: 'bc45e1c85351ce0bafcb9245b3762e75',
description: '',
summary: '',
type: null,
cover_image: 'f1794a9f863d86c4a80aa51c3738fe58',
hook: true,
verify_key: 'd9fda69a8c8a9168d7fc41738822738eb31a4975a261d3172835df3595203f99',
flags: 0,
assets: [
{ id: '565944082250334228', type: 1, name: 'applescript' },
{ id: '565944082258722817', type: 1, name: 'arduino' },
{ id: '565944082266849297', type: 1, name: 'cshtml' },
{ id: '565944082271305778', type: 1, name: 'ahk' },
{ id: '565944082317312000', type: 1, name: 'assembly' },
{ id: '565944082321637386', type: 1, name: 'android' },
{ id: '565944082329763843', type: 1, name: 'csharp' },
{ id: '565944082384551955', type: 1, name: 'cmake' },
{ id: '565944082392940584', type: 1, name: 'autoit' },
{ id: '565944082401198090', type: 1, name: 'c' },
{ id: '565944082409455626', type: 1, name: 'angular' },
{ id: '565944082417975296', type: 1, name: 'asp' },
{ id: '565944082501861376', type: 1, name: 'appveyor' },
{ id: '565944082506055681', type: 1, name: 'crystal' },
{ id: '565944082510249984', type: 1, name: 'cpp' },
{ id: '565944082522963968', type: 1, name: 'cargo' },
{ id: '565944082573295616', type: 1, name: 'cssmap' },
{ id: '565944082585878538', type: 1, name: 'css' },
{ id: '565944082816565284', type: 1, name: 'bower' },
{ id: '565944082833342465', type: 1, name: 'clojure' },
{ id: '565944082858377220', type: 1, name: 'circleci' },
{ id: '565944082992726027', type: 1, name: 'as' },
{ id: '565944083021955093', type: 1, name: 'coffee' },
{ id: '565944083088932884', type: 1, name: 'bat' },
{ id: '565944083441516564', type: 1, name: 'brainfuck' },
{ id: '565944476732882948', type: 1, name: 'dart' },
{ id: '565944476829351967', type: 1, name: 'elixir' },
{ id: '565944476879683585', type: 1, name: 'eslint' },
{ id: '565944477068296243', type: 1, name: 'haskell' },
{ id: '565944477076684801', type: 1, name: 'go' },
{ id: '565944477085073418', type: 1, name: 'dm' },
{ id: '565944477122822179', type: 1, name: 'flowconfig' },
{ id: '565944477152444416', type: 1, name: 'fsharp' },
{ id: '565944477202645033', type: 1, name: 'erlang' },
{ id: '565944477215358986', type: 1, name: 'gemfile' },
{ id: '565944477232136192', type: 1, name: 'd' },
{ id: '565944477232136202', type: 1, name: 'git' },
{ id: '565944477278142465', type: 1, name: 'haxe' },
{ id: '565944477286531072', type: 1, name: 'graphql' },
{ id: '565944477328343040', type: 1, name: 'docker' },
{ id: '565944477336993822', type: 1, name: 'firebase' },
{ id: '565944477340926001', type: 1, name: 'editorconfig' },
{ id: '565944477647241228', type: 1, name: 'delphi' },
{ id: '565944477684989977', type: 1, name: 'handlebars' },
{ id: '565944477752098836', type: 1, name: 'gulp' },
{ id: '565944477961814016', type: 1, name: 'cuda' },
{ id: '565944478142169089', type: 1, name: 'gatsbyjs' },
{ id: '565944478418993152', type: 1, name: 'gradle' },
{ id: '565944478549016577', type: 1, name: 'env' },
{ id: '565944478557274142', type: 1, name: 'ejs' },
{ id: '565944478792155136', type: 1, name: 'elm' },
{ id: '565944479194808320', type: 1, name: 'gruntfile' },
{ id: '565944799245369386', type: 1, name: 'makefile' },
{ id: '565944799312740364', type: 1, name: 'less' },
{ id: '565944799446827009', type: 1, name: 'julia' },
{ id: '565944799450890240', type: 1, name: 'jar' },
{ id: '565944799455346703', type: 1, name: 'html' },
{ id: '565944799459278879', type: 1, name: 'jsmap' },
{ id: '565944799492964353', type: 1, name: 'kotlin' },
{ id: '565944799538970634', type: 1, name: 'heroku' },
{ id: '565944799576719366', type: 1, name: 'js' },
{ id: '565944799618662400', type: 1, name: 'livescript' },
{ id: '565944799707004929', type: 1, name: 'log' },
{ id: '565944799761268737', type: 1, name: 'json' },
{ id: '565944799761268766', type: 1, name: 'jest' },
{ id: '565944799996411914', type: 1, name: 'http' },
{ id: '565944800021446707', type: 1, name: 'java' },
{ id: '565944800021577729', type: 1, name: 'lisp' },
{ id: '565944800105332777', type: 1, name: 'lua' },
{ id: '565944802462531603', type: 1, name: 'jsx' },
{ id: '565945077252489228', type: 1, name: 'nim' },
{ id: '565945077260746763', type: 1, name: 'pascal' },
{ id: '565945077277655043', type: 1, name: 'perl' },
{ id: '565945077323792386', type: 1, name: 'postcss' },
{ id: '565945077348958236', type: 1, name: 'marko' },
{ id: '565945077411741717', type: 1, name: 'prisma' },
{ id: '565945077487108099', type: 1, name: 'nodemon' },
{ id: '565945077491433494', type: 1, name: 'markdown' },
{ id: '565945077524987927', type: 1, name: 'markdownx' },
{ id: '565945077554479114', type: 1, name: 'manifest' },
{ id: '565945077575319552', type: 1, name: 'pawn' },
{ id: '565945077583839243', type: 1, name: 'npm' },
{ id: '565945077625651200', type: 1, name: 'pug' },
{ id: '565945077642559498', type: 1, name: 'ocaml' },
{ id: '565945077709406209', type: 1, name: 'prettier' },
{ id: '565945078166716458', type: 1, name: 'powershell' },
{ id: '565945078359785494', type: 1, name: 'objc' },
{ id: '565945078833741834', type: 1, name: 'php' },
{ id: '565945350532104193', type: 1, name: 'tex' },
{ id: '565945350641418270', type: 1, name: 'reasonml' },
{ id: '565945350645481492', type: 1, name: 'python' },
{ id: '565945350670647298', type: 1, name: 'swift' },
{ id: '565945350695813133', type: 1, name: 'scala' },
{ id: '565945350766985216', type: 1, name: 'svg' },
{ id: '565945350771441676', type: 1, name: 'rust' },
{ id: '565945350792151064', type: 1, name: 'toml' },
{ id: '565945350838419490', type: 1, name: 'sql' },
{ id: '565945350846939145', type: 1, name: 'text' },
{ id: '565945350851002389', type: 1, name: 'shell' },
{ id: '565945350897008640', type: 1, name: 'scss' },
... 50 more items
]
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'b3d5dd03-d425-40ae-132e-8acf53b18497'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'a81c11d1-60e8-4c23-2af3-6626c0791f1a'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '3230ba41-4874-460a-1689-9b9ff1663a7f'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'f6d973b1-1e75-4dd6-2e93-b65a9ef3be0b'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'b8843cb1-aa6e-437d-3da0-1e08cd44cfb5'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'd6a257e0-fa89-449f-38b1-44fa71811fb7'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'ac9e04a8-52c3-4614-04b2-1779e10e263f'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
details: 'Idling',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'f0e4d6e4-7aa8-4f5b-1264-ac76680cfd24'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing server.js',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '3cc9be1b-338f-4867-1cf0-cba574084c45'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing server.js',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'd4965762-a25b-4b8b-2891-11a1ed78289d'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '92243961-65fb-48a2-26d1-1d8980a376f3'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '4d1001fa-6d04-4b0a-0d0d-4ceefd1c79f0'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '1cb43f39-5cd6-40aa-385b-16fd9fe70d4f'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '1b139214-f410-48bc-24d4-2835d2d49f02'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '442a6b6a-126d-435d-2a85-296ec86c36a8'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: 'a0517d56-4927-4761-2642-699fd091dc0c'
}
[arRPC > ipc] message {
cmd: 'SET_ACTIVITY',
args: {
pid: 5707,
activity: {
state: 'Workspace: ArmCord',
details: 'Editing log.txt',
timestamps: [Object],
assets: [Object],
buttons: [Array],
instance: false
}
},
nonce: '8c63a412-f861-49e9-288e-e31765f7c36b'
}
[Config manager] minimizeToTray: true

View file

@ -1,80 +1,76 @@
{
"name": "ArmCord",
"version": "3.1.0",
"description": "ArmCord is a custom client designed to enhance your Discord experience while keeping everything lightweight.",
"main": "ts-out/main.js",
"scripts": {
"build": "tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/**/** ts-out/",
"watch": "tsc -w",
"start": "npm run build && electron ./ts-out/main.js",
"startNoSandbox": "npm run build && electron ./ts-out/main.js --no-sandbox",
"package": "npm run build && electron-builder",
"packageQuick": "npm run build && electron-builder --dir",
"format": "prettier --write src/**/*",
"CIbuild": "npm run build && electron-builder --linux zip && electron-builder --windows zip && electron-builder --macos zip",
"postinstall": "husky install",
"precommit-fix": "husky uninstall && echo - && echo !Make sure to run 'npm run format' before commiting! | chalk --stdin yellow inverse && echo -",
"precommit-fix:format": "husky uninstall && npm run format"
},
"repository": {
"type": "git",
"url": "git+https://github.com/armcord/armcord.git"
},
"author": "smartfrigde",
"license": "OSL-3.0",
"bugs": {
"url": "https://github.com/armcord/armcord/issues"
},
"homepage": "https://github.com/armcord/armcord#readme",
"devDependencies": {
"@types/node": "^17.0.42",
"@types/node-fetch": "^2.6.2",
"@types/ws": "^8.5.3",
"chalk-cli": "^5.0.0",
"copyfiles": "^2.4.1",
"electron": "^20.1.0",
"electron-builder": "^23.6.0",
"husky": "^8.0.1",
"prettier": "^2.7.0",
"typescript": "^4.7.3"
},
"dependencies": {
"@pyke/vibe": "github:pykeio/vibe#11984868ce9e007859ed91ff159c7f7f0a34e7ae",
"electron-context-menu": "github:ArmCord/electron-context-menu",
"extract-zip": "^2.0.1",
"node-fetch": "v2",
"os-locale": "^6.0.2",
"v8-compile-cache": "^2.3.0",
"ws": "^8.8.0"
},
"build": {
"nsis": {
"include": "build/installer.nsh"
"name": "ArmCord",
"version": "3.1.0",
"description": "ArmCord is a custom client designed to enhance your Discord experience while keeping everything lightweight.",
"main": "ts-out/main.js",
"scripts": {
"build": "tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css src/**/**/*.js ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/**/** ts-out/",
"watch": "tsc -w",
"start": "npm run build && electron ./ts-out/main.js",
"startNoSandbox": "npm run build && electron ./ts-out/main.js --no-sandbox",
"package": "npm run build && electron-builder",
"packageQuick": "npm run build && electron-builder --dir",
"format": "prettier --write src *.json",
"CIbuild": "npm run build && electron-builder --linux zip && electron-builder --windows zip && electron-builder --macos zip",
"prepare": "git config --local core.hooksPath .hooks/"
},
"files": [
"!*",
"assets",
"node_modules",
"ts-out",
"package.json",
"LICENSE"
],
"appId": "com.smartfridge.armcord",
"productName": "ArmCord",
"mac": {
"category": "Network"
"repository": {
"type": "git",
"url": "git+https://github.com/armcord/armcord.git"
},
"linux": {
"icon": "build/icon.icns",
"category": "Network",
"maintainer": "smartfridge@vivaldi.net",
"target": [
"deb",
"tar.gz",
"rpm",
"AppImage"
]
}
},
"packageManager": "pnpm@7.13.4"
"author": "smartfrigde",
"license": "OSL-3.0",
"bugs": {
"url": "https://github.com/armcord/armcord/issues"
},
"homepage": "https://github.com/armcord/armcord#readme",
"devDependencies": {
"@types/node": "^18.11.9",
"@types/ws": "^8.5.3",
"chalk-cli": "^5.0.0",
"copyfiles": "^2.4.1",
"electron": "^21.3.0",
"electron-builder": "^23.6.0",
"prettier": "^2.7.1",
"typescript": "^4.9.3"
},
"dependencies": {
"@pyke/vibe": "github:pykeio/vibe#11984868ce9e007859ed91ff159c7f7f0a34e7ae",
"arrpc": "file:src/arrpc",
"cross-fetch": "^3.1.5",
"electron-context-menu": "github:ArmCord/electron-context-menu",
"extract-zip": "^2.0.1",
"v8-compile-cache": "^2.3.0",
"ws": "^8.11.0"
},
"build": {
"nsis": {
"include": "build/installer.nsh"
},
"files": [
"!*",
"assets",
"node_modules",
"ts-out",
"package.json",
"LICENSE"
],
"appId": "com.smartfridge.armcord",
"productName": "ArmCord",
"mac": {
"category": "Network"
},
"linux": {
"icon": "build/icon.icns",
"category": "Network",
"maintainer": "smartfridge@vivaldi.net",
"target": [
"deb",
"tar.gz",
"rpm",
"AppImage"
]
}
},
"packageManager": "pnpm@7.13.4"
}

View file

@ -2,43 +2,39 @@ lockfileVersion: 5.4
specifiers:
'@pyke/vibe': github:pykeio/vibe#11984868ce9e007859ed91ff159c7f7f0a34e7ae
'@types/node': ^17.0.42
'@types/node-fetch': ^2.6.2
'@types/node': ^18.11.9
'@types/ws': ^8.5.3
arrpc: file:src/arrpc
chalk-cli: ^5.0.0
copyfiles: ^2.4.1
electron: ^20.1.0
cross-fetch: ^3.1.5
electron: ^21.3.0
electron-builder: ^23.6.0
electron-context-menu: github:ArmCord/electron-context-menu
extract-zip: ^2.0.1
husky: ^8.0.1
node-fetch: v2
os-locale: ^6.0.2
prettier: ^2.7.0
typescript: ^4.7.3
prettier: ^2.7.1
typescript: ^4.9.3
v8-compile-cache: ^2.3.0
ws: ^8.8.0
ws: ^8.11.0
dependencies:
'@pyke/vibe': github.com/pykeio/vibe/11984868ce9e007859ed91ff159c7f7f0a34e7ae_electron@20.3.1
'@pyke/vibe': github.com/pykeio/vibe/11984868ce9e007859ed91ff159c7f7f0a34e7ae_electron@21.3.0
arrpc: file:src/arrpc
cross-fetch: 3.1.5
electron-context-menu: github.com/ArmCord/electron-context-menu/280c81398c02a063f46e3285a9708d8db1a7ce32
extract-zip: 2.0.1
node-fetch: 2.6.7
os-locale: 6.0.2
v8-compile-cache: 2.3.0
ws: 8.9.0
ws: 8.11.0
devDependencies:
'@types/node': 17.0.45
'@types/node-fetch': 2.6.2
'@types/node': 18.11.9
'@types/ws': 8.5.3
chalk-cli: 5.0.0
copyfiles: 2.4.1
electron: 20.3.1
electron: 21.3.0
electron-builder: 23.6.0
husky: 8.0.1
prettier: 2.7.1
typescript: 4.8.4
typescript: 4.9.3
packages:
@ -150,7 +146,7 @@ packages:
/@types/fs-extra/9.0.13:
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
dependencies:
'@types/node': 17.0.45
'@types/node': 18.11.9
dev: true
/@types/glob/7.2.0:
@ -158,14 +154,14 @@ packages:
requiresBuild: true
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 17.0.45
'@types/node': 18.11.9
dev: true
optional: true
/@types/keyv/3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
'@types/node': 17.0.45
'@types/node': 18.11.9
/@types/minimatch/5.1.2:
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
@ -180,18 +176,11 @@ packages:
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
dev: true
/@types/node-fetch/2.6.2:
resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==}
dependencies:
'@types/node': 17.0.45
form-data: 3.0.1
dev: true
/@types/node/16.18.3:
resolution: {integrity: sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==}
/@types/node/16.11.64:
resolution: {integrity: sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q==}
/@types/node/17.0.45:
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
/@types/node/18.11.9:
resolution: {integrity: sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==}
/@types/normalize-package-data/2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@ -201,7 +190,7 @@ packages:
resolution: {integrity: sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==}
requiresBuild: true
dependencies:
'@types/node': 17.0.45
'@types/node': 18.11.9
xmlbuilder: 15.1.1
dev: true
optional: true
@ -209,7 +198,7 @@ packages:
/@types/responselike/1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
'@types/node': 17.0.45
'@types/node': 18.11.9
/@types/verror/1.10.6:
resolution: {integrity: sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ==}
@ -220,7 +209,7 @@ packages:
/@types/ws/8.5.3:
resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==}
dependencies:
'@types/node': 17.0.45
'@types/node': 18.11.9
dev: true
/@types/yargs-parser/21.0.0:
@ -237,7 +226,7 @@ packages:
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
requiresBuild: true
dependencies:
'@types/node': 17.0.45
'@types/node': 18.11.9
optional: true
/agent-base/6.0.2:
@ -283,8 +272,8 @@ packages:
dependencies:
color-convert: 2.0.1
/ansi-styles/6.1.1:
resolution: {integrity: sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==}
/ansi-styles/6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
dev: true
@ -320,7 +309,7 @@ packages:
read-config-file: 6.2.0
sanitize-filename: 1.6.3
semver: 7.3.8
tar: 6.1.11
tar: 6.1.12
temp-file: 3.4.0
transitivePeerDependencies:
- supports-color
@ -511,8 +500,8 @@ packages:
engines: {node: '>=10'}
dev: true
/cargo-cp-artifact/0.1.6:
resolution: {integrity: sha512-CQw0doK/aaF7j041666XzuilHxqMxaKkn+I5vmBsd8SAwS0cO5CqVEVp0xJwOKstyqWZ6WK4Ww3O6p26x/Goyg==}
/cargo-cp-artifact/0.1.7:
resolution: {integrity: sha512-pxEV9p1on8vu3BOKstVisF9TwMyGKCBRvzaVpQHuU2sLULCKrn3MJWx/4XlNzmG6xNCTPf78DJ7WCGgr2mOzjg==}
hasBin: true
dev: false
@ -521,7 +510,7 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
hasBin: true
dependencies:
ansi-styles: 6.1.1
ansi-styles: 6.2.1
chalk: 4.1.2
dot-prop: 6.0.1
get-stdin: 9.0.0
@ -554,8 +543,9 @@ packages:
resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==}
dev: true
/ci-info/3.4.0:
resolution: {integrity: sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==}
/ci-info/3.6.1:
resolution: {integrity: sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==}
engines: {node: '>=8'}
dev: true
/cli-truncate/2.1.0:
@ -607,7 +597,7 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
/colors/1.0.3:
resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==}
resolution: {integrity: sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=}
engines: {node: '>=0.1.90'}
dev: true
@ -636,7 +626,7 @@ packages:
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
dev: true
/config-chain/1.1.13:
@ -677,6 +667,14 @@ packages:
dev: true
optional: true
/cross-fetch/3.1.5:
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
dependencies:
node-fetch: 2.6.7
transitivePeerDependencies:
- encoding
dev: false
/cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -708,8 +706,8 @@ packages:
dependencies:
ms: 2.1.2
/decamelize-keys/1.1.0:
resolution: {integrity: sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==}
/decamelize-keys/1.1.1:
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
engines: {node: '>=0.10.0'}
dependencies:
decamelize: 1.2.0
@ -838,13 +836,13 @@ packages:
lazy-val: 1.0.5
read-config-file: 6.2.0
simple-update-notifier: 1.0.7
yargs: 17.6.0
yargs: 17.6.2
transitivePeerDependencies:
- supports-color
dev: true
/electron-dl/3.3.1:
resolution: {integrity: sha512-kmcSYZyHVEHHHFKlZWW58GiCmu2NSu3Rdwnl3+/fr/ftQYHJULVf1QkrCBPFE2bp/Ly113Za7c8wJZs1nBy04A==}
/electron-dl/3.5.0:
resolution: {integrity: sha512-Oj+VSuScVx8hEKM2HEvTQswTX6G3MLh7UoAz/oZuvKyNDfudNi1zY6PK/UnFoK1nCl9DF6k+3PFwElKbtZlDig==}
dependencies:
ext-name: 5.0.0
pupa: 2.1.1
@ -865,7 +863,7 @@ packages:
compare-version: 0.1.2
debug: 2.6.9
isbinaryfile: 3.0.3
minimist: 1.2.6
minimist: 1.2.7
plist: 3.0.6
transitivePeerDependencies:
- supports-color
@ -885,14 +883,14 @@ packages:
- supports-color
dev: true
/electron/20.3.1:
resolution: {integrity: sha512-mgFAa79Zj8oCegsluPAo6O1yXd7mVMZ0JZC2Rak9HQUAQ7x9xuQY7yop/+nMbi+bOMWwe5JrtOcvjotBArxioA==}
/electron/21.3.0:
resolution: {integrity: sha512-MGRpshN8fBcx4IRuBABIsGDv0tB/MclIFsyFHFFXsBCUc+vIXaE/E6vuWaniGIFSz5WyeuapfTH5IeRb+7yIfw==}
engines: {node: '>= 10.17.0'}
hasBin: true
requiresBuild: true
dependencies:
'@electron/get': 1.14.1
'@types/node': 16.11.64
'@types/node': 16.18.3
extract-zip: 2.0.1
transitivePeerDependencies:
- supports-color
@ -1008,15 +1006,6 @@ packages:
path-exists: 4.0.0
dev: true
/form-data/3.0.1:
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: true
/form-data/4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@ -1227,12 +1216,6 @@ packages:
- supports-color
dev: true
/husky/8.0.1:
resolution: {integrity: sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==}
engines: {node: '>=14'}
hasBin: true
dev: true
/iconv-corefoundation/1.1.7:
resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==}
engines: {node: ^8.11.2 || >=10}
@ -1277,11 +1260,6 @@ packages:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
optional: true
/invert-kv/3.0.1:
resolution: {integrity: sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==}
engines: {node: '>=8'}
dev: false
/is-arrayish/0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: true
@ -1290,11 +1268,11 @@ packages:
resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
hasBin: true
dependencies:
ci-info: 3.4.0
ci-info: 3.6.1
dev: true
/is-core-module/2.10.0:
resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
/is-core-module/2.11.0:
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
dependencies:
has: 1.0.3
dev: true
@ -1407,13 +1385,6 @@ packages:
resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==}
dev: true
/lcid/3.1.1:
resolution: {integrity: sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==}
engines: {node: '>=8'}
dependencies:
invert-kv: 3.0.1
dev: false
/lines-and-columns/1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
@ -1466,7 +1437,7 @@ packages:
'@types/minimist': 1.2.2
camelcase-keys: 7.0.2
decamelize: 5.0.1
decamelize-keys: 1.1.0
decamelize-keys: 1.1.1
hard-rejection: 2.1.0
minimist-options: 4.1.0
normalize-package-data: 3.0.3
@ -1531,8 +1502,8 @@ packages:
kind-of: 6.0.3
dev: true
/minimist/1.2.6:
resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
/minimist/1.2.7:
resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
dev: true
/minipass/3.3.4:
@ -1598,7 +1569,7 @@ packages:
engines: {node: '>=10'}
dependencies:
hosted-git-info: 4.1.0
is-core-module: 2.10.0
is-core-module: 2.11.0
semver: 7.3.8
validate-npm-package-license: 3.0.4
dev: true
@ -1625,13 +1596,6 @@ packages:
dependencies:
wrappy: 1.0.2
/os-locale/6.0.2:
resolution: {integrity: sha512-qIb8bzRqaN/vVqEYZ7lTAg6PonskO7xOmM7OClD28F6eFa4s5XGe4bGpHUHMoCHbNNuR0pDYFeSLiW5bnjWXIA==}
engines: {node: '>=12.20'}
dependencies:
lcid: 3.1.1
dev: false
/p-cancelable/1.1.0:
resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==}
engines: {node: '>=6'}
@ -2013,9 +1977,9 @@ packages:
has-flag: 4.0.0
dev: true
/tar/6.1.11:
resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
engines: {node: '>= 10'}
/tar/6.1.12:
resolution: {integrity: sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==}
engines: {node: '>=10'}
dependencies:
chownr: 2.0.0
fs-minipass: 2.1.0
@ -2086,8 +2050,8 @@ packages:
engines: {node: '>=10'}
dev: true
/typescript/4.8.4:
resolution: {integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==}
/typescript/4.9.3:
resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
@ -2188,8 +2152,8 @@ packages:
/wrappy/1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/ws/8.9.0:
resolution: {integrity: sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==}
/ws/8.11.0:
resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@ -2243,8 +2207,8 @@ packages:
yargs-parser: 20.2.9
dev: true
/yargs/17.6.0:
resolution: {integrity: sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==}
/yargs/17.6.2:
resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==}
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
@ -2267,17 +2231,28 @@ packages:
engines: {node: '>=10'}
dev: true
file:src/arrpc:
resolution: {directory: src/arrpc, type: directory}
name: arrpc
version: 1.1.0
dependencies:
ws: 8.11.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: false
github.com/ArmCord/electron-context-menu/280c81398c02a063f46e3285a9708d8db1a7ce32:
resolution: {tarball: https://codeload.github.com/ArmCord/electron-context-menu/tar.gz/280c81398c02a063f46e3285a9708d8db1a7ce32}
name: electron-context-menu
version: 3.5.0
dependencies:
cli-truncate: 2.1.0
electron-dl: 3.3.1
electron-dl: 3.5.0
electron-is-dev: 2.0.0
dev: false
github.com/pykeio/vibe/11984868ce9e007859ed91ff159c7f7f0a34e7ae_electron@20.3.1:
github.com/pykeio/vibe/11984868ce9e007859ed91ff159c7f7f0a34e7ae_electron@21.3.0:
resolution: {tarball: https://codeload.github.com/pykeio/vibe/tar.gz/11984868ce9e007859ed91ff159c7f7f0a34e7ae}
id: github.com/pykeio/vibe/11984868ce9e007859ed91ff159c7f7f0a34e7ae
name: '@pyke/vibe'
@ -2286,6 +2261,6 @@ packages:
peerDependencies:
electron: '>=11.0'
dependencies:
cargo-cp-artifact: 0.1.6
electron: 20.3.1
cargo-cp-artifact: 0.1.7
electron: 21.3.0
dev: false

21
src/arrpc/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 OpenAsar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

81
src/arrpc/README.md Normal file
View file

@ -0,0 +1,81 @@
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/19228318/202900211-95e8474b-edbb-4048-ba0b-a581a6d57fc4.png" width=300>
<img alt="arRPC" src="https://user-images.githubusercontent.com/19228318/203024061-064fc015-9096-40c3-9786-ad23d90414a6.png" width=300>
</picture> <br>
<a href="https://choosealicense.com/licenses/mit/l"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
<a href="https://github.com/sponsors/CanadaHonk"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/CanadaHonk?label=Sponsors&logo=github"></a>
<h3>An open implementation of Discord's local RPC servers</h3>
<h4>Allowing RPC where it was otherwise impossible, like Discord Web and custom clients</h4>
</div>
<br>
arRPC is an open source implementation of Discord's half-documented local RPC servers for their desktop client. This open source implementation purely in NodeJS allows it to be used in many places where it is otherwise impossible to do: Discord web and alternative clients like ArmCord/etc. It opens a simple bridge WebSocket server which messages the JSON of exactly what to dispatch with in the client with no extra processing needed, allowing small and simple mods or plugins. **arRPC is experimental and a work in progress, so expect bugs, etc.**
<br>
Rich Presence (RPC) is the name for how some apps can talk to Discord desktop on your PC via localhost servers to display detailed info about the app's state. This usually works via parts of Discord desktop natively doing things + parts of Discord web interpreting that and setting it as your status. arRPC is an open source implementation of the local RPC servers on your PC, allowing apps to talk to it thinking it was just normal Discord. It can then send that info to apps which usually don't get RPC, like Discord Web, ArmCord, etc. which can then set that as your status. This would otherwise not be possible, as web apps/browsers/etc can't just use Discord's already existing code and version.
- App with Discord RPC
- ~~Discord Desktop's native server~~ arRPC
- ~~Discord Web's setting~~ mod/plugin
<br>
## Usage
### Server (**REQUIRED**)
1. Have latest (>=18) Node installed
2. Clone GitHub repo
3. `npm install`
4. Run server with `node src`
### Web
#### No Mods
1. Get [the arRPC server running](#server-required)
2. With Discord open, run the content of [`examples/bridge_mod.js`](examples/bridge_mod.js) in Console (Ctrl+Shift+I).
#### Vencord
1. Get [the arRPC server running](#server-required)
2. Just enable the `WebRichPresence (arRPC)` Vencord plugin!
### Custom Clients
#### ArmCord
ArmCord has arRPC specially integrated, just enable the option in it's settings (server not required)!
#### Webcord
1. Get [the arRPC server running](#server-required)
2. Disable the `Use built-in Content Security Policy` option in Advanced settings: ![image](https://user-images.githubusercontent.com/19228318/202926723-93b772fc-f37d-47d4-81fd-b11c5d4051e8.png)
3. With Webcord open, run the content of [`examples/bridge_mod.js`](examples/bridge_mod.js) in the DevTools Console (Ctrl+Shift+I).
---
Then just use apps with Discord RPC like normal and they _should_ work!
<br>
## Supported
### Transports
- [x] WebSocket Server
- [x] JSON
- [ ] Erlpack
- [ ] HTTP Server
- [x] IPC
### Commands
- [x] DISPATCH
- [x] SET_ACTIVITY
- [x] INVITE_BROWSER
- [x] GUILD_TEMPLATE_BROWSER
- [x] DEEP_LINK

20
src/arrpc/changelog.md Normal file
View file

@ -0,0 +1,20 @@
# arRPC Changelog
## v2.2.0 [20-11-2022]
- Server: Move all looking up/fetching to client
## v2.1.0 [20-11-2022]
- Server: Stop activites when app disconnects
- Server: Added support for several apps shown at once (added `socketId`)
- Bridge: Catchup newly connected clients with last message by socket id
- Transports: Rewrote internal API to use handlers object
- API: Added parsing for GUILD_TEMPLATE_BROWSER
- API: Added parsing for DEEP_LINK
## v2.0.0 [20-11-2022]
- feat (breaking): moved asset lookup to client
- feat: add examples
- feat: add changelog

View file

@ -0,0 +1,9 @@
# arRPC Examples
## [Bridge Mod](bridge_mod.js)
Simple mod for using the arRPC Bridge WebSocket server for setting RPC status (to be used with just Web).
## [Electron](electron)
Example usage for within an Electron client.

View file

@ -0,0 +1,78 @@
(() => {
let Dispatcher,
lookupAsset,
lookupApp,
apps = {};
const ws = new WebSocket("ws://127.0.0.1:1337"); // connect to arRPC bridge websocket
ws.onmessage = async (x) => {
msg = JSON.parse(x.data);
console.log(msg);
if (!Dispatcher) {
const wpRequire = window.webpackChunkdiscord_app.push([[Symbol()], {}, (x) => x]);
const cache = wpRequire.c;
window.webpackChunkdiscord_app.pop();
for (const id in cache) {
let mod = cache[id].exports;
mod = mod && (mod.Z ?? mod.ZP);
if (mod && mod.register && mod.wait) {
Dispatcher = mod;
break;
}
}
const factories = wpRequire.m;
for (const id in factories) {
if (factories[id].toString().includes("getAssetImage: size must === [number, number] for Twitch")) {
const mod = wpRequire(id);
const _lookupAsset = Object.values(mod).find(
(e) => typeof e === "function" && e.toString().includes("apply(")
);
lookupAsset = async (appId, name) => (await _lookupAsset(appId, [name, undefined]))[0];
break;
}
}
for (const id in factories) {
if (factories[id].toString().includes(`e.application={`)) {
const mod = wpRequire(id);
const _lookupApp = Object.values(mod).find(
(e) => typeof e === "function" && e.toString().includes(`e.application={`)
);
lookupApp = async (appId) => {
let socket = {};
await _lookupApp(socket, appId);
return socket.application;
};
break;
}
}
}
if (msg.activity?.assets?.large_image)
msg.activity.assets.large_image = await lookupAsset(
msg.activity.application_id,
msg.activity.assets.large_image
);
if (msg.activity?.assets?.small_image)
msg.activity.assets.small_image = await lookupAsset(
msg.activity.application_id,
msg.activity.assets.small_image
);
const appId = msg.activity.application_id;
if (!apps[appId]) apps[appId] = await lookupApp(appId);
const app = apps[appId];
if (!msg.activity.name) msg.activity.name = app.name;
Dispatcher.dispatch({type: "LOCAL_ACTIVITY_UPDATE", ...msg}); // set RPC status
};
})();

View file

@ -0,0 +1,9 @@
// myWindow = your discord.com BrowserWindow
import Server from "./path/to/arrpc/server.js";
const arrpc = await new Server();
arrpc.on("activity", (data) => myWindow.webContents.send("rpc", data));
arrpc.on("invite", (code) => {
// your invite code handling here
});

View file

@ -0,0 +1,73 @@
import {ipcRenderer} from "electron";
let Dispatcher,
lookupAsset,
lookupApp,
apps = {};
ipcRenderer.on("rpc", async (event, data) => {
if (!Dispatcher) {
const wpRequire = window.webpackChunkdiscord_app.push([[Symbol()], {}, (x) => x]);
const cache = wpRequire.c;
window.webpackChunkdiscord_app.pop();
for (const id in cache) {
let mod = cache[id].exports;
mod = mod && (mod.Z ?? mod.ZP);
if (mod && mod.register && mod.wait) {
Dispatcher = mod;
break;
}
}
const factories = wpRequire.m;
for (const id in factories) {
if (factories[id].toString().includes("getAssetImage: size must === [number, number] for Twitch")) {
const mod = wpRequire(id);
const _lookupAsset = Object.values(mod).find(
(e) => typeof e === "function" && e.toString().includes("apply(")
);
lookupAsset = async (appId, name) => (await _lookupAsset(appId, [name, undefined]))[0];
break;
}
}
for (const id in factories) {
if (factories[id].toString().includes(`e.application={`)) {
const mod = wpRequire(id);
const _lookupApp = Object.values(mod).find(
(e) => typeof e === "function" && e.toString().includes(`e.application={`)
);
lookupApp = async (appId) => {
let socket = {};
await _lookupApp(socket, appId);
return socket.application;
};
break;
}
}
}
if (data.activity?.assets?.large_image)
data.activity.assets.large_image = await lookupAsset(
data.activity.application_id,
data.activity.assets.large_image
);
if (data.activity?.assets?.small_image)
data.activity.assets.small_image = await lookupAsset(
data.activity.application_id,
data.activity.assets.small_image
);
const appId = data.activity.application_id;
if (!apps[appId]) apps[appId] = await lookupApp(appId);
const app = apps[appId];
if (!data.activity.name) data.activity.name = app.name;
Dispatcher.dispatch({type: "LOCAL_ACTIVITY_UPDATE", ...data}); // set RPC status
});

22
src/arrpc/package.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": "arrpc",
"version": "2.2.0",
"description": "Open Discord RPC server for atypical setups",
"main": "src/index.cjs",
"scripts": {
"start": "node src"
},
"repository": {
"type": "git",
"url": "git+https://github.com/OpenAsar/arrpc.git"
},
"author": "OpenAsar",
"license": "MIT",
"bugs": {
"url": "https://github.com/OpenAsar/arrpc/issues"
},
"homepage": "https://github.com/OpenAsar/arrpc#readme",
"dependencies": {
"ws": "^8.11.0"
}
}

18
src/arrpc/src/index.cjs Normal file
View file

@ -0,0 +1,18 @@
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
const log = (...args) => console.log(`[${rgb(88, 101, 242, "arRPC")}]`, ...args);
log("arRPC v2.2.0 [ArmCord]");
const {RPCServer} = require("./server.js");
const {mainWindow} = require("../../../ts-out/window.js");
async function run() {
const server = await new RPCServer();
server.on("activity", (data) => mainWindow.webContents.send("rpc", data));
server.on("invite", (code) => {
console.log(code);
const {createInviteWindow} = require("../../../ts-out/window.js");
createInviteWindow(code);
});
}
run();

116
src/arrpc/src/server.js Normal file
View file

@ -0,0 +1,116 @@
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
const log = (...args) => console.log(`[${rgb(88, 101, 242, "arRPC")} > ${rgb(87, 242, 135, "bridge")}]`, ...args);
const {EventEmitter} = require("events");
const {IPCServer} = require("./transports/ipc.js");
const {WSServer} = require("./transports/websocket.js");
let socketId = 0;
class RPCServer extends EventEmitter {
constructor() {
super();
return (async () => {
this.onConnection = this.onConnection.bind(this);
this.onMessage = this.onMessage.bind(this);
this.onClose = this.onClose.bind(this);
const handlers = {
connection: this.onConnection,
message: this.onMessage,
close: this.onClose
};
this.ipc = await new IPCServer(handlers);
this.ws = await new WSServer(handlers);
return this;
})();
}
onConnection(socket) {
socket.send({
cmd: "DISPATCH",
evt: "READY",
data: {
v: 1
}
});
socket.socketId = socketId++;
this.emit("connection", socket);
}
onClose(socket) {
this.emit("activity", {
activity: null,
pid: socket.lastPid,
socketId: socket.socketId.toString()
});
this.emit("close", socket);
}
async onMessage(socket, {cmd, args, nonce}) {
this.emit("message", {socket, cmd, args, nonce});
switch (cmd) {
case "SET_ACTIVITY":
const {activity, pid} = args; // translate given parameters into what discord dispatch expects
const {buttons, timestamps, instance} = activity;
socket.lastPid = pid ?? socket.lastPid;
const metadata = {};
const extra = {};
if (buttons) {
// map buttons into expected metadata
metadata.button_urls = buttons.map((x) => x.url);
extra.buttons = buttons.map((x) => x.label);
}
if (timestamps)
for (const x in timestamps) {
// translate s -> ms timestamps
if (Date.now().toString().length - timestamps[x].toString().length > 2)
timestamps[x] = Math.floor(1000 * timestamps[x]);
}
this.emit("activity", {
activity: {
application_id: socket.clientId,
type: 0,
metadata,
flags: instance ? 1 << 0 : 0,
...activity,
...extra
},
pid,
socketId: socket.socketId.toString()
});
break;
case "GUILD_TEMPLATE_BROWSER":
case "INVITE_BROWSER":
const {code} = args;
socket.send({
cmd,
data: {
code
},
nonce
});
this.emit(cmd === "INVITE_BROWSER" ? "invite" : "guild_template", code);
break;
case "DEEP_LINK":
this.emit("link", args.params);
break;
}
}
}
module.exports = {RPCServer};

View file

@ -0,0 +1,259 @@
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
const log = (...args) => console.log(`[${rgb(88, 101, 242, "arRPC")} > ${rgb(254, 231, 92, "ipc")}]`, ...args);
const {join} = require("path");
const {platform, env} = require("process");
const {unlinkSync} = require("fs");
const {createServer, createConnection} = require("net");
const SOCKET_PATH =
platform === "win32"
? "\\\\?\\pipe\\discord-ipc"
: join(env.XDG_RUNTIME_DIR || env.TMPDIR || env.TMP || env.TEMP || "/tmp", "discord-ipc");
// enums for various constants
const Types = {
// types of packets
HANDSHAKE: 0,
FRAME: 1,
CLOSE: 2,
PING: 3,
PONG: 4
};
const CloseCodes = {
// codes for closures
CLOSE_NORMAL: 1000,
CLOSE_UNSUPPORTED: 1003,
CLOSE_ABNORMAL: 1006
};
const ErrorCodes = {
// codes for errors
INVALID_CLIENTID: 4000,
INVALID_ORIGIN: 4001,
RATELIMITED: 4002,
TOKEN_REVOKED: 4003,
INVALID_VERSION: 4004,
INVALID_ENCODING: 4005
};
let uniqueId = 0;
const encode = (type, data) => {
data = JSON.stringify(data);
const dataSize = Buffer.byteLength(data);
const buf = Buffer.alloc(dataSize + 8);
buf.writeInt32LE(type, 0); // type
buf.writeInt32LE(dataSize, 4); // data size
buf.write(data, 8, dataSize); // data
return buf;
};
const read = (socket) => {
let resp = socket.read(8);
if (!resp) return;
resp = Buffer.from(resp);
const type = resp.readInt32LE(0);
const dataSize = resp.readInt32LE(4);
if (type < 0 || type >= Object.keys(Types).length) throw new Error("invalid type");
let data = socket.read(dataSize);
if (!data) throw new Error("failed reading data");
data = JSON.parse(Buffer.from(data).toString());
switch (type) {
case Types.PING:
socket.emit("ping", data);
socket.write(encode(Types.PONG, data));
break;
case Types.PONG:
socket.emit("pong", data);
break;
case Types.HANDSHAKE:
if (socket._handshook) throw new Error("already handshook");
socket._handshook = true;
socket.emit("handshake", data);
break;
case Types.FRAME:
if (!socket._handshook) throw new Error("need to handshake first");
socket.emit("request", data);
break;
case Types.CLOSE:
socket.end();
socket.destroy();
break;
}
read(socket);
};
const socketIsAvailable = async (socket) => {
socket.pause();
socket.on("readable", () => {
try {
read(socket);
} catch (e) {
log("error whilst reading", e);
socket.end(
encode(Types.CLOSE, {
code: CloseCodes.CLOSE_UNSUPPORTED,
message: e.message
})
);
socket.destroy();
}
});
const stop = () => {
try {
socket.end();
socket.destroy();
} catch {}
};
const possibleOutcomes = Promise.race([
new Promise((res) => socket.on("error", res)), // errored
new Promise((res, rej) => socket.on("pong", () => rej("socket ponged"))), // ponged
new Promise((res, rej) => setTimeout(() => rej("timed out"), 1000)) // timed out
]).then(
() => true,
(e) => e
);
socket.write(encode(Types.PING, ++uniqueId));
const outcome = await possibleOutcomes;
stop();
log("checked if socket is available:", outcome === true, outcome === true ? "" : `- reason: ${outcome}`);
return outcome === true;
};
const getAvailableSocket = async (tries = 0) => {
if (tries > 9) {
throw new Error("ran out of tries to find socket", tries);
}
const path = SOCKET_PATH + "-" + tries;
const socket = createConnection(path);
log("checking", path);
if (await socketIsAvailable(socket)) {
if (platform !== "win32")
try {
unlinkSync(path);
} catch {}
return path;
}
log(`not available, trying again (attempt ${tries + 1})`);
return getAvailableSocket(tries + 1);
};
class IPCServer {
constructor(handers) {
return new Promise(async (res) => {
this.handlers = handers;
this.onConnection = this.onConnection.bind(this);
this.onMessage = this.onMessage.bind(this);
const server = createServer(this.onConnection);
server.on("error", (e) => {
log("server error", e);
});
const socketPath = await getAvailableSocket();
server.listen(socketPath, () => {
log("listening at", socketPath);
this.server = server;
res(this);
});
});
}
onConnection(socket) {
log("new connection!");
socket.pause();
socket.on("readable", () => {
try {
read(socket);
} catch (e) {
log("error whilst reading", e);
socket.end(
encode(Types.CLOSE, {
code: CloseCodes.CLOSE_UNSUPPORTED,
message: e.message
})
);
socket.destroy();
}
});
socket.once("handshake", (params) => {
log("handshake:", params);
const ver = params.v ?? 1;
const clientId = params.client_id ?? "";
// encoding is always json for ipc
if (ver !== 1) {
log("unsupported version requested", ver);
socket.close(ErrorCodes.INVALID_VERSION);
return;
}
if (clientId === "") {
log("client id required");
socket.close(ErrorCodes.INVALID_CLIENTID);
return;
}
socket.on("error", (e) => {
log("socket error", e);
});
socket.on("close", (e) => {
log("socket closed", e);
this.handlers.close(socket);
});
socket.on("request", this.onMessage.bind(this, socket));
socket._send = socket.send;
socket.send = (msg) => {
log("sending", msg);
socket.write(encode(Types.FRAME, msg));
};
socket.clientId = clientId;
this.handlers.connection(socket);
});
}
onMessage(socket, msg) {
log("message", msg);
this.handlers.message(socket, msg);
}
}
module.exports = {IPCServer};

View file

@ -0,0 +1,130 @@
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
const log = (...args) => console.log(`[${rgb(88, 101, 242, "arRPC")} > ${rgb(235, 69, 158, "websocket")}]`, ...args);
const {WebSocketServer} = require("ws");
const {createServer} = require("http");
const {parse} = require("querystring");
const portRange = [6463, 6472]; // ports available/possible: 6463-6472
class WSServer {
constructor(handlers) {
return (async () => {
this.handlers = handlers;
this.onConnection = this.onConnection.bind(this);
this.onMessage = this.onMessage.bind(this);
let port = portRange[0];
let http, wss;
while (port <= portRange[1]) {
log("trying port", port);
if (
await new Promise((res) => {
http = createServer();
http.on("error", (e) => {
// log('http error', e);
if (e.code === "EADDRINUSE") {
log(port, "in use!");
res(false);
}
});
wss = new WebSocketServer({server: http});
wss.on("error", (e) => {
// log('wss error', e);
});
wss.on("connection", this.onConnection);
http.listen(port, "127.0.0.1", () => {
log("listening on", port);
this.http = http;
this.wss = wss;
res(true);
});
})
)
break;
port++;
}
return this;
})();
}
onConnection(socket, req) {
const params = parse(req.url.split("?")[1]);
const ver = parseInt(params.v ?? 1);
const encoding = params.encoding ?? "json"; // json | etf (erlpack)
const clientId = params.client_id ?? "";
const origin = req.headers.origin ?? "";
log(`new connection! origin:`, origin, JSON.parse(JSON.stringify(params)));
if (
origin !== "" &&
!["https://discord.com", "https://ptb.discord.com", "https://canary.discord.com/"].includes(origin)
) {
log("disallowed origin", origin);
socket.close();
return;
}
if (encoding !== "json") {
log("unsupported encoding requested", encoding);
socket.close();
return;
}
if (ver !== 1) {
log("unsupported version requested", ver);
socket.close();
return;
}
/* if (clientId === '') {
log('client id required');
socket.close();
return;
} */
socket.clientId = clientId;
socket.encoding = encoding;
socket.on("error", (e) => {
log("socket error", e);
});
socket.on("close", (e, r) => {
log("socket closed", e, r);
this.handlers.close(socket);
});
socket.on("message", this.onMessage.bind(this, socket));
socket._send = socket.send;
socket.send = (msg) => {
log("sending", msg);
socket._send(JSON.stringify(msg));
};
this.handlers.connection(socket);
}
onMessage(socket, msg) {
log("message", JSON.parse(msg));
this.handlers.message(socket, JSON.parse(msg));
}
}
module.exports = {WSServer};

79
src/content/js/rpc.js Normal file
View file

@ -0,0 +1,79 @@
(() => {
let Dispatcher,
lookupAsset,
lookupApp,
apps = {};
ArmCordRPC.listen(async (data) => {
msg = data; //already parsed
console.log(msg);
if (!Dispatcher) {
const wpRequire = window.webpackChunkdiscord_app.push([[Symbol()], {}, (x) => x]);
const cache = wpRequire.c;
window.webpackChunkdiscord_app.pop();
for (const id in cache) {
let mod = cache[id].exports;
mod = mod && (mod.Z ?? mod.ZP);
if (mod && mod.register && mod.wait) {
Dispatcher = mod;
break;
}
}
const factories = wpRequire.m;
for (const id in factories) {
if (factories[id].toString().includes("getAssetImage: size must === [number, number] for Twitch")) {
const mod = wpRequire(id);
const _lookupAsset = Object.values(mod).find(
(e) => typeof e === "function" && e.toString().includes("apply(")
);
lookupAsset = async (appId, name) => (await _lookupAsset(appId, [name, undefined]))[0];
break;
}
}
for (const id in factories) {
if (factories[id].toString().includes(`e.application={`)) {
const mod = wpRequire(id);
const _lookupApp = Object.values(mod).find(
(e) => typeof e === "function" && e.toString().includes(`e.application={`)
);
lookupApp = async (appId) => {
let socket = {};
await _lookupApp(socket, appId);
return socket.application;
};
break;
}
}
}
if (msg.activity?.assets?.large_image)
msg.activity.assets.large_image = await lookupAsset(
msg.activity.application_id,
msg.activity.assets.large_image
);
if (msg.activity?.assets?.small_image)
msg.activity.assets.small_image = await lookupAsset(
msg.activity.application_id,
msg.activity.assets.small_image
);
if (msg.activity) {
const appId = msg.activity.application_id;
if (!apps[appId]) apps[appId] = await lookupApp(appId);
const app = apps[appId];
if (!msg.activity.name) msg.activity.name = app.name;
}
Dispatcher.dispatch({type: "LOCAL_ACTIVITY_UPDATE", ...msg}); // set RPC status
});
})();

View file

@ -1,52 +1,29 @@
//https://github.com/GooseMod/GooseMod/wiki/Stuck-Updater-or-Blank-Window-Fix
/*
Copyright 2022 GooseMod
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import electron from "electron";
import {getConfig} from "../utils";
const otherMods = {
generic: {
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 = async () => {
console.log("Setting up CSP unstricter...");
const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"];
const cspAllowAll = ["style-src", "connect-src", "img-src", "font-src", "media-src"];
const corsAllowUrls = [
"https://raw.githubusercontent.com/Cordwood/builds/master/index.js",
"https://github.com/Vendicated/Vencord/releases/download/devbuild/browser.js",
"https://cors.armcord.xyz/raw.githubusercontent.com/uwu/shelter-builds/main/shelter.js"
];
electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, url}, done) => {
const isVencord = await getConfig("mods").then((s) => s.includes("vencord"));
electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders}, done) => {
let csp = responseHeaders!["content-security-policy"];
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
delete responseHeaders!["content-security-policy"];
csp = [];
}
if (csp) {
for (let p of cspAllowAll) {
csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs
for (const directive of cspAllowAll) {
csp[0] = csp[0].replace(new RegExp(`${directive}.+?;`), `${directive} * blob: data: 'unsafe-inline';`);
}
if (isVencord) {
// unpkg and cdnjs are used for QuickCss and some plugins' dependencies (e.g. GifEncoder & APNG for FakeNitro)
csp[0] = csp[0].replace(
/script-src.+?(?=;)/,
"$& 'unsafe-eval' https://unpkg.com https://cdnjs.cloudflare.com"
);
}
// Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?)
csp[0] = csp[0].replace(/'nonce-.*?' /, "");
}
if (corsAllowUrls.some((x) => url.startsWith(x))) {
responseHeaders!["access-control-allow-origin"] = ["*"];
csp[0] = csp[0].replace(/'nonce-.+?' /, "");
}
done({responseHeaders});

View file

@ -16,7 +16,7 @@ import {
import {customTitlebar} from "./main";
import {createSettingsWindow} from "./settings/main";
import os from "os";
import fs from "fs"
import fs from "fs";
import path from "path";
export function registerIpc() {
ipcMain.on("get-app-path", (event, arg) => {

View file

@ -52,7 +52,7 @@ app.whenReady().then(async () => {
}
}
await init();
await installModLoader()
await installModLoader();
session.fromPartition("some-partition").setPermissionRequestHandler((webContents, permission, callback) => {
if (permission === "notifications") {
// Approves the permissions request

View file

@ -1,4 +1,4 @@
import {Menu, app, clipboard, globalShortcut} from "electron";
import {BrowserWindow, Menu, app, clipboard, globalShortcut} from "electron";
import {mainWindow} from "./window";
import {getConfig} from "./utils";
import {createSettingsWindow} from "./settings/main";
@ -49,7 +49,7 @@ export async function setMenu() {
label: "Developer tools",
accelerator: "CmdOrCtrl+Shift+I",
click: function () {
mainWindow.webContents.toggleDevTools();
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
}
},
{

View file

@ -28,6 +28,13 @@ contextBridge.exposeInMainWorld("armcord", {
splashEnd: () => ipcRenderer.send("splashEnd"),
openSettingsWindow: () => ipcRenderer.send("openSettingsWindow")
});
let windowCallback: (arg0: object) => void;
contextBridge.exposeInMainWorld("ArmCordRPC", {
listen: (callback: any) => (windowCallback = callback)
});
ipcRenderer.on("rpc", (event, data: object) => {
windowCallback(data);
});
//to be only used inside armcord internal setup/splash etc
if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) {
contextBridge.exposeInMainWorld("armcordinternal", {

View file

@ -5,7 +5,7 @@ import "./patch";
import * as fs from "fs";
import * as path from "path";
import {injectHummusTitlebar, injectTitlebar} from "./titlebar";
import {sleep, addStyle} from "../utils";
import {sleep, addStyle, addScript} from "../utils";
import {injectMobileStuff} from "./mobile";
var version = ipcRenderer.sendSync("displayVersion");
var channel = ipcRenderer.sendSync("channel");
@ -42,6 +42,23 @@ if (window.location.href.indexOf("splash.html") > -1) {
injectMobileStuff();
}
sleep(5000).then(async () => {
// dirty hack to make clicking notifications focus ArmCord
addScript(`
(() => {
const originalSetter = Object.getOwnPropertyDescriptor(Notification.prototype, "onclick").set;
Object.defineProperty(Notification.prototype, "onclick", {
set(onClick) {
originalSetter.call(this, function() {
onClick.apply(this, arguments);
armcord.window.show();
})
},
configurable: true
});
})();
`);
addScript(fs.readFileSync(path.join(__dirname, "../", "/content/js/rpc.js"), "utf8"));
const cssPath = path.join(__dirname, "../", "/content/css/discord.css");
addStyle(fs.readFileSync(cssPath, "utf8"));
await updateLang();

View file

@ -62,12 +62,12 @@
</div>
<br />
<div class="switch acWebsocket">
<label class="header" id="settings-invitewebsocket">Invite Websocket</label>
<label class="header" id="settings-invitewebsocket">Rich Presence (Experimental)</label>
<input class="tgl tgl-light left" id="websocket" type="checkbox" />
<label class="tgl-btn left" for="websocket"></label>
<p class="description">
When enabled ArmCord will support Discord.gg links which means that if you open an invite link in your
browser, ArmCord will automatically accept the invite. Can be unresponsive at times.
Uses <a target="_blank" href="https://github.com/OpenAsar/arrpc">arRPC</a> to support Discord RPC (Rich
Presence) with local programs on your machine. Work in progress.
</p>
</div>
<br />

View file

@ -1,186 +0,0 @@
import type {Server, WebSocket} from "ws";
import {inviteWindow, createInviteWindow} from "./window";
/*
MIT License
Copyright (c) 2020-2022 Dawid Papiewski "SpacingBat3"
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
async function wsLog(message: string, ...args: unknown[]) {
console.log("[WebSocket] " + message, ...args);
}
/** Generates an inclusive range (as `Array`) from `start` to `end`. */
function range(start: number, end: number) {
return Array.from({length: end - start + 1}, (_v, k) => start + k);
}
interface InviteResponse {
/** Response type/command. */
cmd: "INVITE_BROWSER";
/** Response arguments. */
args: {
/** An invitation code. */
code: string;
};
/** Nonce indentifying the communication. */
nonce: string;
}
function isInviteResponse(data: unknown): data is InviteResponse {
if (!(data instanceof Object)) return false;
if ((data as Partial<InviteResponse>)?.cmd !== "INVITE_BROWSER") return false;
if (typeof (data as Partial<InviteResponse>)?.args?.code !== "string") return false;
if (typeof (data as Partial<InviteResponse>)?.nonce !== "string") return false;
return true;
}
const messages = {
/**
* A fake, hard-coded Discord command to spoof the presence of
* official Discord client (which makes browser to actually start a
* communication with the ArmCord).
*/
handShake: {
/** Message command. */
cmd: "DISPATCH",
/** Message data. */
data: {
/** Message scheme version. */
v: 1,
/** Client properties. */
config: {
/** Discord CDN host (hard-coded for `dicscord.com` instance). */
cdn_host: "cdn.discordapp.com",
/** API endpoint (hard-coded for `dicscord.com` instance). */
api_endpoint: "//discord.com/api",
/** Client type. Can be (probably) `production` or `canary`. */
environment: "production"
}
},
evt: "READY",
nonce: null
}
};
/**
* Tries to reserve the server at given port.
*
* @returns `Promise`, which always resolves (either to `Server<WebSocket>` on
* success or `null` on failure).
*/
async function getServer(port: number) {
const {WebSocketServer} = await import("ws");
return new Promise<Server<WebSocket> | null>((resolve) => {
const wss = new WebSocketServer({host: "127.0.0.1", port});
wss.once("listening", () => resolve(wss));
wss.once("error", () => resolve(null));
});
}
/**
* Tries to start a WebSocket server at given port range. If it suceed, it will
* listen to the browser requests which are meant to be sent to official
* Discord client.
*
* Currently it supports only the invitation link requests.
*
*/
export default async function startServer() {
function isJsonSyntaxCorrect(string: string) {
try {
JSON.parse(string);
} catch {
return false;
}
return true;
}
/** Known Discord instances, including the official ones. */
const knownInstancesList = [
["Discord", new URL("https://discord.com/app")],
["Discord Canary", new URL("https://canary.discord.com/app")],
["Discord PTB", new URL("https://ptb.discord.com/app")],
["Fosscord", new URL("https://dev.fosscord.com/app")]
] as const;
let wss = null,
wsPort = 6463;
for (const port of range(6463, 6472)) {
wss = await getServer(port);
if (wss !== null) {
void wsLog("ArmCord is listening at " + port.toString());
wsPort = port;
break;
}
}
if (wss === null) return;
let lock = false;
wss.on("connection", (wss, request) => {
const origin = request.headers.origin ?? "https://discord.com";
let known = false;
for (const instance of knownInstancesList) {
if (instance[1].origin === origin) known = true;
}
if (!known) return;
wss.send(JSON.stringify(messages.handShake));
wss.once("message", (data, isBinary) => {
if (lock) return;
lock = true;
let parsedData: unknown = data;
if (!isBinary) parsedData = data.toString();
if (isJsonSyntaxCorrect(parsedData as string)) parsedData = JSON.parse(parsedData as string);
if (isInviteResponse(parsedData)) {
// Replies to browser, so it finds the communication successful.
wss.send(
JSON.stringify({
cmd: parsedData.cmd,
data: {
invite: null,
code: parsedData.args.code
},
evt: null,
nonce: parsedData.nonce
})
);
createInviteWindow();
const child = inviteWindow;
if (child === undefined) return;
void child.loadURL(origin + "/invite/" + parsedData.args.code);
child.webContents.once("did-finish-load", () => {
child.show();
});
child.webContents.once("will-navigate", () => {
lock = false;
child.close();
});
child.on("close", (e) => {
lock = false;
});
// Blocks requests to ArmCord's WS, to prevent loops.
child.webContents.session.webRequest.onBeforeRequest(
{
urls: ["ws://127.0.0.1:" + wsPort.toString() + "/*"]
},
(_details, callback) => callback({cancel: true})
);
}
});
});
}

View file

@ -1,6 +1,6 @@
import * as fs from "fs";
import {app, Menu, Tray, nativeImage} from "electron";
import {mainWindow} from "./window";
import {createInviteWindow, mainWindow} from "./window";
import {getConfig, getConfigLocation, setWindowState, getDisplayVersion} from "./utils";
import * as path from "path";
import {createSettingsWindow} from "./settings/main";
@ -113,8 +113,7 @@ app.whenReady().then(async () => {
{
label: "Support Discord Server",
click: function () {
mainWindow.show();
mainWindow.loadURL("https://discord.gg/TnhxcqynZ2");
createInviteWindow("TnhxcqynZ2");
}
},
{

View file

@ -1,10 +1,10 @@
import * as fs from "fs";
import {app, dialog, session} from "electron";
import path from "path";
import fetch from "node-fetch"
import extract from "extract-zip"
import util from "util"
const streamPipeline = util.promisify(require('stream').pipeline)
import fetch from "cross-fetch";
import extract from "extract-zip";
import util from "util";
const streamPipeline = util.promisify(require("stream").pipeline);
export var firstRun: boolean;
export var contentPath: string;
export var transparency: boolean;
@ -77,7 +77,6 @@ export function getDisplayVersion() {
}
}
export async function injectJS(inject: string) {
const js = await (await fetch(`${inject}`)).text();
const el = document.createElement("script");
@ -125,7 +124,7 @@ export async function injectElectronFlags() {
console.log("No performance modes set");
}
if ((await getConfig("windowStyle")) == "transparent" && process.platform === "win32") {
import("@pyke/vibe").then(vibe => {
import("@pyke/vibe").then((vibe) => {
console.log("Transparent mode enabled");
vibe.setup(app);
transparency = true;
@ -286,66 +285,71 @@ export async function checkIfConfigExists() {
// Mods
async function updateModBundle() {
try {
console.log("Downloading mod bundle")
const distFolder = app.getPath("userData") + "/plugins/loader/dist/";
while (!fs.existsSync(distFolder)){
//waiting
if ((await getConfig("noBundleUpdates")) == undefined ?? false) {
try {
console.log("Downloading mod bundle");
const distFolder = app.getPath("userData") + "/plugins/loader/dist/";
while (!fs.existsSync(distFolder)) {
//waiting
}
var name: string = await getConfig("mods");
const clientMods = {
vencord: "https://github.com/Vendicated/Vencord/releases/download/devbuild/browser.js",
cordwood: "https://raw.githubusercontent.com/Cordwood/builds/master/index.js",
shelter: "https://raw.githubusercontent.com/uwu/shelter-builds/main/shelter.js"
};
var bundle: string = await (await fetch(clientMods[name as keyof typeof clientMods])).text();
fs.writeFileSync(distFolder + "bundle.js", bundle, "utf-8");
} catch (e) {
console.log("[Mod loader] Failed to install mods");
console.error(e);
dialog.showErrorBox(
"Oops, something went wrong.",
"ArmCord couldn't install mods, please check if you have stable internet connection and restart the app. If this issue persists, report it on the support server/Github issues."
);
}
} else {
console.log("[Mod loader] Skipping mod bundle update");
}
var name: string = await getConfig("mods")
const clientMods = {
vencord: "https://github.com/Vendicated/Vencord/releases/download/devbuild/browser.js",
cordwood: "https://raw.githubusercontent.com/Cordwood/builds/master/index.js",
shelter: "https://raw.githubusercontent.com/uwu/shelter-builds/main/shelter.js"
};
var bundle: string = await (await fetch(clientMods[name as keyof typeof clientMods])).text()
fs.writeFileSync(distFolder + "bundle.js", bundle, "utf-8");
} catch (e) {
console.log("[Mod loader] Failed to install mods")
console.error(e)
dialog.showErrorBox(
"Oops, something went wrong.",
"ArmCord couldn't install mods, please check if you have stable internet connection and restart the app. If this issue persists, report it on the support server/Github issues."
);
}
}
export var modInstallState: string;
export async function installModLoader() {
if (await getConfig("mods") == "none") {
modInstallState = "none"
if ((await getConfig("mods")) == "none") {
modInstallState = "none";
import("./extensions/plugin");
console.log("[Mod loader] Skipping")
console.log("[Mod loader] Skipping");
} else {
const pluginFolder = app.getPath("userData") + "/plugins/";
if (!fs.existsSync(pluginFolder + "loader")) {
try {
modInstallState = "installing"
modInstallState = "installing";
var zipPath = app.getPath("temp") + "/" + "loader.zip";
if (!fs.existsSync(pluginFolder)) {
fs.mkdirSync(pluginFolder);
console.log("[Mod loader] Created missing plugin folder");
}
var loaderZip = await fetch("https://armcord.xyz/loader.zip")
if (!loaderZip.ok) throw new Error(`unexpected response ${loaderZip.statusText}`)
await streamPipeline(loaderZip.body, fs.createWriteStream(zipPath))
await extract(zipPath, { dir: path.join(app.getPath("userData"), "plugins") })
modInstallState = "modDownload"
updateModBundle()
var loaderZip = await fetch("https://armcord.xyz/loader.zip");
if (!loaderZip.ok) throw new Error(`unexpected response ${loaderZip.statusText}`);
await streamPipeline(loaderZip.body, fs.createWriteStream(zipPath));
await extract(zipPath, {dir: path.join(app.getPath("userData"), "plugins")});
modInstallState = "modDownload";
updateModBundle();
import("./extensions/plugin");
modInstallState = "done"
} catch(e) {
console.log("[Mod loader] Failed to install modloader")
console.error(e)
modInstallState = "done";
} catch (e) {
console.log("[Mod loader] Failed to install modloader");
console.error(e);
dialog.showErrorBox(
"Oops, something went wrong.",
"ArmCord couldn't install internal mod loader, please check if you have stable internet connection and restart the app. If this issue persists, report it on the support server/Github issues."
);
}
} else {
modInstallState = "modDownload"
updateModBundle()
modInstallState = "modDownload";
updateModBundle();
import("./extensions/plugin");
modInstallState = "done"
modInstallState = "done";
}
}
}

View file

@ -12,12 +12,11 @@ import {
setConfig,
setLang,
setWindowState,
transparency,
transparency
} from "./utils";
import {registerIpc} from "./ipc";
import {setMenu} from "./menu";
import * as fs from "fs";
import startServer from "./socket";
import contextMenu from "electron-context-menu";
import os from "os";
import {tray} from "./tray";
@ -51,9 +50,9 @@ contextMenu({
});
async function doAfterDefiningTheWindow() {
if (transparency && process.platform === "win32") {
import("@pyke/vibe").then(vibe => {
import("@pyke/vibe").then((vibe) => {
vibe.applyEffect(mainWindow, "acrylic");
vibe.forceTheme(mainWindow, 'dark');
vibe.forceTheme(mainWindow, "dark");
mainWindow.show();
});
}
@ -85,7 +84,7 @@ async function doAfterDefiningTheWindow() {
}
mainWindow.webContents.setWindowOpenHandler(({url}) => {
// Allow about:blank (used by Vencord QuickCss popup)
if (url === "about:blank") return { action: "allow" };
if (url === "about:blank") return {action: "allow"};
if (url.startsWith("https:" || url.startsWith("http:") || url.startsWith("mailto:"))) {
shell.openExternal(url);
@ -205,7 +204,9 @@ async function doAfterDefiningTheWindow() {
});
console.log(contentPath);
if ((await getConfig("inviteWebsocket")) == true) {
await startServer();
//@ts-ignore
require("arrpc");
//await startServer();
}
if (firstRun) {
await setLang(Intl.DateTimeFormat().resolvedOptions().locale);
@ -290,7 +291,7 @@ export function createTransparentWindow() {
});
doAfterDefiningTheWindow();
}
export function createInviteWindow() {
export function createInviteWindow(code: string) {
inviteWindow = new BrowserWindow({
width: 800,
height: 600,
@ -304,5 +305,16 @@ export function createInviteWindow() {
spellcheck: true
}
});
inviteWindow.hide();
var formInviteURL = `https://discord.com/invite/${code}`;
inviteWindow.webContents.session.webRequest.onBeforeRequest((details, callback) => {
if (details.url.includes("ws://")) return callback({cancel: true});
return callback({});
});
inviteWindow.loadURL(formInviteURL);
inviteWindow.webContents.once("did-finish-load", () => {
inviteWindow.show();
inviteWindow.webContents.once("will-navigate", () => {
inviteWindow.close();
});
});
}

View file

@ -31,4 +31,4 @@
"downlevelIteration": false, // This flag adds extra support when targeting ES3, but adds extra bloat otherwise.
"importHelpers": false // Reduce the amount of bloat that comes from downlevelIteration (when polyfills are redeclared).
}
}
}