Compare commits

...

12 commits
0.1.6 ... main

Author SHA1 Message Date
ed492e9045
Use newer docker compose command
Some checks failed
Docker Build / build-and-push (push) Has been cancelled
2025-10-31 23:54:01 +01:00
24f65956ab Local development with webserver and demo files
Some checks failed
Docker Build / build-and-push (push) Has been cancelled
2025-07-10 17:25:29 +02:00
4e6668c2e5 Increased bot version to 0.1.8 2024-12-12 12:39:05 +01:00
696e8f1749 Added truncate for servers with long list of mods (discord max length 1024 chars) and feed parse optimization 2024-12-12 12:37:32 +01:00
a28796751a Updated the README and uploaded the social banner for this repository (Affinity Photo) 2024-12-11 03:17:38 +00:00
58451f6fd0
Removed the header image of the repository 2024-12-11 04:13:16 +01:00
87a3cb158c
Titelbild aktualisiert 2024-12-11 04:12:14 +01:00
9337105ca7
Update README.md 2024-12-11 04:01:34 +01:00
1e35792419 Changed the image names for correct language association 2024-12-08 02:44:47 +01:00
bcc98514e6
Merge pull request #15 from cloudmaker97/change-time-display 2024-12-08 02:32:00 +01:00
885461f316 Changed version to 0.1.7 (temporarily bugfix) 2024-12-08 02:29:52 +01:00
f4a872546a Removed the display of the game server month due to incorrect values, this must me reimplemented when more details about this is available #2 2024-12-08 02:29:17 +01:00
16 changed files with 52 additions and 61 deletions

View file

