mirror of
https://github.com/kurbezz/discord-bot.git
synced 2026-03-04 03:50:49 +01:00
Refactor
This commit is contained in:
7
src/modules/games_list/__init__.py
Normal file
7
src/modules/games_list/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .discord import start_discord_sevice
|
||||
|
||||
|
||||
start = start_discord_sevice
|
||||
|
||||
|
||||
__all__ = ["start"]
|
||||
161
src/modules/games_list/discord.py
Normal file
161
src/modules/games_list/discord.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import logging
|
||||
|
||||
import discord
|
||||
from discord.abc import Messageable
|
||||
from discord import Object
|
||||
from discord import app_commands
|
||||
|
||||
from modules.games_list.games_list import GameList, GameItem
|
||||
|
||||
from core.config import config
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_game_list_channel_to_message_map() -> dict[int, int]:
|
||||
result = {}
|
||||
|
||||
for streamer in config.STREAMERS:
|
||||
if (integration := streamer.integrations.discord) is None:
|
||||
continue
|
||||
|
||||
if (games_list := integration.games_list) is None:
|
||||
continue
|
||||
|
||||
if games_list.channel_id is None or games_list.message_id is None:
|
||||
continue
|
||||
|
||||
result[games_list.channel_id] = games_list.message_id
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class DiscordClient(discord.Client):
|
||||
def __init__(self) -> None:
|
||||
intents = discord.Intents.default()
|
||||
intents.message_content = True
|
||||
|
||||
super().__init__(intents=intents)
|
||||
|
||||
self.tree = app_commands.CommandTree(self)
|
||||
|
||||
async def setup_hook(self):
|
||||
for streamer in config.STREAMERS:
|
||||
if (integration := streamer.integrations.discord) is None:
|
||||
continue
|
||||
|
||||
if integration.games_list is None:
|
||||
continue
|
||||
|
||||
self.tree.copy_global_to(guild=Object(id=integration.guild_id))
|
||||
await self.tree.sync(guild=Object(id=integration.guild_id))
|
||||
|
||||
async def on_ready(self):
|
||||
await self.change_presence(
|
||||
activity=discord.Game(config.DISCORD_BOT_ACTIVITY),
|
||||
status=discord.Status.online,
|
||||
)
|
||||
|
||||
|
||||
client = DiscordClient()
|
||||
|
||||
|
||||
@client.tree.command()
|
||||
@app_commands.describe(
|
||||
category="Раздел",
|
||||
customer="Кто заказал",
|
||||
game="Игра",
|
||||
date="Дата заказа"
|
||||
)
|
||||
@app_commands.choices(
|
||||
category=[
|
||||
app_commands.Choice(name="Заказ за баллы", value="points"),
|
||||
app_commands.Choice(name="Проплачены", value="paids"),
|
||||
app_commands.Choice(name="Подарки", value="gifts"),
|
||||
],
|
||||
)
|
||||
async def add(
|
||||
interaction: discord.Interaction,
|
||||
category: str,
|
||||
customer: str,
|
||||
game: str,
|
||||
date: str | None = None
|
||||
):
|
||||
channel_to_message = get_game_list_channel_to_message_map()
|
||||
|
||||
if interaction.channel is None:
|
||||
await interaction.response.send_message("Команда не доступна в этом канале (#1)", ephemeral=True)
|
||||
return
|
||||
|
||||
message_id = channel_to_message.get(interaction.channel.id)
|
||||
if message_id is None:
|
||||
await interaction.response.send_message("Команда не доступна в этом канале (#3)", ephemeral=True)
|
||||
return
|
||||
|
||||
if not isinstance(interaction.channel, Messageable):
|
||||
await interaction.response.send_message("Команда не доступна в этом канале (#2)", ephemeral=True)
|
||||
return
|
||||
|
||||
game_list_message = await interaction.channel.fetch_message(message_id)
|
||||
|
||||
game_list = GameList.parse(game_list_message.content)
|
||||
game_list.add_game(category, GameItem(name=game, customer=customer, date=date))
|
||||
|
||||
await game_list_message.edit(content=str(game_list))
|
||||
|
||||
await interaction.response.send_message("Игра добавлена!", ephemeral=True)
|
||||
|
||||
|
||||
async def game_list_autocomplete(
|
||||
interaction: discord.Interaction,
|
||||
current: str,
|
||||
) -> list[app_commands.Choice[str]]:
|
||||
if not isinstance(interaction.channel, Messageable):
|
||||
return []
|
||||
|
||||
channel_to_message = get_game_list_channel_to_message_map()
|
||||
message_id = channel_to_message.get(interaction.channel.id)
|
||||
if message_id is None:
|
||||
return []
|
||||
|
||||
game_list_message = await interaction.channel.fetch_message(message_id)
|
||||
|
||||
game_list = GameList.parse(game_list_message.content)
|
||||
|
||||
return game_list.get_choices(current)
|
||||
|
||||
|
||||
@client.tree.command()
|
||||
@app_commands.describe(game="Игра")
|
||||
@app_commands.autocomplete(game=game_list_autocomplete)
|
||||
async def delete(interaction: discord.Interaction, game: str):
|
||||
channel_to_message = get_game_list_channel_to_message_map()
|
||||
|
||||
if interaction.channel is None:
|
||||
await interaction.response.send_message("Команда не доступна в этом канале (#1)", ephemeral=True)
|
||||
return
|
||||
|
||||
message_id = channel_to_message.get(interaction.channel.id)
|
||||
if message_id is None:
|
||||
await interaction.response.send_message("Команда не доступна в этом канале (#3)", ephemeral=True)
|
||||
return
|
||||
|
||||
if not isinstance(interaction.channel, Messageable):
|
||||
await interaction.response.send_message("Команда не доступна в этом канале (#2)", ephemeral=True)
|
||||
return
|
||||
|
||||
game_list_message = await interaction.channel.fetch_message(message_id)
|
||||
|
||||
game_list = GameList.parse(game_list_message.content)
|
||||
game_list.delete_game(game)
|
||||
|
||||
await game_list_message.edit(content=str(game_list))
|
||||
|
||||
await interaction.response.send_message("Игра удалена!", ephemeral=True)
|
||||
|
||||
|
||||
async def start_discord_sevice():
|
||||
logger.info("Starting Discord service...")
|
||||
|
||||
await client.start(config.DISCORD_BOT_TOKEN)
|
||||
103
src/modules/games_list/games_list.py
Normal file
103
src/modules/games_list/games_list.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from typing import Self
|
||||
from datetime import datetime
|
||||
import re
|
||||
|
||||
from discord import app_commands
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class GameItem(BaseModel):
|
||||
name: str
|
||||
customer: str
|
||||
date: str | None
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.date is not None:
|
||||
return f"* {self.name} ({self.customer}) | {self.date}"
|
||||
else:
|
||||
return f"* {self.name} ({self.customer})"
|
||||
|
||||
@classmethod
|
||||
def parse(cls, line: str) -> Self:
|
||||
regex_result_with_date = re.search(r"^\* (.+) \((.+)\) \| (.+)$", line)
|
||||
if regex_result_with_date is not None:
|
||||
name, customer, date = regex_result_with_date.groups()
|
||||
return cls(name=name, customer=customer, date=date)
|
||||
|
||||
regex_result_without_date = re.search(r"^\* (.+) \((.+)\)$", line)
|
||||
if regex_result_without_date is not None:
|
||||
name, customer = regex_result_without_date.groups()
|
||||
return cls(name=name, customer=customer, date=None)
|
||||
|
||||
raise ValueError(f"Invalid line: {line}")
|
||||
|
||||
|
||||
class Category(BaseModel):
|
||||
name: str
|
||||
games: list[GameItem]
|
||||
|
||||
|
||||
class GameList:
|
||||
CATEGORY_MAP = {
|
||||
"points": "Заказанные игры (за 12к)",
|
||||
"paids": "Проплачены 🤑 ",
|
||||
"gifts": "Подарки",
|
||||
}
|
||||
|
||||
def __init__(self, data: list[Category]):
|
||||
self.data = data
|
||||
|
||||
@classmethod
|
||||
def parse(cls, message: str) -> Self:
|
||||
categories = []
|
||||
|
||||
for line in message.split("\n"):
|
||||
if line == "".strip():
|
||||
continue
|
||||
|
||||
if not line.startswith("*"):
|
||||
name = line.replace(":", "")
|
||||
categories.append(Category(name=name, games=[]))
|
||||
else:
|
||||
categories[-1].games.append(GameItem.parse(line.strip()))
|
||||
|
||||
return cls(data=categories)
|
||||
|
||||
def add_game(self, category: str, game_item: GameItem):
|
||||
_category = self.CATEGORY_MAP.get(category)
|
||||
|
||||
if game_item.date is None:
|
||||
game_item.date = datetime.now().strftime("%d.%m.%Y")
|
||||
|
||||
for category_item in self.data:
|
||||
if category_item.name == _category:
|
||||
category_item.games.append(game_item)
|
||||
|
||||
def delete_game(self, game_name: str):
|
||||
for category in self.data:
|
||||
for game in category.games:
|
||||
if game.name.startswith(game_name):
|
||||
category.games.remove(game)
|
||||
|
||||
def __str__(self) -> str:
|
||||
result = ""
|
||||
|
||||
for category in self.data:
|
||||
result += f"{category.name}:\n"
|
||||
|
||||
for game in category.games:
|
||||
result += f"{game}\n"
|
||||
|
||||
result += "\n\n"
|
||||
|
||||
return result
|
||||
|
||||
def get_choices(self, query: str) -> list[app_commands.Choice[str]]:
|
||||
choices = []
|
||||
|
||||
for category in self.data:
|
||||
for game in category.games:
|
||||
if query.lower() in game.name.lower():
|
||||
choices.append(app_commands.Choice(name=game.name, value=game.name))
|
||||
|
||||
return choices[:25]
|
||||
Reference in New Issue
Block a user