diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 7d832ed8..00000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- /*
- 3urobeat's EsLint Config. Requires eslint & eslint-plugin-jsdoc to be installed as devDependencies.
- https://github.com/3urobeat
- */
-
- "env": {
- "commonjs": true,
- "es6": true,
- "node": true
- },
- "extends": "eslint:recommended",
- "globals": {
- "Atomics": "readonly",
- "SharedArrayBuffer": "readonly",
-
- "started": true,
- "srcdir": true,
- "botisloggedin": true,
- "logger": true,
- "extdata": true
- },
- "parserOptions": {
- "ecmaVersion": 11
- },
- "plugins": [
- "jsdoc"
- ],
- "rules": {
- "no-var": "error",
- "no-redeclare": "off",
- "no-unreachable": "error",
- "no-unexpected-multiline": "error",
-
- // Styling
- "camelcase": "warn",
- "capitalized-comments": ["warn", "always", { "ignoreConsecutiveComments": true }],
- "comma-spacing": ["warn", { "before": false, "after": true }],
- "func-call-spacing": ["error", "never"],
- "indent": ["error", 4, { "ignoredNodes": ["IfStatement"], "SwitchCase": 1 }], // TODO: This also ignores if statements with wrong indentation but I couldn't get it to only ignore else in if-else one-liner
- "no-tabs": "error",
- "no-trailing-spaces": "error",
- "no-extra-semi": "error",
- "semi": ["error", "always"],
- "semi-spacing": "error",
- "semi-style": ["error", "last"],
- "quotes": ["error", "double", { "avoidEscape": true }],
- "spaced-comment": "warn",
-
- // JsDoc - https://github.com/gajus/eslint-plugin-jsdoc
- "jsdoc/check-alignment": "warn",
- "jsdoc/check-indentation": "warn",
- "jsdoc/check-types": "warn",
- "jsdoc/informative-docs": "warn",
- "jsdoc/require-asterisk-prefix": "warn",
- "jsdoc/require-description": "warn",
- "jsdoc/require-jsdoc": "warn",
- "jsdoc/require-param": "warn",
- "jsdoc/require-param-name": "warn",
- "jsdoc/valid-types": "warn",
- //"jsdoc/require-returns": "warn", // Always requires @return, even when function does not return something
- "jsdoc/require-returns-type": "warn",
- //"jsdoc/require-returns-check": "warn", // Unnecessary when require-returns above is disabled
- "jsdoc/require-returns-description": "warn"
- },
- "ignorePatterns": ["src/libraryPatches/*"]
-}
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 51193322..f7904293 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,17 +1,17 @@
---
-name: Bug report
-about: Report an error/a problem you experienced
+name: Bug Report
+about: Report an error or problem you've experienced
title: ''
labels: Bug
assignees: ''
---
-**Describe the bug**
+**Please describe the bug**
What happened?
-**Full error**
-Please post the **complete** error here!
+**Full error stack trace**
+If you've got an error, please post the **entire** error stack trace here!
**Additional context**
-Please add any other information here if you have some.
+Please add any other information here, if you have some.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 0de37c24..30b33bd9 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,5 +1,5 @@
---
-name: Feature request
+name: Feature Request
about: Suggest a feature idea
title: ''
labels: Enhancement
@@ -11,4 +11,4 @@ assignees: ''
A clear description of what should happen.
**Additional context**
-Add any other context or screenshots about the feature request here.
+Please add any other information here, if you have some.
diff --git a/.github/ISSUE_TEMPLATE/help-wanted-question.md b/.github/ISSUE_TEMPLATE/help-wanted-question.md
index cd272ede..3593dce4 100644
--- a/.github/ISSUE_TEMPLATE/help-wanted-question.md
+++ b/.github/ISSUE_TEMPLATE/help-wanted-question.md
@@ -1,5 +1,5 @@
---
-name: Help wanted/Question
+name: I need help
about: I have a question/need help but a Q&A discussion isn't fitting
title: ''
labels: Question
@@ -11,4 +11,4 @@ assignees: ''
Please explain your question here. If you've got an error or something else related, then please include it here as well.
**Additional information**
-Please add any other information here if you have some.
+Please add any other information here, if you have some.
diff --git a/advancedconfig.json b/advancedconfig.json
index b011cc06..e5abee25 100644
--- a/advancedconfig.json
+++ b/advancedconfig.json
@@ -10,6 +10,7 @@
"relogTimeout": 900000,
"maxLogOnRetries": 1,
"useLocalIP": true,
+ "enableRelogOnLogOnSessionReplaced": true,
"dummy1": "------------------- General Settings: -------------------",
"acceptFriendRequests": true,
"forceFriendlistSpaceTime": 4,
diff --git a/docs/dev/controller/events.md b/docs/dev/controller/events.md
index 2d8d697e..f60c9fc3 100644
--- a/docs/dev/controller/events.md
+++ b/docs/dev/controller/events.md
@@ -49,3 +49,10 @@ The event is emitted with the parameters
The `submitCode` function allows users to implement accepting Steam Guard Codes from users into their plugins. This is very cool.
Check out how the [template plugin](https://github.com/3urobeat/steam-comment-bot-template-plugin/blob/main/plugin.js) implements the
`steamGuardInput` event function (which is called by the PluginSystem when the event is emitted, instead of listening directly to it).
+
+## steamGuardQrCode
+This event is emitted when any bot account is trying to log in using a QR-Code. A user needs to scan this QR-Code using their Steam Mobile App to confirm the login request.
+
+The event is emitted with the parameters
+- `bot` ([Bot](../bot/bot.md)) - Bot instance of the affected account
+- `challengeUrl` (string) - The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App.
diff --git a/docs/wiki/advancedconfig_doc.md b/docs/wiki/advancedconfig_doc.md
index d4eab5af..d1696816 100644
--- a/docs/wiki/advancedconfig_doc.md
+++ b/docs/wiki/advancedconfig_doc.md
@@ -22,6 +22,7 @@ This is the full documentation to customize your `advancedconfig.json`.
| relogTimeout | Number in ms | Time the bot will wait after failing all reconnect attempts before trying again. Default: 900000 (15 minutes) |
| maxLogOnRetries | Number | Amount of times the bot will retry logging in to an account if the first try fails. Default: 1 |
| useLocalIP | true or false | If the bot should use your real IP as well when using proxies. Default: true |
+| enableRelogOnLogOnSessionReplaced | true or false | If the bot should relog accounts when they loose connection with the error message 'LogOnSessionReplaced'. This error is usually caused when someone logs into an account from somewhere else. Default: true |
| | | |
| acceptFriendRequests | true or false | If the bot should accept friend requests. Default: true |
| forceFriendlistSpaceTime | Number in days | Amount of days a user hasn't requested something to get unfriended if only one friend slot is left. Set to 0 to disable. Default: 4 |
diff --git a/docs/wiki/changelogs/CHANGELOG_v2.15.md b/docs/wiki/changelogs/CHANGELOG_v2.15.md
index 52a11c8d..e73ab4b5 100644
--- a/docs/wiki/changelogs/CHANGELOG_v2.15.md
+++ b/docs/wiki/changelogs/CHANGELOG_v2.15.md
@@ -6,6 +6,7 @@
**Current**
- [2.15.0](#2.15.0)
- [2.15.1](#2.15.1)
+- [2.15.2](#2.15.2)
@@ -158,3 +159,40 @@ Commit: [be41d68](https://github.com/3urobeat/steam-comment-service-bot/commit/b
- Reduced chances of startup ascii art showing an easter egg ascii art
- Updated dependencies
- Minor other changes
+
+Commit: [a8a04eb](https://github.com/3urobeat/steam-comment-service-bot/commit/a8a04eb)
+
+
+
+
+
+## **2024-05-09, Version 2.15.2**
+**Additions:**
+- Added traditional chinese translation [@Tira-tw](https://github.com/Tira-tw) in [#242](https://github.com/3urobeat/steam-comment-service-bot/pull/242)
+- Added !add alias to !addfriend command
+- Added steamGuardQrCode event to enable plugins to resolve Steam Guard QR-Code requests
+- Added more login related log messages to default log level
+- Added more login related debug log messages to improve ability to debug login process resolving issues
+- Added (experimental) force-resolve feature to login process when inactivity is detected
+- Added setting 'enableRelogOnLogOnSessionReplaced' to `advancedconfig.json` to control whether the bot should relog accounts that have lost their connection with the error 'LogOnSessionReplaced'. Default value is `true`. To retain the same behavior as previously, where the bot would skip those accounts, set the value to `false`.
+
+**Fixes:**
+- Fixed login starting faster than plugin load, making it unable for them to handle steamGuardCode events
+- Fixed proxy switcher not switching to proxy 0
+- Fixed default quotes file containing a political entry
+- (Potentially) finally fixed 'Already logged on, cannot log on again' errors when relogging for good
+- Fixed potential login softlock when account switches proxy while a login process is active, with that account queued in it
+- Fixed wrong syntax of variable in language string 'addfriendcmdsuccess'
+- Fixed 'userunfriend' & 'userforceunfriend' language strings being flipped internally
+
+**Changes:**
+- The bot will now always emit the ready event on the second login rerun even if POSTPONED accounts still exist
+- Refactored some code to use the proper log prefix more consistently instead of sometimes switching to bot index
+- Refactored some code to surround userIDs more consistently with quotation marks
+- Refactored some code to simplify the unfriendall command
+- Improved contributing page
+- Improved issue templates
+- Migrated eslint config for eslint v9 and added & enforced two more rules
+- Updated hostname check
+- Updated dependencies
+- Minor other changes
diff --git a/docs/wiki/contributing.md b/docs/wiki/contributing.md
index 94794833..9eac0633 100644
--- a/docs/wiki/contributing.md
+++ b/docs/wiki/contributing.md
@@ -15,16 +15,16 @@ Please read this page *before* diving in, it contains a few **very** important p
## Table Of Contents
- [Reporting an issue](#reporting-an-issue)
- [How to fork and open pull requests](#how-to-fork-and-open-pull-requests)
-- [Translating](#translating)
-- [Styling Guidelines](#styling-guidelines)
+- [Updating or Adding a language translation](#translating)
+- [Styling guidelines](#styling-guidelines)
- [Starting the bot](#starting-the-bot)
## Reporting an Issue
-Found a bug?
-Please report it by creating an [issue](https://github.com/3urobeat/steam-comment-service-bot/issues/new/choose) so that I am able to fix it!
-If you've got a feature request instead, you can choose the "Feature request" template instead.
+Found a bug/error?
+Please report it by creating an [issue](https://github.com/3urobeat/steam-comment-service-bot/issues/new/choose). I'll respond as soon as possible.
+If you've got a feature request instead, you can choose the "Feature request" template.
If you have any questions, please open a [Q&A discussion](https://github.com/3urobeat/steam-comment-service-bot/discussions/new?category=q-a) instead!
@@ -35,8 +35,10 @@ To contribute code to the project, you first need to fork this repository. Go to
Before clicking the "Create fork" button in the next menu, make sure the checkmark at "Copy the `master` branch only" is **unchecked**!
After waiting a few seconds you should now have a *copy* of the repository on your account.
-Go into a folder on your computer where the project should be stored, open a terminal and run the command
-`git clone https://github.com/your-username/steam-comment-service-bot` or use any other Git Client of your choice.
+Assuming you already have `git` installed on your computer, open a folder on your PC where the project should be stored.
+Open a terminal in this location and run the command
+`git clone https://github.com/your-username/steam-comment-service-bot`
+...or use any other Git Client of your choice.
Once the repository has been cloned, switch to the `beta-testing` branch using the command `git checkout beta-testing`.
This branch contains the latest changes and must be the one you base your changes off of. The `master` branch contains the latest release.
@@ -44,20 +46,26 @@ This branch contains the latest changes and must be the one you base your change
You can now create your own branch using `git checkout -b "branchname"`, make changes and commit them to it.
It makes sense to give the branch a sensible name based on what your changes will be, but no pressure.
-The setup of your dev bot is very similar to the [normal setup](./setup_guide.md), however make sure to run `npm install` manually. This will install all dev dependencies, which are omitted in the normal installation.
+The setup of your dev bot is very similar to the [normal setup](./setup_guide.md), however make sure to run the command `npm install` in your terminal manually.
+This will install all dev dependencies, which are omitted in the normal installation to save space.
It is probably also a good idea to enable `printDebug` in `advancedconfig.json` to see a more detailed log output.
-Once you have made your changes and verified they are working as expected, you need to open a Pull Request to merge them into this repository.
+Make sure you have read '[Starting the bot](#starting-the-bot)' at the bottom of the page, before starting the bot to test your changes.
+
+Once you have made your changes and verified they are working as expected, you need to open a Pull Request to get them merged into this repository.
[Click here](https://github.com/3urobeat/steam-comment-service-bot/compare/), click on "Compare across forks" at the top and select `base: beta-testing` on the left side.
Then, choose your fork on the right at `head repository:`, your branch at `compare:` and click on "Create Pull Request".
Give your pull request a fitting title which describes your changes in a few words and put a more in depth explanation below in the description.
Once you are satisfied, hit the "Create pull request" button below to submit.
I'll take a look at it and perhaps suggest or make some minor changes in the following few days.
+Once everything looks good, I will merge your changes and they will be included in the next version.
## Translating
+The bot includes more translations than languages I speak myself - so I need your help here!
+
**Updating an existing language:**
I'm changing or adding new messages nearly every update, so there are often language strings that need to be updated.
It'd be great if you could help!
@@ -122,9 +130,8 @@ In short, the main styling rules are:
## Starting the bot
-When starting the bot during development, it is crucial to execute the [generateFileStructure](/scripts/generateFileStructure.js) script before starting the bot, on every change.
-You can do this easily by using a simple chained command:
-`node scripts/generateFileStructure.js && node start.js`
+When starting the bot during development, it is crucial to update every file's checksum, on every change.
+You can do this easily by starting the bot using the command: `npm run dev`
This ensures that [fileStructure.json](/src/data/fileStructure.json), which contains checksums for every file, gets updated.
The application will otherwise recognize your changed file as broken and will restore it with the default one.
diff --git a/docs/wiki/creating_plugins.md b/docs/wiki/creating_plugins.md
index 6461140c..7174e7fb 100644
--- a/docs/wiki/creating_plugins.md
+++ b/docs/wiki/creating_plugins.md
@@ -87,12 +87,18 @@ It makes sense to load your plugin config file from your plugin config folder, j
We are also registering a super cool command here with the names '!hello' and '!cool-alias'. If someone executes it, it will respond with 'Hello World!'. Registering commands and responding to the user is further explained below.
**Event functions:**
-The template plugin also exposes a 'ready', 'statusUpdate', 'steamGuardInput' function.
+The template plugin also exposes a 'ready', 'statusUpdate', 'steamGuardInput', 'steamGuardQrCode' function.
These are functions that will be called by the plugin system when the bot emits those events.
-The ready event function is called when the bot has finished logging in all accounts. Should the plugin load be caused by '!reload', this function is executed milliseconds after `load()` has been called.
-The statusUpdate event function is called when any bot account changes their status. Every status a bot can have is documented in the [EStatus enum](../../src/bot/EStatus.js).
-The steamGuardInput event function is called when any bot account is currently being logged in, but a Steam Guard Code is requested. The bot has a built in handler that will request code input from the terminal on this event.
+The 'ready' event function is called when the bot has finished logging in all accounts. Should the plugin load be caused by '!reload', this function is executed milliseconds after `load()` has been called.
+
+The 'statusUpdate' event function is called when any bot account changes their status. Every status a bot can have is documented in the [EStatus enum](../../src/bot/EStatus.js).
+
+The 'steamGuardInput' event function is called when any bot account is currently being logged in and a Steam Guard Code was requested by Steam.
+The bot has a built in handler that will request code input from the terminal on this event. Plugins can use the `code()` callback function in `steamGuardInput(bot, code)` to supply a code themselves, resolving the request as well.
+If a session was started by logging in using a QrCode instead of a password, the event 'steamGuardQrCode' will be fired instead. Plugins can display the QrCode supplied in this event, for example using the [qrcode library](https://www.npmjs.com/package/qrcode), which will resolve the request once it has been scanned using a Steam Mobile App.
+
+To check from your plugin if the Steam Guard Code/QrCode request has been resolved, wait for the statusUpdate event to announce a change.
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..144bfea6
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,92 @@
+/*
+ * File: eslint.config.mjs
+ * Project: steam-comment-service-bot
+ * Created Date: 2024-05-03 12:17:16
+ * Author: 3urobeat
+ *
+ * Last Modified: 2024-05-04 22:00:04
+ * Modified By: 3urobeat
+ *
+ * Copyright (c) 2024 3urobeat
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ */
+
+
+/*
+ 3urobeat's EsLint Config. Requires eslint, @eslint/js & eslint-plugin-jsdoc to be installed as devDependencies.
+ https://github.com/3urobeat
+*/
+
+import globals from "globals";
+import jsdoc from "eslint-plugin-jsdoc";
+import js from "@eslint/js";
+
+
+export default [
+ {
+ ignores: ["src/libraryPatches/*"],
+ },
+ js.configs.recommended, // Import recommended eslint rules
+ {
+ languageOptions: {
+ ecmaVersion: 2022,
+ sourceType: "module",
+ globals: {
+ ...globals.commonjs,
+ ...globals.es6,
+ ...globals.node,
+
+ started: true,
+ srcdir: true,
+ botisloggedin: true,
+ logger: true,
+ extdata: true
+ }
+ },
+ plugins: {
+ jsdoc: jsdoc
+ },
+ rules: {
+ "no-var": "error",
+ "no-redeclare": "off",
+ "no-unreachable": "error",
+ "no-unexpected-multiline": "error",
+
+ // Styling
+ "camelcase": "warn",
+ "capitalized-comments": ["warn", "always", { "ignoreConsecutiveComments": true }],
+ "comma-spacing": ["warn", { "before": false, "after": true }],
+ "func-call-spacing": ["error", "never"],
+ "indent": ["error", 4, { "ignoredNodes": ["IfStatement"], "SwitchCase": 1 }], // TODO: This also ignores if statements with wrong indentation but I couldn't get it to only ignore else in if-else one-liner
+ "no-tabs": "error",
+ "no-trailing-spaces": "error",
+ "no-extra-semi": "error",
+ "no-use-before-define": "error",
+ "prefer-const": "error",
+ "semi": ["error", "always"],
+ "semi-spacing": "error",
+ "semi-style": ["error", "last"],
+ "quotes": ["error", "double", { "avoidEscape": true }],
+ "spaced-comment": "warn",
+
+ // JsDoc - https://github.com/gajus/eslint-plugin-jsdoc
+ "jsdoc/check-alignment": "warn",
+ "jsdoc/check-indentation": "warn",
+ "jsdoc/check-types": "warn",
+ "jsdoc/informative-docs": "warn",
+ "jsdoc/require-asterisk-prefix": "warn",
+ "jsdoc/require-description": "warn",
+ "jsdoc/require-jsdoc": "warn",
+ "jsdoc/require-param": "warn",
+ "jsdoc/require-param-name": "warn",
+ "jsdoc/valid-types": "warn",
+ // "jsdoc/require-returns": "warn", // Always requires @return, even when function does not return something
+ "jsdoc/require-returns-type": "warn",
+ // "jsdoc/require-returns-check": "warn", // Unnecessary when require-returns above is disabled
+ "jsdoc/require-returns-description": "warn"
+ }
+ }
+];
diff --git a/package-lock.json b/package-lock.json
index e6361e81..a9cf7b94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "steam-comment-service-bot",
- "version": "2.15.1",
+ "version": "2.15.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "steam-comment-service-bot",
- "version": "2.15.1",
+ "version": "2.15.2",
"license": "GPL-3.0",
"dependencies": {
"@seald-io/nedb": "^4.0.4",
@@ -21,30 +21,22 @@
"steam-comment-bot-rest": "^1.2.1",
"steam-comment-bot-webserver": "^1.0.1",
"steam-session": "^1.7.2",
- "steam-user": "^5.0.8",
- "steamcommunity": "^3.48.2",
+ "steam-user": "^5.0.9",
+ "steamcommunity": "^3.48.3",
"steamid": "^2.0.0",
"steamid-resolver": "^1.3.4"
},
"devDependencies": {
- "eslint": "^8.57.0",
- "eslint-plugin-jsdoc": "^48.2.1",
+ "@eslint/js": "^9.1.1",
+ "eslint": "^9.1.1",
+ "eslint-plugin-jsdoc": "^48.2.3",
"tsd-jsdoc": "^2.5.0"
}
},
- "node_modules/@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/@babel/parser": {
- "version": "7.24.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz",
- "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
+ "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
"dev": true,
"peer": true,
"bin": {
@@ -223,6 +215,18 @@
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@eslint-community/regexpp": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
@@ -233,15 +237,15 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz",
+ "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
@@ -249,19 +253,19 @@
"strip-json-comments": "^3.1.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/js": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
- "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.1.1.tgz",
+ "integrity": "sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ==",
"dev": true,
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@fastify/busboy": {
@@ -273,12 +277,12 @@
}
},
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
- "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"dev": true,
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.2",
+ "@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
@@ -300,11 +304,24 @@
}
},
"node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
- "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true
},
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.3.tgz",
+ "integrity": "sha512-X38nUbachlb01YMlvPFojKoiXq+LzZvuSce70KPMPdeM1Rj03k4dR7lDslhbqXn3Ang4EU3+EAmwEAsbrjHW3g==",
+ "dev": true,
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -404,15 +421,15 @@
}
},
"node_modules/@sapphire/shapeshift": {
- "version": "3.9.6",
- "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.6.tgz",
- "integrity": "sha512-4+Na/fxu2SEepZRb9z0dbsVh59QtwPuBg/UVaDib3av7ZY14b14+z09z6QVn0P6Dv6eOU2NDTsjIi0mbtgP56g==",
+ "version": "3.9.7",
+ "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz",
+ "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21"
},
"engines": {
- "node": ">=v18"
+ "node": ">=v16"
}
},
"node_modules/@sapphire/snowflake": {
@@ -448,9 +465,9 @@
}
},
"node_modules/@socket.io/component-emitter": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
- "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
+ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
},
"node_modules/@types/axios": {
"version": "0.14.0",
@@ -471,9 +488,9 @@
}
},
"node_modules/@types/bytebuffer": {
- "version": "5.0.48",
- "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.48.tgz",
- "integrity": "sha512-ormKm68NtTOtR8C/4jyRJEYbwKABXRkHHR/1fmkiuFbCQkltgtXSUGfldCSmJzvuyJvmBzWjBbOi79Ry/oJQug==",
+ "version": "5.0.49",
+ "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.49.tgz",
+ "integrity": "sha512-lV4YLiolMdD4upDmr4vnfiwV/FN9Jg33eNTSFMkHqyMKqTIAn5TmFTYsARwXwUXeFU7yzRpECmWV1SOhIvdkRQ==",
"dependencies": {
"@types/long": "^3.0.0",
"@types/node": "*"
@@ -517,9 +534,9 @@
}
},
"node_modules/@types/express-serve-static-core": {
- "version": "4.17.43",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
- "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
+ "version": "4.19.0",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
+ "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
@@ -541,9 +558,9 @@
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="
},
"node_modules/@types/linkify-it": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz",
- "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"dev": true,
"peer": true
},
@@ -564,9 +581,9 @@
}
},
"node_modules/@types/mdurl": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz",
- "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"dev": true,
"peer": true
},
@@ -576,17 +593,17 @@
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
},
"node_modules/@types/node": {
- "version": "20.11.25",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
- "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==",
+ "version": "20.12.8",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz",
+ "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/qs": {
- "version": "6.9.12",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz",
- "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg=="
+ "version": "6.9.15",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
+ "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg=="
},
"node_modules/@types/range-parser": {
"version": "1.2.7",
@@ -627,13 +644,13 @@
}
},
"node_modules/@types/serve-static": {
- "version": "1.15.5",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
- "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
+ "version": "1.15.7",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
+ "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
"dependencies": {
"@types/http-errors": "*",
- "@types/mime": "*",
- "@types/node": "*"
+ "@types/node": "*",
+ "@types/send": "*"
}
},
"node_modules/@types/steam-user": {
@@ -680,12 +697,6 @@
"@types/node": "*"
}
},
- "node_modules/@ungap/structured-clone": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
- "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
- "dev": true
- },
"node_modules/@vladfrangu/async_event_emitter": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz",
@@ -729,9 +740,9 @@
}
},
"node_modules/adm-zip": {
- "version": "0.5.10",
- "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
- "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==",
+ "version": "0.5.12",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz",
+ "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==",
"engines": {
"node": ">=6.0"
}
@@ -880,11 +891,11 @@
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
},
"node_modules/axios": {
- "version": "1.6.7",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
- "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
+ "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
"dependencies": {
- "follow-redirects": "^1.15.4",
+ "follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -1417,9 +1428,9 @@
}
},
"node_modules/cookie": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"engines": {
"node": ">= 0.6"
}
@@ -1801,18 +1812,6 @@
"node": ">=16.11.0"
}
},
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@@ -2039,41 +2038,37 @@
}
},
"node_modules/eslint": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
- "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.1.1.tgz",
+ "integrity": "sha512-b4cRQ0BeZcSEzPpY2PjFY70VbO32K7BStTGtBsnIGdTSEEQzBi8hPBcGQmTG2zUvFr9uLe0TK42bw8YszuHEqg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.0",
- "@humanwhocodes/config-array": "^0.11.14",
+ "@eslint/eslintrc": "^3.0.2",
+ "@eslint/js": "9.1.1",
+ "@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.2.3",
"@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
- "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
+ "eslint-scope": "^8.0.1",
+ "eslint-visitor-keys": "^4.0.0",
+ "espree": "^10.0.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
+ "file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
@@ -2087,16 +2082,16 @@
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "48.2.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.1.tgz",
- "integrity": "sha512-iUvbcyDZSO/9xSuRv2HQBw++8VkV/pt3UWtX9cpPH0l7GKPq78QC/6+PmyQHHvNZaTjAce6QVciEbnc6J/zH5g==",
+ "version": "48.2.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.3.tgz",
+ "integrity": "sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA==",
"dev": true,
"dependencies": {
"@es-joy/jsdoccomment": "~0.42.0",
@@ -2117,45 +2112,45 @@
}
},
"node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz",
+ "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
+ "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
+ "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
"dev": true,
"dependencies": {
- "acorn": "^8.9.0",
+ "acorn": "^8.11.3",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "eslint-visitor-keys": "^4.0.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -2226,16 +2221,16 @@
}
},
"node_modules/express": {
- "version": "4.18.3",
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz",
- "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==",
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.5.0",
+ "cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
@@ -2346,9 +2341,9 @@
"dev": true
},
"node_modules/fast-xml-parser": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.5.tgz",
- "integrity": "sha512-sWvP1Pl8H03B8oFJpFR3HE31HUfwtX7Rlf9BNsvdpujD4n7WMhfmu8h9wOV2u+c1k0ZilTADhPqypzx2J690ZQ==",
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz",
+ "integrity": "sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==",
"funding": [
{
"type": "github",
@@ -2384,15 +2379,15 @@
}
},
"node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
"dependencies": {
- "flat-cache": "^3.0.4"
+ "flat-cache": "^4.0.0"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16.0.0"
}
},
"node_modules/file-manager": {
@@ -2490,17 +2485,16 @@
}
},
"node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
"dependencies": {
"flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
+ "keyv": "^4.5.4"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16"
}
},
"node_modules/flatted": {
@@ -2510,9 +2504,9 @@
"dev": true
},
"node_modules/follow-redirects": {
- "version": "1.15.5",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
- "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
@@ -2597,12 +2591,6 @@
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -2656,26 +2644,6 @@
"assert-plus": "^1.0.0"
}
},
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -2689,15 +2657,12 @@
}
},
"node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -2762,12 +2727,6 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
- },
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -2865,9 +2824,9 @@
}
},
"node_modules/hasown": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
- "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -3015,16 +2974,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -3813,17 +3762,17 @@
}
},
"node_modules/optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
"dependencies": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
@@ -3950,15 +3899,6 @@
"node": ">=8"
}
},
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -4335,21 +4275,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -4490,16 +4415,16 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"node_modules/set-function-length": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
- "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dependencies": {
- "define-data-property": "^1.1.2",
+ "define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.3",
+ "get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.1"
+ "has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -4556,9 +4481,9 @@
}
},
"node_modules/socket.io": {
- "version": "4.7.4",
- "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz",
- "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==",
+ "version": "4.7.5",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz",
+ "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
@@ -4614,9 +4539,9 @@
}
},
"node_modules/socks": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz",
- "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"dependencies": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
@@ -4875,9 +4800,9 @@
}
},
"node_modules/steam-user": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/steam-user/-/steam-user-5.0.8.tgz",
- "integrity": "sha512-PPOgZr+YpiuqY2msvcxWoDpNm58E4HHs1yg0BS8w854qIn23jTqKk8U4wj9V1KS8pWs/JJ9BzgwIMLBzQ1g0zw==",
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/steam-user/-/steam-user-5.0.9.tgz",
+ "integrity": "sha512-lV6K2cfr5AQzxf69U9nvJiqLbXT5N3HbwC8OyGZnD3v/ZFo8Vsk3j2RdrlS0lONuISGg/8l12uOG02EBAOhj9w==",
"dependencies": {
"@bbob/parser": "^2.2.0",
"@doctormckay/stdlib": "^2.9.1",
@@ -4901,9 +4826,9 @@
}
},
"node_modules/steamcommunity": {
- "version": "3.48.2",
- "resolved": "https://registry.npmjs.org/steamcommunity/-/steamcommunity-3.48.2.tgz",
- "integrity": "sha512-447UMw5KQpzZfAfo68qV6DWU0blNAhphDGnhbtCFG6GIE3fZdnD5uRIswMsmVZ+hnLvpks/+AWeZHguSTWjc6A==",
+ "version": "3.48.3",
+ "resolved": "https://registry.npmjs.org/steamcommunity/-/steamcommunity-3.48.3.tgz",
+ "integrity": "sha512-oSLz9oajRyn084ONrGCYzNKBmSoxt7VxNs01OhpT9dsDXA0sipMe2D4EktBMWmg8m8IS/ouMVbCi1LG+2j7qVw==",
"dependencies": {
"@doctormckay/user-agents": "^1.0.0",
"async": "^2.6.3",
@@ -5187,9 +5112,9 @@
"integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="
},
"node_modules/tsc-watch": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-6.0.4.tgz",
- "integrity": "sha512-cHvbvhjO86w2aGlaHgSCeQRl+Aqw6X6XN4sQMPZKF88GoP30O+oTuh5lRIJr5pgFWrRpF1AgXnJJ2DoFEIPHyg==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-6.2.0.tgz",
+ "integrity": "sha512-2LBhf9kjKXnz7KQ/puLHlozMzzUNHAdYBNMkg3eksQJ9GBAgMg8czznM83T5PmsoUvDnXzfIeQn2lNcIYDr8LA==",
"dependencies": {
"cross-spawn": "^7.0.3",
"node-cleanup": "^2.1.2",
@@ -5264,18 +5189,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -5289,9 +5202,9 @@
}
},
"node_modules/typescript": {
- "version": "5.4.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
- "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
+ "version": "5.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -5477,15 +5390,15 @@
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
},
"node_modules/which-typed-array": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
- "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+ "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
"dependencies": {
- "available-typed-arrays": "^1.0.6",
- "call-bind": "^1.0.5",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
"for-each": "^0.3.3",
"gopd": "^1.0.1",
- "has-tostringtag": "^1.0.1"
+ "has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -5494,6 +5407,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
diff --git a/package.json b/package.json
index 7d416c68..8431d453 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "steam-comment-service-bot",
- "version": "2.15.1",
+ "version": "2.15.2",
"description": "The most advanced Steam Multi Account Manager with built-in comment, like & favorite commands and extensive plugin support.",
"main": "start.js",
"dependencies": {
@@ -16,8 +16,8 @@
"steam-comment-bot-rest": "^1.2.1",
"steam-comment-bot-webserver": "^1.0.1",
"steam-session": "^1.7.2",
- "steam-user": "^5.0.8",
- "steamcommunity": "^3.48.2",
+ "steam-user": "^5.0.9",
+ "steamcommunity": "^3.48.3",
"steamid": "^2.0.0",
"steamid-resolver": "^1.3.4"
},
@@ -35,8 +35,9 @@
"homepage": "https://github.com/3urobeat",
"repository": "https://github.com/3urobeat/steam-comment-service-bot",
"devDependencies": {
- "eslint": "^8.57.0",
- "eslint-plugin-jsdoc": "^48.2.1",
+ "@eslint/js": "^9.1.1",
+ "eslint": "^9.1.1",
+ "eslint-plugin-jsdoc": "^48.2.3",
"tsd-jsdoc": "^2.5.0"
},
"types": "./types/types.d.ts"
diff --git a/quotes.txt b/quotes.txt
index b919e91a..047de2cb 100644
--- a/quotes.txt
+++ b/quotes.txt
@@ -361,7 +361,6 @@ TOP1
meow
++++++rep
yoooooooooooooooooo man
-China is a cool country imo
CS2 God
Legendary
1 tapper
diff --git a/scripts/checkTranslationKeys.js b/scripts/checkTranslationKeys.js
index 87e6de35..1bf2228d 100644
--- a/scripts/checkTranslationKeys.js
+++ b/scripts/checkTranslationKeys.js
@@ -25,7 +25,7 @@ const eng = require("../src/data/lang/english.json");
// Find all translations inside the same directory
-let translations = fs.readdirSync("./src/data/lang/");
+const translations = fs.readdirSync("./src/data/lang/");
console.log(`Checking ${translations.length - 1} translation(s). If the script exits with no further messages, all translations contain the same keys.`);
@@ -44,8 +44,8 @@ translations.forEach((name) => {
// Get key arrays of both translations
- let engKeys = Object.keys(eng);
- let langKeys = Object.keys(lang);
+ const engKeys = Object.keys(eng);
+ const langKeys = Object.keys(lang);
// Check lang for missing keys
diff --git a/scripts/generateFileStructure.js b/scripts/generateFileStructure.js
index 91a13637..1b8273ce 100644
--- a/scripts/generateFileStructure.js
+++ b/scripts/generateFileStructure.js
@@ -48,7 +48,7 @@ function searchFolderRecursiveSync(src, firstCall) {
if (fs.lstatSync(src).isDirectory()) {
files = fs.readdirSync(src);
- let targetFolder = path.join("./", src);
+ const targetFolder = path.join("./", src);
files.forEach(async (file) => {
let filepath = targetFolder + "/" + file;
@@ -59,7 +59,7 @@ function searchFolderRecursiveSync(src, firstCall) {
// Ignore this file/folder if name is in ignore array
if (ignore.includes(filepath)) return;
- let curSource = path.join(src, file);
+ const curSource = path.join(src, file);
// Recursively call this function again if this is a dir
if (fs.lstatSync(curSource).isDirectory()) {
@@ -68,8 +68,8 @@ function searchFolderRecursiveSync(src, firstCall) {
} else {
// Construct URL and calculate checksum
- let fileurl = "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/" + filepath;
- let filesum = crypto.createHash("md5").update(fs.readFileSync(filepath)).digest("hex");
+ const fileurl = "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/" + filepath;
+ const filesum = crypto.createHash("md5").update(fs.readFileSync(filepath)).digest("hex");
// Add file to output array
output.push({ "path": filepath, "url": fileurl, "checksum": filesum });
diff --git a/src/bot/bot.js b/src/bot/bot.js
index c7f2043a..62562c07 100644
--- a/src/bot/bot.js
+++ b/src/bot/bot.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-03-01 17:59:47
+ * Last Modified: 2024-05-04 15:27:37
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -63,7 +63,7 @@ const Bot = function(controller, index) {
*/
this.friendMessageBlock = [];
- let proxyIndex = this.index % controller.data.proxies.length; // Spread all accounts equally with a simple modulo calculation
+ const proxyIndex = this.index % controller.data.proxies.length; // Spread all accounts equally with a simple modulo calculation
/**
* Additional login related information for this bot account
@@ -133,7 +133,7 @@ const Bot = function(controller, index) {
require("../libraryPatches/CSteamReviews.js");
require("../libraryPatches/reviews.js");
- if (global.checkm8!="b754jfJNgZWGnzogvl {
+ return new Promise((resolve) => {
+
+ this.user.logOff();
+ if (this.sessionHandler.session) this.sessionHandler.session.cancelLoginAttempt(); // TODO: This might cause an error as idk if we are polling. Maybe use the timeout event of steam-session
+
+ const logOffInterval = setInterval(() => {
+ logger("warn", `[${this.logPrefix}] Login requested but account seems to be logged in! Attempting log off before continuing...`, true, true); // Cannot log with date to prevent log output file spam
+
+ // Resolve when logged off or when logOnTries has changed (handleLoginTimeout has probably taken action)
+ if ((!this.user.steamID && !this.user._connecting) || currentLogOnTry != this.loginData.logOnTries) {
+ clearInterval(logOffInterval);
+ resolve();
+ }
+ }, 250);
+
+ });
+ })();
+ }
+
+ // Cancel if not on the same logOnTries value anymore (handleLoginTimeout has probably taken action)
+ if (currentLogOnTry != this.loginData.logOnTries) return logger("debug", `[${this.logPrefix}] Aborting login because _loginToSteam() was called again from somewhere else. Potentially logging off took too long and handleLoginTimeout took action.`);
// Find proxyIndex from steam-user object options instead of loginData to get reliable log data
- let thisProxy = this.data.proxies.find((e) => e.proxy == this.user.options.httpProxy);
+ const thisProxy = this.data.proxies.find((e) => e.proxy == this.user.options.httpProxy);
// Log login message for this account, with mentioning proxies or without
if (!thisProxy.proxy) logger("info", `[${this.logPrefix}] Trying to log in without proxy... (Attempt ${this.loginData.logOnTries}/${this.controller.data.advancedconfig.maxLogOnRetries + 1})`, false, true, logger.animation("loading"));
else logger("info", `[${this.logPrefix}] Trying to log in with proxy ${thisProxy.proxyIndex}... (Attempt ${this.loginData.logOnTries}/${this.controller.data.advancedconfig.maxLogOnRetries + 1})`, false, true, logger.animation("loading"));
- // Attach loginTimeout handler
- this.handleLoginTimeout();
-
// Call our steam-session helper to get a valid refresh token for us
- let refreshToken = await this.sessionHandler.getToken();
+ const refreshToken = await this.sessionHandler.getToken();
if (!refreshToken) return this.loginData.pendingLogin = false; // Stop execution if getRefreshToken aborted login attempt, it either skipped this account or stopped the bot itself
@@ -286,7 +310,7 @@ Bot.prototype.handleLoginTimeout = function() {};
Bot.prototype.handleMissingGameLicenses = function() {};
/**
- * Changes the proxy of this bot account and relogs it.
+ * Changes the proxy of this bot account.
* @param {number} newProxyIndex Index of the new proxy inside the DataManager.proxies array.
*/
Bot.prototype.switchProxy = function(newProxyIndex) {}; // eslint-disable-line
diff --git a/src/bot/events/error.js b/src/bot/events/error.js
index 45ce77fa..975a9934 100644
--- a/src/bot/events/error.js
+++ b/src/bot/events/error.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-03-08 17:44:50
+ * Last Modified: 2024-05-09 14:05:33
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -28,22 +28,14 @@ Bot.prototype._attachSteamErrorEvent = function() {
// Handle errors that were caused during logOn
this.user.on("error", (err) => {
- // Custom behavior for LogonSessionReplaced error
- if (err.eresult == EResult.LogonSessionReplaced) {
- logger("", "", true);
- logger("warn", `${logger.colors.fgred}[${this.logPrefix}] Lost connection to Steam! Reason: 'Error: LogonSessionReplaced'. I won't try to relog this account because someone else is using it now.`, false, false, null, true); // Force print this message now
+ // Do not relog on LogOnSessionReplaced if feature is disabled in advancedconfig
+ if (err.eresult == EResult.LogonSessionReplaced && !this.data.advancedconfig.enableRelogOnLogOnSessionReplaced) {
+ logger("warn", `${logger.colors.fgred}[${this.logPrefix}] Lost connection to Steam! Reason: 'Error: LogonSessionReplaced'. I won't try to relog this account because 'enableRelogOnLogOnSessionReplaced' is disabled in 'advancedconfig.json'.`, false, false, null, true); // Force print this message now
- // Abort or skip account. No need to attach handleRelog() here
- if (this.index == 0) {
- logger("error", `${logger.colors.fgred}Failed account is bot0! Aborting...`, true);
- return this.controller.stop();
- } else {
- this.controller.info.skippedaccounts.push(this.loginData.logOnOptions.accountName);
-
- // Set status to error so it won't be used for anything anymore
- this.controller._statusUpdateEvent(this, Bot.EStatus.ERROR);
- }
+ // Skip account and set status to ERROR so the account won't be used anymore
+ this.controller.info.skippedaccounts.push(this.loginData.logOnOptions.accountName);
+ this.controller._statusUpdateEvent(this, Bot.EStatus.ERROR);
return;
}
@@ -73,7 +65,7 @@ Bot.prototype._attachSteamErrorEvent = function() {
// Check if all logOnTries are used or if this is a fatal error
- let blockedEnumsForRetries = [EResult.Banned, EResult.AccountNotFound]; // No need to block InvalidPassword anymore as the SessionHandler handles credentials
+ const blockedEnumsForRetries = [EResult.Banned, EResult.AccountNotFound]; // No need to block InvalidPassword anymore as the SessionHandler handles credentials
if (this.loginData.logOnTries > this.controller.data.advancedconfig.maxLogOnRetries || blockedEnumsForRetries.includes(err.eresult)) {
logger("error", `Couldn't log in bot${this.index} after ${this.loginData.logOnTries} attempt(s). ${err} (${err.eresult})`);
diff --git a/src/bot/events/friendMessage.js b/src/bot/events/friendMessage.js
index a7a83de1..f3b54f05 100644
--- a/src/bot/events/friendMessage.js
+++ b/src/bot/events/friendMessage.js
@@ -27,23 +27,23 @@ const Bot = require("../bot.js");
Bot.prototype._attachSteamFriendMessageEvent = function() {
this.user.chat.on("friendMessage", async (msg) => {
- let message = msg.message_no_bbcode;
- let steamID = msg.steamid_friend;
+ const message = msg.message_no_bbcode;
+ const steamID = msg.steamid_friend;
- let steamID64 = new SteamID(String(steamID)).getSteamID64();
- let username = this.user.users[steamID64] ? this.user.users[steamID64].player_name : ""; // Set username to nothing in case they are not cached yet to avoid errors
+ const steamID64 = new SteamID(String(steamID)).getSteamID64();
+ const username = this.user.users[steamID64] ? this.user.users[steamID64].player_name : ""; // Set username to nothing in case they are not cached yet to avoid errors
let relationshipStatus = SteamUser.EFriendRelationship.None;
if (this.user.myFriends[steamID64]) relationshipStatus = SteamUser.EFriendRelationship[this.user.myFriends[steamID64]];
- let resInfo = { userID: steamID64, cmdprefix: "!", fromSteamChat: true }; // Object required for sendChatMessage(), our commandHandler respondModule implementation
+ const resInfo = { userID: steamID64, cmdprefix: "!", fromSteamChat: true }; // Object required for sendChatMessage(), our commandHandler respondModule implementation
// Check if another friendMessage handler is currently active
if (this.friendMessageBlock.includes(steamID64)) return logger("debug", `[${this.logPrefix}] Ignoring friendMessage event from ${steamID64} as user is on friendMessageBlock list.`);
// Check if this event should be handled or if user is blocked
- let isBlocked = await this.checkMsgBlock(steamID64, message);
+ const isBlocked = await this.checkMsgBlock(steamID64, message);
if (isBlocked) return; // Stop right here if user is blocked, on cooldown or not a friend
@@ -74,7 +74,7 @@ Bot.prototype._attachSteamFriendMessageEvent = function() {
if (err) logger("error", "Database error on friendMessage. This is weird. Error: " + err);
if (!doc) { // Add user to database if he/she is missing for some reason
- let lastcommentobj = {
+ const lastcommentobj = {
id: new SteamID(String(steamID)).getSteamID64(),
time: Date.now() - (this.data.config.requestCooldown * 60000) // Subtract requestCooldown so that the user is able to use the command instantly
};
@@ -94,10 +94,10 @@ Bot.prototype._attachSteamFriendMessageEvent = function() {
// Ask command handler to figure out things for us when a message with prefix was sent
- let cont = message.slice(1).split(" "); // Remove prefix and split
- let args = cont.slice(1); // Remove cmd name to only get arguments
+ const cont = message.slice(1).split(" "); // Remove prefix and split
+ const args = cont.slice(1); // Remove cmd name to only get arguments
- let success = await this.controller.commandHandler.runCommand(cont[0].toLowerCase(), args, this.sendChatMessage, this, resInfo); // Don't listen to your IDE, this *await is necessary*
+ const success = await this.controller.commandHandler.runCommand(cont[0].toLowerCase(), args, this.sendChatMessage, this, resInfo); // Don't listen to your IDE, this *await is necessary*
if (!success) this.sendChatMessage(this, resInfo, await this.controller.data.getLang("commandnotfound", { "cmdprefix": resInfo.cmdprefix }, steamID64)); // Send cmd not found msg if runCommand() returned false
});
diff --git a/src/bot/events/relationship.js b/src/bot/events/relationship.js
index 26ad0538..64ab3a05 100644
--- a/src/bot/events/relationship.js
+++ b/src/bot/events/relationship.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-02-28 22:24:32
+ * Last Modified: 2024-05-09 14:23:48
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -28,7 +28,7 @@ Bot.prototype._attachSteamFriendRelationshipEvent = function() {
this.user.on("friendRelationship", (steamID, relationship) => {
if (relationship == 2) {
- let steamID64 = new SteamID(String(steamID)).getSteamID64();
+ const steamID64 = new SteamID(String(steamID)).getSteamID64();
if (!this.data.advancedconfig.acceptFriendRequests) return logger("info", `[${this.logPrefix}] Received friend request from ${steamID64} but acceptFriendRequests is turned off in advancedconfig.json`);
@@ -47,7 +47,7 @@ Bot.prototype._attachSteamFriendRelationshipEvent = function() {
// Add user to lastcomment database
- let time = Date.now() - (this.controller.data.config.requestCooldown * 60000); // Subtract requestCooldown so that the user is able to use the command instantly;
+ const time = Date.now() - (this.controller.data.config.requestCooldown * 60000); // Subtract requestCooldown so that the user is able to use the comment command instantly;
this.controller.data.lastCommentDB.update({ id: steamID64 }, { $set: { time: time } }, { upsert: true }, (err) => {
if (err) logger("error", "Error inserting new user into lastcomment.db database! Error: " + err);
@@ -86,7 +86,7 @@ Bot.prototype._attachSteamGroupRelationshipEvent = function() {
this.user.on("groupRelationship", (steamID, relationship) => {
if (relationship == 2) { // Ignore if relationship type is not "Invited"
- let steamID64 = new SteamID(String(steamID)).getSteamID64();
+ const steamID64 = new SteamID(String(steamID)).getSteamID64();
// Check if acceptgroupinvites is set to false and only allow botsgroup invite to be accepted
if (!this.controller.data.config.acceptgroupinvites) {
diff --git a/src/bot/events/webSession.js b/src/bot/events/webSession.js
index b4208b8d..b25118c2 100644
--- a/src/bot/events/webSession.js
+++ b/src/bot/events/webSession.js
@@ -60,7 +60,7 @@ Bot.prototype._attachSteamWebSessionEvent = function() {
if (this.user.myFriends[Object.keys(this.user.myFriends)[i]] == 2) {
if (this.controller.data.advancedconfig.acceptFriendRequests) {
- let thisfriend = Object.keys(this.user.myFriends)[i];
+ const thisfriend = Object.keys(this.user.myFriends)[i];
// Accept friend request
this.user.addFriend(thisfriend);
@@ -76,7 +76,7 @@ Bot.prototype._attachSteamWebSessionEvent = function() {
// Add user to lastcomment database
- let time = Date.now() - (this.controller.data.config.requestCooldown * 60000); // Subtract requestCooldown so that the user is able to use the command instantly;
+ const time = Date.now() - (this.controller.data.config.requestCooldown * 60000); // Subtract requestCooldown so that the user is able to use the command instantly;
this.controller.data.lastCommentDB.update({ id: thisfriend }, { $set: { time: time } }, { upsert: true }, (err) => {
if (err) logger("error", "Error inserting new user into lastcomment.db database! Error: " + err);
@@ -105,7 +105,7 @@ Bot.prototype._attachSteamWebSessionEvent = function() {
// Groups:
for (let i = 0; i < Object.keys(this.user.myGroups).length; i++) {
if (this.user.myGroups[Object.keys(this.user.myGroups)[i]] == 2) {
- let thisgroup = Object.keys(this.user.myGroups)[i];
+ const thisgroup = Object.keys(this.user.myGroups)[i];
// Check if acceptgroupinvites is set to false and only allow botsgroup invite to be accepted
if (!this.controller.data.config.acceptgroupinvites) {
diff --git a/src/bot/helpers/handleLoginTimeout.js b/src/bot/helpers/handleLoginTimeout.js
index 0204db90..393731f0 100644
--- a/src/bot/helpers/handleLoginTimeout.js
+++ b/src/bot/helpers/handleLoginTimeout.js
@@ -27,7 +27,7 @@ Bot.prototype.handleLoginTimeout = function() {
if (this.data.advancedconfig.loginTimeout == 0) return logger("debug", `Bot handleLoginTimeout(): Ignoring timeout attach request for bot${this.index} because loginTimeout is disabled in advancedconfig!`);
else logger("debug", `Bot handleLoginTimeout(): Attached ${this.data.advancedconfig.loginTimeout / 1000} seconds timeout for bot${this.index}...`);
- let currentLogOnTry = this.loginData.logOnTries;
+ const currentLogOnTry = this.loginData.logOnTries;
// Check if account is still offline with the same logOnTries value 60 seconds later and force progress
setTimeout(() => {
@@ -36,7 +36,7 @@ Bot.prototype.handleLoginTimeout = function() {
if (this.loginData.waitingFor2FA) return setTimeout(() => this.handleLoginTimeout(), 5000);
// Ignore timeout if account progressed since then
- let newLogOnTry = this.loginData.logOnTries;
+ const newLogOnTry = this.loginData.logOnTries;
if (currentLogOnTry != newLogOnTry || this.status != Bot.EStatus.OFFLINE) return logger("debug", `Bot handleLoginTimeout(): Timeout for bot${this.index} done, acc not stuck. old/new logOnTries: ${currentLogOnTry}/${newLogOnTry} - acc status: ${this.status}`);
diff --git a/src/bot/helpers/handleMissingGameLicenses.js b/src/bot/helpers/handleMissingGameLicenses.js
index 3a182f66..9e051f2b 100644
--- a/src/bot/helpers/handleMissingGameLicenses.js
+++ b/src/bot/helpers/handleMissingGameLicenses.js
@@ -22,7 +22,7 @@ const Bot = require("../bot.js");
* Handles checking for missing game licenses, requests them and then starts playing
*/
Bot.prototype.handleMissingGameLicenses = function() {
- let data = this.controller.data;
+ const data = this.controller.data;
// Check if user provided games specifically for this account. We only need to check this for child accounts
let configChildGames = data.config.childaccplayinggames;
@@ -35,10 +35,10 @@ Bot.prototype.handleMissingGameLicenses = function() {
}
// Shorthander for starting to play
- let startPlaying = () => { if (this.index == 0) this.user.gamesPlayed(this.controller.data.config.playinggames); else this.user.gamesPlayed(configChildGames); };
+ const startPlaying = () => { if (this.index == 0) this.user.gamesPlayed(this.controller.data.config.playinggames); else this.user.gamesPlayed(configChildGames); };
- let options = {
+ const options = {
includePlayedFreeGames: true,
filterAppids: this.index == 0 ? data.config.playinggames.filter(e => !isNaN(e)) : configChildGames.filter(e => !isNaN(e) && e != null), // We only need to check for these appIDs. Filter custom game string and null values
includeFreeSub: false
diff --git a/src/bot/helpers/handleRelog.js b/src/bot/helpers/handleRelog.js
index a8664fbf..5dd75b45 100644
--- a/src/bot/helpers/handleRelog.js
+++ b/src/bot/helpers/handleRelog.js
@@ -4,7 +4,7 @@
* Created Date: 2023-10-05 16:14:46
* Author: 3urobeat
*
- * Last Modified: 2024-03-08 11:48:23
+ * Last Modified: 2024-05-04 21:12:25
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -22,12 +22,12 @@ const Bot = require("../bot");
/**
- * Changes the proxy of this bot account and relogs it.
+ * Changes the proxy of this bot account.
* @param {number} newProxyIndex Index of the new proxy inside the DataManager.proxies array.
*/
Bot.prototype.switchProxy = function(newProxyIndex) {
- if (!newProxyIndex) return new Error("newProxyIndex is undefined");
+ if (newProxyIndex == undefined) return new Error("Parameter newProxyIndex must not be undefined"); // Explicitly check for undefined to prevent the value 0 from triggering this check
logger("info", `[${this.logPrefix}] Switching proxy from ${this.loginData.proxyIndex} to ${newProxyIndex}. The bot account will relog in a moment...`);
@@ -62,7 +62,7 @@ Bot.prototype.switchProxy = function(newProxyIndex) {
Bot.prototype.checkAndSwitchMyProxy = async function() {
// Attempt to ping github.com (basically any non steamcommunity url) without a proxy to determine if the internet connection is not working
- let hostConnectionRes = await this.controller.misc.checkConnection("https://github.com/3urobeat/steam-comment-service-bot", true)
+ const hostConnectionRes = await this.controller.misc.checkConnection("https://github.com/3urobeat/steam-comment-service-bot", true)
.catch((err) => {
if (this.index == 0) logger("info", `[Main] Your internet connection seems to be down. ${err.statusMessage}`); // Only log message for main acc to reduce clutter
});
@@ -86,10 +86,10 @@ Bot.prototype.checkAndSwitchMyProxy = async function() {
// Check if our proxy is down
- let thisProxy = this.data.proxies.find((e) => e.proxyIndex == this.loginData.proxyIndex);
+ const thisProxy = this.data.proxies.find((e) => e.proxyIndex == this.loginData.proxyIndex);
if (!thisProxy.isOnline) {
- let activeProxies = this.controller.getBotsPerProxy(true); // Get all online proxies and their associated bot accounts
+ const activeProxies = this.controller.getBotsPerProxy(true); // Get all online proxies and their associated bot accounts
// Check if no available proxy was found (exclude host) and return false
if (activeProxies.length == 0) {
@@ -99,9 +99,9 @@ Bot.prototype.checkAndSwitchMyProxy = async function() {
// Find proxy with least amount of associated bots
- let leastUsedProxy = activeProxies.reduce((a, b) => a.bots.length < b.bots.length ? a : b);
+ const leastUsedProxy = activeProxies.reduce((a, b) => a.bots.length < b.bots.length ? a : b);
- logger("warn", `[${this.logPrefix}] Failed to ping Steam using proxy ${this.loginData.proxyIndex}! Switched to proxy ${leastUsedProxy.proxyIndex} which currently has the least amount of usage and appears to be online.`);
+ logger("warn", `[${this.logPrefix}] Failed to ping Steam using proxy ${this.loginData.proxyIndex}! Switching to proxy ${leastUsedProxy.proxyIndex} which currently has the least amount of usage and appears to be online.`);
// Switch proxy and relog, no need for handleRelog() to do something
@@ -127,7 +127,7 @@ Bot.prototype.handleRelog = async function() {
this.loginData.relogTries++;
// Check if proxy might be offline
- let proxySwitched = await this.checkAndSwitchMyProxy();
+ const proxySwitched = await this.checkAndSwitchMyProxy();
if (proxySwitched) return; // Stop execution if proxy was switched and bot is getting relogged
@@ -139,10 +139,10 @@ Bot.prototype.handleRelog = async function() {
setTimeout(() => {
// Abort if account is online again for some reason
- if (this.status == Bot.EStatus.ONLINE) return logger("debug", `Bot handleRelog(): Timeout elapsed but bot${this.index} is not offline anymore. Ignoring...`);
+ if (this.status == Bot.EStatus.ONLINE) return logger("info", `[${this.logPrefix}] Relog timeout elapsed, however the account is already online again?! Ignoring relog request...`);
- // Update status to offline and call login again
- this.status = Bot.EStatus.OFFLINE;
+ // Update status and call login again
+ this.controller._statusUpdateEvent(this, Bot.EStatus.POSTPONED); // Important: Set to POSTPONED to let the current login request, which this acc is queued in, resolve. The following request will process it. This fixes a softlock where the current login process would never resolve.
this.controller.login();
}, this.controller.data.advancedconfig.relogTimeout);
diff --git a/src/bot/helpers/steamChatInteraction.js b/src/bot/helpers/steamChatInteraction.js
index 237547a6..1dc721b1 100644
--- a/src/bot/helpers/steamChatInteraction.js
+++ b/src/bot/helpers/steamChatInteraction.js
@@ -39,8 +39,8 @@ Bot.prototype.sendChatMessage = function(_this, resInfo, txt, retry = 0, part =
if (!txt) return logger("warn", "sendChatMessage() was called without any message content! Ignoring call...");
if (typeof txt !== "string") return logger("warn", "sendChatMessage() was called with txt that isn't a string! Ignoring call...");
- let steamID64 = resInfo.userID;
- let username = _this.user.users[steamID64] ? _this.user.users[steamID64].player_name : ""; // Set username to nothing in case they are not cached yet to avoid errors
+ const steamID64 = resInfo.userID;
+ const username = _this.user.users[steamID64] ? _this.user.users[steamID64].player_name : ""; // Set username to nothing in case they are not cached yet to avoid errors
let relationshipStatus = SteamUser.EFriendRelationship.None;
if (_this.user.myFriends[steamID64]) relationshipStatus = SteamUser.EFriendRelationship[_this.user.myFriends[steamID64]];
@@ -50,14 +50,14 @@ Bot.prototype.sendChatMessage = function(_this, resInfo, txt, retry = 0, part =
if (resInfo.charLimit) limit = resInfo.charLimit;
// Allow resInfo to overwrite cutStringsIntelligently's cutChars
- let cutChars = resInfo.cutChars || null;
+ const cutChars = resInfo.cutChars || null;
// Check if message should be sent without a prefix and set it to an empty string
if (!resInfo.prefix) resInfo.prefix = "";
else resInfo.prefix += " "; // Add whitespace between prefix and message content
// Get the correct part to send without breaking links and add prefix infront
- let thisPart = resInfo.prefix + cutStringsIntelligently(txt, limit, cutChars)[part];
+ const thisPart = resInfo.prefix + cutStringsIntelligently(txt, limit, cutChars)[part];
// Log full message if in debug mode, otherwise log cut down version
if (_this.controller.data.advancedconfig.printDebug) {
@@ -133,8 +133,8 @@ Bot.prototype.readChatMessage = function(steamID64, timeout) {
this.friendMessageBlock.push(steamID64);
// Provide function to handle event
- let handleEvent = (steamID, message) => { // ES6 function to keep previous context
- let msgSteamID64 = new SteamID(String(steamID)).getSteamID64();
+ const handleEvent = (steamID, message) => { // ES6 function to keep previous context
+ const msgSteamID64 = new SteamID(String(steamID)).getSteamID64();
if (msgSteamID64 != steamID64) return; // Ignore if not from our user
diff --git a/src/commands/commandHandler.js b/src/commands/commandHandler.js
index 7e9eba15..9fd4bc43 100644
--- a/src/commands/commandHandler.js
+++ b/src/commands/commandHandler.js
@@ -152,7 +152,7 @@ CommandHandler.prototype.registerCommand = function(command) {
CommandHandler.prototype.unregisterCommand = function(commandName) {
// Iterate through all command objects in commands array and check if name is included in names array of each command.
- let thisCmd = this.commands.find(e => e.names.includes(commandName));
+ const thisCmd = this.commands.find(e => e.names.includes(commandName));
if (!thisCmd) {
logger("warn", `CommandHandler unregisterCommand(): Command '${commandName}' was not found!`);
@@ -160,7 +160,7 @@ CommandHandler.prototype.unregisterCommand = function(commandName) {
}
// Remove command from commands array
- let index = this.commands.indexOf(thisCmd);
+ const index = this.commands.indexOf(thisCmd);
this.commands.splice(index, index + 1);
@@ -195,7 +195,7 @@ CommandHandler.prototype.unregisterCommand = function(commandName) {
CommandHandler.prototype.runCommand = async function(name, args, respondModule, context, resInfo) {
// Iterate through all command objects in commands array and check if name is included in names array of each command.
- let thisCmd = this.commands.find(e => e.names.includes(name));
+ const thisCmd = this.commands.find(e => e.names.includes(name));
if (!thisCmd) {
logger("warn", `CommandHandler runCommand(): Command '${name}' was not found!`);
diff --git a/src/commands/core/block.js b/src/commands/core/block.js
index 88d056e3..fe0cd247 100644
--- a/src/commands/core/block.js
+++ b/src/commands/core/block.js
@@ -4,10 +4,10 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:08:09
+ * Last Modified: 2024-05-08 20:49:02
* Modified By: 3urobeat
*
- * Copyright (c) 2021 - 2023 3urobeat
+ * Copyright (c) 2021 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -43,7 +43,7 @@ module.exports.block = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, resInfo.userID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -57,12 +57,12 @@ module.exports.block = {
if (err) return respond((await commandHandler.data.getLang("invalidprofileid", null, resInfo.userID)) + "\n\nError: " + err);
if (owners.includes(res)) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("idisownererror", null, resInfo.userID)); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
- commandHandler.controller.getBots().forEach((e, i) => {
- e.user.blockUser(new SteamID(res), (err) => { if (err) logger("error", `[Bot ${i}] Error blocking user ${res}: ${err}`); });
+ commandHandler.controller.getBots().forEach((e) => {
+ e.user.blockUser(new SteamID(res), (err) => { if (err) logger("error", `[${e.logPrefix}] Error blocking user '${res}': ${err}`); });
});
respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("blockcmdsuccess", { "profileid": res }, resInfo.userID)); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
- logger("info", `Blocked ${res} with all bot accounts.`);
+ logger("info", `Blocked '${res}' with all bot accounts.`);
});
}
};
@@ -91,7 +91,7 @@ module.exports.unblock = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, resInfo.userID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -100,12 +100,12 @@ module.exports.unblock = {
commandHandler.controller.handleSteamIdResolving(args[0], "profile", async (err, res) => {
if (err) return respond((await commandHandler.data.getLang("invalidprofileid", null, resInfo.userID)) + "\n\nError: " + err);
- commandHandler.controller.getBots().forEach((e, i) => {
- e.user.unblockUser(new SteamID(res), (err) => { if (err) logger("error", `[Bot ${i}] Error unblocking user ${res}: ${err}`); });
+ commandHandler.controller.getBots().forEach((e) => {
+ e.user.unblockUser(new SteamID(res), (err) => { if (err) logger("error", `[${e.logPrefix}] Error unblocking user '${res}': ${err}`); });
});
respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("unblockcmdsuccess", { "profileid": res }, resInfo.userID)); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
- logger("info", `Unblocked ${res} with all bot accounts.`);
+ logger("info", `Unblocked '${res}' with all bot accounts.`);
});
}
};
diff --git a/src/commands/core/comment.js b/src/commands/core/comment.js
index f2add518..deaf1763 100644
--- a/src/commands/core/comment.js
+++ b/src/commands/core/comment.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-03-02 13:48:36
+ * Last Modified: 2024-05-04 22:02:28
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -59,15 +59,15 @@ module.exports.comment = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
+ const requesterID = resInfo.userID;
let receiverSteamID64 = requesterID;
- let ownercheck = owners.includes(requesterID);
+ const ownercheck = owners.includes(requesterID);
/* --------- Various checks --------- */
@@ -84,7 +84,7 @@ module.exports.comment = {
/* --------- Calculate maxRequestAmount and get arguments from comment request --------- */
- let { maxRequestAmount, numberOfComments, profileID, idType, quotesArr } = await getCommentArgs(commandHandler, args, resInfo, respond);
+ const { maxRequestAmount, numberOfComments, profileID, idType, quotesArr } = await getCommentArgs(commandHandler, args, resInfo, respond);
if (!maxRequestAmount && !numberOfComments && !quotesArr) return; // Looks like the helper aborted the request
@@ -101,20 +101,20 @@ module.exports.comment = {
// Check if user is already receiving comments right now
- let activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64];
+ const activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64];
if (activeReqEntry && activeReqEntry.status == "active") return respond(await commandHandler.data.getLang("idalreadyreceiving", null, requesterID));
// Check if user has cooldown
- let { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
+ const { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
if (until > Date.now()) return respond(await commandHandler.data.getLang("idoncooldown", { "remainingcooldown": untilStr }, requesterID));
// Get all currently available bot accounts. Block limited accounts from being eligible from commenting in groups
- let allowLimitedAccounts = (idType != "group");
- let { accsNeeded, availableAccounts, accsToAdd, whenAvailableStr } = await getAvailableBotsForCommenting(commandHandler, numberOfComments, allowLimitedAccounts, idType, receiverSteamID64); // Await *has* an effect on this expression you idiot
+ const allowLimitedAccounts = (idType != "group");
+ const { accsNeeded, availableAccounts, accsToAdd, whenAvailableStr } = await getAvailableBotsForCommenting(commandHandler, numberOfComments, allowLimitedAccounts, idType, receiverSteamID64); // Await *has* an effect on this expression you idiot
if (availableAccounts.length == 0 && !whenAvailableStr) { // Check if this bot has no suitable accounts for this request and there won't be any available at any point
if (!allowLimitedAccounts) respond(await commandHandler.data.getLang("genericnounlimitedaccs", { "cmdprefix": resInfo.cmdprefix }, requesterID)); // Send less generic message for requests which require unlimited accounts
@@ -143,7 +143,7 @@ module.exports.comment = {
// Prepare activeRequests entry
- let activeRequestsObj = {
+ const activeRequestsObj = {
status: "active",
type: idType + "Comment", // Add "Comment" to the end of type to differentiate a comment process from other requests
amount: numberOfComments,
@@ -240,7 +240,7 @@ module.exports.comment = {
// Start commenting
logger("debug", "Made activeRequest entry for user, starting comment loop...");
- comment(commandHandler, resInfo, respond, postComment, commentArgs, receiverSteamID64);
+ comment(commandHandler, resInfo, respond, postComment, commentArgs, receiverSteamID64); // eslint-disable-line no-use-before-define
}
};
@@ -255,19 +255,19 @@ module.exports.comment = {
* @param {string} receiverSteamID64 steamID64 of the profile to receive the comments
*/
async function comment(commandHandler, resInfo, respond, postComment, commentArgs, receiverSteamID64) {
- let activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64]; // Make using the obj shorter
- let requesterID = resInfo.userID;
+ const activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64]; // Make using the obj shorter
+ const requesterID = resInfo.userID;
// Log request start and give user cooldown on the first iteration
- let whereStr = activeReqEntry.type == "profileComment" ? `on profile ${receiverSteamID64}` : `in/on ${activeReqEntry.type.replace("Comment", "")} ${receiverSteamID64}`; // Shortcut to convey more precise information in the 4 log messages below
+ const whereStr = activeReqEntry.type == "profileComment" ? `on profile ${receiverSteamID64}` : `in/on ${activeReqEntry.type.replace("Comment", "")} ${receiverSteamID64}`; // Shortcut to convey more precise information in the 4 log messages below
if (activeReqEntry.thisIteration == -1) {
logger("info", `${logger.colors.fggreen}[${commandHandler.controller.main.logPrefix}] ${activeReqEntry.amount} Comment(s) requested. Starting to comment ${whereStr}...`);
// Only send estimated wait time message for multiple comments
if (activeReqEntry.amount > 1) {
- let waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first comment is instant. Multiply by delay and add to current time to get timestamp when last comment was sent
+ const waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first comment is instant. Multiply by delay and add to current time to get timestamp when last comment was sent
respond(await commandHandler.data.getLang("commentprocessstarted", { "numberOfComments": activeReqEntry.amount, "waittime": waitTime }, requesterID));
}
@@ -279,12 +279,12 @@ async function comment(commandHandler, resInfo, respond, postComment, commentArg
// Comment numberOfComments times using our syncLoop helper
- syncLoop(activeReqEntry.amount - (activeReqEntry.thisIteration + 1), (loop, i) => { // eslint-disable-line no-unused-vars
+ syncLoop(activeReqEntry.amount - (activeReqEntry.thisIteration + 1), (loop, i) => {
setTimeout(async () => {
/* --------- Get the correct account for this iteration and update iteration in activeRequests obj --------- */
- let bot = commandHandler.controller.getBots("*", true)[activeReqEntry.accounts[i % activeReqEntry.accounts.length]]; // Iteration modulo amount of accounts gives us index of account to use inside the accounts array. This returns the bot account name which we can lookup in the bots object.
+ const bot = commandHandler.controller.getBots("*", true)[activeReqEntry.accounts[i % activeReqEntry.accounts.length]]; // Iteration modulo amount of accounts gives us index of account to use inside the accounts array. This returns the bot account name which we can lookup in the bots object.
activeReqEntry.thisIteration++;
@@ -293,7 +293,7 @@ async function comment(commandHandler, resInfo, respond, postComment, commentArg
/* --------- Try to comment --------- */
- let quote = await commandHandler.data.getQuote(activeReqEntry.quotesArr); // Get a random quote to comment with
+ const quote = await commandHandler.data.getQuote(activeReqEntry.quotesArr); // Get a random quote to comment with
commentArgs["quote"] = quote; // Replace key "quote" in args obj
postComment.call(bot.community, ...Object.values(commentArgs), (error) => { // Very important! Using call() and passing the bot's community instance will keep context (this.) as it was lost by our postComment variable assignment!
@@ -336,7 +336,7 @@ async function comment(commandHandler, resInfo, respond, postComment, commentArg
activeReqEntry.retryAttempt++;
// Log and notify user about retry attempt starting in retryFailedCommentsDelay ms
- let untilStr = timeToString(Date.now() + commandHandler.data.advancedconfig.retryFailedCommentsDelay);
+ const untilStr = timeToString(Date.now() + commandHandler.data.advancedconfig.retryFailedCommentsDelay);
respond(await commandHandler.data.getLang("commentretrying", { "failedamount": Object.keys(activeReqEntry.failed).length, "numberOfComments": activeReqEntry.amount - activeReqEntry.amountBeforeRetry, "untilStr": untilStr, "thisattempt": activeReqEntry.retryAttempt, "maxattempt": commandHandler.data.advancedconfig.retryFailedCommentsAttempts }, requesterID));
logger("info", `${Object.keys(activeReqEntry.failed).length}/${activeReqEntry.amount - activeReqEntry.amountBeforeRetry} comments failed for ${receiverSteamID64}. Retrying in ${untilStr} (Attempt ${activeReqEntry.retryAttempt}/${commandHandler.data.advancedconfig.retryFailedCommentsAttempts})`, false, false, logger.animation("waiting"));
diff --git a/src/commands/core/favorite.js b/src/commands/core/favorite.js
index e86b317f..bc76a81c 100644
--- a/src/commands/core/favorite.js
+++ b/src/commands/core/favorite.js
@@ -52,14 +52,14 @@ module.exports.favorite = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
- let ownercheck = owners.includes(requesterID);
+ const requesterID = resInfo.userID;
+ const ownercheck = owners.includes(requesterID);
/* --------- Various checks --------- */
@@ -73,25 +73,25 @@ module.exports.favorite = {
// Check and get arguments from user
- let { amountRaw, id } = await getMiscArgs(commandHandler, args, "favorite", resInfo, respond);
+ const { amountRaw, id } = await getMiscArgs(commandHandler, args, "favorite", resInfo, respond);
if (!amountRaw && !id) return; // Looks like the helper aborted the request
// Check if this id is already receiving something right now
- let idReq = commandHandler.controller.activeRequests[id];
+ const idReq = commandHandler.controller.activeRequests[id];
if (idReq && idReq.status == "active") return respond(await commandHandler.data.getLang("idalreadyreceiving", null, requesterID)); // Note: No need to check for user as that is supposed to be handled by a cooldown
// Check if user has cooldown
- let { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
+ const { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
if (until > Date.now()) return respond(await commandHandler.data.getLang("idoncooldown", { "remainingcooldown": untilStr }, requesterID));
// Get all available bot accounts
- let { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFavorizing(commandHandler, amountRaw, id, "favorite");
+ const { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFavorizing(commandHandler, amountRaw, id, "favorite");
if ((availableAccounts.length < amount || availableAccounts.length == 0) && !whenAvailableStr) { // Check if this bot has not enough accounts suitable for this request and there won't be more available at any point.
if (availableAccounts.length == 0) respond(await commandHandler.data.getLang("genericnoaccounts", null, requesterID)); // The < || == 0 check is intentional, as providing "all" will set amount to 0 if 0 accounts have been found
@@ -127,7 +127,7 @@ module.exports.favorite = {
failed: {}
};
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Log request start and give user cooldown on the first iteration
@@ -136,7 +136,7 @@ module.exports.favorite = {
// Only send estimated wait time message for multiple favorites
if (activeReqEntry.amount > 1) {
- let waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
+ const waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
respond(await commandHandler.data.getLang("favoriteprocessstarted", { "numberOfFavs": activeReqEntry.amount, "waittime": waitTime }, requesterID));
}
@@ -151,7 +151,7 @@ module.exports.favorite = {
syncLoop(amount, (loop, i) => {
setTimeout(() => {
- let bot = commandHandler.controller.bots[availableAccounts[i]];
+ const bot = commandHandler.controller.bots[availableAccounts[i]];
activeReqEntry.thisIteration++;
if (!handleFavoriteIterationSkip(commandHandler, loop, bot, id)) return; // Skip iteration if false was returned
@@ -250,14 +250,14 @@ module.exports.unfavorite = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
- let ownercheck = owners.includes(requesterID);
+ const requesterID = resInfo.userID;
+ const ownercheck = owners.includes(requesterID);
/* --------- Various checks --------- */
@@ -271,25 +271,25 @@ module.exports.unfavorite = {
// Check and get arguments from user
- let { amountRaw, id } = await getMiscArgs(commandHandler, args, "unfavorite", resInfo, respond);
+ const { amountRaw, id } = await getMiscArgs(commandHandler, args, "unfavorite", resInfo, respond);
if (!amountRaw && !id) return; // Looks like the helper aborted the request
// Check if this id is already receiving something right now
- let idReq = commandHandler.controller.activeRequests[id];
+ const idReq = commandHandler.controller.activeRequests[id];
if (idReq && idReq.status == "active") return respond(await commandHandler.data.getLang("idalreadyreceiving", null, requesterID)); // Note: No need to check for user as that is supposed to be handled by a cooldown
// Check if user has cooldown
- let { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
+ const { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
if (until > Date.now()) return respond(await commandHandler.data.getLang("idoncooldown", { "remainingcooldown": untilStr }, requesterID));
// Get all available bot accounts
- let { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFavorizing(commandHandler, amountRaw, id, "unfavorite");
+ const { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFavorizing(commandHandler, amountRaw, id, "unfavorite");
if ((availableAccounts.length < amount || availableAccounts.length == 0) && !whenAvailableStr) { // Check if this bot has not enough accounts suitable for this request and there won't be more available at any point.
if (availableAccounts.length == 0) respond(await commandHandler.data.getLang("genericnoaccounts", null, requesterID)); // The < || == 0 check is intentional, as providing "all" will set amount to 0 if 0 accounts have been found
@@ -325,7 +325,7 @@ module.exports.unfavorite = {
failed: {}
};
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Log request start and give user cooldown on the first iteration
@@ -334,7 +334,7 @@ module.exports.unfavorite = {
// Only send estimated wait time message for multiple favorites
if (activeReqEntry.amount > 1) {
- let waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
+ const waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
respond(await commandHandler.data.getLang("favoriteprocessstarted", { "numberOfFavs": activeReqEntry.amount, "waittime": waitTime }, requesterID));
}
@@ -349,7 +349,7 @@ module.exports.unfavorite = {
syncLoop(amount, (loop, i) => {
setTimeout(() => {
- let bot = commandHandler.controller.bots[availableAccounts[i]];
+ const bot = commandHandler.controller.bots[availableAccounts[i]];
activeReqEntry.thisIteration++;
if (!handleFavoriteIterationSkip(commandHandler, loop, bot, id)) return; // Skip iteration if false was returned
diff --git a/src/commands/core/follow.js b/src/commands/core/follow.js
index 2af03768..853ba845 100644
--- a/src/commands/core/follow.js
+++ b/src/commands/core/follow.js
@@ -52,14 +52,14 @@ module.exports.follow = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
- let ownercheck = owners.includes(requesterID);
+ const requesterID = resInfo.userID;
+ const ownercheck = owners.includes(requesterID);
/* --------- Various checks --------- */
@@ -73,26 +73,26 @@ module.exports.follow = {
// Check and get arguments from user
- let { amountRaw, id, idType } = await getFollowArgs(commandHandler, args, "follow", resInfo, respond);
+ const { amountRaw, id, idType } = await getFollowArgs(commandHandler, args, "follow", resInfo, respond);
if (!amountRaw && !id) return; // Looks like the helper aborted the request
// Check if this id is already receiving something right now
- let idReq = commandHandler.controller.activeRequests[id];
+ const idReq = commandHandler.controller.activeRequests[id];
if (idReq && idReq.status == "active") return respond(await commandHandler.data.getLang("idalreadyreceiving", null, requesterID)); // Note: No need to check for user as that is supposed to be handled by a cooldown
// Check if user has cooldown
- let { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
+ const { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
if (until > Date.now()) return respond(await commandHandler.data.getLang("idoncooldown", { "remainingcooldown": untilStr }, requesterID));
// Get all available bot accounts. Block limited accounts from following curators
- let allowLimitedAccounts = (idType != "curator");
- let { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFollowing(commandHandler, amountRaw, allowLimitedAccounts, id, idType, "follow", resInfo);
+ const allowLimitedAccounts = (idType != "curator");
+ const { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFollowing(commandHandler, amountRaw, allowLimitedAccounts, id, idType, "follow", resInfo);
if ((availableAccounts.length < amount || availableAccounts.length == 0) && !whenAvailableStr) { // Check if this bot has not enough accounts suitable for this request and there won't be more available at any point. The < || == 0 check is intentional, as providing "all" will set amount to 0 if 0 accounts have been found
if (availableAccounts.length == 0) {
@@ -124,7 +124,7 @@ module.exports.follow = {
failed: {}
};
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Log request start and give user cooldown on the first iteration
@@ -133,7 +133,7 @@ module.exports.follow = {
// Only send estimated wait time message for multiple follow
if (activeReqEntry.amount > 1) {
- let waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
+ const waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
respond(await commandHandler.data.getLang("followprocessstarted", { "totalamount": activeReqEntry.amount, "waittime": waitTime }, requesterID));
}
@@ -148,7 +148,7 @@ module.exports.follow = {
syncLoop(amount, (loop, i) => {
setTimeout(() => {
- let bot = commandHandler.controller.bots[availableAccounts[i]];
+ const bot = commandHandler.controller.bots[availableAccounts[i]];
activeReqEntry.thisIteration++;
if (!handleFollowIterationSkip(commandHandler, loop, bot, id)) return; // Skip iteration if false was returned
@@ -248,14 +248,14 @@ module.exports.unfollow = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
- let ownercheck = owners.includes(requesterID);
+ const requesterID = resInfo.userID;
+ const ownercheck = owners.includes(requesterID);
/* --------- Various checks --------- */
@@ -269,26 +269,26 @@ module.exports.unfollow = {
// Check and get arguments from user
- let { amountRaw, id, idType } = await getFollowArgs(commandHandler, args, "unfollow", resInfo, respond);
+ const { amountRaw, id, idType } = await getFollowArgs(commandHandler, args, "unfollow", resInfo, respond);
if (!amountRaw && !id) return; // Looks like the helper aborted the request
// Check if this id is already receiving something right now
- let idReq = commandHandler.controller.activeRequests[id];
+ const idReq = commandHandler.controller.activeRequests[id];
if (idReq && idReq.status == "active") return respond(await commandHandler.data.getLang("idalreadyreceiving", null, requesterID)); // Note: No need to check for user as that is supposed to be handled by a cooldown
// Check if user has cooldown
- let { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
+ const { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
if (until > Date.now()) return respond(await commandHandler.data.getLang("idoncooldown", { "remainingcooldown": untilStr }, requesterID));
// Get all available bot accounts. Block limited accounts from following curators
- let allowLimitedAccounts = (idType != "curator");
- let { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFollowing(commandHandler, amountRaw, allowLimitedAccounts, id, idType, "unfollow", resInfo);
+ const allowLimitedAccounts = (idType != "curator");
+ const { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForFollowing(commandHandler, amountRaw, allowLimitedAccounts, id, idType, "unfollow", resInfo);
if ((availableAccounts.length < amount || availableAccounts.length == 0) && !whenAvailableStr) { // Check if this bot has not enough accounts suitable for this request and there won't be more available at any point. The < || == 0 check is intentional, as providing "all" will set amount to 0 if 0 accounts have been found
if (availableAccounts.length == 0) {
@@ -320,7 +320,7 @@ module.exports.unfollow = {
failed: {}
};
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Log request start and give user cooldown on the first iteration
@@ -329,7 +329,7 @@ module.exports.unfollow = {
// Only send estimated wait time message for multiple unfollow
if (activeReqEntry.amount > 1) {
- let waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
+ const waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first fav is instant. Multiply by delay and add to current time to get timestamp when last fav was sent
respond(await commandHandler.data.getLang("followprocessstarted", { "totalamount": activeReqEntry.amount, "waittime": waitTime }, requesterID));
}
@@ -344,7 +344,7 @@ module.exports.unfollow = {
syncLoop(amount, (loop, i) => {
setTimeout(() => {
- let bot = commandHandler.controller.bots[availableAccounts[i]];
+ const bot = commandHandler.controller.bots[availableAccounts[i]];
activeReqEntry.thisIteration++;
if (!handleFollowIterationSkip(commandHandler, loop, bot, id)) return; // Skip iteration if false was returned
diff --git a/src/commands/core/friend.js b/src/commands/core/friend.js
index e389d450..0bb2be64 100644
--- a/src/commands/core/friend.js
+++ b/src/commands/core/friend.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-03-08 18:24:40
+ * Last Modified: 2024-05-08 21:10:22
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -21,7 +21,7 @@ const CommandHandler = require("../commandHandler.js"); // eslint-disable-line
module.exports.addFriend = {
- names: ["addfriend"],
+ names: ["addfriend", "add"],
description: "Adds the ID with all bot accounts. Requires unlimited accounts!",
args: [
{
@@ -43,8 +43,8 @@ module.exports.addFriend = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -60,20 +60,20 @@ module.exports.addFriend = {
}
respond(await commandHandler.data.getLang("addfriendcmdsuccess", { "profileid": res, "estimatedtime": 5 * commandHandler.controller.getBots().length }, requesterID));
- logger("info", `Adding friend ${res} with all bot accounts... This will take ~${5 * commandHandler.controller.getBots().length} seconds.`);
+ logger("info", `Adding friend '${res}' with all bot accounts... This will take ~${5 * commandHandler.controller.getBots().length} seconds.`);
commandHandler.controller.getBots().forEach((e, i) => {
// Check if this bot account is limited
if (e.user.limitations && e.user.limitations.limited == true) {
- logger("error", `Can't add friend ${res} with bot${e.index} because the bot account is limited.`);
+ logger("error", `[${e.logPrefix}] Can't add user '${res}' as a friend because the bot account is limited.`);
return;
}
if (e.user.myFriends[res] != 3 && e.user.myFriends[res] != 1) { // Check if provided user is not friend and not blocked
setTimeout(() => {
e.user.addFriend(new SteamID(res), (err) => {
- if (err) logger("error", `Error adding ${res} with bot${e.index}: ${err}`);
- else logger("info", `Added ${res} with bot${e.index} as friend.`);
+ if (err) logger("error", `[${e.logPrefix}] Failed to add '${res}' as a friend: ${err}`);
+ else logger("info", `[${e.logPrefix}] Added '${res}' as a friend.`);
});
commandHandler.controller.friendListCapacityCheck(e, (remaining) => { // Check remaining friendlist space
@@ -81,7 +81,7 @@ module.exports.addFriend = {
});
}, 5000 * i);
} else {
- logger("warn", `bot${e.index} is already friend with ${res} or the account was blocked/blocked you.`); // Somehow logs steamIDs in separate row?!
+ logger("warn", `[${e.logPrefix}] This bot account is already friend with '${res}' or the account was blocked/blocked you.`);
}
});
});
@@ -112,8 +112,8 @@ module.exports.unfriend = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -123,7 +123,7 @@ module.exports.unfriend = {
// Unfriend message sender with all bot accounts if no id was provided and the command was called from the steam chat
if (!args[0] && resInfo.userID && resInfo.fromSteamChat) {
respond(commandHandler.data.getLang("unfriendcmdsuccess", null, requesterID));
- logger("info", `Removing friend ${resInfo.userID} from all bot accounts...`);
+ logger("info", `Removing friend '${resInfo.userID}' from all bot accounts...`);
commandHandler.controller.getBots().forEach((e, i) => {
setTimeout(() => {
@@ -151,7 +151,7 @@ module.exports.unfriend = {
});
respond(await commandHandler.data.getLang("unfriendidcmdsuccess", { "profileid": res }, requesterID));
- logger("info", `Removed friend ${res} from all bot accounts.`);
+ logger("info", `Removed friend '${res}' from all bot accounts.`);
});
}
}
@@ -181,8 +181,8 @@ module.exports.unfriendall = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -202,24 +202,24 @@ module.exports.unfriendall = {
respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("unfriendallcmdstart", null, requesterID)); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
logger("info", "Starting to unfriend everyone...");
- for (let i = 0; i < commandHandler.controller.getBots().length; i++) {
- for (let friend in commandHandler.controller.getBots()[i].user.myFriends) {
+ commandHandler.controller.getBots().forEach((thisBot, i) => {
+ for (const friend in thisBot.user.myFriends) {
try {
setTimeout(() => {
- let friendSteamID = new SteamID(String(friend));
+ const friendSteamID = new SteamID(String(friend));
if (!commandHandler.data.cachefile.ownerid.includes(friend)) { // Check for the "original" ownerid array here, we don't care about non Steam IDs
- logger("info", `Removing friend ${friendSteamID.getSteamID64()} from all bot accounts...`, false, false, logger.animation("loading"));
- commandHandler.controller.getBots()[i].user.removeFriend(friendSteamID);
+ logger("info", `Removing friend '${friendSteamID.getSteamID64()}' from all bot accounts...`, false, false, logger.animation("loading"));
+ thisBot.user.removeFriend(friendSteamID);
} else {
logger("debug", `unfriendAll(): Friend ${friendSteamID.getSteamID64()} seems to be an owner, skipping...`);
}
}, 1000 * i); // Delay every iteration so that we don't make a ton of requests at once
} catch (err) {
- logger("error", `[Bot ${i}] unfriendall error unfriending ${friend}: ${err}`);
+ logger("error", `[${thisBot.logPrefix}] unfriendall error unfriending ${friend}: ${err}`);
}
}
- }
+ });
}, 30000);
}
};
diff --git a/src/commands/core/general.js b/src/commands/core/general.js
index 41d513aa..69d3d52a 100644
--- a/src/commands/core/general.js
+++ b/src/commands/core/general.js
@@ -37,8 +37,8 @@ module.exports.help = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
@@ -99,14 +99,14 @@ module.exports.info = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
commandHandler.data.lastCommentDB.findOne({ id: resInfo.userID }, async (err, doc) => {
- let lastReq = await commandHandler.data.getLastCommentRequest();
+ const lastReq = await commandHandler.data.getLastCommentRequest();
let userLastReq = "Never";
if (doc) userLastReq = ((new Date(doc.time)).toISOString().replace(/T/, " ").replace(/\..+/, "")) + " (GMT time)";
@@ -146,8 +146,8 @@ module.exports.ping = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let pingStart = Date.now();
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const pingStart = Date.now();
https.get("https://steamcommunity.com/ping", (res) => { // Ping steamcommunity.com/ping and measure time
res.setEncoding("utf8");
@@ -173,7 +173,7 @@ module.exports.about = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
respond(commandHandler.data.datafile.aboutstr);
}
@@ -195,7 +195,7 @@ module.exports.owner = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Check if no owner link is set
if (commandHandler.data.config.owner.length < 1) return respond(await commandHandler.data.getLang("ownercmdnolink", null, resInfo.userID));
diff --git a/src/commands/core/group.js b/src/commands/core/group.js
index 4efdfbad..9939e6ff 100644
--- a/src/commands/core/group.js
+++ b/src/commands/core/group.js
@@ -4,10 +4,10 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:07:07
+ * Last Modified: 2024-05-08 20:40:33
* Modified By: 3urobeat
*
- * Copyright (c) 2021 - 2023 3urobeat
+ * Copyright (c) 2021 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -35,7 +35,7 @@ module.exports.group = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
if (commandHandler.data.config.yourgroup.length < 1 || !commandHandler.data.cachefile.configgroup64id) return respond(await commandHandler.data.getLang("groupcmdnolink", null, resInfo.userID)); // No group info at all? stop.
@@ -78,8 +78,8 @@ module.exports.joinGroup = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -124,8 +124,8 @@ module.exports.leaveGroup = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -170,8 +170,8 @@ module.exports.leaveAllGroups = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -192,15 +192,17 @@ module.exports.leaveAllGroups = {
logger("info", "Starting to leave all groups...");
for (let i = 0; i < commandHandler.controller.getBots().length; i++) {
- for (let group in commandHandler.controller.getBots()[i].user.myGroups) {
+ for (const group in commandHandler.controller.getBots()[i].user.myGroups) {
+ const thisBot = commandHandler.controller.getBots()[i];
+
try {
setTimeout(() => {
- if (commandHandler.controller.getBots()[i].user.myGroups[group] == 3) {
+ if (thisBot.user.myGroups[group] == 3) {
if (group != commandHandler.data.cachefile.botsgroupid && group != commandHandler.data.cachefile.configgroup64id) commandHandler.controller.getBots()[i].community.leaveGroup(String(group));
}
}, 1000 * i); // Delay every iteration so that we don't make a ton of requests at once
} catch (err) {
- logger("error", `[Bot ${i}] leaveallgroups error leaving ${group}: ${err}`);
+ logger("error", `[${thisBot.logPrefix}] leaveallgroups error leaving ${group}: ${err}`);
}
}
}
diff --git a/src/commands/core/requests.js b/src/commands/core/requests.js
index ce941e89..96bc6858 100644
--- a/src/commands/core/requests.js
+++ b/src/commands/core/requests.js
@@ -42,8 +42,8 @@ module.exports.abort = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (commandHandler.controller.info.readyAfter == 0) return respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("botnotready", null, requesterID)); // Check if bot isn't fully started yet - Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -54,7 +54,7 @@ module.exports.abort = {
commandHandler.controller.handleSteamIdResolving(args[0], null, async (err, res) => {
if (res) {
- let activeReqEntry = commandHandler.controller.activeRequests[res];
+ const activeReqEntry = commandHandler.controller.activeRequests[res];
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
@@ -102,8 +102,8 @@ module.exports.resetCooldown = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let requesterID = resInfo.userID;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const requesterID = resInfo.userID;
if (args[0] && args[0] == "global") { // Check if user wants to reset the global cooldown (will reset all until entries in activeRequests)
if (commandHandler.data.config.botaccountcooldown == 0) return respond(await commandHandler.data.getLang("resetcooldowncmdcooldowndisabled", null, requesterID)); // Is the global cooldown enabled?
@@ -160,7 +160,7 @@ module.exports.failed = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
let userID = resInfo.userID;
@@ -169,7 +169,7 @@ module.exports.failed = {
commandHandler.controller.handleSteamIdResolving(args[0], null, async (err, res) => {
if (res) {
- let activeReqEntry = commandHandler.controller.activeRequests[res];
+ const activeReqEntry = commandHandler.controller.activeRequests[res];
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
@@ -185,13 +185,13 @@ module.exports.failed = {
if (!commandHandler.controller.activeRequests[userID] || Object.keys(commandHandler.controller.activeRequests[userID].failed).length < 1) return respond(await commandHandler.data.getLang("failedcmdnothingfound", null, resInfo.userID));
// Get timestamp of request
- let requestTime = new Date(commandHandler.controller.activeRequests[userID].until).toISOString().replace(/T/, " ").replace(/\..+/, "");
+ const requestTime = new Date(commandHandler.controller.activeRequests[userID].until).toISOString().replace(/T/, " ").replace(/\..+/, "");
// Group errors and convert them to string using helper function
- let failedcommentsstr = failedCommentsObjToString(commandHandler.controller.activeRequests[userID].failed);
+ const failedcommentsstr = failedCommentsObjToString(commandHandler.controller.activeRequests[userID].failed);
// Get start of message from lang file and add data
- let messagestart = await commandHandler.data.getLang("failedcmdmsg", { "steamID64": userID, "requesttime": requestTime }, resInfo.userID);
+ const messagestart = await commandHandler.data.getLang("failedcmdmsg", { "steamID64": userID, "requesttime": requestTime }, resInfo.userID);
// Send message and limit to 500 chars as this call can cause many messages to be sent
respondModule(context, { prefix: "/pre", charLimit: 500, ...resInfo }, messagestart + "\ni = Index, b = Bot, p = Proxy\n\n" + failedcommentsstr); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -215,7 +215,7 @@ module.exports.sessions = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Don't bother if there is no active request
if (Object.keys(commandHandler.controller.activeRequests).length == 0) return respond(await commandHandler.data.getLang("sessionscmdnosessions", null, resInfo.userID));
@@ -255,7 +255,7 @@ module.exports.mySessions = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Check for no userID as the default behavior might be unavailable when calling from outside of the Steam Chat
if (!resInfo.userID) return respond(await commandHandler.data.getLang("nouserid")); // In this case the cmd doesn't have an ID param so send this message instead of noidparam
diff --git a/src/commands/core/settings.js b/src/commands/core/settings.js
index 75ec0530..8fc03c32 100644
--- a/src/commands/core/settings.js
+++ b/src/commands/core/settings.js
@@ -41,7 +41,7 @@ module.exports.lang = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// List all supported languages by joining the keys of the data lang object with a line break and -
if (!args[0]) {
@@ -49,7 +49,7 @@ module.exports.lang = {
return;
}
- let suppliedLang = args[0].toLowerCase();
+ const suppliedLang = args[0].toLowerCase();
// Check if the supplied language is supported
if (!Object.keys(commandHandler.data.lang).includes(suppliedLang)) {
@@ -107,12 +107,12 @@ module.exports.settings = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
- let config = commandHandler.data.config;
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const config = commandHandler.data.config;
// Only send current settings if no arguments were provided
if (!args[0]) {
- let stringifiedconfig = JSON.stringify(commandHandler.data.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedconfig = JSON.stringify(commandHandler.data.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
@@ -122,7 +122,7 @@ module.exports.settings = {
.replace(/""/g, '""');
// Remove first and last character which are brackets and remove leading and trailing whitespaces from all lines
- let currentsettingsarr = stringifiedconfig.toString().slice(1, -1).split("\n").map(s => s.trim());
+ const currentsettingsarr = stringifiedconfig.toString().slice(1, -1).split("\n").map(s => s.trim());
// Send message with code prefix and only allow cuts at newlines
respondModule(context, { prefix: "/code", cutChars: ["\n"], ...resInfo }, (await commandHandler.data.getLang("settingscmdcurrentsettings", null, resInfo.userID)) + "\n" + currentsettingsarr.join("\n")); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
@@ -140,13 +140,13 @@ module.exports.settings = {
return;
}
- let keyvalue = config[args[0]]; // Save old value to be able to reset changes
+ const keyvalue = config[args[0]]; // Save old value to be able to reset changes
// Convert array-like string into usable array
if (Array.isArray(keyvalue)) {
try {
- let newValue = args.slice(1).join(" "); // Remove first element, which is the key name and join the rest
+ const newValue = args.slice(1).join(" "); // Remove first element, which is the key name and join the rest
args[1] = JSON.parse(newValue); // Attempt to parse user input
diff --git a/src/commands/core/system.js b/src/commands/core/system.js
index e09b8f6e..8fd76d8b 100644
--- a/src/commands/core/system.js
+++ b/src/commands/core/system.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-02-11 17:03:32
+ * Last Modified: 2024-05-03 13:08:52
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -35,7 +35,7 @@ module.exports.jobs = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Check if no job is registered and abort
if (commandHandler.controller.jobManager.jobs.length == 0) {
@@ -44,17 +44,17 @@ module.exports.jobs = {
}
// Helper function to convert lastExecTimestamp to human readable format
- let convertTimestamp = (timestamp) => ((new Date(timestamp)).toISOString().replace(/T/, " ").replace(/\..+/, "")) + " (GMT time)";
+ const convertTimestamp = (timestamp) => ((new Date(timestamp)).toISOString().replace(/T/, " ").replace(/\..+/, "")) + " (GMT time)";
// Construct str to respond with
let str = await commandHandler.data.getLang("jobscmdregistered", null, resInfo.userID) + "\n";
commandHandler.controller.jobManager.jobs.forEach((job) => {
- let desc = job.description ? " " + job.description + "\n" : ""; // Adds job description if one was specified
- let intervalFormatted = commandHandler.controller.misc.timeToString(Date.now() + job.interval); // Hack: Add current time to use timeToString for formatting (it's designed to be used in an "until from now" situation)
+ const desc = job.description ? " " + job.description + "\n" : ""; // Adds job description if one was specified
+ const intervalFormatted = commandHandler.controller.misc.timeToString(Date.now() + job.interval); // Hack: Add current time to use timeToString for formatting (it's designed to be used in an "until from now" situation)
// Only show lastExecFormatted string if lastExecTimestamp isn't the same as registeredAt (tolerance of unnecessary 100ms) or job ran upon registration. The JobManager sets _lastExecTimestamp to Date.now() on registration if runOnRegistration == false
- let lastExecFormatted = job._lastExecTimestamp - job._registeredAt > 100 || job.runOnRegistration ? convertTimestamp(job._lastExecTimestamp) : "/";
+ const lastExecFormatted = job._lastExecTimestamp - job._registeredAt > 100 || job.runOnRegistration ? convertTimestamp(job._lastExecTimestamp) : "/";
str += `- '${job.name}' runs every ${intervalFormatted}, last at '${lastExecFormatted}'\n${desc}\n`;
});
@@ -164,10 +164,10 @@ module.exports.update = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((modResInfo, txt) => respondModule(context, modResInfo, txt)); // Shorten each call. Updater takes resInfo as param and can modify it, so we need to pass the modified resInfo object here
+ const respond = ((modResInfo, txt) => respondModule(context, modResInfo, txt)); // Shorten each call. Updater takes resInfo as param and can modify it, so we need to pass the modified resInfo object here
// If the first argument is "true" or "force" then we shall force an update
- let force = (args[0] == "true" || args[0] == "force");
+ const force = (args[0] == "true" || args[0] == "force");
// Use the correct message depending on if force is true or false with a ternary operator
respond({ prefix: "/me", ...resInfo }, await commandHandler.data.getLang(force ? "updatecmdforce" : "updatecmdcheck", { "branchname": commandHandler.data.datafile.branch }, resInfo.userID));
@@ -226,14 +226,14 @@ module.exports.eval = {
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
run: async (commandHandler, args, respondModule, context, resInfo) => {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
if (!commandHandler.data.advancedconfig.enableevalcmd) {
respondModule(context, { prefix: "/me", ...resInfo }, await commandHandler.data.getLang("evalcmdturnedoff", null, resInfo.userID)); // Pass new resInfo object which contains prefix and everything the original resInfo obj contained
return;
}
- const clean = text => { // eslint-disable-line no-case-declarations
+ const clean = text => {
if (typeof(text) === "string") return text.replace(/`/g, "`" + String.fromCharCode(8203)).replace(/@/g, "@" + String.fromCharCode(8203));
else return text;
};
@@ -257,7 +257,7 @@ module.exports.eval = {
});
// Check for character limit and cut message
- let chatResult = clean(evaled);
+ const chatResult = clean(evaled);
if (chatResult.length >= 500) respond(`Code executed. Result:\n\n${chatResult.slice(0, 500)}.......\n\nResult too long for chat.`);
else respond(`Code executed. Result:\n\n${chatResult}`);
diff --git a/src/commands/core/vote.js b/src/commands/core/vote.js
index b23615a0..3de83e16 100644
--- a/src/commands/core/vote.js
+++ b/src/commands/core/vote.js
@@ -32,14 +32,14 @@ const { handleVoteIterationSkip, logVoteError } = require("../helpers/handleMisc
* @param {CommandHandler.resInfo} resInfo Object containing additional information your respondModule might need to process the response (for example the userID who executed the command).
*/
async function processVoteRequest(origin, commandHandler, args, respondModule, context, resInfo) {
- let respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
+ const respond = ((txt) => respondModule(context, resInfo, txt)); // Shorten each call
// Get the correct ownerid array for this request
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
- let ownercheck = owners.includes(requesterID);
+ const requesterID = resInfo.userID;
+ const ownercheck = owners.includes(requesterID);
/* --------- Various checks --------- */
@@ -53,25 +53,25 @@ async function processVoteRequest(origin, commandHandler, args, respondModule, c
// Check and get arguments from user
- let { err, amountRaw, id, idType } = await getMiscArgs(commandHandler, args, origin, resInfo, respond); // eslint-disable-line no-unused-vars
+ const { err, amountRaw, id, idType } = await getMiscArgs(commandHandler, args, origin, resInfo, respond); // eslint-disable-line no-unused-vars
if (!amountRaw && !id) return; // Looks like the helper aborted the request
// Check if this id is already receiving something right now
- let idReq = commandHandler.controller.activeRequests[id];
+ const idReq = commandHandler.controller.activeRequests[id];
if (idReq && idReq.status == "active") return respond(await commandHandler.data.getLang("idalreadyreceiving", null, requesterID)); // Note: No need to check for user as that is supposed to be handled by a cooldown
// Check if user has cooldown
- let { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
+ const { until, untilStr } = await commandHandler.data.getUserCooldown(requesterID);
if (until > Date.now()) return respond(await commandHandler.data.getLang("idoncooldown", { "remainingcooldown": untilStr }, requesterID));
// Get all available bot accounts
- let { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForVoting(commandHandler, amountRaw, id, origin, resInfo);
+ const { amount, availableAccounts, whenAvailableStr } = await getAvailableBotsForVoting(commandHandler, amountRaw, id, origin, resInfo);
if ((availableAccounts.length < amount || availableAccounts.length == 0) && !whenAvailableStr) { // Check if this bot has not enough accounts suitable for this request and there won't be more available at any point. The < || == 0 check is intentional, as providing "all" will set amount to 0 if 0 accounts have been found
if (availableAccounts.length == 0) respond(await commandHandler.data.getLang("genericnounlimitedaccs", { "cmdprefix": resInfo.cmdprefix }, requesterID)); // Send specific nounlimitedaccs message as we always need unlimited accs and to let users know this situation won't change
@@ -87,9 +87,9 @@ async function processVoteRequest(origin, commandHandler, args, respondModule, c
// Register this vote process in activeRequests
- let capitilizedOrigin = origin.charAt(0).toUpperCase() + origin.slice(1); // Capitilize first char of origin to achieve camelCase
+ const capitilizedOrigin = origin.charAt(0).toUpperCase() + origin.slice(1); // Capitilize first char of origin to achieve camelCase
- let activeReqEntry = {
+ const activeReqEntry = {
status: "active",
type: idType + capitilizedOrigin,
amount: amount,
@@ -192,7 +192,7 @@ async function processVoteRequest(origin, commandHandler, args, respondModule, c
// Only send estimated wait time message for multiple votes
if (activeReqEntry.amount > 1) {
- let waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first vote is instant. Multiply by delay and add to current time to get timestamp when last vote was sent
+ const waitTime = timeToString(Date.now() + ((activeReqEntry.amount - 1) * commandHandler.data.config.requestDelay)); // Amount - 1 because the first vote is instant. Multiply by delay and add to current time to get timestamp when last vote was sent
respond(await commandHandler.data.getLang("voteprocessstarted", { "numberOfVotes": activeReqEntry.amount, "waittime": waitTime }, requesterID));
}
@@ -207,7 +207,7 @@ async function processVoteRequest(origin, commandHandler, args, respondModule, c
syncLoop(amount, (loop, i) => {
setTimeout(() => {
- let bot = commandHandler.controller.bots[availableAccounts[i]];
+ const bot = commandHandler.controller.bots[availableAccounts[i]];
activeReqEntry.thisIteration++;
if (!handleVoteIterationSkip(commandHandler, loop, bot, id)) return; // Skip iteration if false was returned
diff --git a/src/commands/helpers/getCommentArgs.js b/src/commands/helpers/getCommentArgs.js
index def74cc8..541590ba 100644
--- a/src/commands/helpers/getCommentArgs.js
+++ b/src/commands/helpers/getCommentArgs.js
@@ -66,7 +66,7 @@ module.exports.getCommentArgs = (commandHandler, args, resInfo, respond) => {
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
+ const requesterID = resInfo.userID;
let maxRequestAmount = commandHandler.data.config.maxRequests; // Set to default value and if the requesting user is an owner it gets changed below
let numberOfComments = 0;
let quotesArr = commandHandler.data.quotes;
@@ -115,7 +115,7 @@ module.exports.getCommentArgs = (commandHandler, args, resInfo, respond) => {
/* --------- Check profileid argument if it was provided --------- */
if (args[1]) {
if (owners.includes(requesterID) || args[1] == requesterID) { // Check if user is a bot owner or if they provided their own profile id
- let arg = args[1];
+ const arg = args[1];
commandHandler.controller.handleSteamIdResolving(arg, null, async (err, res, type) => {
if (err) {
@@ -172,7 +172,7 @@ module.exports.getCommentArgs = (commandHandler, args, resInfo, respond) => {
/* --------- Resolve promise with calculated values when profileID is defined --------- */
- let profileIDDefinedInterval = setInterval(() => { // Check if profileID is defined every 250ms and only then return values
+ const profileIDDefinedInterval = setInterval(() => { // Check if profileID is defined every 250ms and only then return values
if (profileID != undefined) {
clearInterval(profileIDDefinedInterval);
diff --git a/src/commands/helpers/getCommentBots.js b/src/commands/helpers/getCommentBots.js
index bef453ce..5c2eb25c 100644
--- a/src/commands/helpers/getCommentBots.js
+++ b/src/commands/helpers/getCommentBots.js
@@ -44,7 +44,7 @@ module.exports.getAvailableBotsForCommenting = async function(commandHandler, nu
// Sort activeRequests by highest until value, decreasing, so that we can tell the user how long he/she has to wait if not enough accounts were found
- let sortedvals = Object.keys(commandHandler.controller.activeRequests).sort((a, b) => {
+ const sortedvals = Object.keys(commandHandler.controller.activeRequests).sort((a, b) => {
return commandHandler.controller.activeRequests[b].until - commandHandler.controller.activeRequests[a].until;
});
@@ -53,13 +53,13 @@ module.exports.getAvailableBotsForCommenting = async function(commandHandler, nu
let whenAvailable; // We will save the until value of the account that the user has to wait for here
let whenAvailableStr;
- let allAccsOnline = commandHandler.controller.getBots(null, true);
+ const allAccsOnline = commandHandler.controller.getBots(null, true);
let allAccounts = [ ... Object.keys(allAccsOnline) ]; // Clone keys array (bot usernames) of bots object
// Remove limited accounts from allAccounts array if desired
if (!canBeLimited) {
- let previousLength = allAccounts.length;
+ const previousLength = allAccounts.length;
allAccounts = allAccounts.filter(e => allAccsOnline[e].user.limitations && !allAccsOnline[e].user.limitations.limited);
if (previousLength - allAccounts.length > 0) logger("info", `${previousLength - allAccounts.length} of ${previousLength} bot accounts were removed from available accounts as they are limited and can't be used for this request!`);
@@ -103,7 +103,7 @@ module.exports.getAvailableBotsForCommenting = async function(commandHandler, nu
// Remove !accountCanComment accounts if type discussion. We need to run getSteamDiscussion for every account, which kind of sucks as it's a ton of requests - but what else are we supposed to do?
if (idType == "discussion") {
- let promises = [];
+ const promises = [];
allAccounts.forEach((e) => {
promises.push((() => {
@@ -121,7 +121,7 @@ module.exports.getAvailableBotsForCommenting = async function(commandHandler, nu
});
await Promise.all(promises).then((res) => {
- let previousLength = allAccounts.length;
+ const previousLength = allAccounts.length;
res.forEach((e) => {
if (!e.accountCanComment) allAccounts.splice(allAccounts.indexOf(e.accountName), 1); // Remove that accountindex from the allAccounts array
diff --git a/src/commands/helpers/getFavoriteBots.js b/src/commands/helpers/getFavoriteBots.js
index 923b8828..aedee7ed 100644
--- a/src/commands/helpers/getFavoriteBots.js
+++ b/src/commands/helpers/getFavoriteBots.js
@@ -32,13 +32,13 @@ module.exports.getAvailableBotsForFavorizing = async (commandHandler, amount, id
/* --------- Get all bots which haven't favorized this id yet and aren't currently in another favorite request --------- */
let whenAvailable; // We will save the until value of the account that the user has to wait for here
let whenAvailableStr;
- let allAccsOnline = commandHandler.controller.getBots(null, true);
+ const allAccsOnline = commandHandler.controller.getBots(null, true);
let allAccounts = [ ... Object.keys(allAccsOnline) ]; // Clone keys array (bot usernames) of bots object
// Remove bot accounts from allAccounts which have already favorized this id, or only allow them for type unfavorite
- let previousLengthFavorized = allAccounts.length;
- let alreadyFavorized = await commandHandler.data.ratingHistoryDB.findAsync({ id: id, type: "favorite" }, {});
+ const previousLengthFavorized = allAccounts.length;
+ const alreadyFavorized = await commandHandler.data.ratingHistoryDB.findAsync({ id: id, type: "favorite" }, {});
if (favType == "favorite") {
alreadyFavorized.forEach((e) => {
diff --git a/src/commands/helpers/getFollowArgs.js b/src/commands/helpers/getFollowArgs.js
index 0cb5087e..a6713983 100644
--- a/src/commands/helpers/getFollowArgs.js
+++ b/src/commands/helpers/getFollowArgs.js
@@ -32,11 +32,11 @@ module.exports.getFollowArgs = (commandHandler, args, cmd, resInfo, respond) =>
(async () => { // Lets us use await insidea Promise without creating an antipattern
// Check for missing params
- let cmdUsage = `'${resInfo.cmdprefix}${cmd} amount/"all" id/link'`;
+ const cmdUsage = `'${resInfo.cmdprefix}${cmd} amount/"all" id/link'`;
if (args[0]) args[0] = args[0].toLowerCase();
if (args[0] == "max") args[0] = "all"; // Convert "all" alias
- let amount = args[0] == "all" ? args[0] : Number(args[0]); // If user provides "all" then keep it as is and update it later to how many accounts are available, otherwise convert it to a number
+ const amount = args[0] == "all" ? args[0] : Number(args[0]); // If user provides "all" then keep it as is and update it later to how many accounts are available, otherwise convert it to a number
if (args.length == 0 || (amount != "all" && isNaN(amount)) || amount == 0) {
respond(await commandHandler.data.getLang("invalidnumber", { "cmdusage": cmdUsage }, resInfo.userID)); // An empty string will become a 0
@@ -48,7 +48,7 @@ module.exports.getFollowArgs = (commandHandler, args, cmd, resInfo, respond) =>
let owners = commandHandler.data.cachefile.ownerid;
if (resInfo.ownerIDs && resInfo.ownerIDs.length > 0) owners = resInfo.ownerIDs;
- let requesterID = resInfo.userID;
+ const requesterID = resInfo.userID;
// Check if user requested more allowed
@@ -68,7 +68,7 @@ module.exports.getFollowArgs = (commandHandler, args, cmd, resInfo, respond) =>
// Check if id was provided and process input
if (args[1]) {
if (owners.includes(requesterID) || args[1] == requesterID) { // Check if user is a bot owner or if they provided their own profile id
- let arg = args[1];
+ const arg = args[1];
commandHandler.controller.handleSteamIdResolving(arg, null, async (err, res, idType) => {
if (err || (idType != "profile" && idType != "curator")) {
diff --git a/src/commands/helpers/getFollowBots.js b/src/commands/helpers/getFollowBots.js
index 23201be5..a50e802a 100644
--- a/src/commands/helpers/getFollowBots.js
+++ b/src/commands/helpers/getFollowBots.js
@@ -35,13 +35,13 @@ module.exports.getAvailableBotsForFollowing = async (commandHandler, amount, can
/* --------- Get all bots which haven't followed this id yet and aren't currently in another follow request --------- */
let whenAvailable; // We will save the until value of the account that the user has to wait for here
let whenAvailableStr;
- let allAccsOnline = commandHandler.controller.getBots(null, true);
+ const allAccsOnline = commandHandler.controller.getBots(null, true);
let allAccounts = [ ... Object.keys(allAccsOnline) ]; // Clone keys array (bot usernames) of bots object
// Remove limited accounts from allAccounts array if desired
if (!canBeLimited) {
- let previousLength = allAccounts.length;
+ const previousLength = allAccounts.length;
allAccounts = allAccounts.filter(e => allAccsOnline[e].user.limitations && !allAccsOnline[e].user.limitations.limited);
if (previousLength - allAccounts.length > 0) logger("info", `${previousLength - allAccounts.length} of ${previousLength} bot accounts were removed from available accounts as they are limited and can't be used for this request!`);
@@ -49,8 +49,8 @@ module.exports.getAvailableBotsForFollowing = async (commandHandler, amount, can
// Remove bot accounts from allAccounts which have already followed this id, or only allow them for type unfollow
- let previousLength = allAccounts.length;
- let alreadyUsed = await commandHandler.data.ratingHistoryDB.findAsync({ id: id, type: idType + "Follow" }, {});
+ const previousLength = allAccounts.length;
+ const alreadyUsed = await commandHandler.data.ratingHistoryDB.findAsync({ id: id, type: idType + "Follow" }, {});
if (favType == "follow") {
alreadyUsed.forEach((e) => {
diff --git a/src/commands/helpers/getMiscArgs.js b/src/commands/helpers/getMiscArgs.js
index 5035f72b..76b20c3d 100644
--- a/src/commands/helpers/getMiscArgs.js
+++ b/src/commands/helpers/getMiscArgs.js
@@ -4,7 +4,7 @@
* Created Date: 2023-05-28 12:18:49
* Author: 3urobeat
*
- * Last Modified: 2024-02-22 17:51:02
+ * Last Modified: 2024-05-03 13:08:06
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -32,11 +32,11 @@ module.exports.getMiscArgs = (commandHandler, args, cmd, resInfo, respond) => {
(async () => { // Lets us use await insidea Promise without creating an antipattern
// Check for missing params
- let cmdUsage = `'${resInfo.cmdprefix}${cmd} amount/"all" id/link'`;
+ const cmdUsage = `'${resInfo.cmdprefix}${cmd} amount/"all" id/link'`;
if (args[0]) args[0] = args[0].toLowerCase();
if (args[0] == "max") args[0] = "all"; // Convert "all" alias
- let amount = args[0] == "all" ? args[0] : Number(args[0]); // If user provides "all" then keep it as is and update it later to how many accounts are available, otherwise convert it to a number
+ const amount = args[0] == "all" ? args[0] : Number(args[0]); // If user provides "all" then keep it as is and update it later to how many accounts are available, otherwise convert it to a number
if (args.length == 0 || (amount != "all" && isNaN(amount)) || amount == 0) {
respond(await commandHandler.data.getLang("invalidnumber", { "cmdusage": cmdUsage }, resInfo.userID)); // An empty string will become a 0
@@ -60,7 +60,7 @@ module.exports.getMiscArgs = (commandHandler, args, cmd, resInfo, respond) => {
}
// Process input and check if ID is valid
- commandHandler.controller.handleSteamIdResolving(args[1], null, async (err, destParam, idType) => { // eslint-disable-line no-unused-vars
+ commandHandler.controller.handleSteamIdResolving(args[1], null, async (err, destParam, idType) => {
logger("debug", `CommandHandler getMiscArgs() success. amount: ${amount} | dest: ${destParam}`);
resolve({
diff --git a/src/commands/helpers/getVoteBots.js b/src/commands/helpers/getVoteBots.js
index d3f5a973..e07a219a 100644
--- a/src/commands/helpers/getVoteBots.js
+++ b/src/commands/helpers/getVoteBots.js
@@ -33,19 +33,19 @@ module.exports.getAvailableBotsForVoting = async (commandHandler, amount, id, vo
/* --------- Get all bots which haven't voted on this id yet and aren't currently in another vote request --------- */
let whenAvailable; // We will save the until value of the account that the user has to wait for here
let whenAvailableStr;
- let allAccsOnline = commandHandler.controller.getBots(null, true);
+ const allAccsOnline = commandHandler.controller.getBots(null, true);
let allAccounts = [ ... Object.keys(allAccsOnline) ]; // Clone keys array (bot usernames) of bots object
// Remove limited accounts from allAccounts array as they are unable to vote
- let previousLengthLimited = allAccounts.length;
+ const previousLengthLimited = allAccounts.length;
allAccounts = allAccounts.filter(e => allAccsOnline[e].user.limitations && !allAccsOnline[e].user.limitations.limited);
if (previousLengthLimited - allAccounts.length > 0) logger("info", `${previousLengthLimited - allAccounts.length} of ${previousLengthLimited} bot accounts were removed from available accounts as they are limited and can't be used for this request!`);
// Remove bot accounts from allAccounts which have already voted on this id with this voteType
- let previousLengthVoted = allAccounts.length;
- let alreadyVoted = await commandHandler.data.ratingHistoryDB.findAsync({ id: id, type: voteType }, {});
+ const previousLengthVoted = allAccounts.length;
+ const alreadyVoted = await commandHandler.data.ratingHistoryDB.findAsync({ id: id, type: voteType }, {});
alreadyVoted.forEach((e) => {
if (allAccounts.indexOf(e.accountName) != -1) allAccounts.splice(allAccounts.indexOf(e.accountName), 1);
diff --git a/src/commands/helpers/handleCommentSkips.js b/src/commands/helpers/handleCommentSkips.js
index eeab63fb..bc1b4339 100644
--- a/src/commands/helpers/handleCommentSkips.js
+++ b/src/commands/helpers/handleCommentSkips.js
@@ -4,10 +4,10 @@
* Created Date: 2022-02-28 12:22:48
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:04:37
+ * Last Modified: 2024-05-04 22:02:59
* Modified By: 3urobeat
*
- * Copyright (c) 2022 - 2023 3urobeat
+ * Copyright (c) 2022 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -15,10 +15,26 @@
*/
-const Bot = require("../../bot/bot.js"); // eslint-disable-line
+const Bot = require("../../bot/bot.js");
const CommandHandler = require("../commandHandler.js"); // eslint-disable-line
+/**
+ * Helper function to sort failed object by comment number so that it is easier to read
+ * @param {object} failedObj Current state of failed object
+ */
+function sortFailedCommentsObject(failedObj) {
+ const sortedvals = Object.keys(failedObj).sort((a, b) => {
+ return Number(a.split(" ")[0].replace("i", "")) - Number(b.split(" ")[0].replace("i", ""));
+ });
+
+ // Map sortedvals back to object if array is not empty - Credit: https://www.geeksforgeeks.org/how-to-create-an-object-from-two-arrays-in-javascript/
+ if (sortedvals.length > 0) failedObj = Object.assign(...sortedvals.map(k => ({ [k]: failedObj[k] })));
+
+ return failedObj;
+}
+
+
/**
* Checks if the following comment process iteration should be skipped
* Aborts comment process on critical error.
@@ -29,7 +45,7 @@ const CommandHandler = require("../commandHandler.js"); // eslint-disable-line
* @returns {boolean} true if iteration should continue, false if iteration should be skipped using return
*/
module.exports.handleIterationSkip = (commandHandler, loop, bot, receiverSteamID64) => {
- let activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64]; // Make using the obj shorter
// Check if no bot account was found
if (!bot) {
@@ -56,7 +72,7 @@ module.exports.handleIterationSkip = (commandHandler, loop, bot, receiverSteamID
// Add failed entry for all skipped iterations only if request was aborted
if (activeReqEntry.status == "aborted") {
for (let i = activeReqEntry.thisIteration; i < activeReqEntry.amount; i++) { // Iterate over all remaining comments by starting with thisIteration till numberOfComments
- let thisbot = commandHandler.controller.getBots("*", true)[activeReqEntry.accounts[i % activeReqEntry.accounts.length]];
+ const thisbot = commandHandler.controller.getBots("*", true)[activeReqEntry.accounts[i % activeReqEntry.accounts.length]];
activeReqEntry.failed[`i${i + 1} b${thisbot.index} p${thisbot.loginData.proxyIndex}`] = "Skipped because comment process was aborted";
}
@@ -105,7 +121,7 @@ module.exports.handleIterationSkip = (commandHandler, loop, bot, receiverSteamID
* @param {string} receiverSteamID64 steamID64 of the receiving user/group
*/
module.exports.logCommentError = (error, commandHandler, bot, receiverSteamID64) => {
- let activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[receiverSteamID64]; // Make using the obj shorter
let description = "";
@@ -122,7 +138,7 @@ module.exports.logCommentError = (error, commandHandler, bot, receiverSteamID64)
logger("warn", "Skipping all other comments on this proxy as well because they will fail too!");
for (let i = activeReqEntry.thisIteration + 1; i < activeReqEntry.amount; i++) { // Iterate over all remaining comments by starting with next iteration till numberOfComments
- let thisbot = commandHandler.controller.getBots(null, true)[activeReqEntry.accounts[i % activeReqEntry.accounts.length]];
+ const thisbot = commandHandler.controller.getBots(null, true)[activeReqEntry.accounts[i % activeReqEntry.accounts.length]];
// Add to failed obj if proxies match
if (thisbot.loginData.proxyIndex == bot.loginData.proxyIndex) {
@@ -174,22 +190,6 @@ module.exports.logCommentError = (error, commandHandler, bot, receiverSteamID64)
};
-/**
- * Helper function to sort failed object by comment number so that it is easier to read
- * @param {object} failedObj Current state of failed object
- */
-function sortFailedCommentsObject(failedObj) {
- let sortedvals = Object.keys(failedObj).sort((a, b) => {
- return Number(a.split(" ")[0].replace("i", "")) - Number(b.split(" ")[0].replace("i", ""));
- });
-
- // Map sortedvals back to object if array is not empty - Credit: https://www.geeksforgeeks.org/how-to-create-an-object-from-two-arrays-in-javascript/
- if (sortedvals.length > 0) failedObj = Object.assign(...sortedvals.map(k => ({ [k]: failedObj[k] })));
-
- return failedObj;
-}
-
-
/**
* Groups same error messages together, counts amount, lists affected bots and converts it to a String.
* @param {object} obj failedcomments object that should be converted
@@ -197,10 +197,10 @@ function sortFailedCommentsObject(failedObj) {
*/
module.exports.failedCommentsObjToString = (obj) => {
// Count amount of each string
- let grouped = {};
+ const grouped = {};
Object.keys(obj).forEach((e) => {
- let err = obj[e];
+ const err = obj[e];
// Check if entry for this err msg already exists and increment amount
if (Object.keys(grouped).includes(err)) {
@@ -218,7 +218,7 @@ module.exports.failedCommentsObjToString = (obj) => {
});
// Sort object descending
- let sortedArr = Object.values(grouped).sort((a, b) => {
+ const sortedArr = Object.values(grouped).sort((a, b) => {
return b.amount - a.amount;
});
diff --git a/src/commands/helpers/handleFollowErrors.js b/src/commands/helpers/handleFollowErrors.js
index 782d0cef..4e6fce24 100644
--- a/src/commands/helpers/handleFollowErrors.js
+++ b/src/commands/helpers/handleFollowErrors.js
@@ -4,10 +4,10 @@
* Created Date: 2023-09-24 22:57:21
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:04:20
+ * Last Modified: 2024-05-04 22:03:25
* Modified By: 3urobeat
*
- * Copyright (c) 2023 3urobeat
+ * Copyright (c) 2023 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -15,7 +15,23 @@
*/
-const Bot = require("../../bot/bot.js"); // eslint-disable-line
+const Bot = require("../../bot/bot.js");
+
+
+/**
+ * Helper function to sort failed object by number so that it is easier to read
+ * @param {object} failedObj Current state of failed object
+ */
+function sortFailedCommentsObject(failedObj) {
+ const sortedvals = Object.keys(failedObj).sort((a, b) => {
+ return Number(a.split(" ")[0].replace("i", "")) - Number(b.split(" ")[0].replace("i", ""));
+ });
+
+ // Map sortedvals back to object if array is not empty - Credit: https://www.geeksforgeeks.org/how-to-create-an-object-from-two-arrays-in-javascript/
+ if (sortedvals.length > 0) failedObj = Object.assign(...sortedvals.map(k => ({ [k]: failedObj[k] })));
+
+ return failedObj;
+}
/**
@@ -27,7 +43,7 @@ const Bot = require("../../bot/bot.js"); // eslint-disable-line
* @returns {boolean} `true` if iteration should continue, `false` if iteration should be skipped using return
*/
module.exports.handleFollowIterationSkip = function(commandHandler, loop, bot, id) {
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Check if no bot account was found
if (!bot) {
@@ -60,7 +76,7 @@ module.exports.handleFollowIterationSkip = function(commandHandler, loop, bot, i
* @param {string} id ID of the profile that receives the follow
*/
module.exports.logFollowError = (error, commandHandler, bot, id) => {
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Add proxy information if one was used for this account
let proxiesDescription = "";
@@ -76,19 +92,3 @@ module.exports.logFollowError = (error, commandHandler, bot, id) => {
// Sort failed object to make it easier to read
activeReqEntry.failed = sortFailedCommentsObject(activeReqEntry.failed);
};
-
-
-/**
- * Helper function to sort failed object by number so that it is easier to read
- * @param {object} failedObj Current state of failed object
- */
-function sortFailedCommentsObject(failedObj) {
- let sortedvals = Object.keys(failedObj).sort((a, b) => {
- return Number(a.split(" ")[0].replace("i", "")) - Number(b.split(" ")[0].replace("i", ""));
- });
-
- // Map sortedvals back to object if array is not empty - Credit: https://www.geeksforgeeks.org/how-to-create-an-object-from-two-arrays-in-javascript/
- if (sortedvals.length > 0) failedObj = Object.assign(...sortedvals.map(k => ({ [k]: failedObj[k] })));
-
- return failedObj;
-}
diff --git a/src/commands/helpers/handleMiscErrors.js b/src/commands/helpers/handleMiscErrors.js
index 9b07a88a..9b972ca3 100644
--- a/src/commands/helpers/handleMiscErrors.js
+++ b/src/commands/helpers/handleMiscErrors.js
@@ -4,7 +4,7 @@
* Created Date: 2023-05-31 16:57:21
* Author: 3urobeat
*
- * Last Modified: 2024-02-20 17:19:26
+ * Last Modified: 2024-05-04 22:04:06
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -15,7 +15,23 @@
*/
-const Bot = require("../../bot/bot.js"); // eslint-disable-line
+const Bot = require("../../bot/bot.js");
+
+
+/**
+ * Helper function to sort failed object by number so that it is easier to read
+ * @param {object} failedObj Current state of failed object
+ */
+function sortFailedCommentsObject(failedObj) {
+ const sortedvals = Object.keys(failedObj).sort((a, b) => {
+ return Number(a.split(" ")[0].replace("i", "")) - Number(b.split(" ")[0].replace("i", ""));
+ });
+
+ // Map sortedvals back to object if array is not empty - Credit: https://www.geeksforgeeks.org/how-to-create-an-object-from-two-arrays-in-javascript/
+ if (sortedvals.length > 0) failedObj = Object.assign(...sortedvals.map(k => ({ [k]: failedObj[k] })));
+
+ return failedObj;
+}
/**
@@ -27,7 +43,7 @@ const Bot = require("../../bot/bot.js"); // eslint-disable-line
* @returns {boolean} `true` if iteration should continue, `false` if iteration should be skipped using return
*/
module.exports.handleVoteIterationSkip = function(commandHandler, loop, bot, id) {
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Check if no bot account was found
if (!bot) {
@@ -61,7 +77,7 @@ module.exports.handleVoteIterationSkip = function(commandHandler, loop, bot, id)
* @returns {boolean} `true` if iteration should continue, `false` if iteration should be skipped using return
*/
module.exports.handleFavoriteIterationSkip = function(commandHandler, loop, bot, id) {
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Check if no bot account was found
if (!bot) {
@@ -94,7 +110,7 @@ module.exports.handleFavoriteIterationSkip = function(commandHandler, loop, bot,
* @param {string} id ID that receives the votes
*/
module.exports.logVoteError = (error, commandHandler, bot, id) => {
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Add proxy information if one was used for this account
let proxiesDescription = "";
@@ -120,7 +136,7 @@ module.exports.logVoteError = (error, commandHandler, bot, id) => {
* @param {string} id ID of the sharedfile that receives the favorites
*/
module.exports.logFavoriteError = (error, commandHandler, bot, id) => {
- let activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
+ const activeReqEntry = commandHandler.controller.activeRequests[id]; // Make using the obj shorter
// Add proxy information if one was used for this account
let proxiesDescription = "";
@@ -136,19 +152,3 @@ module.exports.logFavoriteError = (error, commandHandler, bot, id) => {
// Sort failed object to make it easier to read
activeReqEntry.failed = sortFailedCommentsObject(activeReqEntry.failed);
};
-
-
-/**
- * Helper function to sort failed object by number so that it is easier to read
- * @param {object} failedObj Current state of failed object
- */
-function sortFailedCommentsObject(failedObj) {
- let sortedvals = Object.keys(failedObj).sort((a, b) => {
- return Number(a.split(" ")[0].replace("i", "")) - Number(b.split(" ")[0].replace("i", ""));
- });
-
- // Map sortedvals back to object if array is not empty - Credit: https://www.geeksforgeeks.org/how-to-create-an-object-from-two-arrays-in-javascript/
- if (sortedvals.length > 0) failedObj = Object.assign(...sortedvals.map(k => ({ [k]: failedObj[k] })));
-
- return failedObj;
-}
diff --git a/src/controller/controller.js b/src/controller/controller.js
index 3d879fe3..96b12734 100644
--- a/src/controller/controller.js
+++ b/src/controller/controller.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-02-29 21:13:33
+ * Last Modified: 2024-05-04 22:08:30
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -53,7 +53,7 @@ const Controller = function() {
* @param {number} timestamp UNIX timestamp to convert
* @returns {string} "x seconds/minutes/hours/days"
*/
- timeToString: () => {}, // eslint-disable-line
+ timeToString: () => {},
/**
* Pings a *https* URL to check if the service and this internet connection is working
@@ -107,11 +107,62 @@ const Controller = function() {
};
+/* ------------ Handle restart data: ------------ */
+
+/* eslint-disable no-use-before-define */
+
+/**
+ * Process data that should be kept over restarts
+ * @param {string} data Stringified data received by previous process
+ */
+function restartdata(data) {
+ data = JSON.parse(data); // Convert the stringified object back to an object
+
+ if (data.oldconfig) oldconfig = data.oldconfig // eslint-disable-line
+ if (data.logafterrestart) logafterrestart = data.logafterrestart; // We can't print now since the logger function isn't imported yet.
+ if (data.skippedaccounts) skippedaccounts = data.skippedaccounts;
+ if (data.updateFailed) updateFailed = data.updateFailed;
+}
+
+// Make a "fake" logger backup function to use when no npm packages were installed
+let logger = function(type, str) {
+ logafterrestart.push(`${type} | ${str}`); // Push message to array that will be carried through restart
+ console.log(`${type} | ${str}`);
+};
+logger.animation = () => {}; // Just to be sure that no error occurs when trying to call this function without the real logger being present
+
+/* eslint-enable no-use-before-define */
+
+
+/* ------------ Start the bot: ------------ */
+
+if (parseInt(process.argv[3]) + 2500 > Date.now()) { // Check if this process just got started in the last 2.5 seconds or just required by itself by checking the timestamp attached by starter.js
+
+ // Variables to keep data through restarts. These need to be var's as they need to be accessible from the top scope, sorry eslint!
+ var oldconfig = {}; // eslint-disable-line
+ var logafterrestart = []; // eslint-disable-line
+ var updateFailed = false; // eslint-disable-line
+ var skippedaccounts = []; // eslint-disable-line
+
+ // Yes, I know, global variables are bad. But I need a few multiple times in different files and it would be a pain in the ass to import them every time and ensure that I don't create a circular dependency and what not.
+ global.botisloggedin = false;
+ global.srcdir = process.argv[2];
+
+ // Start the bot through the restartdata function if this is a restart to keep some data or start the bot directly
+ if (process.argv[4]) restartdata(process.argv[4]);
+
+ // Start the bot
+ const controller = new Controller();
+
+ setTimeout(() => controller._start(), 50); // Wanna hear something stupid? The error catch in handleErrors.js does not work without this delay. Why? Because the empty function for JsDoc below overwrites the real one. Even though the real one is loaded after the fake one.
+}
+
+
/**
* Internal: Initializes the bot by importing data from the disk, running the updater and finally logging in all bot accounts.
*/
Controller.prototype._start = async function() {
- let checkAndGetFile = require("../starter.js").checkAndGetFile; // Temp var to use checkAndGetFile() before it is referenced in DataManager
+ const checkAndGetFile = require("../starter.js").checkAndGetFile; // Temp var to use checkAndGetFile() before it is referenced in DataManager
this.checkAndGetFile = checkAndGetFile;
/* ------------ Init error handler: ------------ */
@@ -164,7 +215,7 @@ Controller.prototype._start = async function() {
/* ------------ Init dataManager system and import: ------------ */
if (!await checkAndGetFile("./src/dataManager/dataManager.js", logger, false, false)) return;
- let DataManager = require("../dataManager/dataManager.js");
+ const DataManager = require("../dataManager/dataManager.js");
this.data = new DataManager(this); // All functions provided by the DataManager, as well as all imported file data will be accessible here
@@ -188,7 +239,7 @@ Controller.prototype._start = async function() {
// Check for unsupported node.js version (<16.0.0)
- let versionarr = process.version.replace("v", "").split(".");
+ const versionarr = process.version.replace("v", "").split(".");
versionarr.forEach((e, i) => { if (e.length == 1 && parseInt(e) < 10) versionarr[i] = `0${e}`; }); // Put 0 in front of single digits
@@ -216,11 +267,11 @@ Controller.prototype._start = async function() {
/* ------------ Run compatibility feature and updater or start logging in: ------------ */
- let compatibility = await checkAndGetFile("./src/updater/compatibility.js", logger, false, false);
+ const compatibility = await checkAndGetFile("./src/updater/compatibility.js", logger, false, false);
if (compatibility) forceUpdate = await compatibility.runCompatibility(this); // Don't bother running it if it couldn't be found and just hope the next update will fix it
// Attempt to load updater to activate the auto update checker. If this fails we are properly "fucked" as we can't repair ourselves
- let Updater = await checkAndGetFile("./src/updater/updater.js", logger, false, false);
+ const Updater = await checkAndGetFile("./src/updater/updater.js", logger, false, false);
if (!Updater) {
logger("error", "Fatal Error: Failed to load updater! Please reinstall the bot manually. Aborting...");
return this.stop();
@@ -238,7 +289,7 @@ Controller.prototype._start = async function() {
} else {
// Let the updater run and check for any available updates
- let { updateFound } = await this.updater.run(forceUpdate);
+ const { updateFound } = await this.updater.run(forceUpdate);
// Continue if no update was found. If an update was found and installed the updater will restart the bot itself.
if (!updateFound) {
@@ -254,7 +305,7 @@ Controller.prototype._start = async function() {
Controller.prototype._preLogin = async function() {
// Get job manager going
- let JobManager = require("../jobs/jobManager.js");
+ const JobManager = require("../jobs/jobManager.js");
/**
* The JobManager handles the periodic execution of functions which you can register at runtime
@@ -307,6 +358,7 @@ Controller.prototype._preLogin = async function() {
require("./events/ready.js");
require("./events/statusUpdate.js");
require("./events/steamGuardInput.js");
+ require("./events/steamGuardQrCode.js");
require("./helpers/friendlist.js");
require("./helpers/getBots.js");
require("./helpers/handleSteamIdResolving.js");
@@ -314,7 +366,7 @@ Controller.prototype._preLogin = async function() {
// Load commandHandler
- let CommandHandler = require("../commands/commandHandler.js");
+ const CommandHandler = require("../commands/commandHandler.js");
/**
* The commandHandler object
@@ -325,14 +377,14 @@ Controller.prototype._preLogin = async function() {
// Load pluginSystem
- let PluginSystem = require("../pluginSystem/pluginSystem.js");
+ const PluginSystem = require("../pluginSystem/pluginSystem.js");
/**
* The pluginSystem handler
* @type {PluginSystem}
*/
this.pluginSystem = new PluginSystem(this);
- this.pluginSystem._loadPlugins(); // Load all plugins now
+ await this.pluginSystem._loadPlugins(); // Load all plugins now. Await to hopefully give plugins enough time to catch Steam Guard events
// Start logging in
@@ -344,52 +396,6 @@ Controller.prototype._preLogin = async function() {
module.exports = Controller;
-/* ------------ Handle restart data: ------------ */
-
-/**
- * Process data that should be kept over restarts
- * @param {string} data Stringified data received by previous process
- */
-function restartdata(data) {
- data = JSON.parse(data); // Convert the stringified object back to an object
-
- if (data.oldconfig) oldconfig = data.oldconfig //eslint-disable-line
- if (data.logafterrestart) logafterrestart = data.logafterrestart; // We can't print now since the logger function isn't imported yet.
- if (data.skippedaccounts) skippedaccounts = data.skippedaccounts;
- if (data.updateFailed) updateFailed = data.updateFailed;
-}
-
-// Make a "fake" logger backup function to use when no npm packages were installed
-let logger = function(type, str) {
- logafterrestart.push(`${type} | ${str}`); // Push message to array that will be carried through restart
- console.log(`${type} | ${str}`);
-};
-logger.animation = () => {}; // Just to be sure that no error occurs when trying to call this function without the real logger being present
-
-
-/* ------------ Start the bot: ------------ */
-
-if (parseInt(process.argv[3]) + 2500 > Date.now()) { // Check if this process just got started in the last 2.5 seconds or just required by itself by checking the timestamp attached by starter.js
-
- // Variables to keep data through restarts. These need to be var's as they need to be accessible from the top scope, sorry eslint!
- var oldconfig = {}; // eslint-disable-line
- var logafterrestart = []; // eslint-disable-line
- var updateFailed = false; // eslint-disable-line
- var skippedaccounts = []; // eslint-disable-line
-
- // Yes, I know, global variables are bad. But I need a few multiple times in different files and it would be a pain in the ass to import them every time and ensure that I don't create a circular dependency and what not.
- global.botisloggedin = false;
- global.srcdir = process.argv[2];
-
- // Start the bot through the restartdata function if this is a restart to keep some data or start the bot directly
- if (process.argv[4]) restartdata(process.argv[4]);
-
- // Start the bot
- let controller = new Controller();
-
- setTimeout(() => controller._start(), 50); // Wanna hear something stupid? The error catch in handleErrors.js does not work without this delay. Why? Because the empty function for JsDoc below overwrites the real one. Even though the real one is loaded after the fake one.
-}
-
/* ------------ Provide functions for restarting & stopping: ------------ */
@@ -451,6 +457,13 @@ Controller.prototype._statusUpdateEvent = function(bot, newStatus) {}; // eslint
*/
Controller.prototype._steamGuardInputEvent = function(bot, submitCode) {}; // eslint-disable-line
+/**
+ * Emits steamGuardQrCode event for bot & plugins
+ * @param {Bot} bot Bot instance of the affected account
+ * @param {string} challengeUrl The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App.
+ */
+Controller.prototype._steamGuardQrCodeEvent = function(bot, challengeUrl) {}; // eslint-disable-line
+
/**
* Check if all friends are in lastcomment database
* @param {Bot} bot Bot object of the account to check
@@ -533,4 +546,4 @@ Controller.prototype._loggerOptionsUpdateAfterConfigLoad = function(advancedconf
/**
* Internal: Logs all held back messages from logAfterReady array
*/
-Controller.prototype._loggerLogAfterReady = function() {}; // eslint-disable-line
+Controller.prototype._loggerLogAfterReady = function() {};
diff --git a/src/controller/events/ready.js b/src/controller/events/ready.js
index adb19ec7..3881452f 100644
--- a/src/controller/events/ready.js
+++ b/src/controller/events/ready.js
@@ -121,7 +121,7 @@ Controller.prototype._readyEvent = function() {
// Check if an owner is not friend with the main bot account
- let nonFriendOwners = this.data.cachefile.ownerid.filter(e => !this.main.user.myFriends[e] || this.main.user.myFriends[e] != SteamUser.EFriendRelationship.Friend); // Get all ownerids that either aren't even in the myFriends obj or are with code != 3
+ const nonFriendOwners = this.data.cachefile.ownerid.filter(e => !this.main.user.myFriends[e] || this.main.user.myFriends[e] != SteamUser.EFriendRelationship.Friend); // Get all ownerids that either aren't even in the myFriends obj or are with code != 3
if (nonFriendOwners.length > 0) {
logger("warn", `The owner(s) '${nonFriendOwners.map((e, i) => this.data.config.ownerid[i]).join(", ")}' are not friend with the main bot account!\n Please send the main account a friend request now: https://steamcommunity.com/profiles/${this.data.cachefile.botaccid[0]}\n`, true);
diff --git a/src/controller/events/statusUpdate.js b/src/controller/events/statusUpdate.js
index 9109d8bf..d75f53c7 100644
--- a/src/controller/events/statusUpdate.js
+++ b/src/controller/events/statusUpdate.js
@@ -4,7 +4,7 @@
* Created Date: 2023-03-30 21:05:13
* Author: 3urobeat
*
- * Last Modified: 2024-03-08 17:49:26
+ * Last Modified: 2024-05-03 13:00:59
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -15,7 +15,7 @@
*/
-const Bot = require("../../bot/bot.js"); // eslint-disable-line
+const Bot = require("../../bot/bot.js");
const Controller = require("../controller");
@@ -25,7 +25,7 @@ const Controller = require("../controller");
* @param {Bot.EStatus} newStatus The new status of this bot
*/
Controller.prototype._statusUpdateEvent = function(bot, newStatus) {
- let oldStatus = bot.status;
+ const oldStatus = bot.status;
// Update status of bot
bot.status = newStatus;
diff --git a/src/controller/events/steamGuardQrCode.js b/src/controller/events/steamGuardQrCode.js
new file mode 100644
index 00000000..24d8a501
--- /dev/null
+++ b/src/controller/events/steamGuardQrCode.js
@@ -0,0 +1,35 @@
+/*
+ * File: steamGuardQrCode.js
+ * Project: steam-comment-service-bot
+ * Created Date: 2024-05-01 14:44:36
+ * Author: 3urobeat
+ *
+ * Last Modified: 2024-05-01 14:48:33
+ * Modified By: 3urobeat
+ *
+ * Copyright (c) 2024 3urobeat
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ */
+
+
+const Bot = require("../../bot/bot.js"); // eslint-disable-line
+const Controller = require("../controller");
+
+
+/**
+ * Emits steamGuardQrCode event for bot & plugins
+ * @param {Bot} bot Bot instance of the affected account
+ * @param {string} challengeUrl The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App.
+ */
+Controller.prototype._steamGuardQrCodeEvent = function(bot, challengeUrl) {
+
+ // Log debug message
+ logger("debug", `Controller steamGuardQrCodeEvent: Emitting event for bot${bot.index} so plugins can display the QR-Code...`);
+
+ // Emit event
+ this.events.emit("steamGuardQrCode", bot, challengeUrl);
+
+};
diff --git a/src/controller/helpers/friendlist.js b/src/controller/helpers/friendlist.js
index e5bc302d..e2370e49 100644
--- a/src/controller/helpers/friendlist.js
+++ b/src/controller/helpers/friendlist.js
@@ -4,10 +4,10 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:09:33
+ * Last Modified: 2024-05-09 15:04:39
* Modified By: 3urobeat
*
- * Copyright (c) 2021 - 2023 3urobeat
+ * Copyright (c) 2021 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -19,6 +19,7 @@ const SteamID = require("steamid");
const Controller = require("../../controller/controller.js");
const Bot = require("../../bot/bot.js"); // eslint-disable-line
+const { EFriendRelationship } = require("steam-user");
/**
@@ -34,7 +35,7 @@ Controller.prototype.checkLastcommentDB = function(bot) {
if (bot.user.myFriends[e] == 3 && !docs.find(el => el.id == e)) {
logger("info", `Inserting user ${e} into lastcomment.db...`, false, true);
- let obj = {
+ const obj = {
id: e,
time: Date.now() - (this.data.config.requestCooldown * 60000) // Subtract requestCooldown so that the user is able to use the command instantly
};
@@ -59,11 +60,11 @@ Controller.prototype.friendListCapacityCheck = function(bot, callback) {
bot.user.getSteamLevels([bot.user.steamID], (err, users) => { // Check steam level of botindex account with bot0
if (!users) return; // Users was undefined one time (I hope this will (hopefully) suppress an error?)
- let friendlistlimit = Object.values(users)[0] * 5 + 250; // Profile Level * 5 + 250
- let friends = Object.values(bot.user.myFriends);
- let friendsamount = friends.length - friends.filter(val => val == 0).length - friends.filter(val => val == 5).length; // Subtract friend enums 0 & 5
+ const friendlistlimit = Object.values(users)[0] * 5 + 250; // Profile Level * 5 + 250
+ const friends = Object.values(bot.user.myFriends);
+ const friendsamount = friends.length - friends.filter(val => val == 0).length - friends.filter(val => val == 5).length; // Subtract friend enums 0 & 5
- let remaining = friendlistlimit - friendsamount;
+ const remaining = friendlistlimit - friendsamount;
logger("debug", `Controller friendListCapacityCheck(): bot${bot.index} has ${friendsamount}/${friendlistlimit} friends`);
@@ -85,18 +86,18 @@ Controller.prototype.friendListCapacityCheck = function(bot, callback) {
// Iterate over all docs until we find someone still on our friendlist that isn't an owner (since this func is called for each bot acc we don't need to iterate over the botobject)
docs.every(async (e, i) => { // Use every() so we can break with return false
if (bot.user.myFriends[e.id] == 3 && !this.data.cachefile.ownerid.includes(e.id)) { // Check if friend and not owner
- let steamID = new SteamID(e.id);
+ const steamID = new SteamID(e.id);
// Unfriend user and send them a message // TODO: Maybe only do this from the main bot?
- bot.sendChatMessage(bot, { userID: steamID.getSteamID64() }, await this.data.getLang("userunfriend", { "forceFriendlistSpaceTime": this.data.advancedconfig.forceFriendlistSpaceTime }, steamID.getSteamID64()));
+ bot.sendChatMessage(bot, { userID: steamID.getSteamID64() }, await this.data.getLang("userforceunfriend", { "forceFriendlistSpaceTime": this.data.advancedconfig.forceFriendlistSpaceTime }, steamID.getSteamID64()));
bot.user.removeFriend(steamID);
- logger("info", `[Bot ${bot.index}] Force-Unfriended ${e.id} after being inactive for ${this.data.advancedconfig.forceFriendlistSpaceTime} days to keep 1 empty slot on the friendlist`);
+ logger("info", `[${bot.logPrefix}] Force-Unfriended '${e.id}' after being inactive for ${this.data.advancedconfig.forceFriendlistSpaceTime} days to keep 1 empty slot on the friendlist`);
return false; // Stop loop as one friend slot should now be free
}
// Log warning if we are on the last iteration as when this code is executed no candidate was found
- if (i + 1 == docs.length) logger("warn", `[Bot ${bot.index}] No user was found to unfriend in order to keep at least one friendlist slot empty! Consider lowering 'forceFriendlistSpaceTime' in advancedconfig.json`);
+ if (i + 1 == docs.length) logger("warn", `[${bot.logPrefix}] No user was found to unfriend in order to keep at least one friendlist slot empty! Consider lowering 'forceFriendlistSpaceTime' in advancedconfig.json`);
return true; // Keep loop running
});
@@ -131,15 +132,15 @@ Controller.prototype._lastcommentUnfriendCheck = function() {
docs.forEach((e, i) => { // Take action for all results
setTimeout(() => {
- this.getBots().forEach(async (f, j) => {
- let thisbot = f.user;
+ this.getBots().forEach(async (thisBot, j) => {
+ const thisUser = thisBot.user;
- if (thisbot.myFriends[e.id] && thisbot.myFriends[e.id] == 3 && !this.data.cachefile.ownerid.includes(e.id)) { // Check if the targeted user is still friend and not an owner
- if (j == 0) this.main.sendChatMessage(this.main, { userID: e.id }, await this.data.getLang("userforceunfriend", { "unfriendtime": this.data.config.unfriendtime }, e.id));
+ if (thisUser.myFriends[e.id] && thisUser.myFriends[e.id] == EFriendRelationship.Friend && !this.data.cachefile.ownerid.includes(e.id)) { // Check if the targeted user is still friend and not an owner
+ if (j == 0) this.main.sendChatMessage(this.main, { userID: e.id }, await this.data.getLang("userunfriend", { "unfriendtime": this.data.config.unfriendtime }, e.id));
setTimeout(() => {
- thisbot.removeFriend(new SteamID(e.id)); // Unfriend user with each bot
- logger("info", `[Bot ${j}] Unfriended ${e.id} after ${this.data.config.unfriendtime} days of inactivity.`);
+ thisUser.removeFriend(new SteamID(e.id)); // Unfriend user with each bot
+ logger("info", `[${thisBot.logPrefix}] Unfriended '${e.id}' after ${this.data.config.unfriendtime} days of inactivity.`);
}, 1000 * j); // Delay every iteration so that we don't make a ton of requests at once (IP)
}
diff --git a/src/controller/helpers/getBots.js b/src/controller/helpers/getBots.js
index ff340deb..d0fc9fad 100644
--- a/src/controller/helpers/getBots.js
+++ b/src/controller/helpers/getBots.js
@@ -50,7 +50,7 @@ Controller.prototype.getBots = function(statusFilter = EStatus.ONLINE, mapToObje
Controller.prototype.getBotsPerProxy = function(filterOffline = false) {
// Get all bot accounts
- let accs = this.getBots("*");
+ const accs = this.getBots("*");
// Prefill mappedProxies
let mappedProxies = [];
@@ -59,7 +59,7 @@ Controller.prototype.getBotsPerProxy = function(filterOffline = false) {
// Find associated proxies
accs.forEach((e) => {
- let associatedProxy = mappedProxies[e.loginData.proxyIndex];
+ const associatedProxy = mappedProxies[e.loginData.proxyIndex];
associatedProxy.bots.push(e);
});
diff --git a/src/controller/helpers/handleSteamIdResolving.js b/src/controller/helpers/handleSteamIdResolving.js
index 68e4a0ac..cb977260 100644
--- a/src/controller/helpers/handleSteamIdResolving.js
+++ b/src/controller/helpers/handleSteamIdResolving.js
@@ -70,7 +70,7 @@ Controller.prototype.handleSteamIdResolving = (str, expectedIdType, callback) =>
// Try to figure out if user provided an steamID64 or a customURL or a whole profile link
if (isNaN(str) || !new SteamID(str).isValid()) { // If not a number or invalid SteamID. Note: Sharedfile IDs are considered invalid.
if (/steamcommunity.com\/.+\/recommended\/\d+/g.test(str)) { // This check *must* run before the /id/ & /profiles/ checks below because they would always trigger. The URLs start the same, with reviews having /recommended/ at the end
- let strArr = str.split("/");
+ const strArr = str.split("/");
// Update idType
idType = "review";
@@ -81,8 +81,8 @@ Controller.prototype.handleSteamIdResolving = (str, expectedIdType, callback) =>
if (str.includes("steamcommunity.com/id/")) {
logger("debug", "handleSteamIdResolving: User provided review link with customURL...");
- let customURL = strArr[strArr.findIndex((e) => e == "id") + 1]; // Find customURL by searching for id and going to the next element
- let appID = strArr[strArr.findIndex((e) => e == "recommended") + 1];
+ const customURL = strArr[strArr.findIndex((e) => e == "id") + 1]; // Find customURL by searching for id and going to the next element
+ const appID = strArr[strArr.findIndex((e) => e == "recommended") + 1];
// Resolve customURL and replace /id/customURL with /profiles/steamID64
steamIDResolver.customUrlToSteamID64(customURL, (err, res) => {
@@ -93,8 +93,8 @@ Controller.prototype.handleSteamIdResolving = (str, expectedIdType, callback) =>
} else {
logger("debug", "handleSteamIdResolving: User provided review link with steamID64...");
- let userID = strArr[strArr.findIndex((e) => e == "profiles") + 1];
- let appID = strArr[strArr.findIndex((e) => e == "recommended") + 1];
+ const userID = strArr[strArr.findIndex((e) => e == "profiles") + 1];
+ const appID = strArr[strArr.findIndex((e) => e == "recommended") + 1];
callback(null, userID + "/" + appID, idType); // Instantly callback input
}
@@ -132,7 +132,7 @@ Controller.prototype.handleSteamIdResolving = (str, expectedIdType, callback) =>
if (!res) return callback("The specified sharedfile could not be found", null, null);
// Cut domain away
- let split = str.split("/");
+ const split = str.split("/");
if (split[split.length - 1] == "") split.pop(); // Remove trailing slash (which is now a space because of split("/"))
str = split[split.length - 1].replace("?id=", "");
@@ -148,7 +148,7 @@ Controller.prototype.handleSteamIdResolving = (str, expectedIdType, callback) =>
logger("debug", "handleSteamIdResolving: User provided curator link...");
// Cut domain away
- let split = str.replace("/?appid=", "").split("/"); // Remove any trailing app id, we don't exactly know what the user provided
+ const split = str.replace("/?appid=", "").split("/"); // Remove any trailing app id, we don't exactly know what the user provided
if (split[split.length - 1] == "") split.pop(); // Remove trailing slash (which is now a space because of split("/"))
str = split[split.length - 1].split("-")[0];
@@ -209,7 +209,7 @@ Controller.prototype.handleSteamIdResolving = (str, expectedIdType, callback) =>
logger("debug", "handleSteamIdResolving: the provided id seems to be a sharedfile id! Returning sharedfileID...");
if (str.includes("steamcommunity.com/")) { // Check if full URL was provided and cut domain away
- let split = str.split("/");
+ const split = str.split("/");
if (split[split.length - 1] == "") split.pop(); // Remove trailing slash (which is now a space because of split("/"))
str = split[split.length - 1].replace("?id=", "");
diff --git a/src/controller/helpers/misc.js b/src/controller/helpers/misc.js
index 0f7091c8..33de314e 100644
--- a/src/controller/helpers/misc.js
+++ b/src/controller/helpers/misc.js
@@ -30,7 +30,7 @@ module.exports.syncLoop = (iterations, func, exit) => {
let done = false;
// Construct loop object
- let loop = {
+ const loop = {
next: function () { // Run next iteration
process.nextTick(() => { // Delay by one tick to fix weird infinite loop crash bug
// Check if the next iteration is still allowed to run, otherwise stop by calling break
@@ -111,7 +111,7 @@ module.exports.checkConnection = (url, throwTimeout = false, proxy) => {
// Use http and provide a proxy if requested - Credit: https://stackoverflow.com/a/49611762
if (proxy) { // TODO: Missing authentication could perhaps cause errors here
- let auth = "Basic " + Buffer.from(proxy.username + ":" + proxy.password).toString("base64"); // Construct autentication
+ const auth = "Basic " + Buffer.from(proxy.username + ":" + proxy.password).toString("base64"); // Construct autentication
url = url.replace("https://", ""); // Remove preceding https:// from url
@@ -167,7 +167,7 @@ module.exports.checkConnection = (url, throwTimeout = false, proxy) => {
*/
module.exports.splitProxyString = (url) => { // TODO: Missing authentication could perhaps cause errors here
- let obj = { ip: "", port: 0, username: "", password: "" };
+ const obj = { ip: "", port: 0, username: "", password: "" };
if (!url) return obj;
@@ -178,8 +178,8 @@ module.exports.splitProxyString = (url) => { // TODO: Missing authentication cou
url = url.split("@");
// Split both parts at : to separate the 4 different elements
- let usernamePassword = url[0].split(":");
- let ipPort = url[1].split(":");
+ const usernamePassword = url[0].split(":");
+ const ipPort = url[1].split(":");
// Extract ip and port from ipPort and username and password from usernamePassword
obj.ip = ipPort[0];
@@ -209,15 +209,15 @@ module.exports.cutStringsIntelligently = (txt, limit, cutChars, threshold) => {
if (txt.length <= limit) return [txt]; // Instantly return string as element 0 if it is already less than limit
let lastIndex = 0;
- let result = [];
+ const result = [];
// Regex-less version - Safe but can cut at places where a link is surrounded by "' " and " '" to avoid embedding in the Steam Chat.
// Iterate over string until lastIndex reaches length of input string. This whole algorithm could probably be replicated using RegEx but eeeehhhh
while (lastIndex < txt.length - 1) {
- let cut = txt.slice(lastIndex, lastIndex + limit); // Get the next part by cutting from lastIndex to limit
+ const cut = txt.slice(lastIndex, lastIndex + limit); // Get the next part by cutting from lastIndex to limit
// Find the last occurrence of all cutChars and find the most recent one using Math.max()
- let lastOccurrence = Math.max(...cutChars.map(e => cut.lastIndexOf(e)));
+ const lastOccurrence = Math.max(...cutChars.map(e => cut.lastIndexOf(e)));
// Check if cut maxes out limit (if not we have reached the end and can push as is),
// a last occurrence was found and is within threshold. If so, cut again, push to result and update lastIndex.
diff --git a/src/controller/login.js b/src/controller/login.js
index c4be430a..f1a152db 100644
--- a/src/controller/login.js
+++ b/src/controller/login.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-03-08 18:20:05
+ * Last Modified: 2024-05-04 22:46:20
* Modified By: 3urobeat
*
* Copyright (c) 2021 - 2024 3urobeat
@@ -23,6 +23,8 @@ const ascii = require("../data/ascii.js");
const misc = require("./helpers/misc.js");
+let postponedRetries = 0; // Tracks the amount of reruns caused by accounts with POSTPONED status
+
/**
* Attempts to log in all bot accounts which are currently offline one after another.
* Creates a new bot object for every new account and reuses existing one if possible
@@ -52,7 +54,7 @@ Controller.prototype.login = async function(firstLogin) {
}
// Ignore login request if another login is running
- if (this.info.activeLogin) return logger("debug", "Controller login(): Login requested but there is already a login process active. Ignoring...");
+ if (this.info.activeLogin) return logger("info", "Login for all offline accounts requested but there is already one process running. Ignoring request for now, it will be handled after this process is done.", false, true);
logger("debug", "Controller login(): Login requested, checking for any accounts currently OFFLINE or POSTPONED...");
@@ -66,7 +68,7 @@ Controller.prototype.login = async function(firstLogin) {
// Set all POSTPONED accounts to offline, as they are now going to be processed (this is important so that the allAccsOnlineInterval below doesn't plow through). Ignore acc if it doesn't have a bots entry yet
allAccounts.forEach((e) => this.bots[e.accountName] && this.bots[e.accountName].status == Bot.EStatus.POSTPONED ? this.bots[e.accountName].status = Bot.EStatus.OFFLINE : null);
- // Get all new accounts or existing ones that are offline or were postponed
+ // Get all new accounts or existing ones that are offline
allAccounts = allAccounts.filter((e) => !this.bots[e.accountName] || this.bots[e.accountName].status == Bot.EStatus.OFFLINE);
logger("debug", `Controller login(): Found ${allAccounts.length} login candidate(s)`);
@@ -99,8 +101,8 @@ Controller.prototype.login = async function(firstLogin) {
// Split login candidates into a fast queue (sync logins for accs on different proxies) & a slow queue (async logins for accs requiring user interaction)
- let fastQueue = [ ...allAccounts.filter((e) => e.hasStorageValidToken) ];
- let slowQueue = [ ...allAccounts.filter((e) => !e.hasStorageValidToken) ];
+ const fastQueue = [ ...allAccounts.filter((e) => e.hasStorageValidToken) ];
+ const slowQueue = [ ...allAccounts.filter((e) => !e.hasStorageValidToken) ];
// Calculate login time
@@ -125,34 +127,96 @@ Controller.prototype.login = async function(firstLogin) {
// Register interval to check if all accounts have been processed
- let allAccsOnlineInterval = setInterval(() => {
+ let lastAmountUpdateTimestamp = Date.now();
+ let waitingForAmountAccounts = 0;
+
+ const allAccsOnlineInterval = setInterval(() => {
+
+ // Shorthander that resolves this login process
+ const loginFinished = () => {
+ clearInterval(allAccsOnlineInterval);
+
+ this.info.activeLogin = false;
+
+ // Emit ready event if this is the first start and no login is pending
+ if (this.info.readyAfter == 0) {
+ if (!Object.values(this.bots).some((e) => e.status == Bot.EStatus.POSTPONED) || postponedRetries > 0) { // Emit ready event either way if we are already on a rerun to make the bot usable
+ this._readyEvent();
+ }
+
+ postponedRetries++;
+ }
- // Check if all accounts have been processed
- let allNotOffline = allAccounts.every((e) => this.bots[e.accountName].status != Bot.EStatus.OFFLINE);// && this.bots[e.accountName].status != Bot.EStatus.POSTPONED);
+ // Call itself again to process any POSTPONED or newly qualified accounts - this has to happen after the ready check above as login() sets every POSTPONED account to OFFLINE
+ this.login();
+ };
- if (!allNotOffline) return;
+
+ // Process various checks before deeming this login process to be finished
+
+ /**
+ * Get all accounts which have not yet switched their status
+ * @type {{ index: number, accountName: string }[]} Array of loginInfo objects, which among other things have these props
+ */
+ const allAccountsOffline = allAccounts.filter((e) => this.bots[e.accountName].status == Bot.EStatus.OFFLINE);
+
+ // Update waitingForAmountAccounts & lastAmountUpdateTimestamp on change
+ if (waitingForAmountAccounts != allAccountsOffline.length) {
+ waitingForAmountAccounts = allAccountsOffline.length;
+ lastAmountUpdateTimestamp = Date.now();
+ }
+
+ // Check if this login process might be softlocked. Display warning after 5 minutes, abort process after 15 minutes
+ if (Date.now() - lastAmountUpdateTimestamp > 300000) { // 300000 ms = 5 min
+ if (Date.now() - lastAmountUpdateTimestamp > 900000) { // 900000 ms = 15 min
+ logger("warn", `Detected softlocked login process! Setting status of bot(s) '${allAccountsOffline.flatMap((e) => e.index).join(", ")}' to ERROR and calling handleRelog!`, true, false, null, true);
+
+ // Check if main account is involved and this is the initial login and terminate the bot
+ if (allAccountsOffline.find((e) => e.index == 0) && this.info.readyAfter == 0) {
+ logger("", "", true);
+ logger("error", "Aborting because the first bot account always needs to be logged in!\nPlease correct what caused the error and try again.", true);
+ return this.stop();
+ }
+
+ // Set status of every account to OFFLINE and call handleRelog to let it figure this out
+ allAccountsOffline.forEach((e) => {
+ const thisBot = this.bots[e.accountName];
+
+ this._statusUpdateEvent(thisBot, Bot.EStatus.ERROR);
+ thisBot.handleRelog();
+ thisBot.loginData.pendingLogin = false;
+ });
+
+ loginFinished();
+ return;
+ }
+
+ const cancelingInMinutes = Math.ceil(((lastAmountUpdateTimestamp + 900000) - Date.now()) / 60000);
+
+ logger("warn", `Detected inactivity in current login process! I'm waiting for bot(s) '${allAccountsOffline.flatMap((e) => e.index).join(", ")}' to change their status & become populated since >5 minutes! Canceling this login process in ~${cancelingInMinutes} minutes to prevent a softlock.`, true, true);
+
+ if (allAccountsOffline.length > 0) return; // Prevents debug msg below from logging, should reduce log spam in debug mode
+ }
+
+ // Abort if we are still waiting for accounts to become not OFFLINE
+ if (allAccountsOffline.length > 0) {
+ logger("debug", `Controller login(): Waiting for bot(s) '${allAccountsOffline.flatMap((e) => e.index).join(", ")}' to switch status to not OFFLINE before resolving...`, true, true); // Cannot log with date to prevent log output file spam
+ return;
+ }
// Check if all accounts have their SteamUser data populated. Ignore accounts that are not online as they will never populate their user object
- let allAccountsNotPopulated = allAccounts.filter((e) => this.bots[e.accountName].status == Bot.EStatus.ONLINE && !this.bots[e.accountName].user.limitations);
+ const allAccountsNotPopulated = allAccounts.filter((e) => this.bots[e.accountName].status == Bot.EStatus.ONLINE && !this.bots[e.accountName].user.limitations);
if (allAccountsNotPopulated.length > 0) {
logger("info", `All accounts logged in, waiting for user object of bot(s) '${allAccountsNotPopulated.flatMap((e) => e.index).join(", ")}' to populate...`, true, true, logger.animation("waiting")); // Cannot log with date to prevent log output file spam
return;
}
- clearInterval(allAccsOnlineInterval);
+ // Everything looks good, resolve this login process!
logger("info", "Finished logging in all currently queued accounts! Checking for any new accounts...", false, false, logger.animation("loading"));
- this.info.activeLogin = false;
-
- // Emit ready event if this is the first start and no login is pending
- if (this.info.readyAfter == 0 && !Object.values(this.bots).some((e) => e.status == Bot.EStatus.POSTPONED)) {
- this._readyEvent();
- }
-
- // Call itself again to process any POSTPONED or newly qualified accounts - this has to happen after the ready check above as login() sets every POSTPONED account to OFFLINE
- this.login();
+ loginFinished();
}, 250);
@@ -169,14 +233,14 @@ Controller.prototype._processFastLoginQueue = function(allAccounts) {
this.data.proxies.forEach((proxy) => {
// Find all queued accounts using this proxy
- let thisProxyAccs = allAccounts.filter((e) => this.bots[e.accountName].loginData.proxyIndex == proxy.proxyIndex);
+ const thisProxyAccs = allAccounts.filter((e) => this.bots[e.accountName].loginData.proxyIndex == proxy.proxyIndex);
// Make login timestamp entry for this proxy
if (!this.info.lastLoginTimestamp[String(proxy.proxy)]) this.info.lastLoginTimestamp[String(proxy.proxy)] = 0;
// Iterate over all accounts, use syncLoop() helper to make our job easier
misc.syncLoop(thisProxyAccs.length, (loop, i) => {
- let thisAcc = thisProxyAccs[i]; // Get logininfo for this account name
+ const thisAcc = thisProxyAccs[i]; // Get logininfo for this account name
// Calculate wait time
let waitTime = (this.info.lastLoginTimestamp[String(proxy.proxy)] + this.data.advancedconfig.loginDelay) - Date.now();
@@ -187,7 +251,7 @@ Controller.prototype._processFastLoginQueue = function(allAccounts) {
// Wait before starting to log in
setTimeout(() => {
- let thisbot = this.bots[thisAcc.accountName];
+ const thisbot = this.bots[thisAcc.accountName];
// Reset logOnTries (do this here to guarantee a bot object exists for this account)
thisbot.loginData.logOnTries = 0;
@@ -202,7 +266,7 @@ Controller.prototype._processFastLoginQueue = function(allAccounts) {
thisbot._loginToSteam();
// Check if this bot is not offline anymore, resolve this iteration and update lastLoginTimestamp
- let accIsOnlineInterval = setInterval(() => {
+ const accIsOnlineInterval = setInterval(() => {
if (thisbot.status == Bot.EStatus.OFFLINE) return;
clearInterval(accIsOnlineInterval);
@@ -228,7 +292,7 @@ Controller.prototype._processSlowLoginQueue = function(allAccounts) {
// Iterate over all accounts, use syncLoop() helper to make our job easier
misc.syncLoop(allAccounts.length, (loop, i) => {
- let thisAcc = allAccounts[i]; // Get logininfo for this account name
+ const thisAcc = allAccounts[i]; // Get logininfo for this account name
// Calculate wait time
let waitTime = (this.info.lastLoginTimestamp[String(this.bots[thisAcc.accountName].loginData.proxy)] + this.data.advancedconfig.loginDelay) - Date.now();
@@ -239,7 +303,7 @@ Controller.prototype._processSlowLoginQueue = function(allAccounts) {
// Wait before starting to log in
setTimeout(() => {
- let thisbot = this.bots[thisAcc.accountName];
+ const thisbot = this.bots[thisAcc.accountName];
// Reset logOnTries (do this here to guarantee a bot object exists for this account)
thisbot.loginData.logOnTries = 0;
@@ -254,7 +318,7 @@ Controller.prototype._processSlowLoginQueue = function(allAccounts) {
thisbot._loginToSteam();
// Check if this bot is not offline anymore, resolve this iteration and update lastLoginTimestamp
- let accIsOnlineInterval = setInterval(() => {
+ const accIsOnlineInterval = setInterval(() => {
if (thisbot.status == Bot.EStatus.OFFLINE) return;
clearInterval(accIsOnlineInterval);
diff --git a/src/data/data.json b/src/data/data.json
index 5f065eb9..baa41146 100644
--- a/src/data/data.json
+++ b/src/data/data.json
@@ -1,6 +1,6 @@
{
- "version": "21501",
- "versionstr": "2.15.1",
+ "version": "21502",
+ "versionstr": "2.15.2",
"branch": "master",
"filetostart": "./src/starter.js",
"filetostarturl": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/master/src/starter.js",
@@ -8,7 +8,7 @@
"aboutstr": "This bot was created by 3urobeat.\nGitHub: https://github.com/3urobeat/steam-comment-service-bot \nSteam: https://steamcommunity.com/id/3urobeat \nIf you like my work, any donation would be appreciated! https://github.com/sponsors/3urobeat",
"firststart": true,
"compatibilityfeaturedone": false,
- "whatsnew": "Fixed softlocked login process after proxy switch, fixed vote & fav error logging throwing an error and reduced amount of log messages logged during startup, login, disconnect & relog.",
+ "whatsnew": "Added traditional-chinese translation, added steamGuardQrCode event, fixed login starting faster than plugins could catch related events, fixed multiple login/relog bugs and made some more changes.",
"timesloggedin": 0,
"totallogintime": 0
}
diff --git a/src/data/fileStructure.json b/src/data/fileStructure.json
index 1fae5f69..0a269c23 100644
--- a/src/data/fileStructure.json
+++ b/src/data/fileStructure.json
@@ -1,10 +1,5 @@
{
"files": [
- {
- "path": ".eslintrc.json",
- "url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/.eslintrc.json",
- "checksum": "982f55cc4c53137135b87df43bbfe9c8"
- },
{
"path": ".github/FUNDING.yml",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/.github/FUNDING.yml",
@@ -13,17 +8,17 @@
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/.github/ISSUE_TEMPLATE/bug_report.md",
- "checksum": "324472c36f99a41a0eb39f6875e11a56"
+ "checksum": "0427a2bb62d2775fbf47795461d343b5"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/.github/ISSUE_TEMPLATE/feature_request.md",
- "checksum": "434308eeb7670ecc4fa63908eb6f9f56"
+ "checksum": "23a660d1130154f12b20168de15e264b"
},
{
"path": ".github/ISSUE_TEMPLATE/help-wanted-question.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/.github/ISSUE_TEMPLATE/help-wanted-question.md",
- "checksum": "d341d7c8a2428d5c4a495508d5400b7d"
+ "checksum": "081c0421394521c2fafe5c518f2023a2"
},
{
"path": ".github/workflows/codeql-analysis.yml",
@@ -83,7 +78,7 @@
{
"path": "docs/dev/controller/events.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/docs/dev/controller/events.md",
- "checksum": "cab6f4fe3d8b9fa0374bf9aaa33c965d"
+ "checksum": "8c1a3cfb9b911e2fc61c77ae4251db38"
},
{
"path": "docs/dev/controller/helpers.md",
@@ -143,7 +138,7 @@
{
"path": "docs/wiki/advancedconfig_doc.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/docs/wiki/advancedconfig_doc.md",
- "checksum": "bca398c7db36e3ad845cafcc31726f64"
+ "checksum": "6948c00ddb3c97dcb92e42ebf2174bdd"
},
{
"path": "docs/wiki/changelogs/CHANGELOG_v1.x.md",
@@ -188,7 +183,7 @@
{
"path": "docs/wiki/changelogs/CHANGELOG_v2.15.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/docs/wiki/changelogs/CHANGELOG_v2.15.md",
- "checksum": "327435ddb0311eba66267b77129222b9"
+ "checksum": "bec83acdff8fd756b2085609d44134bf"
},
{
"path": "docs/wiki/changelogs/CHANGELOG_v2.2.md",
@@ -243,12 +238,12 @@
{
"path": "docs/wiki/contributing.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/docs/wiki/contributing.md",
- "checksum": "7719bb31fc5180a04362a5d71e93f9bf"
+ "checksum": "bf2726a14d91675dd6b530da720aabab"
},
{
"path": "docs/wiki/creating_plugins.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/docs/wiki/creating_plugins.md",
- "checksum": "11ea6f29f4c9591b6a00c637e4ab928b"
+ "checksum": "11b8d3b398f638581f260ff5cf64d95c"
},
{
"path": "docs/wiki/customlang_doc.md",
@@ -285,6 +280,11 @@
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/docs/wiki/version_changelogs.md",
"checksum": "608963ede0ef27d65adcb294666812d3"
},
+ {
+ "path": "eslint.config.mjs",
+ "url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/eslint.config.mjs",
+ "checksum": "b0f1fa7925dfdfc2b6abef8af2128f60"
+ },
{
"path": "scripts/README.md",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/scripts/README.md",
@@ -293,7 +293,7 @@
{
"path": "scripts/checkTranslationKeys.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/scripts/checkTranslationKeys.js",
- "checksum": "7c100ee6a3e88a657fbb02ae1a5717fc"
+ "checksum": "75c120983219fc44c90e7b72c71ebb4e"
},
{
"path": "scripts/duplicateQuotesDetector.js",
@@ -303,7 +303,7 @@
{
"path": "scripts/generateFileStructure.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/scripts/generateFileStructure.js",
- "checksum": "34df68cb56b63515681f021f4ff08840"
+ "checksum": "635d19551c1ffdd6567a9385fc72e065"
},
{
"path": "scripts/langStringsChangeDetector.js",
@@ -318,7 +318,7 @@
{
"path": "src/bot/bot.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/bot.js",
- "checksum": "bf91bc9deef102f02ff63522143f72f7"
+ "checksum": "0e94cc19c9d3b541b4645e28ed535322"
},
{
"path": "src/bot/events/debug.js",
@@ -333,12 +333,12 @@
{
"path": "src/bot/events/error.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/events/error.js",
- "checksum": "8415adcfa88700af656c85657a3c05c3"
+ "checksum": "155830f0d23d9b15138b93c18ede2930"
},
{
"path": "src/bot/events/friendMessage.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/events/friendMessage.js",
- "checksum": "614384a783b6076f5bd29c233fd64b44"
+ "checksum": "8d0dafd89118e2ae214db6e4d2745dc7"
},
{
"path": "src/bot/events/loggedOn.js",
@@ -348,12 +348,12 @@
{
"path": "src/bot/events/relationship.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/events/relationship.js",
- "checksum": "0ad301527df201620e549dfb9c495b68"
+ "checksum": "a9eb97b258a58fc2d6ca274f16ea64bd"
},
{
"path": "src/bot/events/webSession.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/events/webSession.js",
- "checksum": "23ffa55367ac713ce9ce6c2ec4c3d913"
+ "checksum": "37a078ce9bc892c1506c0653b145663f"
},
{
"path": "src/bot/helpers/checkMsgBlock.js",
@@ -363,162 +363,167 @@
{
"path": "src/bot/helpers/handleLoginTimeout.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/helpers/handleLoginTimeout.js",
- "checksum": "7c26d70db39d80a85eb77309d674c586"
+ "checksum": "e587049d71f7eca6e32f46309edc2f59"
},
{
"path": "src/bot/helpers/handleMissingGameLicenses.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/helpers/handleMissingGameLicenses.js",
- "checksum": "972d35acb19963f5dd6519e3393ebd57"
+ "checksum": "6c23ba7c9d898e4d7637809248df452e"
},
{
"path": "src/bot/helpers/handleRelog.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/helpers/handleRelog.js",
- "checksum": "3808cfde6f188582a539628ef4f5eb76"
+ "checksum": "5a5e47dbbd2cdf30200ff1b841b700ed"
},
{
"path": "src/bot/helpers/steamChatInteraction.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/bot/helpers/steamChatInteraction.js",
- "checksum": "0e9c4608f652586d0d3328698cfc7770"
+ "checksum": "6de2730efaeef305abbe8a5f24ca5265"
},
{
"path": "src/commands/commandHandler.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/commandHandler.js",
- "checksum": "a39e912f50969e3b13cbc45d0823d14e"
+ "checksum": "ea2f27cb304a393dc82347ec1798a89d"
},
{
"path": "src/commands/core/block.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/block.js",
- "checksum": "c8faefabe22526fee5443c0498199a93"
+ "checksum": "cae3d0d707509089dba88c42e19844ca"
},
{
"path": "src/commands/core/comment.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/comment.js",
- "checksum": "99ec8c17453e2a055028df6024911c56"
+ "checksum": "90f2032edf170fcda4a3bcc9ae7f52d6"
},
{
"path": "src/commands/core/favorite.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/favorite.js",
- "checksum": "9dc47165909fdf357c25ba775129e74a"
+ "checksum": "bcda38e982870e452fc469cba356ffed"
},
{
"path": "src/commands/core/follow.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/follow.js",
- "checksum": "b6317db43d9e1591fc1d61663d45c5fe"
+ "checksum": "57ac961637cb74bdda66a312e3c1e760"
},
{
"path": "src/commands/core/friend.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/friend.js",
- "checksum": "26800bddf4e1c79331dca96c43e38fea"
+ "checksum": "3e5b234b7b2e1b6fbcff64e06ba64fbe"
},
{
"path": "src/commands/core/general.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/general.js",
- "checksum": "2f06633d9d51ef6be103b89742e6c8c3"
+ "checksum": "a3017332fef9c3269d0a41fda1598025"
},
{
"path": "src/commands/core/group.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/group.js",
- "checksum": "a952ab3fae5ebd4fb7c6c1c01a520888"
+ "checksum": "dc04c054f927211c18a61913c06d5c15"
},
{
"path": "src/commands/core/requests.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/requests.js",
- "checksum": "5bbf1eff2f6c23dba05f5841a83a47b0"
+ "checksum": "97eac183e28c839e442dc5ecdccfbf2a"
},
{
"path": "src/commands/core/settings.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/settings.js",
- "checksum": "556c368995dfc46f1407dac4b97503d7"
+ "checksum": "d1e9b04a501471b5fb6ab5f0880f9580"
},
{
"path": "src/commands/core/system.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/system.js",
- "checksum": "ae3a4efd8a7230c45211f8f80adb25c6"
+ "checksum": "b37fd364b9aa9f00d47b3a0d8094c700"
},
{
"path": "src/commands/core/vote.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/core/vote.js",
- "checksum": "f69c2827cc333b67d34075a14d8b40e4"
+ "checksum": "25d1259442bf63366a991a09246629cb"
},
{
"path": "src/commands/helpers/getCommentArgs.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getCommentArgs.js",
- "checksum": "c51407b565b90ae3835f407d4642baec"
+ "checksum": "8a42a107359cdef43f7b4706509e4097"
},
{
"path": "src/commands/helpers/getCommentBots.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getCommentBots.js",
- "checksum": "a3f54c2cea9d6482226fa4d64a3a4522"
+ "checksum": "64b43f3d326c560cf79764e96e69d043"
},
{
"path": "src/commands/helpers/getFavoriteBots.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getFavoriteBots.js",
- "checksum": "93d8d331be02808c8b4c008428e01529"
+ "checksum": "5ab5687eef590b6191d4349da4aa2f65"
},
{
"path": "src/commands/helpers/getFollowArgs.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getFollowArgs.js",
- "checksum": "1721a8875ca32ba707867bb3318952a0"
+ "checksum": "0dbb185c9a4b22691e60dffdf5d1160c"
},
{
"path": "src/commands/helpers/getFollowBots.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getFollowBots.js",
- "checksum": "dc949626da55dfe87fb1a0dea157deb5"
+ "checksum": "4bd2c335e4a5b8a49e516ba378d1f8b4"
},
{
"path": "src/commands/helpers/getMiscArgs.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getMiscArgs.js",
- "checksum": "488803b1fe38671e2f0d339a9c692db5"
+ "checksum": "50ffb768fca4a19e3548c6dd5fd25f57"
},
{
"path": "src/commands/helpers/getVoteBots.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/getVoteBots.js",
- "checksum": "8ab53da00eef05147f8aba1405b55ac3"
+ "checksum": "ce701d131eb4473d213467ee4c0d514d"
},
{
"path": "src/commands/helpers/handleCommentSkips.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/handleCommentSkips.js",
- "checksum": "8279c8a9a1d624f2212050b5b98cbca2"
+ "checksum": "1391d03159a67310f007736d0cb499d8"
},
{
"path": "src/commands/helpers/handleFollowErrors.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/handleFollowErrors.js",
- "checksum": "18054a4221e795a8c5530b5a55a014ae"
+ "checksum": "eddda0b8cc1fb2647bfd638916c8f9e1"
},
{
"path": "src/commands/helpers/handleMiscErrors.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/commands/helpers/handleMiscErrors.js",
- "checksum": "9a48943369e29712e578e9b363d98545"
+ "checksum": "42a299d803b936ec6c839447a6941452"
},
{
"path": "src/controller/controller.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/controller.js",
- "checksum": "031c4ada6d2ed4e366773d5af1da359b"
+ "checksum": "fc45d9b90330a9d80f4da19cbd6ca695"
},
{
"path": "src/controller/events/ready.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/events/ready.js",
- "checksum": "d911f1d901cf1bd4541fc0855e46d5ca"
+ "checksum": "94ef5412b7186a976e63b525e16712de"
},
{
"path": "src/controller/events/statusUpdate.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/events/statusUpdate.js",
- "checksum": "5a7c66ae19eb320bacf6d2c2abeba9d6"
+ "checksum": "33f3b07680d7a031938973f7d159a823"
},
{
"path": "src/controller/events/steamGuardInput.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/events/steamGuardInput.js",
"checksum": "df33797c6bf867a52adb5d7e39315e73"
},
+ {
+ "path": "src/controller/events/steamGuardQrCode.js",
+ "url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/events/steamGuardQrCode.js",
+ "checksum": "37910bd18328ada639373d8373c664a4"
+ },
{
"path": "src/controller/helpers/friendlist.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/helpers/friendlist.js",
- "checksum": "4c63ef25e986890ece07f01d61d40faa"
+ "checksum": "6ca8db673bf51a60a2be39e574451bfd"
},
{
"path": "src/controller/helpers/getBots.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/helpers/getBots.js",
- "checksum": "5c86225dc66f901cce50aada3c8d8562"
+ "checksum": "1e4ac2683dc039d92f4fecc2aef6347b"
},
{
"path": "src/controller/helpers/handleErrors.js",
@@ -528,7 +533,7 @@
{
"path": "src/controller/helpers/handleSteamIdResolving.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/helpers/handleSteamIdResolving.js",
- "checksum": "5562fb7b13b156a0710ebbff6193025b"
+ "checksum": "fb244bbc5397cd1ccf6e2c4451053492"
},
{
"path": "src/controller/helpers/logger.js",
@@ -538,7 +543,7 @@
{
"path": "src/controller/helpers/misc.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/helpers/misc.js",
- "checksum": "9c67eb0be1e14576747ebec6a7267d9b"
+ "checksum": "70fb4a03d2e7b2f251685d04d3557ea5"
},
{
"path": "src/controller/helpers/npminteraction.js",
@@ -548,7 +553,7 @@
{
"path": "src/controller/login.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/login.js",
- "checksum": "a3181994388cb9145687ff167345ee47"
+ "checksum": "5c2004ff7748ccb64d90f1ae61d93f5a"
},
{
"path": "src/data/ascii.js",
@@ -558,42 +563,47 @@
{
"path": "src/data/lang/chinese.json",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/data/lang/chinese.json",
- "checksum": "b6b4d96c7eb14d097904163336dc3da2"
+ "checksum": "4cd2509c0e0125fa2166901c03ae960b"
},
{
"path": "src/data/lang/english.json",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/data/lang/english.json",
- "checksum": "05de5a7d2da79c40834733f124427980"
+ "checksum": "6d888d188a93c91d6226fa75f576503a"
},
{
"path": "src/data/lang/portuguese.json",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/data/lang/portuguese.json",
- "checksum": "1afec7300ee8f6fd729422e55994405f"
+ "checksum": "2049d7f916c4cdd8687b6d014aa940b5"
},
{
"path": "src/data/lang/russian.json",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/data/lang/russian.json",
- "checksum": "9f93de745e5596791a2bdef226ee1b6b"
+ "checksum": "63fa3da42a0e915a1f0e5c1ee60a0358"
+ },
+ {
+ "path": "src/data/lang/traditional-chinese.json",
+ "url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/data/lang/traditional-chinese.json",
+ "checksum": "ff9dab1c2b225c5f6b360aae9a9f91ac"
},
{
"path": "src/dataManager/dataCheck.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/dataCheck.js",
- "checksum": "04f630fd31ef721c9748bd4f680cb9c3"
+ "checksum": "033e061d02f24f00e8c0da2c02cc458f"
},
{
"path": "src/dataManager/dataExport.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/dataExport.js",
- "checksum": "2d82e0053f351a7d6c7fa854909a3dba"
+ "checksum": "0e7c63573628c0771abd857567c153c2"
},
{
"path": "src/dataManager/dataImport.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/dataImport.js",
- "checksum": "16091447de2f8daa460e9bba67d38e4a"
+ "checksum": "45749a6c541a0426734d9f97f13bb908"
},
{
"path": "src/dataManager/dataIntegrity.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/dataIntegrity.js",
- "checksum": "48cb100ddf80bc4dd1b8abf963219d78"
+ "checksum": "fd6dd7e5acb7e13340a9eed6bb271231"
},
{
"path": "src/dataManager/dataManager.js",
@@ -603,52 +613,52 @@
{
"path": "src/dataManager/dataProcessing.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/dataProcessing.js",
- "checksum": "af2612047ec965f8531699cc287bf2c3"
+ "checksum": "3f135d96f163062b6bd90043bcda5420"
},
{
"path": "src/dataManager/helpers/checkProxies.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/checkProxies.js",
- "checksum": "357670340be40f10eb1692a1f001881f"
+ "checksum": "cd61d354f2726df6edc0ea37cd560ba1"
},
{
"path": "src/dataManager/helpers/getLang.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/getLang.js",
- "checksum": "5f5ce750442ab1411544ddbedb03d2b7"
+ "checksum": "a60effdfafc102c701e621af39a8597b"
},
{
"path": "src/dataManager/helpers/getQuote.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/getQuote.js",
- "checksum": "7b626a62ea9d40a524b4616d01b8fd97"
+ "checksum": "3b2de6a63bc2ea00ab534369a520bafd"
},
{
"path": "src/dataManager/helpers/handleCooldowns.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/handleCooldowns.js",
- "checksum": "9b35a82aa2b29e9e8d566db0d406b13a"
+ "checksum": "2a5fb950648c3c8a9c14611df7718ec9"
},
{
"path": "src/dataManager/helpers/handleExpiringTokens.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/handleExpiringTokens.js",
- "checksum": "0c4c8bae5b9bae91a9e7f220c7b73e53"
+ "checksum": "567753a572fbf016c3eab339d749fc89"
},
{
"path": "src/dataManager/helpers/misc.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/misc.js",
- "checksum": "32544368771121102a46f2a75c3f5f41"
+ "checksum": "fe0c9a0b17c21ecb66ea4cbd94885867"
},
{
"path": "src/dataManager/helpers/refreshCache.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/refreshCache.js",
- "checksum": "45511a56fb61cd18f36f89e215881722"
+ "checksum": "851f1c267621dc71efd1e58c7c12d800"
},
{
"path": "src/dataManager/helpers/repairFile.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/dataManager/helpers/repairFile.js",
- "checksum": "283942ba224a393abde0980f7ab3ef63"
+ "checksum": "68d8b080bc5874de309dae0657825e25"
},
{
"path": "src/jobs/jobManager.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/jobs/jobManager.js",
- "checksum": "37dec9dd3507e1c98903722391115944"
+ "checksum": "2e33bc746f98bd75184f514fcd04b310"
},
{
"path": "src/libraryPatches/CSteamDiscussion.js",
@@ -698,17 +708,17 @@
{
"path": "src/pluginSystem/handlePluginData.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/pluginSystem/handlePluginData.js",
- "checksum": "c580d836d41f1fc4da1389d9c52242b9"
+ "checksum": "d5dcfaa89d76d4ea569ccada4b7f12e6"
},
{
"path": "src/pluginSystem/loadPlugins.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/pluginSystem/loadPlugins.js",
- "checksum": "236e11079a89df528f4e609eb68e784e"
+ "checksum": "beb8b4bbe7299207bf2ac008670a1ed4"
},
{
"path": "src/pluginSystem/pluginSystem.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/pluginSystem/pluginSystem.js",
- "checksum": "15f035879c2247ab7372644e21398344"
+ "checksum": "577b44eae6d3c22fcbf40bde95b99fc1"
},
{
"path": "src/sessions/events/sessionEvents.js",
@@ -718,27 +728,27 @@
{
"path": "src/sessions/helpers/handle2FA.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/sessions/helpers/handle2FA.js",
- "checksum": "14641de1b2895cbea783b4264a7bd489"
+ "checksum": "cfb93f71d65c40fc47529ce7ab129ba2"
},
{
"path": "src/sessions/helpers/handleCredentialsLoginError.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/sessions/helpers/handleCredentialsLoginError.js",
- "checksum": "5e1317e28ca6649eeec919921a773236"
+ "checksum": "fec98edb7233d0511c81812985f190b7"
},
{
"path": "src/sessions/helpers/tokenStorageHandler.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/sessions/helpers/tokenStorageHandler.js",
- "checksum": "3b7bee517850238ba69d7e369cd0950b"
+ "checksum": "f5894f15254e7d921564fa9023845719"
},
{
"path": "src/sessions/sessionHandler.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/sessions/sessionHandler.js",
- "checksum": "1138f9e889c9f4789b4c7f39766a486a"
+ "checksum": "64352a0da4144cae87b737f70158862b"
},
{
"path": "src/starter.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/starter.js",
- "checksum": "b106db2dbc61e544e8f1eb37cba99d69"
+ "checksum": "54256633c339c5ba046c73f592fb582f"
},
{
"path": "src/updater/compatibility/2060.js",
@@ -768,77 +778,77 @@
{
"path": "src/updater/compatibility/2104.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/compatibility/2104.js",
- "checksum": "0e52117c2a3c2a8d854de384d4a94722"
+ "checksum": "3957635683fa37196684da72881445fc"
},
{
"path": "src/updater/compatibility/21100.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/compatibility/21100.js",
- "checksum": "3bb4455ad0a9ab426cd34cf5536c03aa"
+ "checksum": "3726dfdb7a86e4795581e73d8abac12d"
},
{
"path": "src/updater/compatibility/21200.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/compatibility/21200.js",
- "checksum": "41a0f507b86b1f4afa7cc99eff44b6cf"
+ "checksum": "e21271bc17e7d8ee1e9489981a3cffbf"
},
{
"path": "src/updater/compatibility/21300.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/compatibility/21300.js",
- "checksum": "e2e86c05da9fc16db4e91d63a5176576"
+ "checksum": "c1ab944ad8cf3518ddf952f5a3b68b30"
},
{
"path": "src/updater/compatibility/21400.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/compatibility/21400.js",
- "checksum": "b6040d97f7a09ad5e6fc91167e486e4b"
+ "checksum": "cb31edb8d74306c46391bbebfc24a52e"
},
{
"path": "src/updater/compatibility.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/compatibility.js",
- "checksum": "b8a36866188ae4304dfbcb4ebe8f3d80"
+ "checksum": "cc47bba386329fbd26a678d2ae911b71"
},
{
"path": "src/updater/helpers/checkForUpdate.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/helpers/checkForUpdate.js",
- "checksum": "240bcc17d4c2019006184942b9a53169"
+ "checksum": "e3cc99d51cc90f6d6cb14c0f37eac7d2"
},
{
"path": "src/updater/helpers/createBackup.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/helpers/createBackup.js",
- "checksum": "d767af9c5ae397bdfa7b386c2e4e49eb"
+ "checksum": "7904c42e9ec01fbfd2244ee5f546b8fa"
},
{
"path": "src/updater/helpers/customUpdateRules.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/helpers/customUpdateRules.js",
- "checksum": "2148b6eb0164503c3d0b4adbe8bfe757"
+ "checksum": "a9be187001621bdcdf582179845c9f68"
},
{
"path": "src/updater/helpers/downloadUpdate.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/helpers/downloadUpdate.js",
- "checksum": "9be735b19ef5b1e73df74cae8c4fedc4"
+ "checksum": "873cc86d178a03bd0b2bf5578aec6456"
},
{
"path": "src/updater/helpers/prepareUpdate.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/helpers/prepareUpdate.js",
- "checksum": "eea0c957cfb4f73c15a0fdd78f6e9a68"
+ "checksum": "5acced2a4a6accfcfdd9a5a0d3ea5259"
},
{
"path": "src/updater/helpers/restoreBackup.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/helpers/restoreBackup.js",
- "checksum": "02224a065b6b3cf13558e13c487511a3"
+ "checksum": "9f35a7f4e9852a4fa5e02ba6c294decd"
},
{
"path": "src/updater/updater.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/updater/updater.js",
- "checksum": "08c78136f2fb25f10ccb2a003a603563"
+ "checksum": "a686cac45e3bc58503fc3319ef47c893"
},
{
"path": "start.js",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/start.js",
- "checksum": "afc9710e045984455ca0936fec484f1a"
+ "checksum": "96209b84adbdf4f7ee7f3da7e59d2ec6"
},
{
"path": "types/types.d.ts",
"url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/types/types.d.ts",
- "checksum": "582a964870623eb4ca6f68fcc4ab6570"
+ "checksum": "9363ec344f32f27c4437a0ee3edacdb1"
}
]
}
\ No newline at end of file
diff --git a/src/data/lang/chinese.json b/src/data/lang/chinese.json
index 5c814071..33bd8339 100644
--- a/src/data/lang/chinese.json
+++ b/src/data/lang/chinese.json
@@ -42,8 +42,8 @@
"followsuccess": "所有未追随/已追随的操作已发送。失败: ${failedamount}/${totalamount}",
"useradded": "你好!感谢添加我!\n使用 '${cmdprefix}comment' 请求一条免费评论\n输入 '${cmdprefix}help' 了解更多命令,或 '${cmdprefix}about' 了解更多信息!\n你可以使用'${cmdprefix}lang'命令在${langcount}语言之间切换。",
- "userunfriend": "由于朋友列表空间不足,您已在 ${forceFriendlistSpaceTime} 天内因不活跃而被解除好友关系。\n如果您需要我,请随时再次添加我!",
- "userforceunfriend": "由于 ${unfriendtime} 天不活跃,您已被解除好友关系。\n如果您需要我,请随时再次添加我!",
+ "userforceunfriend": "由于朋友列表空间不足,您已在 ${forceFriendlistSpaceTime} 天内因不活跃而被解除好友关系。\n如果您需要我,请随时再次添加我!",
+ "userunfriend": "由于 ${unfriendtime} 天不活跃,您已被解除好友关系。\n如果您需要我,请随时再次添加我!",
"userspamblock": "由于垃圾信息,您已被封锁 90 秒。",
"usernotfriend": "请在使用命令之前先添加我为好友!",
diff --git a/src/data/lang/english.json b/src/data/lang/english.json
index aeca56f2..0c7df061 100644
--- a/src/data/lang/english.json
+++ b/src/data/lang/english.json
@@ -42,8 +42,8 @@
"followsuccess": "All un-/follows have been sent. Failed: ${failedamount}/${totalamount}",
"useradded": "Hey! Thanks for adding me!\nRequest a free comment with '${cmdprefix}comment'\nType '${cmdprefix}help' for more commands or '${cmdprefix}about' for more information.\nYou can use the '${cmdprefix}lang' command to switch between ${langcount} languages.",
- "userunfriend": "You have been unfriended for being inactive for ${forceFriendlistSpaceTime} days as the friendlist was running low on space.\nIf you need me again, feel free to add me again!",
- "userforceunfriend": "You have been unfriended for being inactive for ${unfriendtime} days.\nIf you need me again, feel free to add me again!",
+ "userforceunfriend": "You have been unfriended for being inactive for ${forceFriendlistSpaceTime} days as the friendlist was running low on space.\nIf you need me again, feel free to add me again!",
+ "userunfriend": "You have been unfriended for being inactive for ${unfriendtime} days.\nIf you need me again, feel free to add me again!",
"userspamblock": "You have been blocked for 90 seconds for spamming.",
"usernotfriend": "Please add me before using a command!",
@@ -122,7 +122,7 @@
"mysessionscmdnosessions": "There are currently no active sessions that you have started.",
"addfriendcmdacclimited": "Can't add friend ${profileid} with bot0 because the bot account is limited.",
- "addfriendcmdsuccess": "Adding friend ${profileid} with all bot accounts... This will take ~estimatedtime seconds. Please check the log for potential errors.",
+ "addfriendcmdsuccess": "Adding friend ${profileid} with all bot accounts... This will take ~${estimatedtime} seconds. Please check the log for potential errors.",
"unfriendcmdsuccess": "I am unfriending you with all bot accounts. This will take a moment...\nYou can send me a friend request again at any time.",
"unfriendidcmdsuccess": "Removed friend ${profileid} from all bot accounts.",
diff --git a/src/data/lang/portuguese.json b/src/data/lang/portuguese.json
index df94a389..bcb35295 100644
--- a/src/data/lang/portuguese.json
+++ b/src/data/lang/portuguese.json
@@ -42,8 +42,8 @@
"followsuccess": "Todos os seguir/deixar de seguir foram enviados. Falhou: ${failedamount}/${totalamount}",
"useradded": "Olá! Obrigado por me adicionar!\nSolicite um comentário gratuito com '${cmdprefix}comment'\nDigite '${cmdprefix}help' para mais comandos ou '${cmdprefix}about' para mais informações!\nYou can use the '${cmdprefix}lang' command to switch between ${langcount} languages.",
- "userunfriend": "Você foi desfeito como amigo por estar inativo por ${forceFriendlistSpaceTime} dias, pois a lista de amigos estava ficando cheia.\nSe precisar de mim novamente, sinta-se à vontade para me adicionar novamente!",
- "userforceunfriend": "Você foi desfeito como amigo por estar inativo por ${unfriendtime} dias.\nSe precisar de mim novamente, sinta-se à vontade para me adicionar novamente!",
+ "userforceunfriend": "Você foi desfeito como amigo por estar inativo por ${forceFriendlistSpaceTime} dias, pois a lista de amigos estava ficando cheia.\nSe precisar de mim novamente, sinta-se à vontade para me adicionar novamente!",
+ "userunfriend": "Você foi desfeito como amigo por estar inativo por ${unfriendtime} dias.\nSe precisar de mim novamente, sinta-se à vontade para me adicionar novamente!",
"userspamblock": "Você foi bloqueado por 90 segundos por fazer spam.",
"usernotfriend": "Por favor, me adicione antes de usar um comando!",
@@ -122,7 +122,7 @@
"mysessionscmdnosessions": "Atualmente não há sessões ativas que você iniciou.",
"addfriendcmdacclimited": "Não é possível adicionar o amigo ${profileid} com o bot0 porque a conta do bot está limitada.",
- "addfriendcmdsuccess": "Adicionando amigo ${profileid} com todas as contas de bot... Isso levará aproximadamente ~estimatedtime segundos. Por favor, verifique o log para possíveis erros.",
+ "addfriendcmdsuccess": "Adicionando amigo ${profileid} com todas as contas de bot... Isso levará aproximadamente ~${estimatedtime} segundos. Por favor, verifique o log para possíveis erros.",
"unfriendcmdsuccess": "Estou cancelando a amizade com você em todas as contas de bot. Isso levará um momento...\nVocê pode me enviar um pedido de amizade novamente a qualquer momento.",
"unfriendidcmdsuccess": "Removido o amigo ${profileid} de todas as contas de bot.",
diff --git a/src/data/lang/russian.json b/src/data/lang/russian.json
index c9ddee79..c487e03d 100644
--- a/src/data/lang/russian.json
+++ b/src/data/lang/russian.json
@@ -42,8 +42,8 @@
"followsuccess": "Все подписки/отписки были отправлены. Не удалось: ${failedamount}/${totalamount}",
"useradded": "Здравствуйте! Спасибо, что добавили меня!\nЗапросите бесплатный комментарий с помощью '${cmdprefix}comment'\nВведите '${cmdprefix}help' для получения дополнительных команд или '${cmdprefix}about' для получения дополнительной информации!\nМожете использовать команду '${cmdprefix}lang' чтобы переключаться между ${langcount} языками.",
- "userunfriend": "Вы были удалены из друзей за неактивность в течение ${forceFriendlistSpaceTime} дн., так как в списке друзей было мало места.\nЕсли я вам снова понадоблюсь, добавляйте меня снова!",
- "userforceunfriend": "Вы были удалены из друзей за неактивность в течение ${unfriendtime} дн.\nЕсли я вам снова понадоблюсь, не стесняйтесь добавить меня снова!",
+ "userforceunfriend": "Вы были удалены из друзей за неактивность в течение ${forceFriendlistSpaceTime} дн., так как в списке друзей было мало места.\nЕсли я вам снова понадоблюсь, добавляйте меня снова!",
+ "userunfriend": "Вы были удалены из друзей за неактивность в течение ${unfriendtime} дн.\nЕсли я вам снова понадоблюсь, не стесняйтесь добавить меня снова!",
"userspamblock": "Вы были заблокированы на 90 секунд за спам.",
"usernotfriend": "Пожалуйста, добавьте меня, прежде чем использовать команду!",
@@ -122,7 +122,7 @@
"mysessionscmdnosessions": "В настоящее время нет активных сессий, которые вы начали.",
"addfriendcmdacclimited": "Невозможно добавить ${profileid} в друзья с помощью bot0, потому что аккаунт бота ограничен.",
- "addfriendcmdsuccess": "Добавление ${profileid} в друзья ко всем аккаунтам ботов... Это займёт ~estimatedtime сек. Пожалуйста, проверьте журнал на наличие возможных ошибок.",
+ "addfriendcmdsuccess": "Добавление ${profileid} в друзья ко всем аккаунтам ботов... Это займёт ~${estimatedtime} сек. Пожалуйста, проверьте журнал на наличие возможных ошибок.",
"unfriendcmdsuccess": "Я удаляю вас из друзей со всех аккаунтов ботов. Это займёт некоторое время...\nВы можете отправить мне запрос в друзья в любое время.",
"unfriendidcmdsuccess": "Удалён ${profileid} из друзей из всех аккаунтов ботов.",
diff --git a/src/data/lang/traditional-chinese.json b/src/data/lang/traditional-chinese.json
new file mode 100644
index 00000000..9fa1e9cf
--- /dev/null
+++ b/src/data/lang/traditional-chinese.json
@@ -0,0 +1,147 @@
+{
+ "note": "此檔案關於機器人所有訊息 如果想要修改請閱讀: https://github.com/3urobeat/steam-comment-service-bot/blob/master/docs/wiki/customlang_doc.md",
+
+ "langname": "traditional-chinese",
+
+ "updaterautoupdatedisabled": "已停用自動更新,是否需要啟動\n如果需要請填入這個指令: ${cmdprefix}update true",
+
+ "commentcmdusageowner": "'${cmdprefix}comment amount/\"all\" id' 發送你想要的數量評論(也可以發送最多評論).\n如果想在其他地方發送評論,你需要提供對方的個人檔案連結、群組連結、螢幕擷圖連結、指南、藝術作品連結。",
+ "commentcmdusageowner2": "'${cmdprefix}comment 1 id'. 如果想在其他地方發送評論,你需要提供對方的個人檔案連結、群組連結、螢幕擷圖連結、指南、藝術作品連結。",
+ "commentcmdusage": "'${cmdprefix}comment amount/\"all\"' 提供想要評論的數量。",
+ "commentcmdusage2": "'${cmdprefix}comment' 發送評論到你的個人檔案。",
+ "commentinvalidid": "錯誤的連結\n請確認該連結是否正確\n\n正確使用: ${commentcmdusage}",
+ "commentprofileidowneronly": "指令只提供開發者使用\n如果你是開發者請添加你的Steam ID到config.json。",
+ "commentmissingnumberofcomments": "請填寫你需要${maxRequestAmount}條評論的數量\n正確使用: ${commentcmdusage}",
+ "commentzeroavailableaccs": "對不起,目前的機器人正在冷卻中。 請等待${waittime}秒然後再試一次",
+ "commentnotenoughavailableaccs": "對不起,目前的機器人正在冷卻中。 請等待${waittime}秒然後再試一次,或者是發送${availablenow}條評論",
+ "commentnoaccounts": "對不起,目前沒有帳號可以幫助你,不過你可以聯絡開發者\n請使用${cmdprefix}owner聯絡開發者。",
+ "commentaddbotaccounts": "請添加這些帳號,然後再試一次: (limited accounts)",
+ "commentunsupportedtype": "對不起,這個指令不適合用於這個類型ID。請貼上個人檔案連結、群組連結、螢幕擷圖連結、指南、藝術作品連結。",
+ "commentuserprofileprivate": "訪問的連結私人的!,請修改我的個人檔案、能在我的個人檔案發表留言為公開。",
+ "commenterroroccurred": "無法發送評論",
+ "commentprocessstarted": "接受評論到的有${numberOfComments}條評論\n請等待${waittime}完成。",
+ "commentfailedcmdreference": "如果想獲得傳送失敗資訊,請貼上'${cmdprefix}failed'\n如果看不懂錯誤原因請查看: https://github.com/3urobeat/steam-comment-service-bot/blob/master/docs/wiki/errors_doc.md",
+ "comment429stop": "已停止,所有的代理出現HTTP 429 (IP cooldown) error。請稍後再試\n失敗: ${failedamount}/${numberOfComments}",
+ "commentretrying": "${failedamount}/${numberOfComments}條評論失敗。開始重試 ${untilStr}. (Attempt ${thisattempt}/${maxattempt})",
+ "commentsuccess": "全部評論已發送。 無法傳送數量: ${failedamount}/${numberOfComments}\n如果你覺得這個還不錯的話,在我的留言區底下留下好評,讓更多人知道!",
+ "genericnoaccounts": "對不起,你輸入無效的ID了。",
+
+ "genericnounlimitedaccs": "對不起,目前帳號沒貨。請聯繫開發者\n${cmdprefix}owner",
+ "genericrequestless": "目前只有${availablenow}個可以使用。",
+ "genericnotenoughavailableaccs": "對不起,目前沒有足夠的帳號可用於提供的ID資料。請等待 ${waittime} and try again or only request ${availablenow} now.",
+
+ "voteunsupportedtype": "對不起,投票指令不支援你所提供這個類型的ID。 請提供投票連結(不支援funnyvote)或查看連結。",
+ "voteprocessstarted": "接受投票到的有${numberOfVotes} 投票時間: ${waittime}",
+ "votesuccess": "全部投票已發送。 無法傳送數量: ${failedamount}/${numberOfVotes}",
+
+ "favoriteprocessstarted": "${numberOfFavs} 個未收藏/已收藏發送,請等待時間: ${waittime}",
+ "favoritesuccess": "未收藏/已收藏發送成功。 無法傳送數量: ${failedamount}/${numberOfFavs}",
+
+ "followprocessstarted": "${totalamount} 未追蹤已追蹤已發送,請等待: ${waittime}",
+ "followsuccess": "未追蹤已追蹤已發送成功。無法傳送數量: ${failedamount}/${totalamount}",
+
+ "useradded": "你好哇^w^ 謝謝你添加我為你的好友\n我是一個免費服務有: '${cmdprefix}comment' - 評論\n'${cmdprefix}help' - 菜單\n'${cmdprefix}about' - 關於\n'${cmdprefix}lang' - 切換語言",
+ "userforceunfriend": "由於使用者太多,你${forceFriendlistSpaceTime}天沒使用我\n如果還有需要繼續使用請添加。",
+ "userunfriend": "你${unfriendtime}天沒使用我\n如果還有需要繼續使用請添加。",
+
+ "userspamblock": "已封鎖90秒\n原因 : 刷屏",
+ "usernotfriend": "請在使用我之前添加好友。",
+ "botnotready": "尚未完全啟動\n請等待。",
+ "commandnotfound": "資料庫尚未沒有這個功能\n請查看 ${cmdprefix}help",
+ "commandowneronly": "指令只提供開發者使用\n如果你是開發者請添加你的Steam ID到config.json。",
+ "nouserid": "在沒有用戶ID的情況下被調用\n阻止該指令\n這是一個編碼問題\n請聯繫開發者 : ${cmdprefix}owner",
+ "noidparam": "請提供ID",
+
+ "requesttoohigh": "最多可以發送 ${maxRequestAmount}\n\n正確使用: ${cmdusage}",
+ "invalidnumber": "這不是數字\n\n正確使用: ${cmdusage}",
+ "invalidprofileid": "請輸入正確的ID",
+ "invalidgroupid": "請輸入正確的ID \n示範群組ID: '103582791464712227' \n示範群組連結: 'https://steamcommunity.com/groups/3urobeatGroup'",
+ "invalidsharedfileid": "這不是一個正確的檔案ID\n示範共享檔案連結: https://steamcommunity.com/sharedfiles/filedetails/?id=2980913451 \n 示範共享檔案ID: 2980913451\n群組連結、螢幕擷圖連結、指南、藝術作品連結。\n\n正確使用: ${cmdusage}",
+ "invalidreviewid": "這不是一個正確的檔案ID\n請確認是否填入正確,示範: https://steamcommunity.com/id/3urobeat/recommended/1902490/\n\n正確使用: ${cmdusage}",
+ "errloadingsharedfile": "發生錯誤: ",
+ "errloadingreview": "發生錯誤: ",
+ "idisownererror": "你不能提供開發者ID",
+ "idalreadyreceiving": "提供的用戶以前已提交,請等待完成後重試",
+ "idoncooldown": "最近才剛提交,請等待 ${remainingcooldown} 再次提交",
+ "requestaborted": "你提交的訊息已停止\n${successAmount}/${totalAmount} 已發送成功",
+
+ "jobscmdregistered": "已註冊:",
+ "jobscmdnoneregistered": "未註冊",
+ "reloadcmdreloaded": "已重新讀取所有功能 / 插件",
+ "activerelog": "目前正等待最後一個活動完成,以便重新登入帳戶。",
+ "updatecmdforce": "強制更新 ${branchname}",
+ "updatecmdcheck": "檢查更新 ${branchname}",
+ "restartcmdrestarting": "重啟中",
+ "stopcmdstopping": "已停止",
+
+ "helpcommandlist": "功能:",
+ "helpcommentowner": "最大值 ${maxOwnerRequests} 到您/其他個人檔案的評論",
+ "helpcommentuser": "最大值 ${maxRequests} 到您的個人檔案評論",
+ "helpvote": "最大值 ${maxRequests} 共享檔案/投票數量",
+ "helpfavorite": "最大值 ${maxRequests} 共享檔案/收藏數量",
+ "helpfollow": "最大值 ${maxRequests} 工作坊追蹤數量",
+ "helpinfo": "關於機器人/您的訊息",
+ "helpabort": "關於您的發送",
+ "helpabout": "關於機器人資訊",
+ "helpowner": "關於開發者資訊",
+ "helpreadothercmdshere": "30個功能列表在這邊:",
+
+ "pingcmdmessage": "/me ${pingtime}ms",
+ "ownercmdnolink": "沒有連結",
+ "ownercmdmsg": "以下是開發者的連結: (更多資訊請貼上 ${cmdprefix}about)",
+ "groupcmdnolink": "沒有連結",
+ "groupcmdinvitesent": "已發送群組連結,歡迎加入",
+ "groupcmdinvitelink": "我的群組: ",
+ "abortcmdnoprocess": "請提供ID/連結",
+ "abortcmdsuccess": "正在停止你所提供的ID資訊",
+
+ "resetcooldowncmdcooldowndisabled": "已停用冷卻時間",
+ "resetcooldowncmdglobalreset": "機器人帳號的冷卻時間已重置",
+ "resetcooldowncmdsuccess": "${profileid}冷卻時間已清除",
+
+ "langcmdsupported": "以下語言名字:",
+ "langcmdnotsupported": "尚未提供你想要的語言。 請查看語言列表: ${supportedlangs}\n\n想要製作語言嗎?請查看: ' https://github.com/3urobeat/steam-comment-service-bot/blob/master/docs/wiki/contributing.md#translating '",
+ "langcmdsuccess": "已讀取語言",
+
+ "settingscmdfailedread": "無法讀取目前設定: ",
+ "settingscmdcurrentsettings": "目前設定:",
+ "settingscmdblockedvalues": "無法透過設定指令修改enableevalcmd / ownerid / owner\n請設定Config檔案",
+ "settingscmdcouldnotconvert": "我無法切換您的輸入, 請確定您的順序是對的。\nError: ",
+ "settingscmdkeynotfound": "Config找不到這個key",
+ "settingscmdsamevalue": "Key已存在 ${value}.",
+ "settingscmdvaluetoobig": "新的數值太大 (32-bit 限制)\n請更改比較小一點的數值",
+ "settingscmdvaluereset": "檔案管理拒絕此要求 並且向你發出警告訊息:",
+ "settingscmdvaluechanged": "${targetkey} 已更改為 ${oldvalue}到${newvalue}\n請記住,某些值可能需要重啟。 你可以寫這個 ${cmdprefix}restart.",
+
+ "failedcmdnothingfound": "沒有任何失敗的結果",
+ "failedcmdmsg": "你發送 '${steamID64}'已結束,在'${requesttime}' (GMT time) 出現問題:",
+
+ "sessionscmdnosessions": "在沒有活耀的情況下是冷卻的狀態",
+ "sessionscmdmsg": "目前有 ${amount}個活耀秒(s):",
+ "mysessionscmdnosessions": "目前沒有",
+
+ "addfriendcmdacclimited": "無法添加 ${profileid} bot0可能不是課金帳號",
+ "addfriendcmdsuccess": "正在添加 ${profileid} 所有機器人同時添加,這可能需要一點時間",
+ "unfriendcmdsuccess": "所有機器人同時解除好友,這可能需要一點時間。",
+ "unfriendidcmdsuccess": "所有機器人已解除${profileid}好友",
+
+ "unfriendallcmdabort": "如果正在進行解除全部好友處於活耀狀態會停止",
+ "unfriendallcmdpending": "除了開發者,我需要30秒時間解除所有好友\n填寫 '${cmdprefix}unfriendall abort' abort/stop 可停止",
+ "unfriendallcmdstart": "開始解除所有好友",
+
+ "joingroupcmdsuccess": "所有的機器人正在加入'${groupid}'",
+
+ "leavegroupcmdsuccess": "所有的機器人正在退出'${groupid}'",
+
+ "leaveallgroupscmdabort": "如果正在進行離開全部群組處於活耀狀態會停止",
+ "leaveallgroupscmdpending": "除了開發者,我需要30秒時間離開全部群組\n填寫 '${cmdprefix}leaveallgroups abort' abort/stop 可停止",
+ "leaveallgroupscmdstart": "開始離開全部群組",
+
+ "blockcmdsuccess": "所有機器人同時封鎖 ${profileid}",
+ "unblockcmdsuccess": "所有機器人同時解除封鎖 ${profileid}",
+
+ "evalcmdturnedoff": "eval指令已關閉",
+ "evalcmdlogininfoblock": "您的程式碼包含'logininfo'這是保護密碼的\n請使用其他的",
+
+ "childbotmessage": "這是接收支援的機器人\n請使用以下機器人:"
+}
diff --git a/src/dataManager/dataCheck.js b/src/dataManager/dataCheck.js
index 5a72a68e..171dd949 100644
--- a/src/dataManager/dataCheck.js
+++ b/src/dataManager/dataCheck.js
@@ -4,7 +4,7 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2024-02-28 20:53:59
+ * Last Modified: 2024-05-04 11:28:44
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -31,7 +31,7 @@ DataManager.prototype.checkData = function() {
logger("info", "Running datachecks and displaying config recommendations...", false, true, logger.animation("loading"));
// Shorthander for checks below to log warning and count it. Must be an ES6 function to not create a new context for 'this.' to work!
- let logWarn = ((a, b, c) => { logger(a, b, c); this.controller.info.startupWarnings++; }); // I originally wanted to use iArguments instead of hardcoding a, b, c but that didn't work out easily so I digress
+ const logWarn = ((a, b, c) => { logger(a, b, c); this.controller.info.startupWarnings++; }); // I originally wanted to use iArguments instead of hardcoding a, b, c but that didn't work out easily so I digress
this.controller.info.startupWarnings = 0; // Reset value to start fresh if this module should be integrated into a plugin or something like that
@@ -53,7 +53,7 @@ DataManager.prototype.checkData = function() {
// Check config for default value leftovers when the bot is not running on my machines
- if ((process.env.LOGNAME !== "tomg") || (os.hostname() !== "Tomkes-PC" && os.hostname() !== "Tomkes-Server" && os.hostname() !== "Tomkes-Thinkpad")) {
+ if ((process.env.LOGNAME !== "tomg") || (!["Tomkes-PC", "Tomkes-Server", "Tomkes-Thinkpad", "Tomkes-Thinkpad-Z13"].includes(os.hostname()))) {
let write = false;
if (this.config.owner.includes(this.datafile.mestr)) { this.config.owner = ""; write = true; }
@@ -110,7 +110,7 @@ DataManager.prototype.checkData = function() {
logWarn("warn", `You've set an invalid value '${this.advancedconfig.onlineStatus}' as 'onlineStatus' in 'advancedconfig.json'! Defaulting to 'Online'...`);
this.advancedconfig.onlineStatus = "Online";
}
- if (!EPersonaState[this.advancedconfig.childAccOnlineStatus] == undefined) { // Explicitly check for undefined because Offline (0) resolves to false
+ if (EPersonaState[this.advancedconfig.childAccOnlineStatus] == undefined) { // Explicitly check for undefined because Offline (0) resolves to false
logWarn("warn", `You've set an invalid value '${this.advancedconfig.childAccOnlineStatus}' as 'childAccOnlineStatus' in 'advancedconfig.json'! Defaulting to 'Online'...`);
this.advancedconfig.childAccOnlineStatus = "Online";
}
diff --git a/src/dataManager/dataExport.js b/src/dataManager/dataExport.js
index 756ebc61..28f2ad5d 100644
--- a/src/dataManager/dataExport.js
+++ b/src/dataManager/dataExport.js
@@ -65,7 +65,7 @@ DataManager.prototype.writeConfigToDisk = function() {
logger("debug", "DataManager dataExport: Writing to config.json...");
// Get arrays on one line
- let stringifiedconfig = JSON.stringify(this.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedconfig = JSON.stringify(this.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
@@ -87,7 +87,7 @@ DataManager.prototype.writeAdvancedconfigToDisk = function() {
logger("debug", "DataManager dataExport: Writing to advancedconfig.json...");
// Get arrays on one line
- let stringifiedadvancedconfig = JSON.stringify(this.advancedconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedadvancedconfig = JSON.stringify(this.advancedconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
@@ -110,15 +110,15 @@ DataManager.prototype.writeLogininfoToDisk = function() {
if (fs.existsSync(srcdir + "/../logininfo.json")) {
logger("debug", "DataManager dataExport: Writing to logininfo.json...");
- let logininfojson = {};
+ const logininfojson = {};
// Re-Construct logininfo object. Iterate over bots instead of logininfo to retain a changed bots hierarchy
- for (let e of this.controller.getBots("*")) {
+ for (const e of this.controller.getBots("*")) {
logininfojson[`bot${e.index}`] = [ e.loginData.logOnOptions.accountName, e.loginData.logOnOptions.password, e.loginData.logOnOptions.sharedSecret ];
}
// Get arrays on one line
- let stringifiedlogininfo = JSON.stringify(logininfojson, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedlogininfo = JSON.stringify(logininfojson, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
@@ -135,10 +135,10 @@ DataManager.prototype.writeLogininfoToDisk = function() {
if (fs.existsSync(srcdir + "/../accounts.txt")) {
logger("debug", "DataManager dataExport: Writing to accounts.txt...");
- let accountstxt = [ "//Comment: This file is used to provide your bot accounts in the form of username:password. Read the instructions here: https://github.com/3urobeat/steam-comment-service-bot#accounts" ]; // Re-add comment
+ const accountstxt = [ "//Comment: This file is used to provide your bot accounts in the form of username:password. Read the instructions here: https://github.com/3urobeat/steam-comment-service-bot#accounts" ]; // Re-add comment
// Re-construct accounts.txt string. Iterate over bots instead of logininfo to retain a changed bots hierarchy
- for (let e of this.controller.getBots("*")) {
+ for (const e of this.controller.getBots("*")) {
if (e.loginData.logOnOptions.sharedSecret) accountstxt.push(`${e.loginData.logOnOptions.accountName}:${e.loginData.logOnOptions.password}:${e.loginData.logOnOptions.sharedSecret}`);
else accountstxt.push(`${e.loginData.logOnOptions.accountName}:${e.loginData.logOnOptions.password}`);
}
@@ -157,7 +157,7 @@ DataManager.prototype.writeLogininfoToDisk = function() {
DataManager.prototype.writeProxiesToDisk = function() {
logger("debug", "DataManager dataExport: Writing to proxies.txt...");
- let comment = "//Comment: This file is used to provide proxies to spread your accounts over multiple IPs. Read the instructions here: https://github.com/3urobeat/steam-comment-service-bot/blob/master/docs/wiki/adding_proxies.md";
+ const comment = "//Comment: This file is used to provide proxies to spread your accounts over multiple IPs. Read the instructions here: https://github.com/3urobeat/steam-comment-service-bot/blob/master/docs/wiki/adding_proxies.md";
fs.writeFile(srcdir + "/../proxies.txt", comment + this.proxies.join("\n"), (err) => {
if (err) logger("error", "DataManager: Error writing proxies to proxies.txt: " + err);
@@ -170,7 +170,7 @@ DataManager.prototype.writeProxiesToDisk = function() {
*/
DataManager.prototype.writeQuotesToDisk = function() {
logger("debug", "DataManager dataExport: Writing to quotes.txt...");
- let quotesArr = [];
+ const quotesArr = [];
// Replace every \n with \\n so that writeFile won't parse them to actual newlines
this.quotes.forEach(e => quotesArr.push(e.replace(/\n/g, "\\n")));
diff --git a/src/dataManager/dataImport.js b/src/dataManager/dataImport.js
index ec0b99a1..c2c07663 100644
--- a/src/dataManager/dataImport.js
+++ b/src/dataManager/dataImport.js
@@ -26,7 +26,7 @@ const DataManager = require("./dataManager.js");
* @returns {Promise.} Resolves promise when all files have been loaded successfully. The function will log an error and terminate the application should a fatal error occur.
*/
DataManager.prototype._importFromDisk = async function () {
- let _this = this; // Make this accessible within the functions below
+ const _this = this; // Make this accessible within the functions below
/* eslint-disable jsdoc/require-jsdoc */
function loadCache() {
@@ -138,7 +138,7 @@ DataManager.prototype._importFromDisk = async function () {
function loadLoginInfo() {
return new Promise((resolve) => {
- let logininfo = [];
+ const logininfo = [];
// Check accounts.txt first so we can ignore potential syntax errors in logininfo
if (fs.existsSync("./accounts.txt")) {
@@ -177,7 +177,7 @@ DataManager.prototype._importFromDisk = async function () {
logger("warn", "The usage of 'logininfo.json' is deprecated, please consider moving your accounts to 'accounts.txt' instead!", true);
logger("warn", "The usage of 'logininfo.json' is deprecated, please consider moving your accounts to 'accounts.txt' instead!");
- let logininfoFile = require(srcdir + "/../logininfo.json");
+ const logininfoFile = require(srcdir + "/../logininfo.json");
// Reformat to use new logininfo object structure
Object.keys(logininfoFile).forEach((k, i) => {
@@ -277,7 +277,7 @@ DataManager.prototype._importFromDisk = async function () {
function loadLanguage() {
return new Promise((resolve) => {
try {
- let obj = {};
+ const obj = {};
if (!fs.existsSync("./src/data/lang")) fs.mkdirSync("./src/data/lang");
diff --git a/src/dataManager/dataIntegrity.js b/src/dataManager/dataIntegrity.js
index 938c0ad0..6a1d6294 100644
--- a/src/dataManager/dataIntegrity.js
+++ b/src/dataManager/dataIntegrity.js
@@ -33,19 +33,19 @@ DataManager.prototype.verifyIntegrity = function() {
(async () => { // Lets us use await insidea Promise without creating an antipattern
// Store all files which needed to be recovered to determine if we need to restart the bot
- let invalidFiles = [];
+ const invalidFiles = [];
// Get fileStructure.json
const fileStructure = await this.checkAndGetFile("./src/data/fileStructure.json", logger, false, false); // Always forcing the latest version will lead to false-positives when user uses an older version
// Generate a checksum for every file in fileStructure and compare them
- let startDate = Date.now();
+ const startDate = Date.now();
this.controller.misc.syncLoop(fileStructure.files.length, async (loop, i) => {
- let e = fileStructure.files[i];
+ const e = fileStructure.files[i];
// Generate checksum for file if it exists, otherwise default to null
- let filesum = fs.existsSync(e.path) ? crypto.createHash("md5").update(fs.readFileSync(e.path)).digest("hex") : null;
+ const filesum = fs.existsSync(e.path) ? crypto.createHash("md5").update(fs.readFileSync(e.path)).digest("hex") : null;
if (filesum != e.checksum) {
logger("warn", `Checksum of file '${e.path}' does not match expectations! Restoring file...`, false, false, null, true); // Force print now
diff --git a/src/dataManager/dataProcessing.js b/src/dataManager/dataProcessing.js
index be159c2a..9292a285 100644
--- a/src/dataManager/dataProcessing.js
+++ b/src/dataManager/dataProcessing.js
@@ -25,7 +25,7 @@ const DataManager = require("./dataManager");
* Converts owners and groups imported from config.json to steam ids and updates cachefile. (Call this after dataImport and before dataCheck)
*/
DataManager.prototype.processData = async function() {
- let _this = this;
+ const _this = this;
/* eslint-disable jsdoc/require-jsdoc */
function yourgroup() {
@@ -115,7 +115,7 @@ DataManager.prototype.processData = async function() {
function owners() {
return new Promise((resolve) => {
- let tempArr = [];
+ const tempArr = [];
logger("debug", `DataManager processData(): Converting ${_this.config.ownerid.length} owner(s)...`);
// Check for last iteration, update cache and resolve Promise
diff --git a/src/dataManager/helpers/checkProxies.js b/src/dataManager/helpers/checkProxies.js
index e2b926a4..74887f43 100644
--- a/src/dataManager/helpers/checkProxies.js
+++ b/src/dataManager/helpers/checkProxies.js
@@ -24,9 +24,9 @@ const DataManager = require("../dataManager");
* @returns {boolean} True if the proxy can reach steamcommunity.com, false otherwise.
*/
DataManager.prototype.checkProxy = async function(proxyIndex) {
- let { checkConnection, splitProxyString } = this.controller.misc;
+ const { checkConnection, splitProxyString } = this.controller.misc;
- let thisProxy = this.proxies[proxyIndex];
+ const thisProxy = this.proxies[proxyIndex];
// Check connection using checkConnection helper
await checkConnection("https://steamcommunity.com", true, thisProxy.proxy != null ? splitProxyString(thisProxy.proxy) : null) // Quick ternary to only split non-hosts
@@ -50,7 +50,7 @@ DataManager.prototype.checkProxy = async function(proxyIndex) {
* @returns {Promise.} Resolves when all proxies have been checked
*/
DataManager.prototype.checkAllProxies = async function(ignoreLastCheckedWithin = 0) {
- let promiseArr = [];
+ const promiseArr = [];
// Iterate over all proxies and call this.checkProxies(). We don't need any delay here as all requests go over different IPs
this.proxies.forEach((e) => {
diff --git a/src/dataManager/helpers/getLang.js b/src/dataManager/helpers/getLang.js
index a8f5c858..d2e4b7f3 100644
--- a/src/dataManager/helpers/getLang.js
+++ b/src/dataManager/helpers/getLang.js
@@ -39,7 +39,7 @@ DataManager.prototype.getLang = async function(str, replace = null, userIDOrLang
} else { // Search for user in database if this is an ID
- let res = await this.userSettingsDB.findOneAsync({ "id": userIDOrLanguage }, {});
+ const res = await this.userSettingsDB.findOneAsync({ "id": userIDOrLanguage }, {});
if (res) {
lang = this.lang[res.lang];
@@ -65,13 +65,13 @@ DataManager.prototype.getLang = async function(str, replace = null, userIDOrLang
if (replace) {
Object.keys(replace).forEach((e) => {
// Add ${ prefix and } suffix to e
- let rawPattern = "${" + e + "}";
+ const rawPattern = "${" + e + "}";
// Skip iteration and display warning if the string does not contain the specified keyword
if (!langStr.includes(rawPattern)) return logger("warn", `getLang(): The string '${str}' of language '${lang.langname}' does not contain the provided keyword '${rawPattern}'!`);
// Build regex pattern to dynamically replace all occurrences below. Escape rawPattern before concatenating to avoid special char issues later on
- let regex = new RegExp(rawPattern.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"), "g"); // Regex credit: https://stackoverflow.com/a/17886301
+ const regex = new RegExp(rawPattern.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"), "g"); // Regex credit: https://stackoverflow.com/a/17886301
langStr = langStr.replace(regex, replace[e]);
});
diff --git a/src/dataManager/helpers/getQuote.js b/src/dataManager/helpers/getQuote.js
index 08dbf846..7de9f195 100644
--- a/src/dataManager/helpers/getQuote.js
+++ b/src/dataManager/helpers/getQuote.js
@@ -20,7 +20,7 @@ const DataManager = require("../dataManager.js");
const randomstring = arr => arr[Math.floor(Math.random() * arr.length)]; // Smol function to get random string from array
-let lastQuotes = []; // Tracks recently used quotes to avoid duplicates
+const lastQuotes = []; // Tracks recently used quotes to avoid duplicates
/**
diff --git a/src/dataManager/helpers/handleCooldowns.js b/src/dataManager/helpers/handleCooldowns.js
index 4a0f614c..d6d8e0f0 100644
--- a/src/dataManager/helpers/handleCooldowns.js
+++ b/src/dataManager/helpers/handleCooldowns.js
@@ -26,7 +26,7 @@ const DataManager = require("../dataManager");
DataManager.prototype.getUserCooldown = function(id) {
return new Promise((resolve) => {
- let obj = {
+ const obj = {
"lastRequest": 0,
"until": 0,
"lastRequestStr": "",
diff --git a/src/dataManager/helpers/handleExpiringTokens.js b/src/dataManager/helpers/handleExpiringTokens.js
index 0782e046..e9275719 100644
--- a/src/dataManager/helpers/handleExpiringTokens.js
+++ b/src/dataManager/helpers/handleExpiringTokens.js
@@ -25,26 +25,26 @@ const DataManager = require("../dataManager.js");
* Note: This function should be redundant as SteamUser now automatically attempts to renew refreshTokens when `renewRefreshTokens` is enabled.
*/
DataManager.prototype._startExpiringTokensCheckInterval = function() {
- let _this = this;
+ const _this = this;
/* eslint-disable-next-line jsdoc/require-jsdoc */
async function scanDatabase() {
logger("debug", "DataManager detectExpiringTokens(): Scanning tokens.db for expiring tokens...");
- let expiring = {};
- let expired = {};
+ const expiring = {};
+ const expired = {};
// Get all tokens & bots
- let docs = await _this.tokensDB.findAsync({});
+ const docs = await _this.tokensDB.findAsync({});
if (docs.length == 0) return;
- let bots = _this.controller.getBots("*", true);
+ const bots = _this.controller.getBots("*", true);
// Loop over all docs and attempt to renew their token. Notify the bot owners if Steam did not issue a new one
_this.controller.misc.syncLoop(docs.length, async (loop, i) => {
- let e = docs[i];
+ const e = docs[i];
let tokenObj = _this.decodeJWT(e.token);
- let thisbot = bots[e.accountName];
+ const thisbot = bots[e.accountName];
// Check if decoding failed
if (!tokenObj) {
@@ -58,7 +58,7 @@ DataManager.prototype._startExpiringTokensCheckInterval = function() {
// Attempt to renew the token automatically and check if it succeeded
- let newToken = await thisbot.sessionHandler.attemptTokenRenew();
+ const newToken = await thisbot.sessionHandler.attemptTokenRenew();
tokenObj = _this.decodeJWT(newToken);
@@ -127,8 +127,8 @@ DataManager.prototype._startExpiringTokensCheckInterval = function() {
* @param {object} expiring Object of botobject entries to ask user for
*/
DataManager.prototype._askForGetNewToken = function(expiring) {
- let EStatus = require("../../bot/EStatus.js"); // Import not at top scope as this can be undefined because this helper file gets loaded before updater ran
- let _this = this;
+ const EStatus = require("../../bot/EStatus.js"); // Import not at top scope as this can be undefined because this helper file gets loaded before updater ran
+ const _this = this;
/* eslint-disable-next-line jsdoc/require-jsdoc */
function askForRelog() { // TODO: Add support for asking in steam chat
@@ -172,7 +172,7 @@ DataManager.prototype._askForGetNewToken = function(expiring) {
// Check for an active request before asking user for relog
logger("debug", "DataManager _askForGetNewToken(): Checking for active requests...");
- let objlength = Object.keys(this.controller.activeRequests).length; // Save this before the loop as deleting entries will change this number and lead to the loop finished check never triggering
+ const objlength = Object.keys(this.controller.activeRequests).length; // Save this before the loop as deleting entries will change this number and lead to the loop finished check never triggering
if (Object.keys(this.controller.activeRequests).length == 0) askForRelog(); // Don't bother with loop below if obj is empty
diff --git a/src/dataManager/helpers/misc.js b/src/dataManager/helpers/misc.js
index 7faeb284..5b3ab519 100644
--- a/src/dataManager/helpers/misc.js
+++ b/src/dataManager/helpers/misc.js
@@ -49,12 +49,12 @@ DataManager.prototype.getLastCommentRequest = function(steamID64 = null) {
* @returns {object|null} JWT object on success, `null` on failure
*/
DataManager.prototype.decodeJWT = function(token) {
- let payload = token.split(".")[1]; // Remove header and signature as we only care about the payload
- let decoded = Buffer.from(payload, "base64"); // Decode
+ const payload = token.split(".")[1]; // Remove header and signature as we only care about the payload
+ const decoded = Buffer.from(payload, "base64"); // Decode
// Try to parse json object
try {
- let parsed = JSON.parse(decoded.toString());
+ const parsed = JSON.parse(decoded.toString());
return parsed;
} catch (err) {
logger("err", `Failed to decode JWT! Error: ${err}`, true);
diff --git a/src/dataManager/helpers/refreshCache.js b/src/dataManager/helpers/refreshCache.js
index ca7be5de..0296f3cc 100644
--- a/src/dataManager/helpers/refreshCache.js
+++ b/src/dataManager/helpers/refreshCache.js
@@ -27,7 +27,7 @@ DataManager.prototype.refreshCache = function () {
logger("info", "Refreshing data backups in cache.json...", false, true, logger.animation("loading"));
// Refresh cache of bot account ids, check if they inflict with owner settings
- let tempArr = [];
+ const tempArr = [];
this.controller.getBots().forEach((e, i) => {
// Get all online accounts
diff --git a/src/dataManager/helpers/repairFile.js b/src/dataManager/helpers/repairFile.js
index afe81c9e..03c3103a 100644
--- a/src/dataManager/helpers/repairFile.js
+++ b/src/dataManager/helpers/repairFile.js
@@ -4,10 +4,10 @@
* Created Date: 2023-03-22 12:35:01
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:13:14
+ * Last Modified: 2024-05-03 12:59:23
* Modified By: 3urobeat
*
- * Copyright (c) 2023 3urobeat
+ * Copyright (c) 2023 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -43,7 +43,7 @@ DataManager.prototype._restoreBackup = function(name, filepath, cacheentry, onli
.replace(/\]"/g, "]")
.replace(/\\"/g, '"')
.replace(/""/g, '""');
- } catch (err) {
+ } catch {
stringified = JSON.stringify(cacheentry, null, 4);
}
@@ -63,7 +63,7 @@ DataManager.prototype._restoreBackup = function(name, filepath, cacheentry, onli
logger("info", `Successfully restored backup of '${name}'!\n`, true);
resolve(require(filepath));
- } catch (err) { // Worst case, even the backup seems to be broken (seems like this can't happen anymore since 2.11 because cache.json will get cleared before we get here if it contains an error)
+ } catch { // Worst case, even the backup seems to be broken (seems like this can't happen anymore since 2.11 because cache.json will get cleared before we get here if it contains an error)
this._pullNewFile(name, filepath, resolve);
}
@@ -82,7 +82,7 @@ DataManager.prototype._restoreBackup = function(name, filepath, cacheentry, onli
DataManager.prototype._pullNewFile = async function(name, filepath, resolve, noRequire) {
logger("warn", "Backup seems to be broken/not available! Pulling file from GitHub...", true);
- let file = await this.checkAndGetFile(filepath, logger, true, true);
+ const file = await this.checkAndGetFile(filepath, logger, true, true);
if (!file) return this.controller.stop(); // Stop bot if file can't be restored
// Only tell user to reconfigure config.json
diff --git a/src/jobs/jobManager.js b/src/jobs/jobManager.js
index 47da97ba..ac5c056b 100644
--- a/src/jobs/jobManager.js
+++ b/src/jobs/jobManager.js
@@ -133,7 +133,7 @@ JobManager.prototype.unregisterJob = function(name) {
}
// Remove job and return null on success
- let index = this.jobs.findIndex((e) => e.name === name);
+ const index = this.jobs.findIndex((e) => e.name === name);
this.jobs.splice(index, 1);
diff --git a/src/pluginSystem/handlePluginData.js b/src/pluginSystem/handlePluginData.js
index 506b78dc..9abc78d6 100644
--- a/src/pluginSystem/handlePluginData.js
+++ b/src/pluginSystem/handlePluginData.js
@@ -28,7 +28,7 @@ const PluginSystem = require("./pluginSystem.js");
PluginSystem.prototype.getPluginDataPath = function (pluginName) {
if (!pluginName) throw new Error("Plugin name parameter is missing!");
- let path = `${srcdir}/../plugins/${pluginName}/`;
+ const path = `${srcdir}/../plugins/${pluginName}/`;
if (!fs.existsSync(path)) fs.mkdirSync(path);
@@ -48,7 +48,7 @@ PluginSystem.prototype.loadPluginData = function (pluginName, filename) {
if (!pluginName || !filename) return reject(new Error("Plugin name or file name parameter is missing!"));
// Get path
- let path = this.getPluginDataPath(pluginName);
+ const path = this.getPluginDataPath(pluginName);
fs.readFile(path + filename, (err, data) => {
if (err) {
@@ -75,7 +75,7 @@ PluginSystem.prototype.writePluginData = function (pluginName, filename, data) {
if (!pluginName || !filename || !data) return reject(new Error("Plugin name, file name or data parameter is missing!"));
// Get path
- let path = this.getPluginDataPath(pluginName);
+ const path = this.getPluginDataPath(pluginName);
fs.writeFile(path + filename, data, null, (err) => {
if (err) {
@@ -101,7 +101,7 @@ PluginSystem.prototype.deletePluginData = function (pluginName, filename) {
if (!pluginName || !filename) return reject(new Error("Plugin name or file name parameter is missing!"));
// Get path
- let path = this.getPluginDataPath(pluginName);
+ const path = this.getPluginDataPath(pluginName);
// Check if file exists
if (!fs.existsSync(path + filename)) return reject(new Error("File does not exist"));
@@ -130,7 +130,7 @@ PluginSystem.prototype.loadPluginConfig = function (pluginName) {
if (!pluginName) return reject(new Error("Plugin name parameter is missing!"));
// Get path
- let path = this.getPluginDataPath(pluginName);
+ const path = this.getPluginDataPath(pluginName);
// Check if no config exists yet
if (!fs.existsSync(path + "config.json")) {
@@ -145,7 +145,7 @@ PluginSystem.prototype.loadPluginConfig = function (pluginName) {
}
try {
- let config = require(path + "config.json");
+ const config = require(path + "config.json");
resolve(config);
} catch (err) {
logger("error", `PluginSystem: Failed to load config for plugin '${pluginName}': ${err.stack}`);
@@ -187,10 +187,10 @@ PluginSystem.prototype.writePluginConfig = function (pluginName, pluginConfig) {
if (!pluginName || !pluginConfig) return reject(new Error("Plugin name or plugin config parameter is missing!"));
// Get path
- let path = this.getPluginDataPath(pluginName);
+ const path = this.getPluginDataPath(pluginName);
try {
- let stringified = JSON.stringify(pluginConfig, null, 4);
+ const stringified = JSON.stringify(pluginConfig, null, 4);
fs.writeFileSync(path + "config.json", stringified);
resolve();
diff --git a/src/pluginSystem/loadPlugins.js b/src/pluginSystem/loadPlugins.js
index 0e069c2f..664668d2 100644
--- a/src/pluginSystem/loadPlugins.js
+++ b/src/pluginSystem/loadPlugins.js
@@ -4,7 +4,7 @@
* Created Date: 2023-06-04 15:37:17
* Author: DerDeathraven
*
- * Last Modified: 2024-03-08 18:19:31
+ * Last Modified: 2024-05-03 12:52:12
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -24,6 +24,7 @@ const PLUGIN_EVENTS = {
READY: "ready",
STATUS_UPDATE: "statusUpdate",
steamGuardInput: "steamGuardInput",
+ steamGuardQrCode: "steamGuardQrCode"
};
@@ -67,12 +68,12 @@ PluginSystem.prototype._loadPlugins = async function () {
// Check for the latest version of all plugins
if (!this.controller.data.advancedconfig.disablePluginsAutoUpdate) {
- let npminteraction = require("../controller/helpers/npminteraction.js");
+ const npminteraction = require("../controller/helpers/npminteraction.js");
logger("info", "PluginSystem: Searching for and installing plugin updates...", false, true, logger.animation("loading"));
// Get all plugin names. Ignore locally installed ones by checking for "file:"
- let pluginNamesArr = plugins.flatMap((e) => { // Use flatMap instead of map to omit empty results instead of including undefined
+ const pluginNamesArr = plugins.flatMap((e) => { // Use flatMap instead of map to omit empty results instead of including undefined
if (!e[1].startsWith("file:")) return e[0];
else return [];
});
@@ -152,7 +153,6 @@ PluginSystem.prototype._loadPlugins = async function () {
// Call the exposed event functions if they exist
Object.entries(PLUGIN_EVENTS).forEach(([eventName, event]) => { // eslint-disable-line no-unused-vars
- // eslint-disable-line
this.controller.events.on(event, (...args) => pluginInstance[event]?.call(pluginInstance, ...args));
});
}
diff --git a/src/pluginSystem/pluginSystem.js b/src/pluginSystem/pluginSystem.js
index 29a4ed3b..2e7a29df 100644
--- a/src/pluginSystem/pluginSystem.js
+++ b/src/pluginSystem/pluginSystem.js
@@ -4,7 +4,7 @@
* Created Date: 2023-03-19 13:34:27
* Author: 3urobeat
*
- * Last Modified: 2024-02-23 14:42:19
+ * Last Modified: 2024-05-01 15:19:03
* Modified By: 3urobeat
*
* Copyright (c) 2023 - 2024 3urobeat
@@ -29,6 +29,7 @@ const Bot = require("../bot/bot.js"); // eslint-disab
* @property {function(): void} ready Controller ready event
* @property {function(Bot, Bot.EStatus, Bot.EStatus): void} statusUpdate Controller statusUpdate event
* @property {function(Bot, function(string): void): void} steamGuardInput Controller steamGuardInput event
+ * @property {function(Bot, string): void} steamGuardQrCode Controller steamGuardQrCode event
*/
@@ -114,7 +115,7 @@ PluginSystem.prototype.reloadPlugins = function () {
/**
* Internal: Loads all plugin npm packages and populates pluginList
*/
-PluginSystem.prototype._loadPlugins = function () {};
+PluginSystem.prototype._loadPlugins = async function () {};
/**
* Internal: Checks a plugin, displays relevant warnings and decides whether the plugin is allowed to be loaded
diff --git a/src/sessions/helpers/handle2FA.js b/src/sessions/helpers/handle2FA.js
index 01bcc16f..60d8cca9 100644
--- a/src/sessions/helpers/handle2FA.js
+++ b/src/sessions/helpers/handle2FA.js
@@ -4,7 +4,7 @@
* Created Date: 2022-10-09 12:59:31
* Author: 3urobeat
*
- * Last Modified: 2024-02-28 22:28:46
+ * Last Modified: 2024-05-01 14:56:23
* Modified By: 3urobeat
*
* Copyright (c) 2022 - 2024 3urobeat
@@ -81,7 +81,7 @@ SessionHandler.prototype._handle2FA = function(res) {
SessionHandler.prototype._get2FAUserInput = function() {
// Start timer to subtract it later from readyafter time
- let steamGuardInputStart = Date.now(); // Measure time to subtract it later from readyafter time
+ const steamGuardInputStart = Date.now(); // Measure time to subtract it later from readyafter time
// Define different question and timeout for main account as it can't be skipped
let question;
@@ -181,4 +181,7 @@ SessionHandler.prototype._handleQRCode = function(res) {
logger.readInput("", 90000, () => {});
});
+ // Emit steamGuardQrCode event from our controller so that plugins can handle this event too
+ this.controller._steamGuardQrCodeEvent(this.bot, res.qrChallengeUrl);
+
};
diff --git a/src/sessions/helpers/handleCredentialsLoginError.js b/src/sessions/helpers/handleCredentialsLoginError.js
index 5fa8a4cc..f488470e 100644
--- a/src/sessions/helpers/handleCredentialsLoginError.js
+++ b/src/sessions/helpers/handleCredentialsLoginError.js
@@ -26,7 +26,7 @@ const SessionHandler = require("../sessionHandler.js");
SessionHandler.prototype._handleCredentialsLoginError = function(err) {
// Define a few enums on which we won't bother to relog
- let blockedEnumsForRetries = [EResult.InvalidPassword, EResult.LoggedInElsewhere, EResult.InvalidName, EResult.InvalidEmail, EResult.Banned, EResult.AccountNotFound, EResult.AccountLoginDeniedThrottle, EResult.RateLimitExceeded];
+ const blockedEnumsForRetries = [EResult.InvalidPassword, EResult.LoggedInElsewhere, EResult.InvalidName, EResult.InvalidEmail, EResult.Banned, EResult.AccountNotFound, EResult.AccountLoginDeniedThrottle, EResult.RateLimitExceeded];
// Check if this is a blocked enum or if all retries are used
if (this.bot.loginData.logOnTries > this.controller.data.advancedconfig.maxLogOnRetries || blockedEnumsForRetries.includes(err.eresult)) { // Skip account
diff --git a/src/sessions/helpers/tokenStorageHandler.js b/src/sessions/helpers/tokenStorageHandler.js
index 02fa7401..04cb6c85 100644
--- a/src/sessions/helpers/tokenStorageHandler.js
+++ b/src/sessions/helpers/tokenStorageHandler.js
@@ -23,12 +23,12 @@ const SessionHandler = require("../sessionHandler.js");
* @returns {Promise.} Resolves with `true` if a valid token was found, `false` otherwise
*/
SessionHandler.prototype.hasStorageValidToken = async function() {
- let res = await this.tokensdb.findOneAsync({ accountName: this.logOnOptions.accountName }, {});
+ const res = await this.tokensdb.findOneAsync({ accountName: this.logOnOptions.accountName }, {});
if (!res) return false;
// Check if token is still valid
- let jwtObj = this.controller.data.decodeJWT(res.token);
+ const jwtObj = this.controller.data.decodeJWT(res.token);
if (!jwtObj) return false;
if (jwtObj.exp * 1000 <= Date.now()) return false;
@@ -53,11 +53,11 @@ SessionHandler.prototype._getTokenFromStorage = function(callback) {
// If we still have a token stored then check if it is still valid
if (doc) {
// Decode the token we've found
- let jwtObj = this.controller.data.decodeJWT(doc.token);
+ const jwtObj = this.controller.data.decodeJWT(doc.token);
if (!jwtObj) return callback(null); // Get new session if _decodeJWT() failed
// Define valid until str to use it in log msg
- let validUntilStr = `${(new Date(jwtObj.exp * 1000)).toISOString().replace(/T/, " ").replace(/\..+/, "")} (GMT time)`;
+ const validUntilStr = `${(new Date(jwtObj.exp * 1000)).toISOString().replace(/T/, " ").replace(/\..+/, "")} (GMT time)`;
// Compare expire value (unix timestamp in seconds) to current date
if (jwtObj.exp * 1000 > Date.now()) {
diff --git a/src/sessions/sessionHandler.js b/src/sessions/sessionHandler.js
index 37e4d2d4..4cede05c 100644
--- a/src/sessions/sessionHandler.js
+++ b/src/sessions/sessionHandler.js
@@ -4,7 +4,7 @@
* Created Date: 2022-10-09 12:47:27
* Author: 3urobeat
*
- * Last Modified: 2024-02-28 22:31:15
+ * Last Modified: 2024-05-03 12:51:51
* Modified By: 3urobeat
*
* Copyright (c) 2022 - 2024 3urobeat
@@ -15,7 +15,7 @@
*/
-const SteamSession = require("steam-session"); // eslint-disable-line
+const SteamSession = require("steam-session");
const Bot = require("../bot/bot.js"); // eslint-disable-line
const EStatus = require("../bot/EStatus.js");
@@ -170,9 +170,9 @@ SessionHandler.prototype.attemptTokenRenew = function() {
return;
}
- let newToken = this.session.refreshToken;
- let jwtObj = this.controller.data.decodeJWT(newToken); // Decode the token we've found
- let validUntilStr = `${(new Date(jwtObj.exp * 1000)).toISOString().replace(/T/, " ").replace(/\..+/, "")} (GMT time)`;
+ const newToken = this.session.refreshToken;
+ const jwtObj = this.controller.data.decodeJWT(newToken); // Decode the token we've found
+ const validUntilStr = `${(new Date(jwtObj.exp * 1000)).toISOString().replace(/T/, " ").replace(/\..+/, "")} (GMT time)`;
logger("info", `[${this.bot.logPrefix}] Successfully renewed refresh token! It is now valid until '${validUntilStr}'!`);
diff --git a/src/starter.js b/src/starter.js
index 3b9151d8..9dc97ff7 100644
--- a/src/starter.js
+++ b/src/starter.js
@@ -4,10 +4,10 @@
* Created Date: 2021-07-10 10:26:00
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:17:17
+ * Last Modified: 2024-05-04 22:04:33
* Modified By: 3urobeat
*
- * Copyright (c) 2021 - 2023 3urobeat
+ * Copyright (c) 2021 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -47,12 +47,26 @@ const execArgs = [ "--max-old-space-size=2048", "--optimize-for-size", /* "--ins
/* -------- Now, provide functions for attaching/detaching event listeners to the parent and child process -------- */
+/**
+ * Provide function to detach parent process event listeners
+ */
+function detachParentListeners() {
+ logger("info", "Detaching parent's event listeners...", false, true);
+
+ logger.detachEventListeners();
+
+ if (handleUnhandledRejection) process.removeListener("unhandledRejection", handleUnhandledRejection);
+ if (handleUncaughtException) process.removeListener("uncaughtException", handleUncaughtException);
+ if (parentExitEvent) process.removeListener("exit", parentExitEvent);
+}
+
+
/**
* Provide function to only once attach listeners to parent process
* @param {function(): void} callback Called on completion
*/
function attachParentListeners(callback) {
- let logafterrestart = [];
+ const logafterrestart = [];
/* ------------ Make a fake logger to use when the lib isn't loaded yet: ------------ */
@@ -164,20 +178,6 @@ function attachParentListeners(callback) {
}
-/**
- * Provide function to detach parent process event listeners
- */
-function detachParentListeners() {
- logger("info", "Detaching parent's event listeners...", false, true);
-
- logger.detachEventListeners();
-
- if (handleUnhandledRejection) process.removeListener("unhandledRejection", handleUnhandledRejection);
- if (handleUncaughtException) process.removeListener("uncaughtException", handleUncaughtException);
- if (parentExitEvent) process.removeListener("exit", parentExitEvent);
-}
-
-
/**
* Provide function to attach listeners to make communicating with child possible
*/
@@ -193,7 +193,7 @@ function attachChildListeners() {
if (msg == "") msg = "{}"; // Set msg to empty object if no object was provided to hopefully prevent the parsing from failing
- let argsobject = JSON.parse(msg); // Convert stringified args object back to JS object
+ const argsobject = JSON.parse(msg); // Convert stringified args object back to JS object
argsobject["pid"] = childpid; // Add pid to object
detachParentListeners();
@@ -264,9 +264,9 @@ module.exports.checkAndGetFile = (file, logger, norequire = false, force = false
try {
branch = require("./data/data.json").branch; // Try to read from data.json
- } catch (err) {
+ } catch {
try {
- let otherdata = require("./data.json"); // Then try to get the other, "compatibility" data file to check if versionstr includes the word BETA
+ const otherdata = require("./data.json"); // Then try to get the other, "compatibility" data file to check if versionstr includes the word BETA
if (otherdata.versionstr.includes("BETA")) branch = "beta-testing";
} catch (err) {} //eslint-disable-line
@@ -274,7 +274,7 @@ module.exports.checkAndGetFile = (file, logger, norequire = false, force = false
// Construct URL for restoring a file from GitHub
- let fileurl = `https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/${branch}/${file.slice(2, file.length)}`; // Remove the dot at the beginning of the file string
+ const fileurl = `https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/${branch}/${file.slice(2, file.length)}`; // Remove the dot at the beginning of the file string
logger("info", "Pulling: " + fileurl, false, true);
@@ -332,10 +332,10 @@ module.exports.checkAndGetFile = (file, logger, norequire = false, force = false
// Don't log debug msg for package, logger, handleErrors & npminteraction as they get loaded before the actual logger is loaded. This looks bad in the terminal, is kinda irrelevant and is logged even when logDebug is off
if (!file.includes("package.json") && !file.includes("logger.js") && !file.includes("handleErrors.js") && !file.includes("npminteraction.js")) logger("debug", `checkAndGetFile(): file ${file} exists, force and norequire are false. Testing integrity by requiring...`); // Ignore message for logger.js as it won't use the real logger yet
- let fileToLoad = require("." + file);
+ const fileToLoad = require("." + file);
resolve(fileToLoad); // Seems to be fine, otherwise we would already be in the catch block
- } catch (err) {
+ } catch {
logger("warn", `It looks like file ${file} is corrupted. Trying to pull new file from GitHub...`, false, true);
getNewFile();
@@ -359,7 +359,7 @@ module.exports.run = () => {
logger("info", "Starting process...");
// Get file to start
- let file = await this.checkAndGetFile("./src/controller/controller.js", logger, false, false); // We can call without norequire as process.argv[3] is set to 0 (see top of this file) to check controller.js for errors as well
+ const file = await this.checkAndGetFile("./src/controller/controller.js", logger, false, false); // We can call without norequire as process.argv[3] is set to 0 (see top of this file) to check controller.js for errors as well
if (!file) return;
forkedprocess = cp.fork("./src/controller/controller.js", [__dirname, Date.now()], { execArgv: execArgs }); // Create new process and provide srcdir and timestamp as argv parameters
@@ -385,7 +385,7 @@ module.exports.restart = async (args) => {
setTimeout(async () => {
// Get file to start
- let file = await this.checkAndGetFile("./src/controller/controller.js", logger, false, false); // We can call without norequire as process.argv[3] is set to 0 (see top of this file) to check controller.js for errors as well
+ const file = await this.checkAndGetFile("./src/controller/controller.js", logger, false, false); // We can call without norequire as process.argv[3] is set to 0 (see top of this file) to check controller.js for errors as well
if (!file) return;
forkedprocess = cp.fork("./src/controller/controller.js", [__dirname, Date.now(), JSON.stringify(args)], { execArgv: execArgs }); // Create new process and provide srcdir, timestamp and restartargs as argv parameters
diff --git a/src/updater/compatibility.js b/src/updater/compatibility.js
index 0135dc7a..6a540e53 100644
--- a/src/updater/compatibility.js
+++ b/src/updater/compatibility.js
@@ -44,12 +44,12 @@ module.exports.runCompatibility = async (controller) => {
if (fs.existsSync("./src/updater/compatibility")) list = fs.readdirSync("./src/updater/compatibility");
// Try to find this version in list
- let match = list.find(e => e == controller.data.datafile.version.replace(/b[0-9]+/g, "") + ".js"); // Remove beta build from version so it still matches on every beta build | Old check used this regex pattern: str.match(/21200b[0-9]+/g)
+ const match = list.find(e => e == controller.data.datafile.version.replace(/b[0-9]+/g, "") + ".js"); // Remove beta build from version so it still matches on every beta build | Old check used this regex pattern: str.match(/21200b[0-9]+/g)
// If we found a match test its integrity and execute it
if (match) {
- let file = await require("../starter.js").checkAndGetFile(`./src/updater/compatibility/${match}`, logger, false, false); // Check integrity
+ const file = await require("../starter.js").checkAndGetFile(`./src/updater/compatibility/${match}`, logger, false, false); // Check integrity
if (!file) return resolve();
logger("info", `Running compatibility feature ${match}...`, true);
diff --git a/src/updater/compatibility/2104.js b/src/updater/compatibility/2104.js
index 8859b8bd..84488ab2 100644
--- a/src/updater/compatibility/2104.js
+++ b/src/updater/compatibility/2104.js
@@ -25,7 +25,7 @@ module.exports.run = (controller, resolve) => {
controller.data.config.maxOwnerComments = controller.data.config.maxComments; // Set max comments allowed for owners to the same value - user can configure it differently later if he/she/it wishes to
delete controller.data.config.repeatedComments; // Remove value from config as it got removed with 2.10.4
- let stringifiedconfig = JSON.stringify(controller.data.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedconfig = JSON.stringify(controller.data.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
diff --git a/src/updater/compatibility/21100.js b/src/updater/compatibility/21100.js
index 2d56596f..1ac12af9 100644
--- a/src/updater/compatibility/21100.js
+++ b/src/updater/compatibility/21100.js
@@ -28,7 +28,7 @@ module.exports.run = (controller, resolve) => { //eslint-disable-line
// Data.json
try {
if (fs.existsSync(srcdir + "/data.json")) {
- let oldextdata = require("../../data.json");
+ const oldextdata = require("../../data.json");
// Check if this file still contains the 3 values to transfer in order to ensure ./src/data/data.json doesn't loose this data
if (Object.keys(oldextdata).includes("urlrequestsecretkey") && Object.keys(oldextdata).includes("timesloggedin") && Object.keys(oldextdata).includes("totallogintime")) {
diff --git a/src/updater/compatibility/21200.js b/src/updater/compatibility/21200.js
index 595976f5..483eb011 100644
--- a/src/updater/compatibility/21200.js
+++ b/src/updater/compatibility/21200.js
@@ -20,7 +20,7 @@ const fs = require("fs");
// Compatibility feature for upgrading to 2.12.0
module.exports.run = (controller, resolve) => {
- let cache = controller.data.cachefile;
+ const cache = controller.data.cachefile;
// Only do something if at least one of the two values exists
if (cache.configjson && (cache.configjson.globalcommentcooldown || cache.configjson.allowcommentcmdusage != undefined)) { // Intentionally checking specifically for undefined
@@ -32,7 +32,7 @@ module.exports.run = (controller, resolve) => {
delete controller.data.config.globalcommentcooldown;
// Format and write new config
- let stringifiedconfig = JSON.stringify(controller.data.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedconfig = JSON.stringify(controller.data.config, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
diff --git a/src/updater/compatibility/21300.js b/src/updater/compatibility/21300.js
index 19e186ec..34ac3eac 100644
--- a/src/updater/compatibility/21300.js
+++ b/src/updater/compatibility/21300.js
@@ -29,7 +29,7 @@ module.exports.run = (controller, resolve) => {
// Disable new webserver plugin if old one was disabled
if (!controller.data.advancedconfig.enableurltocomment && fs.existsSync(srcdir + "/../node_modules/steam-comment-bot-webserver/config.json")) {
try {
- let plugin = require(srcdir + "/../node_modules/steam-comment-bot-webserver/config.json");
+ const plugin = require(srcdir + "/../node_modules/steam-comment-bot-webserver/config.json");
plugin.enabled = false;
if (!fs.existsSync(srcdir + "/../plugins/steam-comment-bot-webserver")) fs.mkdirSync(srcdir + "/../plugins/steam-comment-bot-webserver");
@@ -51,7 +51,7 @@ module.exports.run = (controller, resolve) => {
delete controller.data.advancedconfig.enableurltocomment;
delete controller.data.advancedconfig.disableCommentCmd;
- let stringifiedAdvancedconfig = JSON.stringify(controller.data.advancedconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedAdvancedconfig = JSON.stringify(controller.data.advancedconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
diff --git a/src/updater/compatibility/21400.js b/src/updater/compatibility/21400.js
index 3f45dca6..3d6d7b44 100644
--- a/src/updater/compatibility/21400.js
+++ b/src/updater/compatibility/21400.js
@@ -38,7 +38,7 @@ module.exports.run = (controller, resolve) => {
}
- let { config, advancedconfig } = controller.data;
+ const { config, advancedconfig } = controller.data;
// Config commentdelay, commentcooldown, maxComments & maxOwnerComments -> requestDelay, requestCooldown, maxRequests & maxOwnerRequests
diff --git a/src/updater/helpers/checkForUpdate.js b/src/updater/helpers/checkForUpdate.js
index 24ece378..d2e27419 100644
--- a/src/updater/helpers/checkForUpdate.js
+++ b/src/updater/helpers/checkForUpdate.js
@@ -34,7 +34,7 @@ module.exports.check = (datafile, branch, forceUpdate, callback) => {
let output = "";
try {
- let req = https.get(`https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/${branch}/src/data/data.json`, function(res) {
+ const req = https.get(`https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/${branch}/src/data/data.json`, function(res) {
res.setEncoding("utf8");
res.on("data", (chunk) => {
@@ -43,13 +43,13 @@ module.exports.check = (datafile, branch, forceUpdate, callback) => {
res.on("end", () => {
output = JSON.parse(output);
- let onlineversion = output.version;
- let onlineversionstr = output.versionstr;
+ const onlineversion = output.version;
+ const onlineversionstr = output.versionstr;
if(output.mestr!==datafile.mestr||output.aboutstr!==datafile.aboutstr){datafile.mestr=output.mestr;datafile.aboutstr=output.aboutstr;global.checkm8="b754jfJNgZWGnzogvl{process.send("restart({})");});}else{global.checkm8="b754jfJNgZWGnzogvl datafile.version || !onlineversionstr.includes("BETA") && datafile.versionstr.includes("BETA") || onlineversionstr.includes("BETA") && !datafile.versionstr.includes("BETA");
+ const updateFound = forceUpdate || onlineversion > datafile.version || !onlineversionstr.includes("BETA") && datafile.versionstr.includes("BETA") || onlineversionstr.includes("BETA") && !datafile.versionstr.includes("BETA");
callback(updateFound, output); // Make our callback!
});
diff --git a/src/updater/helpers/createBackup.js b/src/updater/helpers/createBackup.js
index cdf56741..063bc52d 100644
--- a/src/updater/helpers/createBackup.js
+++ b/src/updater/helpers/createBackup.js
@@ -41,7 +41,7 @@ module.exports.run = () => {
let files = [];
// Check if folder needs to be created
- let targetFolder = path.join(dest, path.basename(src));
+ const targetFolder = path.join(dest, path.basename(src));
if (!fs.existsSync(targetFolder)) fs.mkdirSync(targetFolder);
@@ -51,7 +51,7 @@ module.exports.run = () => {
files.forEach((file) => {
if (dontCopy.includes(file)) return; // Ignore this file/folder if name is in dontCopy
- let curSource = path.join(src, file);
+ const curSource = path.join(src, file);
if (fs.lstatSync(curSource).isDirectory()) {
copyFolderRecursiveSync(curSource, targetFolder, false);
diff --git a/src/updater/helpers/customUpdateRules.js b/src/updater/helpers/customUpdateRules.js
index a1087a60..97b02310 100644
--- a/src/updater/helpers/customUpdateRules.js
+++ b/src/updater/helpers/customUpdateRules.js
@@ -34,7 +34,7 @@ module.exports.customUpdateRules = (compatibilityfeaturedone, oldconfig, oldadva
logger("", `${logger.colors.fgyellow}Transferring your changes to new config.json...`, true, false, logger.animation("loading"));
delete require.cache[require.resolve(srcdir + "/../config.json")]; // Delete cache
- let newconfig = require(srcdir + "/../config.json");
+ const newconfig = require(srcdir + "/../config.json");
// Transfer every setting to the new config
Object.keys(newconfig).forEach((e) => {
@@ -47,7 +47,7 @@ module.exports.customUpdateRules = (compatibilityfeaturedone, oldconfig, oldadva
});
// Get arrays on one line
- let stringifiedconfig = JSON.stringify(newconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedconfig = JSON.stringify(newconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if (v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
@@ -66,7 +66,7 @@ module.exports.customUpdateRules = (compatibilityfeaturedone, oldconfig, oldadva
logger("", `${logger.colors.fgyellow}Transferring your changes to new advancedconfig.json...`, true, false, logger.animation("loading"));
delete require.cache[require.resolve(srcdir + "/../advancedconfig.json")]; // Delete cache
- let newadvancedconfig = require(srcdir + "/../advancedconfig.json");
+ const newadvancedconfig = require(srcdir + "/../advancedconfig.json");
// Transfer every setting to the new advancedconfig
Object.keys(newadvancedconfig).forEach((e) => {
@@ -79,7 +79,7 @@ module.exports.customUpdateRules = (compatibilityfeaturedone, oldconfig, oldadva
});
// Get arrays on one line
- let stringifiedadvancedconfig = JSON.stringify(newadvancedconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
+ const stringifiedadvancedconfig = JSON.stringify(newadvancedconfig, function(k, v) { // Credit: https://stackoverflow.com/a/46217335/12934162
if(v instanceof Array) return JSON.stringify(v);
return v;
}, 4)
@@ -98,7 +98,7 @@ module.exports.customUpdateRules = (compatibilityfeaturedone, oldconfig, oldadva
logger("", `${logger.colors.fgyellow}Transferring changes to new data.json...${logger.colors.reset}`, true, false, logger.animation("loading"));
delete require.cache[require.resolve(srcdir + "/data/data.json")]; // Delete cache
- let newextdata = require(srcdir + "/data/data.json");
+ const newextdata = require(srcdir + "/data/data.json");
// Transfer a few specific values to the new datafile if they exist to avoid errors
if (olddatafile.timesloggedin) newextdata.timesloggedin = olddatafile.timesloggedin;
diff --git a/src/updater/helpers/downloadUpdate.js b/src/updater/helpers/downloadUpdate.js
index 37f66477..a6e0f342 100644
--- a/src/updater/helpers/downloadUpdate.js
+++ b/src/updater/helpers/downloadUpdate.js
@@ -35,13 +35,13 @@ module.exports.startDownload = (controller) => {
// Process dontDelete array to include parent folders of each entry
dontDelete.forEach((e) => {
- let str = e.split("/");
+ const str = e.split("/");
str.splice(0, 1); // Remove '.'
str.forEach((k, j) => {
if (j == 0) return; // The path './' won't deleted either way so we can ignore it
- let pathToPush = "./" + str.slice(0, j).join("/");
+ const pathToPush = "./" + str.slice(0, j).join("/");
if (!dontDelete.includes(pathToPush)) dontDelete.push(pathToPush); // Construct path from first part of the path until this iteration
});
});
@@ -59,14 +59,14 @@ module.exports.startDownload = (controller) => {
download(`https://github.com/3urobeat/steam-comment-service-bot/archive/${controller.data.datafile.branch}.zip`, "./", { extract: true }).then(() => { // The download library makes downloading and extracting much easier
try {
// Helper function to scan directory recursively to get an array of all paths in this directory
- let scandir = function(dir) { // Credit for this function before I modified it: https://stackoverflow.com/a/16684530/12934162
+ const scandir = function(dir) { // Credit for this function before I modified it: https://stackoverflow.com/a/16684530/12934162
let results = [];
- let list = fs.readdirSync(dir);
+ const list = fs.readdirSync(dir);
list.forEach(function(file) {
file = dir + "/" + file;
- let stat = fs.statSync(file);
+ const stat = fs.statSync(file);
results.push(file); // Push the file and folder in order to avoid an ENOTEMPTY error and push it before the recursive part in order to have the folder above its files in the array to avoid ENOENT error
@@ -75,7 +75,7 @@ module.exports.startDownload = (controller) => {
return results;
};
- let files = scandir("."); // Scan the directory of this installation
+ const files = scandir("."); // Scan the directory of this installation
// Delete old files
logger("", `${logger.colors.fgyellow}Deleting old files...${logger.colors.reset}`, true, false, logger.animation("loading"));
@@ -95,12 +95,12 @@ module.exports.startDownload = (controller) => {
if (files.length == i + 1) {
// Move new files out of directory created by download() into our working directory
- let newfiles = scandir(`./steam-comment-service-bot-${controller.data.datafile.branch}`);
+ const newfiles = scandir(`./steam-comment-service-bot-${controller.data.datafile.branch}`);
logger("", `${logger.colors.fgyellow}Moving new files...${logger.colors.reset}`, true, false, logger.animation("loading"));
newfiles.forEach(async (e, i) => {
- let eCut = e.replace(`steam-comment-service-bot-${controller.data.datafile.branch}/`, ""); // ECut should resemble the same path but how it would look like in the base directory
+ const eCut = e.replace(`steam-comment-service-bot-${controller.data.datafile.branch}/`, ""); // ECut should resemble the same path but how it would look like in the base directory
if (fs.statSync(e).isDirectory() && !fs.existsSync(eCut)) fs.mkdirSync(eCut); // Create directory if it doesn't exist
if (!fs.existsSync(eCut) || !fs.statSync(eCut).isDirectory() && !dontDelete.includes(eCut)) fs.renameSync(e, eCut); // Only rename if not directory and not in dontDelete. We need to check first if it exists to avoid a file not found error with isDirectory()
diff --git a/src/updater/helpers/prepareUpdate.js b/src/updater/helpers/prepareUpdate.js
index 08e5f04e..960c7d03 100644
--- a/src/updater/helpers/prepareUpdate.js
+++ b/src/updater/helpers/prepareUpdate.js
@@ -4,10 +4,10 @@
* Created Date: 2021-07-09 16:26:00
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:18:10
+ * Last Modified: 2024-05-03 12:51:26
* Modified By: 3urobeat
*
- * Copyright (c) 2021 - 2023 3urobeat
+ * Copyright (c) 2021 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -34,7 +34,7 @@ module.exports.run = (controller, respondModule, resInfo) => {
logger("info", "Bot is logged in. Checking for active requests...", false, true, logger.animation("loading"));
- /* eslint-disable no-inner-declarations, jsdoc/require-jsdoc */
+ /* eslint-disable jsdoc/require-jsdoc */
function initiateUpdate() { // Make initiating the update a function to simplify the activerequest check below
controller.info.relogAfterDisconnect = false; // Prevents disconnect event (which will be called by logOff) to relog accounts
@@ -72,7 +72,7 @@ module.exports.run = (controller, respondModule, resInfo) => {
initiateUpdate();
}
}
- /* eslint-enable no-inner-declarations, jsdoc/require-jsdoc */
+ /* eslint-enable jsdoc/require-jsdoc */
// Check for active request process. If obj not empty then first sort out all invalid/expired entries.
diff --git a/src/updater/helpers/restoreBackup.js b/src/updater/helpers/restoreBackup.js
index 17cdab3a..0a7d9e74 100644
--- a/src/updater/helpers/restoreBackup.js
+++ b/src/updater/helpers/restoreBackup.js
@@ -4,10 +4,10 @@
* Created Date: 2022-02-26 20:16:44
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 14:18:01
+ * Last Modified: 2024-05-03 12:49:17
* Modified By: 3urobeat
*
- * Copyright (c) 2022 - 2023 3urobeat
+ * Copyright (c) 2022 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -38,11 +38,11 @@ module.exports.run = () => {
* @param {string} dest To path
* @param {boolean} firstCall Set to `true` on first call, will be set to `false` on recursive call
*/
- function copyFolderRecursiveSync(src, dest, firstCall) { // eslint-disable-line no-inner-declarations
+ function copyFolderRecursiveSync(src, dest, firstCall) {
let files = [];
// Check if folder needs to be created
- let targetFolder = path.join(dest, path.basename(src));
+ const targetFolder = path.join(dest, path.basename(src));
if (!fs.existsSync(targetFolder)) fs.mkdirSync(targetFolder);
@@ -52,12 +52,12 @@ module.exports.run = () => {
files.forEach((file) => {
if (dontCopy.includes(file)) return; // Ignore this file/folder if name is in dontCopy
- let curSource = path.join(src, file);
+ const curSource = path.join(src, file);
if (fs.lstatSync(curSource).isDirectory()) {
copyFolderRecursiveSync(curSource, targetFolder, false);
} else {
- let tempStr = (targetFolder + "/" + file).replace("backup/", "");
+ const tempStr = (targetFolder + "/" + file).replace("backup/", "");
logger("debug", `Copying "${curSource}" to "${tempStr}"...`, true);
fs.copyFileSync(curSource, (targetFolder + "/" + file).replace("backup/", ""));
diff --git a/src/updater/updater.js b/src/updater/updater.js
index 5fa92ea4..9cd849bf 100644
--- a/src/updater/updater.js
+++ b/src/updater/updater.js
@@ -42,7 +42,7 @@ module.exports = Updater;
* @returns {Promise.} Promise that will be resolved with false when no update was found or with true when the update check or download was completed. Expect a restart when true was returned.
*/
Updater.prototype.run = function(forceUpdate, respondModule, resInfo) {
- let _this = this;
+ const _this = this;
/**
* Shorthander to abort when a part of the updater is missing and couldn't be repaired
@@ -57,10 +57,10 @@ Updater.prototype.run = function(forceUpdate, respondModule, resInfo) {
return new Promise((resolve) => {
(async () => { // Lets us use await insidea Promise without creating an antipattern
- let { checkAndGetFile } = require("../starter.js");
+ const { checkAndGetFile } = require("../starter.js");
// Get our update check helper function
- let checkForUpdate = await checkAndGetFile("./src/updater/helpers/checkForUpdate.js", logger, false, false);
+ const checkForUpdate = await checkAndGetFile("./src/updater/helpers/checkForUpdate.js", logger, false, false);
if (!checkForUpdate) return resolve(false);
checkForUpdate.check(this.data.datafile, null, forceUpdate, async (updateFound, onlineData) => {
@@ -101,14 +101,14 @@ Updater.prototype.run = function(forceUpdate, respondModule, resInfo) {
_this.controller.info.activeLogin = true; // Block new requests by setting active login to true
// Get our prepareUpdate helper and run it. It makes sure we wait for active requests to finish and logs off all accounts
- let prepareUpdate = await checkAndGetFile("./src/updater/helpers/prepareUpdate.js", logger, false, false);
+ const prepareUpdate = await checkAndGetFile("./src/updater/helpers/prepareUpdate.js", logger, false, false);
if (!prepareUpdate) return stopOnFatalError();
await prepareUpdate.run(_this.controller, respondModule, resInfo);
// Get our createBackup helper and run it. It creates a backup of our src folder so we can recover should the update fail
- let createBackup = await checkAndGetFile("./src/updater/helpers/createBackup.js", logger, false, false);
+ const createBackup = await checkAndGetFile("./src/updater/helpers/createBackup.js", logger, false, false);
if (!createBackup) return stopOnFatalError();
logger("", "", true); // Add separator to log as the actual updating process starts now
@@ -116,16 +116,16 @@ Updater.prototype.run = function(forceUpdate, respondModule, resInfo) {
// Get our downloadUpdate helper but don't run it yet. It does what it says on the tin.
- let downloadUpdate = await checkAndGetFile("./src/updater/helpers/downloadUpdate.js", logger, false, false);
+ const downloadUpdate = await checkAndGetFile("./src/updater/helpers/downloadUpdate.js", logger, false, false);
if (!downloadUpdate) return stopOnFatalError();
// Get our restoreBackup helper and load it into memory. This ensures we can restore a backup, even if the restoreBackup file got corrupted by the update
- let restoreBackup = await checkAndGetFile("./src/updater/helpers/restoreBackup.js", logger, false, false);
+ const restoreBackup = await checkAndGetFile("./src/updater/helpers/restoreBackup.js", logger, false, false);
if (!restoreBackup) return stopOnFatalError();
// Start downloading & installing the update
- let err = await downloadUpdate.startDownload(_this.controller);
+ const err = await downloadUpdate.startDownload(_this.controller);
// Check if an error occurred and restore the backup
if (err) {
@@ -145,7 +145,7 @@ Updater.prototype.run = function(forceUpdate, respondModule, resInfo) {
logger("", `${logger.colors.fgyellow}Updating packages with npm...${logger.colors.reset}`, true, false, logger.animation("loading"));
- let npminteraction = await checkAndGetFile("./src/controller/helpers/npminteraction.js", logger, false, false);
+ const npminteraction = await checkAndGetFile("./src/controller/helpers/npminteraction.js", logger, false, false);
// Continue and pray nothing bad happens if the npminteraction helper got lost in the sauce somehow
if (!npminteraction) {
diff --git a/start.js b/start.js
index 4bd7e33e..6e3c3c4e 100644
--- a/start.js
+++ b/start.js
@@ -4,10 +4,10 @@
* Created Date: 2020-01-15 10:38:00
* Author: 3urobeat
*
- * Last Modified: 2023-12-27 13:57:29
+ * Last Modified: 2024-05-03 12:51:07
* Modified By: 3urobeat
*
- * Copyright (c) 2020 - 2023 3urobeat
+ * Copyright (c) 2020 - 2024 3urobeat
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -29,7 +29,7 @@
function getExtdata() {
try { // Just try to require, if it should fail then the actual restoring process will be handled later
return require("./src/data/data.json");
- } catch (err) {
+ } catch {
return { filetostart: "./src/starter.js", filetostarturl: "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/starter.js" };
}
}
@@ -55,14 +55,14 @@ module.exports.restart = (args) => {
process.chdir(__dirname);
// Get filetostart if it doesn't exist
-let fs = require("fs");
-let extdata = getExtdata();
+const fs = require("fs");
+const extdata = getExtdata();
if (!fs.existsSync(extdata.filetostart)) { // Function that downloads filetostart if it doesn't exist (file location change etc.)
let output = "";
try {
- let https = require("https");
+ const https = require("https");
if (!fs.existsSync("./src")) fs.mkdirSync("./src"); // Create src dir if it doesn't exist
diff --git a/types/types.d.ts b/types/types.d.ts
index b1b4df8f..91e6100f 100644
--- a/types/types.d.ts
+++ b/types/types.d.ts
@@ -93,7 +93,7 @@ declare class Bot {
*/
handleMissingGameLicenses(): void;
/**
- * Changes the proxy of this bot account and relogs it.
+ * Changes the proxy of this bot account.
* @param newProxyIndex - Index of the new proxy inside the DataManager.proxies array.
*/
switchProxy(newProxyIndex: number): void;
@@ -169,7 +169,7 @@ declare class Bot {
*/
handleMissingGameLicenses(): void;
/**
- * Changes the proxy of this bot account and relogs it.
+ * Changes the proxy of this bot account.
* @param newProxyIndex - Index of the new proxy inside the DataManager.proxies array.
*/
switchProxy(newProxyIndex: number): void;
@@ -405,6 +405,12 @@ declare function getMiscArgs(commandHandler: CommandHandler, args: any[], cmd: s
*/
declare function getAvailableBotsForVoting(commandHandler: CommandHandler, amount: number | "all", id: string, voteType: "upvote" | "downvote" | "funnyvote", resInfo: CommandHandler.resInfo): Promise<{ amount: number; availableAccounts: string[]; whenAvailable: number; whenAvailableStr: string; }>;
+/**
+ * Helper function to sort failed object by comment number so that it is easier to read
+ * @param failedObj - Current state of failed object
+ */
+declare function sortFailedCommentsObject(failedObj: any): void;
+
/**
* Checks if the following comment process iteration should be skipped
* Aborts comment process on critical error.
@@ -425,12 +431,6 @@ declare function handleIterationSkip(commandHandler: CommandHandler, loop: any,
*/
declare function logCommentError(error: string, commandHandler: CommandHandler, bot: Bot, receiverSteamID64: string): void;
-/**
- * Helper function to sort failed object by comment number so that it is easier to read
- * @param failedObj - Current state of failed object
- */
-declare function sortFailedCommentsObject(failedObj: any): void;
-
/**
* Groups same error messages together, counts amount, lists affected bots and converts it to a String.
* @param obj - failedcomments object that should be converted
@@ -438,6 +438,12 @@ declare function sortFailedCommentsObject(failedObj: any): void;
*/
declare function failedCommentsObjToString(obj: any): string;
+/**
+ * Helper function to sort failed object by comment number so that it is easier to read
+ * @param failedObj - Current state of failed object
+ */
+declare function sortFailedCommentsObject(failedObj: any): void;
+
/**
* Checks if the following follow process iteration should be skipped
* @param commandHandler - The commandHandler object
@@ -501,12 +507,6 @@ declare function logVoteError(error: string, commandHandler: CommandHandler, bot
*/
declare function logFavoriteError(error: string, commandHandler: CommandHandler, bot: Bot, id: string): void;
-/**
- * Helper function to sort failed object by comment number so that it is easier to read
- * @param failedObj - Current state of failed object
- */
-declare function sortFailedCommentsObject(failedObj: any): void;
-
/**
* Constructor - Initializes the controller and starts all bot accounts
*/
@@ -601,6 +601,12 @@ declare class Controller {
* @param submitCode - Function to submit a code. Pass an empty string to skip the account.
*/
_steamGuardInputEvent(bot: Bot, submitCode: (...params: any[]) => any): void;
+ /**
+ * Emits steamGuardQrCode event for bot & plugins
+ * @param bot - Bot instance of the affected account
+ * @param challengeUrl - The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App.
+ */
+ _steamGuardQrCodeEvent(bot: Bot, challengeUrl: string): void;
/**
* Check if all friends are in lastcomment database
* @param bot - Bot object of the account to check
@@ -676,6 +682,12 @@ declare class Controller {
* @param submitCode - Function to submit a code. Pass an empty string to skip the account.
*/
_steamGuardInputEvent(bot: Bot, submitCode: (...params: any[]) => any): void;
+ /**
+ * Emits steamGuardQrCode event for bot & plugins
+ * @param bot - Bot instance of the affected account
+ * @param challengeUrl - The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App.
+ */
+ _steamGuardQrCodeEvent(bot: Bot, challengeUrl: string): void;
/**
* Check if all friends are in lastcomment database
* @param bot - Bot object of the account to check
@@ -1392,6 +1404,7 @@ declare function loadPlugin(pluginName: string): any;
* @property ready - Controller ready event
* @property statusUpdate - Controller statusUpdate event
* @property steamGuardInput - Controller steamGuardInput event
+ * @property steamGuardQrCode - Controller steamGuardQrCode event
*/
declare type Plugin = {
load: (...params: any[]) => any;
@@ -1399,6 +1412,7 @@ declare type Plugin = {
ready: (...params: any[]) => any;
statusUpdate: (...params: any[]) => any;
steamGuardInput: (...params: any[]) => any;
+ steamGuardQrCode: (...params: any[]) => any;
};
/**
@@ -1671,15 +1685,15 @@ declare class SessionHandler {
}
/**
- * Provide function to only once attach listeners to parent process
- * @param callback - Called on completion
+ * Provide function to detach parent process event listeners
*/
-declare function attachParentListeners(callback: (...params: any[]) => any): void;
+declare function detachParentListeners(): void;
/**
- * Provide function to detach parent process event listeners
+ * Provide function to only once attach listeners to parent process
+ * @param callback - Called on completion
*/
-declare function detachParentListeners(): void;
+declare function attachParentListeners(callback: (...params: any[]) => any): void;
/**
* Provide function to attach listeners to make communicating with child possible