This commit is contained in:
2024-11-17 01:48:35 +01:00
parent e54dd7e8e0
commit 3197a788f8
15 changed files with 42 additions and 22 deletions

View File

@@ -0,0 +1,7 @@
from .discord import start_discord_sevice
start = start_discord_sevice
__all__ = ["start"]

View 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)

View 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]