forked from zovos/bot_tg
Compare commits
No commits in common. "4ecc25239e3f567bf69bdd7fc79f22c8fa134a03" and "aee53349b13aa74afac12ef77b6287a35d6135ce" have entirely different histories.
4ecc25239e
...
aee53349b1
5 changed files with 42 additions and 259 deletions
|
|
@ -56,7 +56,7 @@ docker compose down
|
||||||
- `/gadanie <тема>` — ИИ-гадание на фене + авто-мем.
|
- `/gadanie <тема>` — ИИ-гадание на фене + авто-мем.
|
||||||
- `/ebalnik` — вкл/выкл авто-ответы бота в чате.
|
- `/ebalnik` — вкл/выкл авто-ответы бота в чате.
|
||||||
- `/matches [cs|dota|football]` — ближайшие матчи с коэффициентами.
|
- `/matches [cs|dota|football]` — ближайшие матчи с коэффициентами.
|
||||||
- `/bet [спорт] <номер> <исход> <ставка>` — поставить см на матч.
|
- `/bet <спорт> <номер> <команда> <ставка>` — поставить см на матч.
|
||||||
- `/mybets` — мои активные ставки.
|
- `/mybets` — мои активные ставки.
|
||||||
- `/svodka` — сводка СВО.
|
- `/svodka` — сводка СВО.
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ docker compose down
|
||||||
- `/talk` шлёт запрос к llama.cpp серверу с контекстом 100 сообщений (хранятся в SQLite).
|
- `/talk` шлёт запрос к llama.cpp серверу с контекстом 100 сообщений (хранятся в SQLite).
|
||||||
- `/penis_casino` — слоты с множителем x1.2–x3 (`games/casino.py`).
|
- `/penis_casino` — слоты с множителем x1.2–x3 (`games/casino.py`).
|
||||||
- `/gadanie` — ИИ-гадание + авто-мем через `generate_meme` (`games/fortune.py`).
|
- `/gadanie` — ИИ-гадание + авто-мем через `generate_meme` (`games/fortune.py`).
|
||||||
- `/matches` + `/bet` — ставки на реальные матчи, коэффициенты через The-Odds-API (`games/betting.py`). После `/matches cs|dota|football` можно короче: `/bet <номер> <исход> <ставка>`.
|
- `/matches` + `/bet` — ставки на реальные матчи, коэффициенты через The-Odds-API (`games/betting.py`).
|
||||||
|
|
||||||
## ИИ-модуль (`AI/talk_handler.py`)
|
## ИИ-модуль (`AI/talk_handler.py`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,6 @@ POLYCHAETSI_IMAGE_PATH = BASE_DIR / "maket" / "cvetok.jpg"
|
||||||
# --- Казино ---
|
# --- Казино ---
|
||||||
CASINO_MAX_BET = 1.0
|
CASINO_MAX_BET = 1.0
|
||||||
|
|
||||||
# --- E621 API ---
|
|
||||||
E621_LOGIN = os.getenv("E621_LOGIN", "")
|
|
||||||
E621_API_KEY = os.getenv("E621_API_KEY", "")
|
|
||||||
|
|
||||||
# --- Ставки на матчи ---
|
# --- Ставки на матчи ---
|
||||||
ODDS_API_KEY = os.getenv("ODDS_API_KEY", "")
|
ODDS_API_KEY = os.getenv("ODDS_API_KEY", "")
|
||||||
ODDS_API_BASE = "https://api.the-odds-api.com/v4"
|
ODDS_API_BASE = "https://api.the-odds-api.com/v4"
|
||||||
|
|
@ -210,10 +206,9 @@ def get_hint_text(templates_str: str) -> str:
|
||||||
"• /penis_casino [ставка] — казино на размер.\n"
|
"• /penis_casino [ставка] — казино на размер.\n"
|
||||||
"• /gadanie [тема] — гадание на фене с мемом.\n"
|
"• /gadanie [тема] — гадание на фене с мемом.\n"
|
||||||
"• /matches [cs|dota|football] — матчи для ставок.\n"
|
"• /matches [cs|dota|football] — матчи для ставок.\n"
|
||||||
"• /bet [спорт] [номер] [исход] [ставка] — поставить см.\n"
|
"• /bet <спорт> <номер> <команда> <ставка> — поставить см.\n"
|
||||||
"• /mybets — мои ставки.\n"
|
"• /mybets — мои ставки.\n"
|
||||||
"• /ebalnik — включить/выключить автоответы в чате.\n"
|
"• /ebalnik — включить/выключить автоответы в чате.\n"
|
||||||
"• /uwu [теги] — случайная картинка с e621.\n"
|
|
||||||
"• /polychaetsi — топ по слову «получается».\n"
|
"• /polychaetsi — топ по слову «получается».\n"
|
||||||
"• /prices /fetch — цены и остатки Магнита.\n"
|
"• /prices /fetch — цены и остатки Магнита.\n"
|
||||||
"Подсказка: в группах пиши /команда@username_бота."
|
"Подсказка: в группах пиши /команда@username_бота."
|
||||||
|
|
|
||||||
116
games/betting.py
116
games/betting.py
|
|
@ -13,8 +13,6 @@ from games.casino import get_user_length, update_user_length
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_matches_cache: dict[str, tuple[float, list]] = {}
|
_matches_cache: dict[str, tuple[float, list]] = {}
|
||||||
_last_viewed_sport_by_user: dict[int, str] = {}
|
|
||||||
_DRAW_NAMES = {"draw", "tie", "ничья"}
|
|
||||||
|
|
||||||
|
|
||||||
def _init_bets_db() -> None:
|
def _init_bets_db() -> None:
|
||||||
|
|
@ -45,19 +43,6 @@ def _init_bets_db() -> None:
|
||||||
_init_bets_db()
|
_init_bets_db()
|
||||||
|
|
||||||
|
|
||||||
def remember_user_sport_context(user_id: int, sport_alias: str) -> None:
|
|
||||||
if sport_alias in config.ODDS_SPORTS:
|
|
||||||
_last_viewed_sport_by_user[user_id] = sport_alias
|
|
||||||
|
|
||||||
|
|
||||||
def clear_user_sport_context(user_id: int) -> None:
|
|
||||||
_last_viewed_sport_by_user.pop(user_id, None)
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_sport_context(user_id: int) -> str | None:
|
|
||||||
return _last_viewed_sport_by_user.get(user_id)
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_matches(sport_key: str) -> list[dict]:
|
async def fetch_matches(sport_key: str) -> list[dict]:
|
||||||
now = _time.time()
|
now = _time.time()
|
||||||
cached = _matches_cache.get(sport_key)
|
cached = _matches_cache.get(sport_key)
|
||||||
|
|
@ -111,87 +96,16 @@ async def fetch_matches(sport_key: str) -> list[dict]:
|
||||||
return matches
|
return matches
|
||||||
|
|
||||||
|
|
||||||
def _get_match_outcomes(match: dict) -> list[dict[str, str | float]]:
|
def format_matches(matches: list[dict], sport_label: str) -> str:
|
||||||
odds = match.get("odds", {})
|
|
||||||
outcomes: list[dict[str, str | float]] = []
|
|
||||||
added: set[str] = set()
|
|
||||||
|
|
||||||
def append_outcome(code: str, name: str) -> None:
|
|
||||||
if name in odds and name not in added:
|
|
||||||
outcomes.append({"code": code, "name": name, "odds": odds[name]})
|
|
||||||
added.add(name)
|
|
||||||
|
|
||||||
home = match.get("home", "")
|
|
||||||
away = match.get("away", "")
|
|
||||||
append_outcome("1", home)
|
|
||||||
|
|
||||||
draw_name = next((name for name in odds if name.casefold() in _DRAW_NAMES), None)
|
|
||||||
if draw_name:
|
|
||||||
append_outcome("X", draw_name)
|
|
||||||
|
|
||||||
append_outcome("2", away)
|
|
||||||
|
|
||||||
next_code = 3
|
|
||||||
for name in odds:
|
|
||||||
if name in added:
|
|
||||||
continue
|
|
||||||
append_outcome(str(next_code), name)
|
|
||||||
next_code += 1
|
|
||||||
|
|
||||||
return outcomes
|
|
||||||
|
|
||||||
|
|
||||||
def describe_match_outcomes(match: dict) -> str:
|
|
||||||
return ", ".join(
|
|
||||||
f"{item['code']}={item['name']} x{item['odds']:.2f}"
|
|
||||||
for item in _get_match_outcomes(match)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_match_outcome(match: dict, raw_choice: str) -> str | None:
|
|
||||||
choice = raw_choice.strip()
|
|
||||||
if not choice:
|
|
||||||
return None
|
|
||||||
|
|
||||||
normalized = choice.casefold()
|
|
||||||
outcomes = _get_match_outcomes(match)
|
|
||||||
|
|
||||||
for item in outcomes:
|
|
||||||
if normalized == str(item["code"]).casefold():
|
|
||||||
return str(item["name"])
|
|
||||||
|
|
||||||
if normalized in _DRAW_NAMES or normalized == "x":
|
|
||||||
for item in outcomes:
|
|
||||||
if str(item["code"]).casefold() == "x":
|
|
||||||
return str(item["name"])
|
|
||||||
|
|
||||||
for item in outcomes:
|
|
||||||
if normalized == str(item["name"]).casefold():
|
|
||||||
return str(item["name"])
|
|
||||||
|
|
||||||
try:
|
|
||||||
choice_odds = round(float(choice.replace(",", ".")), 2)
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
for item in outcomes:
|
|
||||||
if round(float(item["odds"]), 2) == choice_odds:
|
|
||||||
return str(item["name"])
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def format_matches(matches: list[dict], sport_alias: str, sport_label: str) -> str:
|
|
||||||
if not matches:
|
if not matches:
|
||||||
return f"🏟 {sport_label} [{sport_alias}] — матчей не найдено."
|
return f"🏟 {sport_label} — матчей не найдено."
|
||||||
|
|
||||||
lines = [f"🏟 {sport_label} [{sport_alias}] — ближайшие матчи:\n"]
|
lines = [f"🏟 {sport_label} — ближайшие матчи:\n"]
|
||||||
for i, m in enumerate(matches[:10], 1):
|
for i, m in enumerate(matches[:10], 1):
|
||||||
outcomes = _get_match_outcomes(m)
|
odds_parts = []
|
||||||
odds_str = "\n".join(
|
for team, coeff in m["odds"].items():
|
||||||
f" {item['code']}) {item['name']}: {item['odds']:.2f}"
|
odds_parts.append(f"{team}: {coeff:.2f}")
|
||||||
for item in outcomes
|
odds_str = " | ".join(odds_parts)
|
||||||
)
|
|
||||||
|
|
||||||
start_str = ""
|
start_str = ""
|
||||||
if m["commence"]:
|
if m["commence"]:
|
||||||
|
|
@ -202,11 +116,9 @@ def format_matches(matches: list[dict], sport_alias: str, sport_label: str) -> s
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
lines.append(f"{i}️⃣ {m['home']} vs {m['away']}{start_str}\n{odds_str}\n")
|
lines.append(f"{i}️⃣ {m['home']} vs {m['away']}\n {odds_str}{start_str}\n")
|
||||||
|
|
||||||
lines.append(f"Ставка: /bet {sport_alias} [номер] [исход] [ставка]")
|
lines.append("Ставка: /bet <номер> <команда> <сумма>")
|
||||||
lines.append(f"Коротко после /matches {sport_alias}: /bet [номер] [исход] [ставка]")
|
|
||||||
lines.append("Исход: 1/2, для ничьи X. Можно писать ещё название команды или коэффициент.")
|
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -219,15 +131,18 @@ async def get_formatted_matches(sport_alias: str | None) -> str:
|
||||||
if sport_alias and sport_alias in config.ODDS_SPORTS:
|
if sport_alias and sport_alias in config.ODDS_SPORTS:
|
||||||
sport_key = config.ODDS_SPORTS[sport_alias]
|
sport_key = config.ODDS_SPORTS[sport_alias]
|
||||||
matches = await fetch_matches(sport_key)
|
matches = await fetch_matches(sport_key)
|
||||||
return format_matches(matches, sport_alias, _get_sport_label(sport_alias))
|
return format_matches(matches, _get_sport_label(sport_alias))
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
for alias, sport_key in config.ODDS_SPORTS.items():
|
for alias, sport_key in config.ODDS_SPORTS.items():
|
||||||
matches = await fetch_matches(sport_key)
|
matches = await fetch_matches(sport_key)
|
||||||
parts.append(format_matches(matches, alias, _get_sport_label(alias)))
|
parts.append(format_matches(matches, _get_sport_label(alias)))
|
||||||
return "\n\n".join(parts)
|
return "\n\n".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
_last_fetched_matches: dict[str, list[dict]] = {}
|
||||||
|
|
||||||
|
|
||||||
async def get_match_by_index(sport_alias: str, index: int) -> dict | None:
|
async def get_match_by_index(sport_alias: str, index: int) -> dict | None:
|
||||||
sport_key = config.ODDS_SPORTS.get(sport_alias)
|
sport_key = config.ODDS_SPORTS.get(sport_alias)
|
||||||
if not sport_key:
|
if not sport_key:
|
||||||
|
|
@ -257,7 +172,8 @@ def place_bet(user_id: int, match: dict, sport: str, chosen_team: str, amount: f
|
||||||
|
|
||||||
team_odds = match["odds"].get(chosen_team)
|
team_odds = match["odds"].get(chosen_team)
|
||||||
if team_odds is None:
|
if team_odds is None:
|
||||||
return f"Исход не найден. Доступные: {describe_match_outcomes(match)}"
|
available = ", ".join(match["odds"].keys())
|
||||||
|
return f"Команда не найдена. Доступные: {available}"
|
||||||
|
|
||||||
new_length = update_user_length(user_id, -amount)
|
new_length = update_user_length(user_id, -amount)
|
||||||
if new_length is None:
|
if new_length is None:
|
||||||
|
|
|
||||||
68
games/uwu.py
68
games/uwu.py
|
|
@ -1,68 +0,0 @@
|
||||||
import aiohttp
|
|
||||||
from aiogram import types
|
|
||||||
import config
|
|
||||||
import logging
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
async def handle_uwu_cmd(message: types.Message):
|
|
||||||
args = message.text.split(maxsplit=1)
|
|
||||||
|
|
||||||
if len(args) > 1 and args[1].strip() == "-h":
|
|
||||||
help_msg = (
|
|
||||||
"🐈 <b>Справка по тегам e621:</b>\n\n"
|
|
||||||
"Перечислите любые теги через пробел после команды.\n"
|
|
||||||
"• <b>rating</b>: <code>rating:safe</code> (безопасные), <code>rating:questionable</code>, <code>rating:explicit</code> (NSFW)\n"
|
|
||||||
"• <b>score</b>: <code>score:>500</code> (искать популярные посты с рейтингом больше 500)\n"
|
|
||||||
"• Исключить тег: поставьте минус, например <code>-fox</code>\n\n"
|
|
||||||
"<i>Пример:</i> <code>/uwu wolf -rating:explicit score:>100</code>\n"
|
|
||||||
"<i>По умолчанию:</i> <code>rating:safe score:>500</code>"
|
|
||||||
)
|
|
||||||
await message.reply(help_msg, parse_mode="HTML")
|
|
||||||
return
|
|
||||||
|
|
||||||
tags = "rating:safe score:>500"
|
|
||||||
if len(args) > 1:
|
|
||||||
tags = args[1].strip()
|
|
||||||
|
|
||||||
tags += " order:random"
|
|
||||||
|
|
||||||
url = "https://e621.net/posts.json"
|
|
||||||
params = {
|
|
||||||
"tags": tags,
|
|
||||||
"limit": 1
|
|
||||||
}
|
|
||||||
|
|
||||||
auth = None
|
|
||||||
if config.E621_LOGIN and config.E621_API_KEY:
|
|
||||||
auth = aiohttp.BasicAuth(config.E621_LOGIN, config.E621_API_KEY)
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"User-Agent": f"Sex Bomba TG Bot/1.0 (by {config.E621_LOGIN or 'unknown'} on e621)"
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
async with aiohttp.ClientSession() as session:
|
|
||||||
async with session.get(url, params=params, headers=headers, auth=auth) as resp:
|
|
||||||
if resp.status != 200:
|
|
||||||
logger.error(f"e621 API Error: {resp.status}")
|
|
||||||
await message.reply("Не удалось получить картинку от сервера :(")
|
|
||||||
return
|
|
||||||
data = await resp.json()
|
|
||||||
|
|
||||||
posts = data.get("posts", [])
|
|
||||||
if not posts:
|
|
||||||
await message.reply("Ничего не найдено по этим тегам :(")
|
|
||||||
return
|
|
||||||
|
|
||||||
post = posts[0]
|
|
||||||
file_url = post.get("file", {}).get("url")
|
|
||||||
if not file_url:
|
|
||||||
await message.reply("У найденного поста нет прямого URL изображения :(")
|
|
||||||
return
|
|
||||||
|
|
||||||
await message.answer_photo(photo=types.URLInputFile(file_url), caption="Ня :3")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception("Error in uwu command")
|
|
||||||
await message.reply("Произошла ошибка при обращении к API :(")
|
|
||||||
106
main.py
106
main.py
|
|
@ -22,19 +22,7 @@ from aiogram.client.default import DefaultBotProperties
|
||||||
from AI.talk_handler import handle_talk, generate_autoreply, push_message
|
from AI.talk_handler import handle_talk, generate_autoreply, push_message
|
||||||
from games.casino import play_casino
|
from games.casino import play_casino
|
||||||
from games.fortune import generate_fortune
|
from games.fortune import generate_fortune
|
||||||
from games.uwu import handle_uwu_cmd
|
from games.betting import get_formatted_matches, get_match_by_index, place_bet, get_user_bets, settle_bets
|
||||||
from games.betting import (
|
|
||||||
clear_user_sport_context,
|
|
||||||
describe_match_outcomes,
|
|
||||||
get_formatted_matches,
|
|
||||||
get_match_by_index,
|
|
||||||
get_user_bets,
|
|
||||||
get_user_sport_context,
|
|
||||||
place_bet,
|
|
||||||
remember_user_sport_context,
|
|
||||||
resolve_match_outcome,
|
|
||||||
settle_bets,
|
|
||||||
)
|
|
||||||
from zparser import get_military_data
|
from zparser import get_military_data
|
||||||
import config
|
import config
|
||||||
|
|
||||||
|
|
@ -943,7 +931,7 @@ def build_polychaetsi_top(limit: int = config.POLYCHAETSI_TOP_LIMIT) -> str:
|
||||||
# --- Хендлеры aiogram ---
|
# --- Хендлеры aiogram ---
|
||||||
|
|
||||||
async def handle_help(message: Message):
|
async def handle_help(message: Message):
|
||||||
await message.answer(config.get_hint_text(templates_list_text()), parse_mode=None)
|
await message.answer(config.get_hint_text(templates_list_text()))
|
||||||
|
|
||||||
async def handle_start(message: Message):
|
async def handle_start(message: Message):
|
||||||
await message.answer("Соси")
|
await message.answer("Соси")
|
||||||
|
|
@ -1197,7 +1185,7 @@ async def handle_penis_casino_cmd(message: Message):
|
||||||
return
|
return
|
||||||
parts = message.text.split(maxsplit=1)
|
parts = message.text.split(maxsplit=1)
|
||||||
if len(parts) < 2:
|
if len(parts) < 2:
|
||||||
await message.reply("Формат: /penis_casino [ставка]\nПример: /penis_casino 0.5", parse_mode=None)
|
await message.reply("Формат: /penis_casino <ставка>\nПример: /penis_casino 0.5")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
bet = round(float(parts[1].replace(",", ".")), 1)
|
bet = round(float(parts[1].replace(",", ".")), 1)
|
||||||
|
|
@ -1229,19 +1217,8 @@ async def handle_gadanie_cmd(message: Message):
|
||||||
await message.reply("Бля, карты рассыпались, попробуй позже.")
|
await message.reply("Бля, карты рассыпались, попробуй позже.")
|
||||||
|
|
||||||
async def handle_matches_cmd(message: Message):
|
async def handle_matches_cmd(message: Message):
|
||||||
raw_text = message.text or ""
|
parts = message.text.split(maxsplit=1)
|
||||||
parts = raw_text.split(maxsplit=1)
|
|
||||||
sport_alias = parts[1].strip().lower() if len(parts) > 1 else None
|
sport_alias = parts[1].strip().lower() if len(parts) > 1 else None
|
||||||
if sport_alias and sport_alias not in config.ODDS_SPORTS:
|
|
||||||
if message.from_user:
|
|
||||||
clear_user_sport_context(message.from_user.id)
|
|
||||||
await message.reply("Неизвестный спорт. Доступно: cs / dota / football", parse_mode=None)
|
|
||||||
return
|
|
||||||
if message.from_user:
|
|
||||||
if sport_alias and sport_alias in config.ODDS_SPORTS:
|
|
||||||
remember_user_sport_context(message.from_user.id, sport_alias)
|
|
||||||
else:
|
|
||||||
clear_user_sport_context(message.from_user.id)
|
|
||||||
await message.bot.send_chat_action(chat_id=message.chat.id, action="typing")
|
await message.bot.send_chat_action(chat_id=message.chat.id, action="typing")
|
||||||
result = await get_formatted_matches(sport_alias)
|
result = await get_formatted_matches(sport_alias)
|
||||||
await message.reply(result, parse_mode=None)
|
await message.reply(result, parse_mode=None)
|
||||||
|
|
@ -1250,70 +1227,35 @@ async def handle_bet_cmd(message: Message):
|
||||||
if not message.from_user:
|
if not message.from_user:
|
||||||
await message.answer("Команда доступна только пользователям.")
|
await message.answer("Команда доступна только пользователям.")
|
||||||
return
|
return
|
||||||
raw_text = message.text or ""
|
parts = message.text.split()
|
||||||
parts = raw_text.split()
|
|
||||||
if len(parts) < 4:
|
if len(parts) < 4:
|
||||||
await message.reply(
|
await message.reply(
|
||||||
"Формат: /bet [спорт] [номер] [исход] [ставка]\n"
|
"Формат: /bet <номер> <команда> <ставка>\n"
|
||||||
"Коротко после /matches cs|dota|football: /bet [номер] [исход] [ставка]\n"
|
"Пример: /bet cs 1 NAVI 0.5\n"
|
||||||
"Исход: 1/2, для ничьи X, можно ещё название команды или коэффициент.\n"
|
"Спорт: cs / dota / football"
|
||||||
"Пример: /bet cs 1 1 0.5",
|
|
||||||
parse_mode=None,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
sport_alias: str | None
|
|
||||||
if parts[1].lower() in config.ODDS_SPORTS:
|
|
||||||
if len(parts) < 5:
|
|
||||||
await message.reply(
|
|
||||||
"Формат: /bet [спорт] [номер] [исход] [ставка]\nПример: /bet cs 1 1 0.5",
|
|
||||||
parse_mode=None,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
# /bet <спорт> <номер> <команда> <ставка>
|
||||||
|
if len(parts) >= 5:
|
||||||
sport_alias = parts[1].lower()
|
sport_alias = parts[1].lower()
|
||||||
index_token = parts[2]
|
try:
|
||||||
selection = " ".join(parts[3:-1]).strip()
|
index = int(parts[2])
|
||||||
amount_token = parts[-1]
|
except ValueError:
|
||||||
|
await message.reply("Номер матча должен быть числом.")
|
||||||
|
return
|
||||||
|
team = parts[3]
|
||||||
|
try:
|
||||||
|
amount = round(float(parts[4].replace(",", ".")), 1)
|
||||||
|
except ValueError:
|
||||||
|
await message.reply("Ставка должна быть числом.")
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
sport_alias = get_user_sport_context(message.from_user.id)
|
await message.reply("Формат: /bet <спорт> <номер> <команда> <ставка>")
|
||||||
if not sport_alias:
|
|
||||||
await message.reply(
|
|
||||||
"Сначала открой /matches cs, /matches dota или /matches football.\n"
|
|
||||||
"Либо пиши полный формат: /bet [спорт] [номер] [исход] [ставка]",
|
|
||||||
parse_mode=None,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
index_token = parts[1]
|
|
||||||
selection = " ".join(parts[2:-1]).strip()
|
|
||||||
amount_token = parts[-1]
|
|
||||||
|
|
||||||
if not selection:
|
|
||||||
await message.reply("Нужен исход: 1, 2, X, название команды или коэффициент.", parse_mode=None)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
index = int(index_token)
|
|
||||||
except ValueError:
|
|
||||||
await message.reply("Номер матча должен быть числом.", parse_mode=None)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
amount = round(float(amount_token.replace(",", ".")), 1)
|
|
||||||
except ValueError:
|
|
||||||
await message.reply("Ставка должна быть числом.", parse_mode=None)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
match = await get_match_by_index(sport_alias, index)
|
match = await get_match_by_index(sport_alias, index)
|
||||||
if not match:
|
if not match:
|
||||||
await message.reply(f"Матч не найден. Посмотри /matches {sport_alias}", parse_mode=None)
|
await message.reply("Матч не найден. Посмотри /matches")
|
||||||
return
|
|
||||||
|
|
||||||
team = resolve_match_outcome(match, selection)
|
|
||||||
if not team:
|
|
||||||
await message.reply(
|
|
||||||
f"Исход не найден. Доступные: {describe_match_outcomes(match)}",
|
|
||||||
parse_mode=None,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
result = await asyncio.to_thread(place_bet, message.from_user.id, match, sport_alias, team, amount)
|
result = await asyncio.to_thread(place_bet, message.from_user.id, match, sport_alias, team, amount)
|
||||||
|
|
@ -1368,7 +1310,6 @@ def main():
|
||||||
dp.message.register(handle_bet_cmd, Command("bet"))
|
dp.message.register(handle_bet_cmd, Command("bet"))
|
||||||
dp.message.register(handle_mybets_cmd, Command("mybets"))
|
dp.message.register(handle_mybets_cmd, Command("mybets"))
|
||||||
dp.message.register(handle_gen_mem, Command("gen_mem"))
|
dp.message.register(handle_gen_mem, Command("gen_mem"))
|
||||||
dp.message.register(handle_uwu_cmd, Command("uwu"))
|
|
||||||
dp.message.register(handle_keywords, F.text)
|
dp.message.register(handle_keywords, F.text)
|
||||||
|
|
||||||
async def on_startup(bot: Bot):
|
async def on_startup(bot: Bot):
|
||||||
|
|
@ -1395,7 +1336,6 @@ def main():
|
||||||
BotCommand(command="bet", description="поставить см на матч"),
|
BotCommand(command="bet", description="поставить см на матч"),
|
||||||
BotCommand(command="mybets", description="мои ставки"),
|
BotCommand(command="mybets", description="мои ставки"),
|
||||||
BotCommand(command="svodka", description="СВО: итоги"),
|
BotCommand(command="svodka", description="СВО: итоги"),
|
||||||
BotCommand(command="uwu", description="Случайная картинка с e621"),
|
|
||||||
]
|
]
|
||||||
scopes = (
|
scopes = (
|
||||||
BotCommandScopeDefault(),
|
BotCommandScopeDefault(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue