feat: добавить команду !cat и консольную команду pogoda
This commit is contained in:
parent
3f921680cf
commit
b8afbfa6b1
@ -1,4 +1,5 @@
|
||||
from .pogoda import Pogoda
|
||||
from .news import News
|
||||
from .cat import Cat
|
||||
|
||||
ALL_COMMANDS = [Pogoda, News]
|
||||
ALL_COMMANDS = [Pogoda, News, Cat]
|
||||
|
||||
28
commands/cat.py
Normal file
28
commands/cat.py
Normal file
@ -0,0 +1,28 @@
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import requests
|
||||
|
||||
|
||||
class Cat(commands.Cog):
|
||||
"""Команда !cat — случайный котик"""
|
||||
|
||||
@commands.command(name="cat")
|
||||
async def cat(self, ctx):
|
||||
"""Получить случайного котика"""
|
||||
try:
|
||||
response = requests.get(
|
||||
"https://api.thecatapi.com/v1/images/search",
|
||||
timeout=10
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
url = data[0]["url"]
|
||||
|
||||
embed = discord.Embed(
|
||||
title="🐱 Котик для тебя!",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
embed.set_image(url=url)
|
||||
await ctx.send(embed=embed)
|
||||
except requests.RequestException:
|
||||
await ctx.send("Не удалось получить котика. Попробуйте позже.")
|
||||
@ -1,7 +1,11 @@
|
||||
from .stop import stop
|
||||
from .news import news
|
||||
from .cat import cat
|
||||
from .pogoda import pogoda
|
||||
|
||||
ALL_CONSOLE_COMMANDS = {
|
||||
"stop": stop,
|
||||
"news": news,
|
||||
"cat": cat,
|
||||
"pogoda": pogoda,
|
||||
}
|
||||
|
||||
3
console_commands/cat.py
Normal file
3
console_commands/cat.py
Normal file
@ -0,0 +1,3 @@
|
||||
def cat(stop_event, bot):
|
||||
"""Заглушка: тут должен быть котик"""
|
||||
print("🐱 тут должен быть котик")
|
||||
168
console_commands/pogoda.py
Normal file
168
console_commands/pogoda.py
Normal file
@ -0,0 +1,168 @@
|
||||
import requests
|
||||
from requests.exceptions import ConnectionError, Timeout, SSLError
|
||||
|
||||
|
||||
def pogoda(stop_event, bot):
|
||||
"""Вывести прогноз погоды для Магнитогорска"""
|
||||
api_url = "https://wttr.in/Magnitogorsk?format=j1&lang=ru"
|
||||
data = _fetch_weather(api_url)
|
||||
|
||||
if data is None:
|
||||
print("Не удалось получить данные о погоде.")
|
||||
return
|
||||
|
||||
current = data.get("current_condition", [{}])[0]
|
||||
if not current:
|
||||
print("Не удалось получить данные о погоде.")
|
||||
return
|
||||
|
||||
temp = current.get("temp_C", "—")
|
||||
feels_like = current.get("FeelsLikeC", "—")
|
||||
description = _translate_weather(current.get("weatherDesc", [{}])[0].get("value", "—"))
|
||||
humidity = current.get("humidity", "—")
|
||||
wind_kmh = current.get("windspeedKmph", "—")
|
||||
try:
|
||||
wind = round(int(wind_kmh) / 3.6, 1) if wind_kmh != "—" else "—"
|
||||
except (ValueError, TypeError):
|
||||
wind = "—"
|
||||
pressure_mb = current.get("pressure", "—")
|
||||
pressure_mm = _pressure_to_mmhg(pressure_mb)
|
||||
|
||||
print(f"[TEMP] Температура: {temp}°C (ощущается как {feels_like}°C)")
|
||||
print(f"[DESC] Описание: {description}")
|
||||
print(f"[HUMID] Влажность: {humidity}%")
|
||||
print(f"[WIND] Ветер: {wind} м/с")
|
||||
print(f"[PRESS] Давление: {pressure_mm} мм рт. ст.")
|
||||
|
||||
|
||||
def _fetch_weather(url):
|
||||
"""Получить данные о погоде с retry и fallback."""
|
||||
# Пробуем wttr.in с retry
|
||||
for attempt in range(3):
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except (SSLError, ConnectionError, Timeout):
|
||||
if attempt < 2:
|
||||
continue
|
||||
break
|
||||
except requests.RequestException:
|
||||
return None
|
||||
|
||||
# Fallback: Open-Meteo API (без ключа, HTTPS)
|
||||
return _fetch_open_meteo()
|
||||
|
||||
|
||||
def _fetch_open_meteo():
|
||||
"""Fallback на Open-Meteo API."""
|
||||
url = (
|
||||
"https://api.open-meteo.com/v1/forecast?"
|
||||
"latitude=53.4069&longitude=58.9797¤t=temperature,"
|
||||
"apparent_temperature,weather_code,wind_speed_10m,"
|
||||
"relative_humidity_2m,pressure_msl&timezone=Asia/Chelyabinsk"
|
||||
)
|
||||
for attempt in range(3):
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
current = data.get("current", {})
|
||||
# weather_code WMO код → перевод (https://open-meteo.com/en/docs)
|
||||
weather_code = current.get("weather_code", None)
|
||||
desc = _wmo_to_russian(weather_code)
|
||||
return {
|
||||
"current_condition": [{
|
||||
"temp_C": current.get("temperature", "—"),
|
||||
"FeelsLikeC": current.get("apparent_temperature", "—"),
|
||||
"weatherDesc": [{"value": desc}],
|
||||
"humidity": current.get("relative_humidity_2m", "—"),
|
||||
"windspeedKmph": current.get("wind_speed_10m", "—"),
|
||||
"pressure": current.get("pressure_msl", "—"),
|
||||
}]
|
||||
}
|
||||
except (SSLError, ConnectionError, Timeout):
|
||||
if attempt < 2:
|
||||
continue
|
||||
break
|
||||
except requests.RequestException:
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _wmo_to_russian(code):
|
||||
"""Перевод WMO weather code в русский."""
|
||||
mapping = {
|
||||
0: "Ясно",
|
||||
1: "Ясно", 2: "Переменная облачность",
|
||||
3: "Пасмурно",
|
||||
45: "Туман", 48: "Туман",
|
||||
51: "Лёгкая морось", 53: "Морось", 55: "Сильная морось",
|
||||
56: "Ледяная морось", 57: "Сильная ледяная морось",
|
||||
61: "Небольшой дождь", 63: "Дождь", 65: "Сильный дождь",
|
||||
66: "Ледяной дождь", 67: "Сильный ледяной дождь",
|
||||
71: "Небольшой снег", 73: "Снег", 75: "Сильный снег",
|
||||
77: "Снежная крупа",
|
||||
80: "Небольшой ливень", 81: "Ливень", 82: "Сильный ливень",
|
||||
85: "Снежный ливень", 86: "Сильный снежный ливень",
|
||||
95: "Гроза", 96: "Гроза с градом", 99: "Сильная гроза с градом",
|
||||
}
|
||||
return mapping.get(code, "Неизвестно")
|
||||
|
||||
|
||||
def _translate_weather(en):
|
||||
if not en:
|
||||
return "—"
|
||||
mapping = {
|
||||
"Moderate or heavy freezing rain in area": "Ледяной дождь",
|
||||
"Moderate or heavy sleet in area": "Слякоть",
|
||||
"Moderate or heavy snow in area": "Снег",
|
||||
"Moderate or heavy rain in area": "Дождь",
|
||||
"Thundery outbreaks in nearby": "Гроза вблизи",
|
||||
"Patchy rain nearby": "Местами дождь",
|
||||
"Patchy snow nearby": "Местами снег",
|
||||
"Patchy sleet nearby": "Местами слякоть",
|
||||
"Heavy freezing rain": "Сильный ледяной дождь",
|
||||
"Heavy snow": "Сильный снег",
|
||||
"Heavy rain": "Сильный дождь",
|
||||
"Moderate or heavy rain at times": "Дождь",
|
||||
"Moderate or heavy snow at times": "Снег",
|
||||
"Blowing snow": "Метель",
|
||||
"Patchy light drizzle": "Местами лёгкая морось",
|
||||
"Moderate or heavy freezing rain at a distance": "Ледяной дождь",
|
||||
"Moderate or heavy sleet at a distance": "Слякоть",
|
||||
"Light rain shower": "Небольшой дождь",
|
||||
"Heavy rain shower": "Сильный дождь",
|
||||
"Moderate rain": "Умеренный дождь",
|
||||
"Light rain": "Небольшой дождь",
|
||||
"Moderate rain at times": "Умеренный дождь",
|
||||
"Heavy rain at times": "Сильный дождь",
|
||||
"Light snow": "Небольшой снег",
|
||||
"Moderate snow": "Умеренный снег",
|
||||
"Patchy light snow": "Местами лёгкий снег",
|
||||
"Partly cloudy": "Переменная облачность",
|
||||
"Moderate or light sleet": "Слякоть",
|
||||
"Light freezing rain": "Лёгкий ледяной дождь",
|
||||
"Foggy": "Туманно",
|
||||
"Fog": "Туман",
|
||||
"Mist": "Туман",
|
||||
"Haze": "Дымка",
|
||||
"Overcast": "Пасмурно",
|
||||
"Cloudy": "Облачно",
|
||||
"Clear": "Ясно",
|
||||
"Sunny": "Ясно",
|
||||
}
|
||||
for key, value in mapping.items():
|
||||
if key.lower() in en.lower():
|
||||
return value
|
||||
return en
|
||||
|
||||
|
||||
def _pressure_to_mmhg(mb):
|
||||
if mb == "—" or not mb:
|
||||
return "—"
|
||||
try:
|
||||
return round(float(mb) * 0.750062, 1)
|
||||
except (ValueError, TypeError):
|
||||
return "—"
|
||||
Loading…
x
Reference in New Issue
Block a user