diff --git a/.gitignore b/.gitignore index 892975a..621a683 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ config_mysql.py hugo.exe spectre/ velconnect_backup.sql +discord_bot/graph.png +discord_bot/config.py diff --git a/README.md b/README.md index 45ad11f..44ff7b2 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,13 @@ 2. Create pip env: `python3 -m venv env` 3. Activate the env `. env/bin/activate` 4. Install packages `pip install -r requirements.txt` -5. Run `./run_server.sh` +5. Add `config_mysql.py` + - Get from some old server +6. Run `./run_server.sh` - Or set up systemctl service: ```ini [Unit] - Description=VelNet Logging + Description=VELConnect API Requires=network.target After=network.target @@ -22,5 +24,5 @@ WantedBy=multi-user.target ``` - Enter the above in `/etc/systemd/system/velconnect.service` - - `sudo systemctl enable velconnect.service` - - `sudo systemctl start velconnect.service` \ No newline at end of file + - `sudo systemctl enable velconnect` + - `sudo systemctl start velconnect` \ No newline at end of file diff --git a/discord_bot/discord_bot.py b/discord_bot/discord_bot.py new file mode 100644 index 0000000..f6dc2e1 --- /dev/null +++ b/discord_bot/discord_bot.py @@ -0,0 +1,102 @@ +import requests +import json +import discord +import random +from discord_slash import SlashContext, SlashCommand +from discord_slash.utils.manage_commands import create_option +from discord.ext import commands +import pandas as pd +import matplotlib.pyplot as plt +import config + +user_count_url = "http://velconnect2.ugavel.com/api/get_user_count" + +# guild_ids = [706393774804303924] +guild_ids = [706393774804303924,630847214511587328] + +def get_prefix(client, message): + return 'velbot' + + +bot = commands.Bot(command_prefix=get_prefix) +slash = SlashCommand(bot, sync_commands=True) + + +@bot.event +async def on_ready(): + print("Ready!") + + +# @bot.command(name="velbot") +# async def stats_command(ctx, *args): +# await ctx.send(random.choice(["yes", "no"])) + + +@slash.slash( + name="convrged_count", + description="Shows a graph with the current user count in conVRged.", + options=[ + create_option( + name="hours", + description="Number of hours of history to include. The default is 24 hours.", + option_type=4, + required=False + ) + ], + guild_ids=guild_ids +) +async def _convrged_count(ctx: SlashContext, hours: int = 24): + data = get_user_count(hours) + + await post_graph(pd.DataFrame(data), ctx, "Last "+str(hours)+" hours:") + + + +def get_user_count(graph_hours=24): + r = requests.get(user_count_url, params={'hours': graph_hours}) + + if r.status_code != 200: + return -1 + else: + return json.loads(r.text) + + +async def post_graph(df, ctx, length_message, scatter=False): + if len(df) > 0: + await ctx.defer() + df['timestamp'] = pd.to_datetime(df['timestamp']) + df.columns = ['Time', 'Player Count'] + + df = df[df['Player Count'] >= 0] + + params = {"ytick.color": "w", + "xtick.color": "w", + "axes.labelcolor": "w", + "axes.edgecolor": "w"} + plt.rcParams.update(params) + fig = plt.figure(figsize=(7, 3), dpi=200) + ax = plt.axes() + plt.margins(x=0) + + if scatter: + plt.scatter(x=df['Time'], y=df['Player Count'], + alpha=.1, s=.5, c='w') + else: + df.plot(ax=ax, x='Time', y='Player Count', linewidth=3.0, c='w') + # ax.step(df['Time'], df['Player Count'], linewidth=3.0, c='w') + ax.get_legend().remove() + + # ax.get_xaxis().set_visible(False) + # ax.get_legend().remove() + + plt.savefig('graph.png', transparent=True, bbox_inches='tight') + plt.draw() + plt.clf() + plt.close("all") + + await ctx.send(content=f"Player Count: **{df.iloc[-1]['Player Count']:,.0f}**\n{length_message}", file=discord.File('graph.png')) + else: + await ctx.send('No players :(') + + +bot.run(config.bot_token) \ No newline at end of file diff --git a/discord_bot/discord_bot_slash.py.bak b/discord_bot/discord_bot_slash.py.bak new file mode 100644 index 0000000..a096879 --- /dev/null +++ b/discord_bot/discord_bot_slash.py.bak @@ -0,0 +1,115 @@ +import requests +import io +import json +import interactions +import pandas as pd +import matplotlib.pyplot as plt +import config + +user_count_url = "http://velconnect2.ugavel.com/api/get_user_count" + +guild_ids = [706393774804303924, 630847214511587328] + + +bot = interactions.Client(config.bot_token) +bot.load('interactions.ext.files') +# bot.load('interactions.ext.enhanced') + + +@bot.event +async def on_ready(): + print("Ready!") + + +@bot.command( + name="convrged_count", + description="Shows a graph with the current user count in conVRged.", + scope=706393774804303924, + # options=[ + # interactions.Option( + # name="hours", + # description="Number of hours of history to include. The default is 24 hours.", + # option_type=interactions.OptionType.NUMBER, + # required=False + # ), + # ], +) +async def _convrged_count(ctx: interactions.CommandContext, hours: float = 24): + await ctx.defer() + data = get_user_count(hours) + + await post_graph(pd.DataFrame(data), ctx, f"Last {hours} hours:") + + +def get_user_count(graph_hours=24): + r = requests.get(user_count_url, params={'hours': graph_hours}) + + if r.status_code != 200: + return -1 + else: + return json.loads(r.text) + + +async def post_graph(df, ctx, length_message, scatter=False): + if len(df) > 0: + df['timestamp'] = pd.to_datetime(df['timestamp']) + df.columns = ['Time', 'Player Count'] + + df = df[df['Player Count'] >= 0] + + params = {"ytick.color": "w", + "xtick.color": "w", + "axes.labelcolor": "w", + "axes.edgecolor": "w"} + plt.rcParams.update(params) + fig = plt.figure(figsize=(7, 3), dpi=200) + ax = plt.axes() + plt.margins(x=0) + + if scatter: + plt.scatter(x=df['Time'], y=df['Player Count'], + alpha=.1, s=.5, c='w') + else: + df.plot(ax=ax, x='Time', y='Player Count', linewidth=3.0, c='w') + # ax.step(df['Time'], df['Player Count'], linewidth=3.0, c='w') + ax.get_legend().remove() + + ax.get_xaxis().set_visible(False) + # ax.get_legend().remove() + + plt.savefig('graph.png', transparent=True, bbox_inches='tight') + plt.draw() + plt.clf() + plt.close("all") + + with open('graph.png') as f: + await ctx.send(content=f"Player Count: **{df.iloc[-1]['Player Count']:,.0f}**\n{length_message}", files=interactions.File(filename='graph.png', fp=f)) + else: + await ctx.channel.send('No players :(') + + + + +@bot.command( + name="file", + description="Send a message as a text file", + scope = 706393774804303924, + options=[ + interactions.Option( + type=interactions.OptionType.STRING, + name="message", + description="Message", + required=True + ) + ] +) +async def _file(ctx: interactions.CommandContext, message: str): + file = io.StringIO(message) + with file as f: + file = interactions.File(filename="message.txt", fp=f) + await ctx.send(files=file) + + + + +bot.start() diff --git a/discord_bot/requirements.txt b/discord_bot/requirements.txt new file mode 100644 index 0000000..66ea3c5 --- /dev/null +++ b/discord_bot/requirements.txt @@ -0,0 +1,6 @@ +discord.py==1.7.3 +discord_py_slash_command==3.0.3 +fuzzywuzzy==0.18.0 +matplotlib==3.3.3 +pandas==1.1.3 +requests==2.25.1 diff --git a/discord_bot/velbot.service b/discord_bot/velbot.service new file mode 100644 index 0000000..a57fa6c --- /dev/null +++ b/discord_bot/velbot.service @@ -0,0 +1,11 @@ +[Unit] +Description=VEL Connect Discord Bot +After=multi-user.target + +[Service] +Type=simple +ExecStart=/home/ubuntu/VEL-Connect/discord_bot/env/bin/python /home/ubuntu/VEL-Connect/discord_bot/discord_bot.py +Restart=on-abort + +[Install] +WantedBy=multi-user.target \ No newline at end of file