New structure

This commit is contained in:
2025-04-21 13:50:51 +02:00
parent 1eba79cc5a
commit abe0cbb173
45 changed files with 10 additions and 50 deletions

View File

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

View File

@@ -0,0 +1,248 @@
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
from repositories.streamers import StreamerConfigRepository
logger = logging.getLogger(__name__)
async def get_game_list_channel_to_message_map() -> dict[int, int]:
result = {}
streamers = await StreamerConfigRepository.all()
for streamer in 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):
streamers = await StreamerConfigRepository.all()
for streamer in 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(description="Добавление игры")
@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
):
if not isinstance(interaction.channel, Messageable):
await interaction.response.send_message(
"Interation not allowed in this channel!", ephemeral=True
)
return
streamer = await StreamerConfigRepository.find_one(
integration_discord_guild_id=interaction.guild_id,
integration_discord_games_list_channel_id=interaction.channel_id
)
if streamer is None:
await interaction.response.send_message(
"Interation not allowed in this channel!", ephemeral=True
)
return
if streamer.integrations.discord is None or streamer.integrations.discord.games_list is None:
await interaction.response.send_message(
"Need setup!", ephemeral=True
)
return
game_list = await GameList.get(streamer.twitch.id)
if game_list is None:
await interaction.response.send_message(
"Game list not found!", ephemeral=True
)
return
game_list.add_game(category, GameItem(name=game, customer=customer, date=date))
game_list_message = await interaction.channel.fetch_message(
streamer.integrations.discord.games_list.message_id
)
await game_list_message.edit(content=str(game_list))
await game_list.save()
await interaction.response.send_message("Игра добавлена!", ephemeral=True)
async def game_list_autocomplete(
interaction: discord.Interaction,
current: str,
) -> list[app_commands.Choice[str]]:
streamer = await StreamerConfigRepository.find_one(
integration_discord_guild_id=interaction.guild_id,
integration_discord_games_list_channel_id=interaction.channel_id
)
if streamer is None:
return []
game_list = await GameList.get(streamer.twitch.id)
if game_list is None:
return []
return game_list.get_choices(current)
@client.tree.command(description="Удаление игры")
@app_commands.describe(game="Игра")
@app_commands.autocomplete(game=game_list_autocomplete)
async def delete(interaction: discord.Interaction, game: str):
if not isinstance(interaction.channel, Messageable):
await interaction.response.send_message(
"Interation not allowed in this channel!", ephemeral=True
)
return
streamer = await StreamerConfigRepository.find_one(
integration_discord_guild_id=interaction.guild_id,
integration_discord_games_list_channel_id=interaction.channel_id
)
if streamer is None:
await interaction.response.send_message(
"Interation not allowed in this channel!", ephemeral=True
)
return
if streamer.integrations.discord is None or streamer.integrations.discord.games_list is None:
await interaction.response.send_message(
"Need setup!", ephemeral=True
)
return
game_list = await GameList.get(streamer.twitch.id)
if game_list is None:
await interaction.response.send_message(
"Game list not found!", ephemeral=True
)
return
game_list.delete_game(game)
game_list_message = await interaction.channel.fetch_message(
streamer.integrations.discord.games_list.message_id
)
await game_list_message.edit(content=str(game_list))
await game_list.save()
await interaction.response.send_message("Игра удалена!", ephemeral=True)
@client.tree.command(description="Замена игры")
@app_commands.describe(
game="Старая игра",
new="Новая игра"
)
@app_commands.autocomplete(game=game_list_autocomplete)
async def replace(interaction: discord.Interaction, game: str, new: str):
if not isinstance(interaction.channel, Messageable):
await interaction.response.send_message(
"Interation not allowed in this channel!", ephemeral=True
)
return
streamer = await StreamerConfigRepository.find_one(
integration_discord_guild_id=interaction.guild_id,
integration_discord_games_list_channel_id=interaction.channel_id
)
if streamer is None:
await interaction.response.send_message(
"Interation not allowed in this channel!", ephemeral=True
)
return
if streamer.integrations.discord is None or streamer.integrations.discord.games_list is None:
await interaction.response.send_message(
"Need setup!", ephemeral=True
)
return
game_list = await GameList.get(streamer.twitch.id)
if game_list is None:
await interaction.response.send_message(
"Game list not found!", ephemeral=True
)
return
game_list.replace_game(game, new)
game_list_message = await interaction.channel.fetch_message(
streamer.integrations.discord.games_list.message_id
)
await game_list_message.edit(content=str(game_list))
await game_list.save()
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,115 @@
from typing import Self
from datetime import datetime
from discord import app_commands
from pydantic import BaseModel
from core.mongo import mongo_manager
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})"
class Category(BaseModel):
name: str
games: list[GameItem]
class GameList:
COLLECTION_NAME = "games_list_data"
CATEGORY_MAP = {
"points": "Заказанные игры (за 12к)",
"paids": "Проплачены 🤑 ",
"gifts": "Подарки",
}
def __init__(self, twitch_id: int, data: list[Category]):
self.twitch_id = twitch_id
self.data = data
@classmethod
async def get(cls, twitch_id: int) -> Self | None:
async with mongo_manager.connect() as client:
db = client.get_default_database()
collection = db[cls.COLLECTION_NAME]
doc = await collection.find_one({"twitch_id": twitch_id})
if doc is None:
return None
return cls(
twitch_id,
[
Category(**category)
for category in doc["data"]
]
)
async def save(self):
async with mongo_manager.connect() as client:
db = client.get_default_database()
collection = db[self.COLLECTION_NAME]
await collection.replace_one(
{"twitch_id": self.twitch_id},
{
"twitch_id": self.twitch_id,
"data": [category.model_dump() for category in self.data]
},
upsert=True
)
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 replace_game(self, game_name: str, new_game_name: str):
for category in self.data:
for game in category.games:
if game.name.startswith(game_name):
game.name = new_game_name
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 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]
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