mirror of
https://github.com/kurbezz/discord-bot.git
synced 2025-12-08 09:30:44 +01:00
New structure
This commit is contained in:
7
src/applications/games_list/__init__.py
Normal file
7
src/applications/games_list/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .discord import start_discord_sevice
|
||||
|
||||
|
||||
start = start_discord_sevice
|
||||
|
||||
|
||||
__all__ = ["start"]
|
||||
248
src/applications/games_list/discord.py
Normal file
248
src/applications/games_list/discord.py
Normal 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)
|
||||
115
src/applications/games_list/games_list.py
Normal file
115
src/applications/games_list/games_list.py
Normal 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
|
||||
Reference in New Issue
Block a user