This commit is contained in:
Florian Brinker 2022-03-19 23:20:09 +01:00
parent c0f63af638
commit 61175d4334
11 changed files with 3681 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
vendor/
*.log
public/states/*.json

28
Dockerfile Normal file
View File

@ -0,0 +1,28 @@
FROM php:apache
RUN apt-get update
RUN apt-get install -y libzip-dev
RUN docker-php-ext-install zip
WORKDIR /var/www/html
COPY public/ public
COPY src/ src
COPY app.php app.php
COPY README.md README.md
COPY composer.json composer.json
COPY composer.lock composer.lock
# Application
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
RUN composer install --no-dev
# Apache
COPY docker/vhost.conf /etc/apache2/sites-available/project.conf
RUN a2enmod rewrite &&\
a2dissite 000-default &&\
a2ensite project &&\
service apache2 restart
EXPOSE 80
ENTRYPOINT ["bash", "-c", "apache2-foreground & php app.php"]

View File

@ -1,3 +1,36 @@
# VoiceState - Discord Bot
This is a simple bot, tracking the mute state of members currently using the voice chat. The generated json files are named by the userId and contain just the mute state and no other information.
## Example
```
# https://discordbot.f-brinker.de/voice-state/states/userId123.json
{"state":"selfMuted"}
```
### Possible States
* active
* muted
* selfMuted
## Usage
* Add the Bot to your Discord Guild: [Add VoiceState Bot](https://discord.com/api/oauth2/authorize?client_id=954772647575703602&permissions=0&scope=bot)
* Grab the state by fetching https://discordbot.f-brinker.de/voice-state/states/userId123.json
* Replace userId123 with your Discord userId
## Host your own!
You can host your own bot by building the project on your own or by using the pre-built image `fbrinker/discordbot-voice-state`.
You need to create your own Discord application and bot. You need the Bot Token below. Replace `yourBotToken` with your actual token.
### Examle Docker-Compose
```
discordbot-voice-state:
container_name: discordbot-voice-state
image: fbrinker/discordbot-voice-state
restart: always
environment:
- "BOT_TOKEN=yourBotToken"
```
## Contribute
Feel free to add Pull-Request @ https://git.f-brinker.de/fbrinker/discordbot-voice-state

46
app.php Normal file
View File

@ -0,0 +1,46 @@
<?php
error_reporting(E_ALL ^ E_DEPRECATED);
ini_set('memory_limit', '128M');
include __DIR__.'/vendor/autoload.php';
use \Monolog\Logger;
use \Monolog\Handler\ErrorLogHandler;
use \Monolog\Handler\RotatingFileHandler;
use Discord\Discord;
use Discord\WebSockets\Intents;
use Discord\WebSockets\Event;
use Discord\Parts\WebSockets\VoiceStateUpdate;
use VoiceState\Bot;
$botToken = getenv("BOT_TOKEN");
if (empty($botToken)) {
die("Missing BOT_TOKEN");
}
$logger = new Logger(Bot::NAME);
$logger->pushHandler(new ErrorLogHandler(ErrorLogHandler::SAPI, Logger::INFO));
$logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/' . Bot::NAME . ".log", Bot::MAX_LOG_FILE_COUNT, Logger::WARNING));
$bot = new Bot(__DIR__ . '/public/states/', $logger);
$discord = new Discord([
'token' => $botToken,
'intents' => [
Intents::GUILD_VOICE_STATES
],
'logger' => $logger
]);
$discord->on('ready', function (Discord $discord) use ($logger) {
$logger->info("Bot is ready!");
});
$discord->on(Event::VOICE_STATE_UPDATE, function (VoiceStateUpdate $state, Discord $discord, $oldstate) use ($bot, $logger) {
$logger->info('Event: ' . Event::VOICE_STATE_UPDATE);
$bot->updateVoiceState($state);
});
$discord->run();

14
composer.json Normal file
View File

@ -0,0 +1,14 @@
{
"autoload": {
"psr-4": {
"VoiceState\\": "src/"
}
},
"require": {
"team-reflex/discord-php": "dev-master",
"league/commonmark": "^2.2"
},
"require-dev": {
"roave/security-advisories": "dev-latest"
}
}

3468
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

3
docker/vhost.conf Normal file
View File

@ -0,0 +1,3 @@
<VirtualHost *:80>
DocumentRoot /var/www/html/public
</VirtualHost>

0
logs/.gitkeep Normal file
View File

9
public/index.php Normal file
View File

@ -0,0 +1,9 @@
<?php
//error_reporting(0);
include __DIR__.'/../vendor/autoload.php';
use League\CommonMark\CommonMarkConverter;
$converter = new CommonMarkConverter();
echo $converter->convert(file_get_contents(__DIR__ . '/../README.md'));

0
public/states/.gitkeep Normal file
View File

76
src/Bot.php Normal file
View File

@ -0,0 +1,76 @@
<?php
namespace VoiceState;
use \Monolog\Logger;
use Discord\Parts\WebSockets\VoiceStateUpdate;
class Bot
{
public const NAME = "VoiceState";
public const MAX_LOG_FILE_COUNT = 7;
private const STATE_FILE_TEMPLATE = "%s.json";
private const STATE_DEFAULT = [
'state' => null,
];
private const STATE_ACTIVE = 'active';
private const STATE_MUTE = 'muted';
private const STATE_SELF_MUTE = 'selfMuted';
private string $stateFileDir;
private Logger $logger;
public function __construct(string $stateFileDir, Logger $logger)
{
if (!is_dir($stateFileDir)) {
throw new \RuntimeException("stateFileDir is no directory");
}
$this->stateFileDir = rtrim($stateFileDir, '/');
$this->logger = $logger;
}
public function updateVoiceState(VoiceStateUpdate $voiceState): void
{
try {
$stateFile = $this->stateFileDir . '/' . sprintf(self::STATE_FILE_TEMPLATE, $voiceState->user_id);
if (!file_exists($stateFile)) {
$this->createStatusFile($stateFile);
}
$state = $this->getState($voiceState);
file_put_contents($stateFile, json_encode($state));
} catch (\Throwable $t) {
$this->logger->error($t);
}
}
private function getState(VoiceStateUpdate $voiceState)
{
$state = self::STATE_DEFAULT;
$state['state'] = self::STATE_ACTIVE;
if ($voiceState->mute) {
$state['state'] = self::STATE_MUTE;
}
if ($voiceState->self_mute) {
$state['state'] = self::STATE_SELF_MUTE;
}
return $state;
}
private function createStatusFile(string $stateFile): void
{
if (file_exists($stateFile)) {
return;
}
file_put_contents($stateFile, json_encode(self::STATE_DEFAULT));
if (!file_exists($stateFile)) {
throw new \RuntimeException("could not create statefile: " . $stateFile);
}
}
}