Refactor: add commands/, console_commands/, !pogoda command
This commit is contained in:
parent
83fc714b8e
commit
89f17d53d8
22
AGENTS.md
22
AGENTS.md
@ -1,7 +1,7 @@
|
|||||||
# AGENTS.md
|
# AGENTS.md
|
||||||
|
|
||||||
## Проект
|
## Проект
|
||||||
Discord-бот на Python (discord.py). Команда `!msg <текст>` повторяет текст.
|
Discord-бот на Python (discord.py). Команды: `!msg` (повтор текста), `!pogoda` (прогноз погоды для Магнитогорска).
|
||||||
|
|
||||||
## Запуск
|
## Запуск
|
||||||
```
|
```
|
||||||
@ -16,3 +16,23 @@ python bot.py
|
|||||||
|
|
||||||
## Конвенции
|
## Конвенции
|
||||||
Используй TODO-списки для каждого запроса с несколькими шагами.
|
Используй TODO-списки для каждого запроса с несколькими шагами.
|
||||||
|
|
||||||
|
## Архитектура
|
||||||
|
```
|
||||||
|
commands/ # Discord команды (cogs)
|
||||||
|
__init__.py # ALL_COMMANDS — явные импорты
|
||||||
|
pogoda.py # !pogoda
|
||||||
|
console_commands/ # Консольные команды
|
||||||
|
__init__.py # ALL_CONSOLE_COMMANDS — явные импорты
|
||||||
|
stop.py # stop
|
||||||
|
```
|
||||||
|
|
||||||
|
**Добавление Discord команды:**
|
||||||
|
1. Создать файл `commands/имя.py` с классом, наследующим `commands.Cog`
|
||||||
|
2. Добавить импорт в `commands/__init__.py`
|
||||||
|
3. Добавить класс в `ALL_COMMANDS`
|
||||||
|
|
||||||
|
**Добавление консольной команды:**
|
||||||
|
1. Создать файл `console_commands/имя.py` с функцией
|
||||||
|
2. Добавить импорт в `console_commands/__init__.py`
|
||||||
|
3. Добавить функцию в `ALL_CONSOLE_COMMANDS`
|
||||||
|
|||||||
21
bot.py
21
bot.py
@ -7,6 +7,8 @@ import discord
|
|||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from commands import ALL_COMMANDS
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
@ -19,6 +21,11 @@ stop_event = threading.Event()
|
|||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
print(f"Бот вошёл как {bot.user}")
|
print(f"Бот вошёл как {bot.user}")
|
||||||
|
for cog_class in ALL_COMMANDS:
|
||||||
|
cog = cog_class()
|
||||||
|
await bot.add_cog(cog)
|
||||||
|
for cog in bot.cogs:
|
||||||
|
print(f" Загружен: {cog}")
|
||||||
|
|
||||||
|
|
||||||
@bot.command(name="msg")
|
@bot.command(name="msg")
|
||||||
@ -34,13 +41,19 @@ def console_input():
|
|||||||
if cmd == "stop":
|
if cmd == "stop":
|
||||||
print("\nОстановка бота...")
|
print("\nОстановка бота...")
|
||||||
stop_event.set()
|
stop_event.set()
|
||||||
asyncio.run_coroutine_threadsafe(bot.close(), bot.loop)
|
try:
|
||||||
|
bot.loop.stop()
|
||||||
|
except (AttributeError, RuntimeError):
|
||||||
|
pass
|
||||||
break
|
break
|
||||||
elif cmd:
|
elif cmd:
|
||||||
print(f"Неизвестная команда: {cmd}")
|
print(f"Неизвестная команда: {cmd}")
|
||||||
except EOFError:
|
except EOFError:
|
||||||
stop_event.set()
|
stop_event.set()
|
||||||
asyncio.run_coroutine_threadsafe(bot.close(), bot.loop)
|
try:
|
||||||
|
bot.loop.stop()
|
||||||
|
except (AttributeError, RuntimeError):
|
||||||
|
pass
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@ -58,5 +71,9 @@ if __name__ == "__main__":
|
|||||||
bot.run(token)
|
bot.run(token)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nОстановка бота...")
|
print("\nОстановка бота...")
|
||||||
|
try:
|
||||||
bot.loop.stop()
|
bot.loop.stop()
|
||||||
|
except (AttributeError, RuntimeError):
|
||||||
|
pass
|
||||||
stop_event.set()
|
stop_event.set()
|
||||||
|
sys.exit(0)
|
||||||
|
|||||||
3
commands/__init__.py
Normal file
3
commands/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from .pogoda import Pogoda
|
||||||
|
|
||||||
|
ALL_COMMANDS = [Pogoda]
|
||||||
BIN
commands/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
commands/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/pogoda.cpython-314.pyc
Normal file
BIN
commands/__pycache__/pogoda.cpython-314.pyc
Normal file
Binary file not shown.
87
commands/pogoda.py
Normal file
87
commands/pogoda.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Pogoda(commands.Cog):
|
||||||
|
"""Команда !pogoda — прогноз погоды для Магнитогорска"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.api_url = "https://api.open-meteo.com/v1/forecast"
|
||||||
|
self.lat = 53.41
|
||||||
|
self.lon = 59.06
|
||||||
|
|
||||||
|
@commands.command(name="pogoda")
|
||||||
|
async def pogoda(self, ctx):
|
||||||
|
params = {
|
||||||
|
"latitude": self.lat,
|
||||||
|
"longitude": self.lon,
|
||||||
|
"current": "temperature_2m,weather_code,relative_humidity_2m,wind_speed_10m,pressure_msl",
|
||||||
|
"timezone": "Asia/Yekaterinburg",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(self.api_url, params=params, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
except requests.RequestException as e:
|
||||||
|
await ctx.send(f"Ошибка при получении данных: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
current = data.get("current", {})
|
||||||
|
if not current:
|
||||||
|
await ctx.send("Не удалось получить данные о погоде.")
|
||||||
|
return
|
||||||
|
|
||||||
|
temp = current.get("temperature_2m", "—")
|
||||||
|
weather_code = current.get("weather_code", "—")
|
||||||
|
humidity = current.get("relative_humidity_2m", "—")
|
||||||
|
wind = current.get("wind_speed_10m", "—")
|
||||||
|
pressure = current.get("pressure_msl", "—")
|
||||||
|
|
||||||
|
description = self._get_weather_description(weather_code)
|
||||||
|
pressure_mm = self._pressure_to_mmhg(pressure)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
f"🌡 Температура: {temp}°C\n"
|
||||||
|
f"📝 Описание: {description}\n"
|
||||||
|
f"💧 Влажность: {humidity}%\n"
|
||||||
|
f"💨 Ветер: {wind} км/ч\n"
|
||||||
|
f"🌍 Давление: {pressure_mm} мм рт. ст."
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_weather_description(self, code):
|
||||||
|
descriptions = {
|
||||||
|
0: "Ясно",
|
||||||
|
1: "Преимущественно ясно",
|
||||||
|
2: "Переменная облачность",
|
||||||
|
3: "Пасмурно",
|
||||||
|
45: "Туман",
|
||||||
|
48: "Изморозь",
|
||||||
|
51: "Лёгкая морось",
|
||||||
|
53: "Морось",
|
||||||
|
55: "Сильная морось",
|
||||||
|
61: "Небольшой дождь",
|
||||||
|
63: "Дождь",
|
||||||
|
65: "Сильный дождь",
|
||||||
|
66: "Ледяной дождь",
|
||||||
|
67: "Сильный ледяной дождь",
|
||||||
|
71: "Небольшой снег",
|
||||||
|
73: "Снег",
|
||||||
|
75: "Сильный снег",
|
||||||
|
77: "Снежная крупа",
|
||||||
|
80: "Небольшой ливень",
|
||||||
|
81: "Ливень",
|
||||||
|
82: "Сильный ливень",
|
||||||
|
85: "Небольшой снегопад",
|
||||||
|
86: "Сильный снегопад",
|
||||||
|
95: "Гроза",
|
||||||
|
96: "Гроза с градом",
|
||||||
|
99: "Сильная гроза с градом",
|
||||||
|
}
|
||||||
|
return descriptions.get(code, "Неизвестно")
|
||||||
|
|
||||||
|
def _pressure_to_mmhg(self, hpa):
|
||||||
|
if hpa == "—":
|
||||||
|
return "—"
|
||||||
|
return round(hpa * 0.750062, 1)
|
||||||
5
console_commands/__init__.py
Normal file
5
console_commands/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from .stop import stop
|
||||||
|
|
||||||
|
ALL_CONSOLE_COMMANDS = {
|
||||||
|
"stop": stop,
|
||||||
|
}
|
||||||
3
console_commands/stop.py
Normal file
3
console_commands/stop.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
def stop(stop_event):
|
||||||
|
"""Остановка бота"""
|
||||||
|
pass
|
||||||
@ -1,2 +1,3 @@
|
|||||||
discord.py>=2.3.2
|
discord.py>=2.3.2
|
||||||
python-dotenv>=1.0.0
|
python-dotenv>=1.0.0
|
||||||
|
requests>=2.31.0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user