Compare commits
No commits in common. "95fca1c026e3c5dd95eeb69acacb5bbc5bc32c29" and "6b90fbd8d4c686e5784ca6e0cec109d6c1f934ed" have entirely different histories.
95fca1c026
...
6b90fbd8d4
17 changed files with 126 additions and 634 deletions
33
README.md
33
README.md
|
@ -8,24 +8,16 @@ A CLI-based client for Discord inspired by [SDF](https://sdf.org)'s [commode](ht
|
||||||
## Usage
|
## Usage
|
||||||
1. `pnpm i`
|
1. `pnpm i`
|
||||||
2. `node src/index.js <token>`
|
2. `node src/index.js <token>`
|
||||||
Your token will be then stored in `.comcordrc` after the first launch.
|
|
||||||
|
|
||||||
### User Accounts
|
Currently only bot accounts are supported, and that is unlikely to change anytime soon.
|
||||||
User accounts are *partially* supported via `allowUserAccounts=true` in your `.comcordrc`.
|
Eris has a lot of user-only endpoints implemented, but it would require hacking apart Eris to do the things nessicary to spoof being the actual client.
|
||||||
This is use at your own risk, despite spoofing the official client. I am not responsible for any banned accounts.
|
I also don't want to give skids an easy point of reference of how to spoof the client. :^)
|
||||||
|
|
||||||
#### Guild members not populating
|
|
||||||
This is due to Oceanic not implementing Lazy Guilds as they are user account specific. **DO NOT bother Oceanic to implement it!** They are purely a bot-focused library.
|
|
||||||
|
|
||||||
If you are willing to implement Lazy Guilds based off of [unofficial documentation](https://luna.gitlab.io/discord-unofficial-docs/lazy_guilds.html)
|
|
||||||
and my already existing horrible hacks to make user accounts work in the first place, feel free to send a PR (on GitLab, GitHub repo is a read only mirror).
|
|
||||||
|
|
||||||
### Bot Accounts (prefered)
|
|
||||||
You **MUST** grant your bot all Privileged Gateway Intents.
|
You **MUST** grant your bot all Privileged Gateway Intents.
|
||||||
|
|
||||||
## Design Decisions
|
## Design Decisions
|
||||||
* Node.js was chosen currently due to familiarity.
|
* Node.js was chosen currently due to familiarity.
|
||||||
* Oceanic was chosen due to familiarity and the nature of everything not being abstracted out to 200 different classes unlike discord.js.
|
* Eris was chosen due to familiarity and the nature of everything not being abstracted out to 200 different classes unlike discord.js.
|
||||||
* "Jank" by design. While I don't expect anyone to actually use comcord on serial terminals or teletypes other than for meme factor, the option is still there.
|
* "Jank" by design. While I don't expect anyone to actually use comcord on serial terminals or teletypes other than for meme factor, the option is still there.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
@ -46,16 +38,12 @@ You **MUST** grant your bot all Privileged Gateway Intents.
|
||||||
- [x] Clear (c)
|
- [x] Clear (c)
|
||||||
- [ ] Surf channels forwards (>)
|
- [ ] Surf channels forwards (>)
|
||||||
- [ ] Surf channels backwards (<)
|
- [ ] Surf channels backwards (<)
|
||||||
- [x] AFK toggle (A)
|
|
||||||
- [x] Send DM (s)
|
|
||||||
- [x] Answer DM (a)
|
|
||||||
- [x] Message Receiving
|
- [x] Message Receiving
|
||||||
- [x] Markdown styling
|
- [ ] Markdown styling
|
||||||
- [ ] Common markdown (bold, italic, etc)
|
- [ ] Common markdown (bold, italic, etc)
|
||||||
- [ ] Figure out how spoilers would work
|
- [ ] Figure out how spoilers would work
|
||||||
- [x] Emotes?????
|
- [ ] Emotes?????
|
||||||
- [x] Timestamp parsing
|
- [ ] Timestamp parsing
|
||||||
- [x] Mentions parsing
|
|
||||||
- [ ] Embeds in the style of commode's posted links
|
- [ ] Embeds in the style of commode's posted links
|
||||||
- [x] Messages wrapped in `*`'s or `_`'s parsed as emotes
|
- [x] Messages wrapped in `*`'s or `_`'s parsed as emotes
|
||||||
- [ ] Inline DMs to replicate commode's private messages
|
- [ ] Inline DMs to replicate commode's private messages
|
||||||
|
@ -64,9 +52,8 @@ You **MUST** grant your bot all Privileged Gateway Intents.
|
||||||
- [x] Puts incoming messages into queue whilst in send mode
|
- [x] Puts incoming messages into queue whilst in send mode
|
||||||
- [ ] Mentions
|
- [ ] Mentions
|
||||||
- [ ] Replies
|
- [ ] Replies
|
||||||
- [x] Configuration
|
- [ ] Configuration
|
||||||
- [x] Default guild/channel
|
- [ ] Default guild/channel
|
||||||
- No way to set in client (yet?), `defaultChannel=` and `defaultGuild=` in your `.comcordrc`.
|
|
||||||
- [ ] Threads
|
- [ ] Threads
|
||||||
- [x] Not have the token just be in argv
|
- [ ] Not have the token just be in argv
|
||||||
- [x] Not have everything in one file
|
- [x] Not have everything in one file
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "4.1.2",
|
"chalk": "4.1.2",
|
||||||
"discord-rpc": "^4.0.1",
|
"discord-rpc": "^4.0.1",
|
||||||
"oceanic.js": "^1.1.2"
|
"eris": "github:abalabahaha/eris#dev"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
120
pnpm-lock.yaml
120
pnpm-lock.yaml
|
@ -3,47 +3,15 @@ lockfileVersion: 5.4
|
||||||
specifiers:
|
specifiers:
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
discord-rpc: ^4.0.1
|
discord-rpc: ^4.0.1
|
||||||
oceanic.js: ^1.1.2
|
eris: github:abalabahaha/eris#dev
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
discord-rpc: 4.0.1
|
discord-rpc: 4.0.1
|
||||||
oceanic.js: 1.1.2
|
eris: github.com/abalabahaha/eris/eb403730855714eafa36c541dbe2cb84c9979158
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
/@discordjs/voice/0.11.0:
|
|
||||||
resolution: {integrity: sha512-6+9cj1dxzBJm7WJ9qyG2XZZQ8rcLl6x2caW0C0OxuTtMLAaEDntpb6lqMTFiBg/rDc4Rd59g1w0gJmib33CuHw==}
|
|
||||||
engines: {node: '>=16.9.0'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@types/ws': 8.5.3
|
|
||||||
discord-api-types: 0.36.3
|
|
||||||
prism-media: 1.3.4
|
|
||||||
tslib: 2.4.0
|
|
||||||
ws: 8.9.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@discordjs/opus'
|
|
||||||
- bufferutil
|
|
||||||
- ffmpeg-static
|
|
||||||
- node-opus
|
|
||||||
- opusscript
|
|
||||||
- utf-8-validate
|
|
||||||
dev: false
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
/@types/node/18.8.3:
|
|
||||||
resolution: {integrity: sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==}
|
|
||||||
dev: false
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
/@types/ws/8.5.3:
|
|
||||||
resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==}
|
|
||||||
dependencies:
|
|
||||||
'@types/node': 18.8.3
|
|
||||||
dev: false
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
/ansi-styles/4.3.0:
|
/ansi-styles/4.3.0:
|
||||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -58,13 +26,6 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/busboy/1.6.0:
|
|
||||||
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
|
||||||
engines: {node: '>=10.16.0'}
|
|
||||||
dependencies:
|
|
||||||
streamsearch: 1.1.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/chalk/4.1.2:
|
/chalk/4.1.2:
|
||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -84,11 +45,6 @@ packages:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/discord-api-types/0.36.3:
|
|
||||||
resolution: {integrity: sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==}
|
|
||||||
dev: false
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
/discord-rpc/4.0.1:
|
/discord-rpc/4.0.1:
|
||||||
resolution: {integrity: sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA==}
|
resolution: {integrity: sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -129,47 +85,12 @@ packages:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/oceanic.js/1.1.2:
|
/opusscript/0.0.8:
|
||||||
resolution: {integrity: sha512-aABMK2UERHvyiwjWFx5m5ZZY7oPUHmVSOhICadZh/vqyxvGf48p+aqGlRu9bEtN6XZYPZJecQi/9IPN+phXn1Q==}
|
resolution: {integrity: sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ==}
|
||||||
engines: {node: '>=16.16.0'}
|
requiresBuild: true
|
||||||
dependencies:
|
|
||||||
undici: 5.11.0
|
|
||||||
ws: 8.9.0
|
|
||||||
optionalDependencies:
|
|
||||||
'@discordjs/voice': 0.11.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@discordjs/opus'
|
|
||||||
- bufferutil
|
|
||||||
- ffmpeg-static
|
|
||||||
- node-opus
|
|
||||||
- opusscript
|
|
||||||
- utf-8-validate
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/prism-media/1.3.4:
|
|
||||||
resolution: {integrity: sha512-eW7LXORkTCQznZs+eqe9VjGOrLBxcBPXgNyHXMTSRVhphvd/RrxgIR7WaWt4fkLuhshcdT5KHL88LAfcvS3f5g==}
|
|
||||||
peerDependencies:
|
|
||||||
'@discordjs/opus': ^0.8.0
|
|
||||||
ffmpeg-static: ^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0
|
|
||||||
node-opus: ^0.3.3
|
|
||||||
opusscript: ^0.0.8
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@discordjs/opus':
|
|
||||||
optional: true
|
|
||||||
ffmpeg-static:
|
|
||||||
optional: true
|
|
||||||
node-opus:
|
|
||||||
optional: true
|
|
||||||
opusscript:
|
|
||||||
optional: true
|
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/streamsearch/1.1.0:
|
|
||||||
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
|
||||||
engines: {node: '>=10.0.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/supports-color/7.2.0:
|
/supports-color/7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -181,18 +102,12 @@ packages:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/tslib/2.4.0:
|
/tweetnacl/1.0.3:
|
||||||
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
|
resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/undici/5.11.0:
|
|
||||||
resolution: {integrity: sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw==}
|
|
||||||
engines: {node: '>=12.18'}
|
|
||||||
dependencies:
|
|
||||||
busboy: 1.6.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/webidl-conversions/3.0.1:
|
/webidl-conversions/3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -217,8 +132,8 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/ws/8.9.0:
|
/ws/8.8.1:
|
||||||
resolution: {integrity: sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==}
|
resolution: {integrity: sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
bufferutil: ^4.0.1
|
bufferutil: ^4.0.1
|
||||||
|
@ -230,6 +145,21 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
github.com/abalabahaha/eris/eb403730855714eafa36c541dbe2cb84c9979158:
|
||||||
|
resolution: {tarball: https://codeload.github.com/abalabahaha/eris/tar.gz/eb403730855714eafa36c541dbe2cb84c9979158}
|
||||||
|
name: eris
|
||||||
|
version: 0.17.2-dev
|
||||||
|
engines: {node: '>=10.4.0'}
|
||||||
|
dependencies:
|
||||||
|
ws: 8.8.1
|
||||||
|
optionalDependencies:
|
||||||
|
opusscript: 0.0.8
|
||||||
|
tweetnacl: 1.0.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
dev: false
|
||||||
|
|
||||||
github.com/devsnek/node-register-scheme/e7cc9a63a1f512565da44cb57316d9fb10750e17:
|
github.com/devsnek/node-register-scheme/e7cc9a63a1f512565da44cb57316d9fb10750e17:
|
||||||
resolution: {tarball: https://codeload.github.com/devsnek/node-register-scheme/tar.gz/e7cc9a63a1f512565da44cb57316d9fb10750e17}
|
resolution: {tarball: https://codeload.github.com/devsnek/node-register-scheme/tar.gz/e7cc9a63a1f512565da44cb57316d9fb10750e17}
|
||||||
name: register-scheme
|
name: register-scheme
|
||||||
|
|
|
@ -4,13 +4,13 @@ const {updatePresence} = require("../lib/presence");
|
||||||
addCommand("A", "toggles AFK mode", function () {
|
addCommand("A", "toggles AFK mode", function () {
|
||||||
if (comcord.state.afk == true) {
|
if (comcord.state.afk == true) {
|
||||||
comcord.state.afk = false;
|
comcord.state.afk = false;
|
||||||
comcord.client.shards.forEach((shard) => (shard.presence.afk = false));
|
|
||||||
comcord.client.editStatus("online");
|
comcord.client.editStatus("online");
|
||||||
|
comcord.client.editAFK(false);
|
||||||
console.log("<you have returned>");
|
console.log("<you have returned>");
|
||||||
} else {
|
} else {
|
||||||
comcord.state.afk = true;
|
comcord.state.afk = true;
|
||||||
comcord.client.shards.forEach((shard) => (shard.presence.afk = true));
|
|
||||||
comcord.client.editStatus("idle");
|
comcord.client.editStatus("idle");
|
||||||
|
comcord.client.editAFK(true);
|
||||||
console.log("<you go AFK>");
|
console.log("<you go AFK>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ addCommand("e", "emote", function () {
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
process.stdout.write("\n");
|
process.stdout.write("\n");
|
||||||
await comcord.client.guilds
|
await comcord.client.createMessage(
|
||||||
.get(comcord.state.currentGuild)
|
comcord.state.currentChannel,
|
||||||
.channels.get(comcord.state.currentChannel)
|
`*${input}*`
|
||||||
.createMessage({content: `*${input}*`});
|
);
|
||||||
console.log(`<${comcord.client.user.username} ${input}>`);
|
console.log(`<${comcord.client.user.username} ${input}>`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("<failed to send message: " + err.message + ">");
|
console.log("<failed to send message: " + err.message + ">");
|
||||||
|
|
|
@ -8,10 +8,10 @@ async function getHistory(limit = 20) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = await comcord.client.guilds
|
const messages = await comcord.client.getMessages(
|
||||||
.get(comcord.state.currentGuild)
|
comcord.state.currentChannel,
|
||||||
.channels.get(comcord.state.currentChannel)
|
{limit}
|
||||||
.getMessages({limit});
|
);
|
||||||
messages.reverse();
|
messages.reverse();
|
||||||
|
|
||||||
console.log("--Beginning-Review".padEnd(72, "-"));
|
console.log("--Beginning-Review".padEnd(72, "-"));
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const Eris = require("eris");
|
||||||
|
|
||||||
const {addCommand} = require("../lib/command");
|
const {addCommand} = require("../lib/command");
|
||||||
|
|
||||||
function listChannels() {
|
function listChannels() {
|
||||||
|
@ -7,26 +9,34 @@ function listChannels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let longest = 0;
|
let longest = 0;
|
||||||
|
let longestTopic = 0;
|
||||||
const guild = comcord.client.guilds.get(comcord.state.currentGuild);
|
const guild = comcord.client.guilds.get(comcord.state.currentGuild);
|
||||||
const channels = [...guild.channels.values()].filter((c) => c.type == 0);
|
const channels = [...guild.channels.values()].filter((c) => c.type == 0);
|
||||||
channels.sort((a, b) => a.position - b.position);
|
channels.sort((a, b) => a.position - b.position);
|
||||||
|
|
||||||
for (const channel of channels) {
|
for (const channel of channels) {
|
||||||
const perms = channel.permissionsOf(comcord.client.user.id);
|
const perms = channel.permissionsOf(comcord.client.user.id);
|
||||||
const private = !perms.has("VIEW_CHANNEL");
|
const private = !perms.has(Eris.Constants.Permissions.readMessages);
|
||||||
|
|
||||||
if (channel.name.length + (private ? 1 : 0) > longest)
|
if (channel.name.length + (private ? 1 : 0) > longest)
|
||||||
longest = Math.min(25, channel.name.length + (private ? 1 : 0));
|
longest = Math.min(25, channel.name.length + (private ? 1 : 0));
|
||||||
|
if (channel.topic != null && channel.topic.length > longestTopic)
|
||||||
|
longestTopic = channel.topic.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log(" " + "channel-name".padStart(longest, " ") + " " + "topic");
|
console.log(
|
||||||
|
" " +
|
||||||
|
"channel-name".padStart(longest, " ") +
|
||||||
|
" " +
|
||||||
|
"topic".padStart(Math.min(80 - (longest + 5), longestTopic), " ")
|
||||||
|
);
|
||||||
console.log("-".repeat(80));
|
console.log("-".repeat(80));
|
||||||
for (const channel of channels) {
|
for (const channel of channels) {
|
||||||
const topic =
|
const topic =
|
||||||
channel.topic != null ? channel.topic.replace(/\n/g, " ") : "";
|
channel.topic != null ? channel.topic.replace(/\n/g, " ") : "";
|
||||||
const perms = channel.permissionsOf(comcord.client.user.id);
|
const perms = channel.permissionsOf(comcord.client.user.id);
|
||||||
const private = !perms.has("VIEW_CHANNEL");
|
const private = !perms.has(Eris.Constants.Permissions.readMessages);
|
||||||
|
|
||||||
const name = (private ? "*" : "") + channel.name;
|
const name = (private ? "*" : "") + channel.name;
|
||||||
|
|
||||||
|
@ -37,12 +47,11 @@ function listChannels() {
|
||||||
" "
|
" "
|
||||||
) +
|
) +
|
||||||
" " +
|
" " +
|
||||||
(topic.length > 80 - (longest + 5)
|
(topic.length > 80 - longest + 9
|
||||||
? topic.substring(0, 79 - (longest + 5)) + "\u2026"
|
? topic.substring(0, 79 - (longest + 5)) + "\u2026"
|
||||||
: topic)
|
: topic.padStart(Math.min(80 - (longest + 5), longestTopic), " "))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log("-".repeat(80));
|
|
||||||
console.log("");
|
console.log("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ function listGuilds() {
|
||||||
for (const guild of comcord.client.guilds.values()) {
|
for (const guild of comcord.client.guilds.values()) {
|
||||||
if (guild.name.length > longest) longest = guild.name.length;
|
if (guild.name.length > longest) longest = guild.name.length;
|
||||||
|
|
||||||
const online = [...guild.members.values()].filter((m) => m.presence).length;
|
const online = [...guild.members.values()].filter((m) => m.status).length;
|
||||||
guilds.push({name: guild.name, members: guild.memberCount, online});
|
guilds.push({name: guild.name, members: guild.memberCount, online});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ function listGuilds() {
|
||||||
guild.members.toString().padStart(5, " ")
|
guild.members.toString().padStart(5, " ")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log("-".repeat(80));
|
|
||||||
console.log("");
|
console.log("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,23 +39,22 @@ function listUsers() {
|
||||||
`\n[you are in '${guild.name}' in '${channel.name}' among ${guild.memberCount}]\n`
|
`\n[you are in '${guild.name}' in '${channel.name}' among ${guild.memberCount}]\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
const online = [...guild.members.values()].filter((m) => m.presence);
|
const online = [...guild.members.values()].filter((m) => m.status);
|
||||||
online.sort((a, b) => a.tag.localeCompare(b.tag));
|
online.sort((a, b) => a.name - b.name);
|
||||||
|
|
||||||
let longest = 0;
|
let longest = 0;
|
||||||
for (const member of online) {
|
for (const member of online) {
|
||||||
const name = member.tag;
|
const name = member.user.username + "#" + member.user.discriminator;
|
||||||
if (name.length + 3 > longest) longest = name.length + 3;
|
if (name.length + 3 > longest) longest = name.length + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = Math.floor(process.stdout.columns / longest);
|
const columns = Math.ceil(process.stdout.columns / longest);
|
||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (const member of online) {
|
for (const member of online) {
|
||||||
const name = member.tag;
|
const name = member.user.username + "#" + member.user.discriminator;
|
||||||
const status = getStatus(member.presence.status);
|
const status = getStatus(member.status);
|
||||||
const nameAndStatus =
|
const nameAndStatus = chalk.reset(name) + status;
|
||||||
(member.user.bot ? chalk.yellow(name) : chalk.reset(name)) + status;
|
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
const chalk = require("chalk");
|
|
||||||
|
|
||||||
const {addCommand} = require("../lib/command");
|
|
||||||
const {startPrompt} = require("../lib/prompt");
|
|
||||||
const {listUsers} = require("./listUsers");
|
|
||||||
|
|
||||||
function startDM(user) {
|
|
||||||
startPrompt(":msg> ", async function (input) {
|
|
||||||
if (input == "") {
|
|
||||||
console.log(`\n<message not sent to ${user.tag}>`);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const channel = await user.createDM();
|
|
||||||
await channel.createMessage({content: input});
|
|
||||||
console.log(chalk.bold.green(`\n<message sent to ${user.tag}>`));
|
|
||||||
} catch (err) {
|
|
||||||
console.log("\n<failed to send message: " + err.message + ">");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addCommand("s", "send private", function () {
|
|
||||||
console.log("Provide a RECIPIENT");
|
|
||||||
startPrompt(":to> ", function (who) {
|
|
||||||
let target;
|
|
||||||
for (const user of comcord.client.users.values()) {
|
|
||||||
if (user.tag == who) {
|
|
||||||
target = user;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target) {
|
|
||||||
console.log("");
|
|
||||||
startDM(target);
|
|
||||||
} else {
|
|
||||||
listUsers();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
addCommand("a", "answer a send", function () {
|
|
||||||
if (comcord.state.lastDM) {
|
|
||||||
console.log(chalk.bold.green(`<answering ${comcord.state.lastDM.tag}>`));
|
|
||||||
startDM(comcord.state.lastDM);
|
|
||||||
} else {
|
|
||||||
// FIXME: figure out the actual message in com
|
|
||||||
console.log("<no one to answer>");
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -21,10 +21,10 @@ function sendMode() {
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
process.stdout.write("\n");
|
process.stdout.write("\n");
|
||||||
await comcord.client.guilds
|
await comcord.client.createMessage(
|
||||||
.get(comcord.state.currentGuild)
|
comcord.state.currentChannel,
|
||||||
.channels.get(comcord.state.currentChannel)
|
input
|
||||||
.createMessage({content: input});
|
);
|
||||||
|
|
||||||
if (comcord.state.afk == true) {
|
if (comcord.state.afk == true) {
|
||||||
comcord.state.afk = false;
|
comcord.state.afk = false;
|
||||||
|
|
|
@ -56,5 +56,3 @@ function switchGuild(input) {
|
||||||
addCommand("G", "goto guild", function () {
|
addCommand("G", "goto guild", function () {
|
||||||
startPrompt(":guild> ", switchGuild);
|
startPrompt(":guild> ", switchGuild);
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {switchGuild};
|
|
||||||
|
|
252
src/index.js
252
src/index.js
|
@ -1,36 +1,15 @@
|
||||||
const {Client, Constants} = require("oceanic.js");
|
const Eris = require("eris");
|
||||||
const DiscordRPC = require("discord-rpc");
|
|
||||||
const chalk = require("chalk");
|
const chalk = require("chalk");
|
||||||
const fs = require("fs");
|
const DiscordRPC = require("discord-rpc");
|
||||||
|
|
||||||
const rcfile = require("./lib/rcfile");
|
|
||||||
const config = {};
|
|
||||||
|
|
||||||
if (fs.existsSync(rcfile.path)) {
|
|
||||||
console.log("% Reading " + rcfile.path + " ...");
|
|
||||||
rcfile.readFile(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CLIENT_ID = "1026163285877325874";
|
const CLIENT_ID = "1026163285877325874";
|
||||||
|
|
||||||
const token = process.argv[2];
|
const token = process.argv[2];
|
||||||
if (!config.token && token) {
|
|
||||||
console.log("% Writing token to .comcordrc");
|
|
||||||
config.token = token;
|
|
||||||
rcfile.writeFile(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.token && !token) {
|
|
||||||
console.log("No token provided.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.title = "comcord";
|
process.title = "comcord";
|
||||||
|
|
||||||
global.comcord = {
|
global.comcord = {
|
||||||
config,
|
|
||||||
state: {
|
state: {
|
||||||
rpcConnected: false,
|
|
||||||
startTime: Date.now(),
|
startTime: Date.now(),
|
||||||
currentGuild: null,
|
currentGuild: null,
|
||||||
currentChannel: null,
|
currentChannel: null,
|
||||||
|
@ -42,30 +21,10 @@ global.comcord = {
|
||||||
},
|
},
|
||||||
commands: {},
|
commands: {},
|
||||||
};
|
};
|
||||||
const client = new Client({
|
const client = new Eris("Bot " + token, {
|
||||||
auth:
|
|
||||||
(config.allowUserAccounts == "true" ? "" : "Bot ") +
|
|
||||||
(token ?? config.token),
|
|
||||||
defaultImageFormat: "png",
|
defaultImageFormat: "png",
|
||||||
defaultImageSize: 1024,
|
defaultImageSize: 1024,
|
||||||
gateway: {
|
intents: Eris.Constants.Intents.all,
|
||||||
intents: ["ALL"],
|
|
||||||
maxShards: 1,
|
|
||||||
concurrency: 1,
|
|
||||||
presence: {
|
|
||||||
status: "online",
|
|
||||||
activities: [
|
|
||||||
{
|
|
||||||
name: "comcord",
|
|
||||||
type: 0,
|
|
||||||
application_id: CLIENT_ID,
|
|
||||||
timestamps: {
|
|
||||||
start: comcord.state.startTime,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
comcord.client = client;
|
comcord.client = client;
|
||||||
const rpc = new DiscordRPC.Client({transport: "ipc"});
|
const rpc = new DiscordRPC.Client({transport: "ipc"});
|
||||||
|
@ -81,11 +40,10 @@ require("./commands/help");
|
||||||
const {sendMode} = require("./commands/send");
|
const {sendMode} = require("./commands/send");
|
||||||
require("./commands/emote");
|
require("./commands/emote");
|
||||||
const {listGuilds} = require("./commands/listGuilds");
|
const {listGuilds} = require("./commands/listGuilds");
|
||||||
const {switchGuild} = require("./commands/switchGuild"); // loads listChannels and listUsers
|
require("./commands/switchGuild"); // loads listChannels and listUsers
|
||||||
require("./commands/switchChannel"); //loads listUsers
|
require("./commands/switchChannel"); //loads listUsers
|
||||||
require("./commands/history"); // includes extended history
|
require("./commands/history"); // includes extended history
|
||||||
require("./commands/afk");
|
require("./commands/afk");
|
||||||
require("./commands/privateMessages");
|
|
||||||
|
|
||||||
process.stdin.setRawMode(true);
|
process.stdin.setRawMode(true);
|
||||||
process.stdin.resume();
|
process.stdin.resume();
|
||||||
|
@ -93,118 +51,63 @@ process.stdin.setEncoding("utf8");
|
||||||
|
|
||||||
client.once("ready", function () {
|
client.once("ready", function () {
|
||||||
console.log(
|
console.log(
|
||||||
"Logged in as: " + chalk.yellow(`${client.user.tag} (${client.user.id})`)
|
"Logged in as: " +
|
||||||
|
chalk.yellow(
|
||||||
|
`${client.user.username}#${client.user.discriminator} (${client.user.id})`
|
||||||
|
)
|
||||||
);
|
);
|
||||||
comcord.state.nameLength = client.user.username.length + 2;
|
comcord.state.nameLength = client.user.username.length + 2;
|
||||||
|
|
||||||
listGuilds();
|
listGuilds();
|
||||||
|
|
||||||
if (config.defaultGuild) {
|
client.editStatus("online", [
|
||||||
const guild = client.guilds.get(config.defaultGuild);
|
{
|
||||||
if (guild != null) {
|
application_id: CLIENT_ID,
|
||||||
if (config.defaultChannel) {
|
name: "comcord",
|
||||||
comcord.state.currentChannel = config.defaultChannel;
|
timestamps: {
|
||||||
comcord.state.lastChannel.set(
|
start: comcord.state.startTime,
|
||||||
config.defaultGuild,
|
},
|
||||||
config.defaultChannel
|
},
|
||||||
);
|
]);
|
||||||
}
|
|
||||||
switchGuild(guild.name);
|
|
||||||
} else {
|
|
||||||
console.log("% This account is not in the defined default guild.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (config.defaultChannel) {
|
|
||||||
console.log("% Default channel defined without defining default guild.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client.user.bot) {
|
rpc
|
||||||
rpc
|
.login({
|
||||||
.login({
|
clientId: CLIENT_ID,
|
||||||
clientId: CLIENT_ID,
|
})
|
||||||
})
|
.catch(function () {});
|
||||||
.catch(function () {});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
client.on("error", function () {});
|
client.on("error", function () {});
|
||||||
|
|
||||||
rpc.on("connected", function () {
|
rpc.on("connected", function () {
|
||||||
comcord.state.rpcConnected = true;
|
|
||||||
updatePresence();
|
updatePresence();
|
||||||
});
|
});
|
||||||
let retryingRPC = false;
|
|
||||||
rpc.once("ready", function () {
|
rpc.once("ready", function () {
|
||||||
rpc.transport.on("close", function () {
|
rpc.transport.on("close", async function () {
|
||||||
comcord.state.rpcConnected = false;
|
try {
|
||||||
if (!retryingRPC) {
|
await rpc.transport.connect();
|
||||||
retryingRPC = true;
|
} catch (err) {
|
||||||
setTimeout(function () {
|
rpc.transport.emit("close");
|
||||||
rpc.transport
|
|
||||||
.connect()
|
|
||||||
.then(() => {
|
|
||||||
retryingRPC = false;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
retryingRPC = false;
|
|
||||||
rpc.transport.emit("close");
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
rpc.on("error", function () {});
|
rpc.on("error", function () {});
|
||||||
|
|
||||||
client.on("messageCreate", async function (msg) {
|
client.on("messageCreate", function (msg) {
|
||||||
if (msg.author.id === client.user.id) return;
|
if (msg.author.id === client.user.id) return;
|
||||||
|
|
||||||
if (msg.channelID && !msg.channel) {
|
if (msg.channel.id == comcord.state.currentChannel) {
|
||||||
try {
|
|
||||||
const dmChannel = await msg.author.createDM();
|
|
||||||
if (dmChannel.id === msg.channelID) {
|
|
||||||
msg.channel = dmChannel;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(msg.channel ? msg.channel.id : msg.channelID) ==
|
|
||||||
comcord.state.currentChannel ||
|
|
||||||
msg.channel?.recipient != null
|
|
||||||
) {
|
|
||||||
if (comcord.state.inPrompt) {
|
if (comcord.state.inPrompt) {
|
||||||
comcord.state.messageQueue.push(msg);
|
comcord.state.messageQueue.push(msg);
|
||||||
} else {
|
} else {
|
||||||
processMessage(msg);
|
processMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.channel?.recipient != null) {
|
|
||||||
comcord.state.lastDM = msg.author;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
client.on("messageUpdate", async function (msg, old) {
|
client.on("messageUpdate", function (msg, old) {
|
||||||
if (msg.author.id === client.user.id) return;
|
if (msg.author.id === client.user.id) return;
|
||||||
|
|
||||||
if (msg.channelID && !msg.channel) {
|
if (msg.channel.id == comcord.state.currentChannel) {
|
||||||
try {
|
if (msg.content == old.content) return;
|
||||||
const dmChannel = await msg.author.createDM();
|
|
||||||
if (dmChannel.id === msg.channelID) {
|
|
||||||
msg.channel = dmChannel;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(msg.channel ? msg.channel.id : msg.channelID) ==
|
|
||||||
comcord.state.currentChannel ||
|
|
||||||
msg.channel?.recipient != null
|
|
||||||
) {
|
|
||||||
if (old && msg.content == old.content) return;
|
|
||||||
|
|
||||||
if (comcord.state.inPrompt) {
|
if (comcord.state.inPrompt) {
|
||||||
comcord.state.messageQueue.push(msg);
|
comcord.state.messageQueue.push(msg);
|
||||||
|
@ -212,10 +115,6 @@ client.on("messageUpdate", async function (msg, old) {
|
||||||
processMessage(msg);
|
processMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.channel?.recipient != null) {
|
|
||||||
comcord.state.lastDM = msg.author;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
process.stdin.on("data", async function (key) {
|
process.stdin.on("data", async function (key) {
|
||||||
|
@ -249,89 +148,7 @@ process.stdin.on("data", async function (key) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
client.connect();
|
||||||
config.allowUserAccounts == "true" &&
|
|
||||||
!(token ?? config.token).startsWith("Bot ")
|
|
||||||
) {
|
|
||||||
if (fetch == null) {
|
|
||||||
console.log("Node v18+ needed for user account support.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
comcord.clientSpoof = require("./lib/clientSpoof");
|
|
||||||
const superProperties = await comcord.clientSpoof.getSuperProperties();
|
|
||||||
|
|
||||||
console.log("% Allowing non-bot tokens to connect");
|
|
||||||
const connectLines = client.connect.toString().split("\n");
|
|
||||||
connectLines.splice(0, 4);
|
|
||||||
connectLines.splice(-1, 1);
|
|
||||||
|
|
||||||
const newConnect = new client.connect.constructor(connectLines.join("\n"));
|
|
||||||
client.connect = newConnect.bind(client);
|
|
||||||
|
|
||||||
// gross hack
|
|
||||||
global.Constants_1 = Constants;
|
|
||||||
try {
|
|
||||||
global.Erlpack = require("erlpack");
|
|
||||||
} catch {
|
|
||||||
global.Erlpack = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("% Injecting headers into request handler");
|
|
||||||
client.rest.handler.options.userAgent = `Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/${superProperties.client_version} Chrome/91.0.4472.164 Electron/13.6.6 Safari/537.36`;
|
|
||||||
client.rest.handler._request = client.rest.handler.request.bind(
|
|
||||||
client.rest.handler
|
|
||||||
);
|
|
||||||
client.rest.handler.request = async function (options) {
|
|
||||||
options.headers = options.headers ?? {};
|
|
||||||
options.headers["X-Super-Properties"] =
|
|
||||||
await comcord.clientSpoof.getSuperPropertiesBase64();
|
|
||||||
|
|
||||||
return await this._request.apply(this, [options]);
|
|
||||||
}.bind(client.rest.handler);
|
|
||||||
|
|
||||||
console.log("% Setting gateway connection properties");
|
|
||||||
client.shards.options.connectionProperties = superProperties;
|
|
||||||
|
|
||||||
console.log("% Injecting application into READY payload");
|
|
||||||
client.shards._spawn = client.shards.spawn.bind(client.shards);
|
|
||||||
client.shards.spawn = function (id) {
|
|
||||||
const res = this._spawn.apply(this, [id]);
|
|
||||||
const shard = this.get(id);
|
|
||||||
if (shard) {
|
|
||||||
shard._onDispatch = shard.onDispatch.bind(shard);
|
|
||||||
shard.onDispatch = async function (packet) {
|
|
||||||
if (packet.t == "READY") {
|
|
||||||
packet.d.application = {id: CLIENT_ID, flags: 565248};
|
|
||||||
}
|
|
||||||
|
|
||||||
const ret = await this._onDispatch.apply(this, [packet]);
|
|
||||||
|
|
||||||
if (packet.t == "READY") {
|
|
||||||
for (const guild of packet.d.guilds) {
|
|
||||||
await this._onDispatch.apply(this, [
|
|
||||||
{
|
|
||||||
t: "GUILD_CREATE",
|
|
||||||
d: guild,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}.bind(shard);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}.bind(client.shards);
|
|
||||||
|
|
||||||
console.log("% Connecting to gateway now");
|
|
||||||
await client.connect();
|
|
||||||
})();
|
|
||||||
} else {
|
|
||||||
client.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("COMcord (c)left 2022");
|
console.log("COMcord (c)left 2022");
|
||||||
console.log("Type 'h' for Commands");
|
console.log("Type 'h' for Commands");
|
||||||
|
@ -380,7 +197,6 @@ setInterval(function () {
|
||||||
} else {
|
} else {
|
||||||
console.log(timeString);
|
console.log(timeString);
|
||||||
}
|
}
|
||||||
comcord.state.nameLength = client.user.username.length + 2;
|
|
||||||
sentTime = true;
|
sentTime = true;
|
||||||
} else if (seconds > 2 && sentTime) {
|
} else if (seconds > 2 && sentTime) {
|
||||||
sentTime = false;
|
sentTime = false;
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* This single file is **EXCLUDED** from the project license.
|
|
||||||
*
|
|
||||||
* (c) 2022 Cynthia Foxwell, all rights reserved.
|
|
||||||
* Permission is hereby granted to redistribute this file ONLY with copies of comcord.
|
|
||||||
* You may not reverse engineer, modify, copy, or redistribute this file for any other uses outside of comcord.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const os = require("os");
|
|
||||||
|
|
||||||
async function fetchMainPage() {
|
|
||||||
const res = await fetch("https://discord.com/channels/@me");
|
|
||||||
return await res.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchAsset(assetPath) {
|
|
||||||
return await fetch("https://discord.com/" + assetPath).then((res) =>
|
|
||||||
res.text()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MATCH_SCRIPT = '<script src="(.+?)" integrity=".+?">';
|
|
||||||
const REGEX_SCRIPT = new RegExp(MATCH_SCRIPT);
|
|
||||||
const REGEX_SCRIPT_GLOBAL = new RegExp(MATCH_SCRIPT, "g");
|
|
||||||
|
|
||||||
async function extractScripts() {
|
|
||||||
const mainPage = await fetchMainPage();
|
|
||||||
|
|
||||||
return mainPage
|
|
||||||
.match(REGEX_SCRIPT_GLOBAL)
|
|
||||||
.map((script) => script.match(REGEX_SCRIPT)[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const REGEX_BUILD_NUMBER = /Build Number: (\d+), Version Hash:/;
|
|
||||||
const REGEX_BUILD_NUMBER_SWC = /Build Number: "\).concat\("(\d+)"/;
|
|
||||||
|
|
||||||
async function getBuildNumber() {
|
|
||||||
if (comcord.state.cachedBuildNumber) {
|
|
||||||
return comcord.state.cachedBuildNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
const scripts = await extractScripts();
|
|
||||||
const chunkWithBuildInfoAsset = scripts[3];
|
|
||||||
const chunkWithBuildInfo = await fetchAsset(chunkWithBuildInfoAsset);
|
|
||||||
|
|
||||||
const buildNumber =
|
|
||||||
chunkWithBuildInfo.match(REGEX_BUILD_NUMBER_SWC)?.[1] ??
|
|
||||||
chunkWithBuildInfo.match(REGEX_BUILD_NUMBER)?.[1];
|
|
||||||
comcord.state.cachedBuildNumber = buildNumber;
|
|
||||||
|
|
||||||
return buildNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getClientVersion() {
|
|
||||||
if (comcord.state.cachedClientVersion) {
|
|
||||||
return comcord.state.cachedClientVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await fetch(
|
|
||||||
"https://updates.discord.com/distributions/app/manifests/latest?channel=stable&platform=win&arch=x86"
|
|
||||||
).then((res) => res.json());
|
|
||||||
const clientVersion = data.full.host_version.join(".");
|
|
||||||
comcord.state.cachedClientVersion = clientVersion;
|
|
||||||
|
|
||||||
return clientVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getSuperProperties() {
|
|
||||||
const buildNumber = await getBuildNumber();
|
|
||||||
const clientVersion = await getClientVersion();
|
|
||||||
|
|
||||||
let _os;
|
|
||||||
switch (process.platform) {
|
|
||||||
case "win32":
|
|
||||||
_os = "Windows";
|
|
||||||
break;
|
|
||||||
case "darwin":
|
|
||||||
_os = "Mac OS X";
|
|
||||||
break;
|
|
||||||
case "linux":
|
|
||||||
_os = "Linux";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_os = process.platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = {
|
|
||||||
os: _os,
|
|
||||||
browser: "Discord Client",
|
|
||||||
releaseChannel: "stable",
|
|
||||||
client_version: clientVersion,
|
|
||||||
os_version: os.release(),
|
|
||||||
os_arch: os.arch(),
|
|
||||||
system_locale: "en-US",
|
|
||||||
client_build_number: buildNumber,
|
|
||||||
client_event_source: null,
|
|
||||||
};
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getSuperPropertiesBase64() {
|
|
||||||
return Buffer.from(JSON.stringify(await getSuperProperties())).toString(
|
|
||||||
"base64"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {getSuperProperties, getSuperPropertiesBase64};
|
|
|
@ -155,7 +155,6 @@ function replaceTimestamps(_, time, format = "f") {
|
||||||
|
|
||||||
function formatMessage({
|
function formatMessage({
|
||||||
name,
|
name,
|
||||||
tag,
|
|
||||||
content,
|
content,
|
||||||
bot,
|
bot,
|
||||||
attachments,
|
attachments,
|
||||||
|
@ -164,7 +163,6 @@ function formatMessage({
|
||||||
noColor = false,
|
noColor = false,
|
||||||
dump = false,
|
dump = false,
|
||||||
history = false,
|
history = false,
|
||||||
dm = false,
|
|
||||||
}) {
|
}) {
|
||||||
if (name.length + 2 > comcord.state.nameLength)
|
if (name.length + 2 > comcord.state.nameLength)
|
||||||
comcord.state.nameLength = name.length + 2;
|
comcord.state.nameLength = name.length + 2;
|
||||||
|
@ -182,9 +180,9 @@ function formatMessage({
|
||||||
.replace(REGEX_EMOTE, replaceEmotes)
|
.replace(REGEX_EMOTE, replaceEmotes)
|
||||||
.replace(REGEX_COMMAND, replaceCommands)
|
.replace(REGEX_COMMAND, replaceCommands)
|
||||||
.replace(REGEX_TIMESTAMP, replaceTimestamps);
|
.replace(REGEX_TIMESTAMP, replaceTimestamps);
|
||||||
if (reply.attachments.size > 0) {
|
if (reply.attachments.length > 0) {
|
||||||
replyContent += ` <${reply.attachments.size} attachment${
|
replyContent += `<${reply.attachments.length} attachment${
|
||||||
reply.attachments.size > 1 ? "s" : ""
|
reply.attachments.length > 1 ? "s" : ""
|
||||||
}>`;
|
}>`;
|
||||||
replyContent = replyContent.trim();
|
replyContent = replyContent.trim();
|
||||||
}
|
}
|
||||||
|
@ -250,15 +248,7 @@ function formatMessage({
|
||||||
.replace(REGEX_COMMAND, replaceCommands)
|
.replace(REGEX_COMMAND, replaceCommands)
|
||||||
.replace(REGEX_TIMESTAMP, replaceTimestamps);
|
.replace(REGEX_TIMESTAMP, replaceTimestamps);
|
||||||
|
|
||||||
if (dm) {
|
if (
|
||||||
if (noColor) {
|
|
||||||
console.log(`*${tag}* ${content}\x07`);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
chalk.bold.red(`*${tag}*`) + chalk.reset(" " + content + "\x07")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
(content.length > 1 &&
|
(content.length > 1 &&
|
||||||
content.startsWith("*") &&
|
content.startsWith("*") &&
|
||||||
content.endsWith("*")) ||
|
content.endsWith("*")) ||
|
||||||
|
@ -294,7 +284,7 @@ function formatMessage({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachments) {
|
if (attachments) {
|
||||||
for (const attachment of attachments.values()) {
|
for (const attachment of attachments) {
|
||||||
if (noColor) {
|
if (noColor) {
|
||||||
console.log(`<attachment: ${attachment.url} >`);
|
console.log(`<attachment: ${attachment.url} >`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -320,18 +310,13 @@ function formatMessage({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processMessage(msg, options = {}) {
|
function processMessage(msg, options) {
|
||||||
if (msg.channel?.recipient) {
|
|
||||||
options.dm = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.time) {
|
if (msg.time) {
|
||||||
console.log(msg.content);
|
console.log(msg.content);
|
||||||
} else if (msg.content && msg.content.indexOf("\n") > -1) {
|
} else if (msg.content.indexOf("\n") > -1) {
|
||||||
if (msg.content.match(REGEX_CODEBLOCK)) {
|
if (msg.content.match(REGEX_CODEBLOCK)) {
|
||||||
formatMessage({
|
formatMessage({
|
||||||
name: msg.author.username,
|
name: msg.author.username,
|
||||||
tag: msg.author.tag,
|
|
||||||
bot: msg.author.bot,
|
bot: msg.author.bot,
|
||||||
content: msg.content.replace(
|
content: msg.content.replace(
|
||||||
REGEX_CODEBLOCK_GLOBAL,
|
REGEX_CODEBLOCK_GLOBAL,
|
||||||
|
@ -349,7 +334,6 @@ function processMessage(msg, options = {}) {
|
||||||
const line = lines[index];
|
const line = lines[index];
|
||||||
formatMessage({
|
formatMessage({
|
||||||
name: msg.author.username,
|
name: msg.author.username,
|
||||||
tag: msg.author.tag,
|
|
||||||
bot: msg.author.bot,
|
bot: msg.author.bot,
|
||||||
content:
|
content:
|
||||||
line +
|
line +
|
||||||
|
@ -366,7 +350,6 @@ function processMessage(msg, options = {}) {
|
||||||
} else {
|
} else {
|
||||||
formatMessage({
|
formatMessage({
|
||||||
name: msg.author.username,
|
name: msg.author.username,
|
||||||
tag: msg.author.tag,
|
|
||||||
bot: msg.author.bot,
|
bot: msg.author.bot,
|
||||||
content: msg.content + (msg.editedTimestamp != null ? " (edited)" : ""),
|
content: msg.content + (msg.editedTimestamp != null ? " (edited)" : ""),
|
||||||
attachments: msg.attachments,
|
attachments: msg.attachments,
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const CLIENT_ID = "1026163285877325874";
|
|
||||||
|
|
||||||
function updatePresence() {
|
function updatePresence() {
|
||||||
let guild, channel;
|
let guild, channel;
|
||||||
if (comcord.state.currentGuild != null) {
|
if (comcord.state.currentGuild != null) {
|
||||||
|
@ -9,54 +7,19 @@ function updatePresence() {
|
||||||
channel = guild.channels.get(comcord.state.currentChannel);
|
channel = guild.channels.get(comcord.state.currentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comcord.client.user.bot) {
|
try {
|
||||||
if (comcord.state.rpcConnected) {
|
|
||||||
try {
|
|
||||||
const activity = {
|
|
||||||
startTimestamp: comcord.state.startTime,
|
|
||||||
smallImageKey: `https://cdn.discordapp.com/avatars/${comcord.client.user.id}/${comcord.client.user.avatar}.png?size=1024`,
|
|
||||||
smallImageText: comcord.client.user.tag,
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: "comcord Repo",
|
|
||||||
url: "https://github.com/Cynosphere/comcord",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (guild != null) {
|
|
||||||
activity.largeImageKey = `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=1024`;
|
|
||||||
activity.largeImageText = guild.name;
|
|
||||||
if (channel != null) {
|
|
||||||
activity.details = `#${channel.name} - ${guild.name}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (comcord.state.afk == true) {
|
|
||||||
activity.state = "AFK";
|
|
||||||
}
|
|
||||||
comcord.rpc.setActivity(activity);
|
|
||||||
} catch (err) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const activity = {
|
const activity = {
|
||||||
application_id: CLIENT_ID,
|
startTimestamp: comcord.state.startTime,
|
||||||
name: "comcord",
|
smallImageKey: `https://cdn.discordapp.com/avatars/${comcord.client.user.id}/${comcord.client.user.avatar}.png?size=1024`,
|
||||||
timestamps: {
|
smallImageText: `${comcord.client.user.username}#${comcord.client.user.discriminator}`,
|
||||||
start: comcord.state.startTime,
|
buttons: [
|
||||||
},
|
{label: "comcord Repo", url: "https://github.com/Cynosphere/comcord"},
|
||||||
assets: {},
|
],
|
||||||
buttons: ["comcord Repo"],
|
|
||||||
metadata: {
|
|
||||||
button_urls: ["https://github.com/Cynosphere/comcord"],
|
|
||||||
},
|
|
||||||
type: 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (guild != null) {
|
if (guild != null) {
|
||||||
activity.assets.large_image = `mp:icons/${guild.id}/${guild.icon}.png?size=1024`;
|
activity.largeImageKey = `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=1024`;
|
||||||
activity.assets.large_text = guild.name;
|
activity.largeImageText = guild.name;
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
activity.details = `#${channel.name} - ${guild.name}`;
|
activity.details = `#${channel.name} - ${guild.name}`;
|
||||||
}
|
}
|
||||||
|
@ -64,13 +27,9 @@ function updatePresence() {
|
||||||
if (comcord.state.afk == true) {
|
if (comcord.state.afk == true) {
|
||||||
activity.state = "AFK";
|
activity.state = "AFK";
|
||||||
}
|
}
|
||||||
|
comcord.rpc.setActivity(activity);
|
||||||
comcord.client.shards.forEach((shard) => {
|
} catch (err) {
|
||||||
if (shard.ready) {
|
//
|
||||||
shard.presence.activities = [activity];
|
|
||||||
shard.sendPresenceUpdate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const os = require("os");
|
|
||||||
|
|
||||||
const RCPATH = path.resolve(os.homedir(), ".comcordrc");
|
|
||||||
|
|
||||||
function readFile(config) {
|
|
||||||
const rc = fs.readFileSync(RCPATH, "utf8");
|
|
||||||
const lines = rc.split("\n");
|
|
||||||
for (const line of lines) {
|
|
||||||
const [key, value] = line.split("=");
|
|
||||||
config[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeFile(config) {
|
|
||||||
if (fs.existsSync(RCPATH)) {
|
|
||||||
readFile(config);
|
|
||||||
}
|
|
||||||
const newrc = [];
|
|
||||||
|
|
||||||
for (const key in config) {
|
|
||||||
const value = config[key];
|
|
||||||
newrc.push(`${key}=${value}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(RCPATH, newrc.join("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {readFile, writeFile, path: RCPATH};
|
|
Loading…
Reference in a new issue