@ -1,31 +1,30 @@
# Farming Simulator 25 - Discord Bot
This bot periodically updates a Discord channel with stats from a Farming Simulator 25 server.
It posts the server name, password, time, and player count. Written in Node.js, it uses the
discord.js library to interact with Discord and fetches server stats via the XML feed
This bot periodically updates a Discord channel with stats from a Farming Simulator 25 server.
It posts the server name, password, time, and player count. Written in Node.js, it uses the
discord.js library to interact with Discord and fetches server stats via the XML feed
(accessible through the server's web interface). The update interval is configurable.
## Screenshots
<details>
<summary>Discord embed in english</summary>
![discord_en.png](misc%2Fimages%2Fdiscord_en.png)
![discord_en.png](misc%2Fimages%2Freadme%2Fdiscord_en.png)
</details>
<details>
<summary>Discord embed in german</summary>
![discord_de.png](misc%2Fimages%2Fdiscord_de.png)
![discord_de.png](misc%2Fimages%2Freadme%2Fdiscord_de.png)
</details>
<details>
<summary>Terminal output (NodeJS)</summary>
![bot_terminal.png](misc%2Fimages%2Fbot_terminal.png)
![bot_terminal.png](misc%2Fimages%2Freadme%2Fbot_terminal.png)
</details>
@ -57,8 +56,8 @@ discord.js library to interact with Discord and fetches server stats via the XML
1. Clone the repository to your server
2. Locate the configuration files:
- Use either
- `config.example-de.json` (for German)
- Use either
- `config.example-de.json` (for German)
- `config.example-en.json` (for English)
- Rename the chosen file to `config.json`.
3. Open `config.json` and fill in the required fields:
@ -73,21 +72,27 @@ discord.js library to interact with Discord and fetches server stats via the XML
1. Navigate to the root directory of the cloned repository.
2. Build and start the container:
```bash
docker-compose up -d --build
docker compose up -d --build
```
3. The bot should now be running and posting server stats to the specified Discord channel.
### Option 2: Run Without Docker (Using Node.js)
1. Navigate to the root directory of the cloned repository.
2. Install dependencies:
```bash
npm install
```
3. Start the bot:
```bash
npm start
```
4. The bot should now be running and posting server stats to the specified Discord channel.
- Note: Closing the terminal will stop the bot. Use a process manager like [PM2](https://pm2.io/) to keep it running.

View file

@ -1,8 +1,8 @@
{
"application": {
"serverPassword": "TypeMyServerPasswordHere",
"serverStatsUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats.xml",
"serverMapUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats-map.jpg",
"serverStatsUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats.xml",
"serverMapUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats-map.jpg",
"updateIntervalSeconds": 30
},
"discord": {

View file

@ -1,8 +1,8 @@
{
"application": {
"serverPassword": "TypeMyServerPasswordHere",
"serverStatsUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats.xml",
"serverMapUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats-map.jpg",
"serverStatsUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats.xml",
"serverMapUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats-map.jpg",
"updateIntervalSeconds": 30
},
"discord": {

View file

@ -1,5 +1,3 @@
version: "2"
services:
ls25bot:
build:
@ -24,4 +22,14 @@ services:
sleep 7200 # Each 2 hours
echo "Restarting ls25bot container at $(date)"
docker restart ls25bot
done
done
# This is used for development purposes only
webserver:
image: nginx:alpine
container_name: ls25bot-webserver
restart: always
volumes:
- ./misc/files:/usr/share/nginx/html
ports:
- "8080:80"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View file

@ -1,6 +1,6 @@
{
"name": "ls25-discord-bot",
"version": "0.1.6",
"version": "0.1.8",
"description": "A simple discord bot for farming simulator 25",
"main": "source/Main.ts",
"scripts": {

View file

@ -92,6 +92,16 @@ export default class DiscordEmbed {
return true;
}
/**
* Truncates a string at a given length
* @param text The input text to truncate
* @param maxLength The allowed characters until truncation
* @returns The truncated string
*/
private async truncateText(text: string, maxLength = 1024): Promise<string> {
return text.length > maxLength ? text.slice(0, maxLength - 3) + '...' : text;
}
/**
* Send server stats embed in a channel
* @param serverStats
@ -100,8 +110,6 @@ export default class DiscordEmbed {
let embed = new EmbedBuilder();
let config = this.appConfiguration;
serverStats.getServerMonth();
embed.setTitle(config.translation.discordEmbed.title);
if (!serverStats.isOnline()) {
embed.setColor(0xCA0000);
@ -115,6 +123,8 @@ export default class DiscordEmbed {
embed.setThumbnail(config.application.serverMapUrl);
let playerListString: string;
let playerListTitleString = `${config.translation.discordEmbed.titlePlayerCount} (${serverStats.getPlayerCount()??0}/${serverStats.getMaxPlayerCount()??0}):`;
if(serverStats.getPlayerList().length === 0) {
playerListString = config.translation.discordEmbed.noPlayersOnline;
} else {
@ -129,7 +139,7 @@ export default class DiscordEmbed {
let serverMods = serverStats.getServerMods();
let serverModsText = "-/-";
if(serverMods.length > 0) {
serverModsText = serverMods.map(mod => `${mod.name}`).join(', ');
serverModsText = await this.truncateText(serverMods.map(mod => `${mod.name}`).join(', '));
}
// @ts-ignore
@ -140,12 +150,11 @@ export default class DiscordEmbed {
{name: config.translation.discordEmbed.titleServerMap, value: serverStats.getServerMap()},
{name: config.translation.discordEmbed.titleServerMods, value: serverModsText},
{
name: `${config.translation.discordEmbed.titlePlayerCount} (${serverStats.getPlayerCount()}/${serverStats.getMaxPlayerCount()}):`,
name: playerListTitleString,
value: playerListString
},
);
}
this.appLogger.debug(embed);
return embed;
}
}

View file

@ -137,37 +137,6 @@ export default class ServerStatusFeed {
});
}
/**
* Returns the server month as a string
* @returns {string} The server month as a string
*/
public getServerMonth(): string {
let config: IConfiguration = Configuration.getConfiguration();
let dayTime = this.getServerStats()?.Server.dayTime;
if (dayTime === undefined) {
return "Error";
}
let month = dayTime / (60 * 60 * 1000 * 24);
month = month % 1;
month = month * 12;
month = Math.floor(month);
let months = [
config.translation.common.monthJanuary,
config.translation.common.monthFebruary,
config.translation.common.monthMarch,
config.translation.common.monthApril,
config.translation.common.monthMay,
config.translation.common.monthJune,
config.translation.common.monthJuly,
config.translation.common.monthAugust,
config.translation.common.monthSeptember,
config.translation.common.monthOctober,
config.translation.common.monthNovember,
config.translation.common.monthDecember
]
return months[month-1];
}
/**
* Returns the server time in the format HH:MM
* @returns {string} The server time in the format HH:MM
@ -187,23 +156,23 @@ export default class ServerStatusFeed {
if(minutesString.length === 1) {
minutesString = `0${minutesString}`;
}
return `${hoursString}:${minutesString} (${this.getServerMonth()})`;
return `${hoursString}:${minutesString}`;
}
/**
* Returns the server player count
* @returns {number} The server player count
* @returns {number | null | undefined} The server player count
*/
public getPlayerCount(): number {
return <number>this.getServerStats()?.Server.Slots.numUsed;
public getPlayerCount(): number | null | undefined {
return <number>this.getServerStats()?.Server?.Slots?.numUsed;
}
/**
* Returns the server player count
* @returns {number} The server player count
* @returns {number | null | undefined} The server player count
*/
public getMaxPlayerCount(): number {
return <number>this.getServerStats()?.Server.Slots.capacity;
public getMaxPlayerCount(): number | null | undefined {
return <number>this.getServerStats()?.Server?.Slots?.capacity;
}
/**