Compare commits
5 commits
29cd511186
...
3039326100
| Author | SHA1 | Date | |
|---|---|---|---|
| 3039326100 | |||
|
|
481965e8f2 | ||
|
|
e014019912 | ||
|
|
f0cefc7f23 | ||
|
|
3baf71ab98 |
5 changed files with 58 additions and 21 deletions
2
.env
2
.env
|
|
@ -1,3 +1,3 @@
|
||||||
BOT_TOKEN=8488665890:AAH7FY5I2xzHhfOdxlzb11ewl2I-MMTH2-o
|
BOT_TOKEN=8156642467:AAEalekr-33lFS3tTTkXIEiaawfDzR6lBJc
|
||||||
TZ=Europe/Moscow
|
TZ=Europe/Moscow
|
||||||
ODDS_API_KEY=c29bc26dee8aa9d95a5ce8d14ea63923
|
ODDS_API_KEY=c29bc26dee8aa9d95a5ce8d14ea63923
|
||||||
|
|
|
||||||
16
config.py
16
config.py
|
|
@ -35,13 +35,17 @@ 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"
|
||||||
ODDS_SPORTS = {
|
ODDS_SPORTS = {
|
||||||
"cs": "esports_csgo",
|
"epl": "soccer_epl",
|
||||||
"dota": "esports_dota2",
|
"ucl": "soccer_uefa_champs_league",
|
||||||
"football": "soccer_epl",
|
"laliga": "soccer_spain_la_liga",
|
||||||
|
"bundesliga": "soccer_germany_bundesliga",
|
||||||
|
"seriea": "soccer_italy_serie_a",
|
||||||
|
"ligue1": "soccer_france_ligue_one",
|
||||||
|
"europa": "soccer_uefa_europa_league",
|
||||||
}
|
}
|
||||||
BET_MAX_AMOUNT = 3.0
|
BET_MAX_AMOUNT = 3.0
|
||||||
BET_DB_PATH = "/db/bets.sqlite3"
|
BET_DB_PATH = "/db/bets.sqlite3"
|
||||||
ODDS_CACHE_TTL = 900
|
ODDS_CACHE_TTL = 86400 # 24 часа — экономим запросы (500/мес бесплатно)
|
||||||
|
|
||||||
# --- Magnit API ---
|
# --- Magnit API ---
|
||||||
MAGNIT_API_BASE_URL = os.getenv("MAGNIT_API_BASE_URL", "https://mirror.porno4free.ru/magnit")
|
MAGNIT_API_BASE_URL = os.getenv("MAGNIT_API_BASE_URL", "https://mirror.porno4free.ru/magnit")
|
||||||
|
|
@ -209,8 +213,8 @@ def get_hint_text(templates_str: str) -> str:
|
||||||
"• /talk [текст] — ИИ базарит на фене.\n"
|
"• /talk [текст] — ИИ базарит на фене.\n"
|
||||||
"• /penis_casino [ставка] — казино на размер.\n"
|
"• /penis_casino [ставка] — казино на размер.\n"
|
||||||
"• /gadanie [тема] — гадание на фене с мемом.\n"
|
"• /gadanie [тема] — гадание на фене с мемом.\n"
|
||||||
"• /matches [cs|dota|football] — матчи для ставок.\n"
|
"• /matches [epl|ucl|laliga|bundesliga|seriea|ligue1|europa] — матчи для ставок.\n"
|
||||||
"• /bet [спорт] [номер] [исход] [ставка] — поставить см.\n"
|
"• /bet [лига] [номер] [исход] [ставка] — поставить см.\n"
|
||||||
"• /mybets — мои активные ставки.\n"
|
"• /mybets — мои активные ставки.\n"
|
||||||
"• /bet_history — история ставок за месяц + статистика.\n"
|
"• /bet_history — история ставок за месяц + статистика.\n"
|
||||||
"• /sports_debug — диагностика API матчей.\n"
|
"• /sports_debug — диагностика API матчей.\n"
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,15 @@ def format_matches(matches: list[dict], sport_alias: str, sport_label: str) -> s
|
||||||
|
|
||||||
|
|
||||||
def _get_sport_label(key: str) -> str:
|
def _get_sport_label(key: str) -> str:
|
||||||
labels = {"cs": "🎮 CS2", "dota": "🎮 Dota 2", "football": "⚽ Футбол"}
|
labels = {
|
||||||
|
"epl": "⚽ EPL",
|
||||||
|
"ucl": "⚽ Champions League",
|
||||||
|
"laliga": "⚽ La Liga",
|
||||||
|
"bundesliga": "⚽ Bundesliga",
|
||||||
|
"seriea": "⚽ Serie A",
|
||||||
|
"ligue1": "⚽ Ligue 1",
|
||||||
|
"europa": "⚽ Europa League",
|
||||||
|
}
|
||||||
return labels.get(key, key)
|
return labels.get(key, key)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -436,15 +444,17 @@ def get_user_bet_history(user_id: int) -> str:
|
||||||
status = r["status"]
|
status = r["status"]
|
||||||
amount = float(r["amount"])
|
amount = float(r["amount"])
|
||||||
odds_val = float(r["odds"])
|
odds_val = float(r["odds"])
|
||||||
payout = float(r["payout"] or 0)
|
payout_raw = float(r["payout"] or 0)
|
||||||
|
|
||||||
total_bet += amount
|
total_bet += amount
|
||||||
|
|
||||||
if status == "won":
|
if status == "won":
|
||||||
wins += 1
|
wins += 1
|
||||||
total_won += payout
|
# Для старых ставок payout может быть 0, пересчитываем
|
||||||
|
actual_payout = payout_raw if payout_raw > 0 else round(amount * odds_val, 1)
|
||||||
|
total_won += actual_payout
|
||||||
status_icon = "✅"
|
status_icon = "✅"
|
||||||
result_text = f"+{payout:.1f} см"
|
result_text = f"+{actual_payout:.1f} см"
|
||||||
elif status == "lost":
|
elif status == "lost":
|
||||||
losses += 1
|
losses += 1
|
||||||
total_lost += amount
|
total_lost += amount
|
||||||
|
|
|
||||||
15
games/uwu.py
15
games/uwu.py
|
|
@ -68,15 +68,18 @@ async def handle_uwu_cmd(message: types.Message):
|
||||||
await message.reply("У найденного поста нет прямого URL изображения :(")
|
await message.reply("У найденного поста нет прямого URL изображения :(")
|
||||||
return
|
return
|
||||||
|
|
||||||
input_file = types.URLInputFile(file_url)
|
|
||||||
caption = random.choice(CAPTIONS)
|
caption = random.choice(CAPTIONS)
|
||||||
if ext in ("png", "jpg", "jpeg", "webp"):
|
if ext in ("gif", "webm", "mp4"):
|
||||||
|
# Для анимаций: отправляем caption отдельным сообщением,
|
||||||
|
# а саму гифку/видео через URL напрямую — так Telegram
|
||||||
|
# корректно показывает её как анимацию, а не как файл
|
||||||
|
await message.answer(caption)
|
||||||
|
await message.answer_animation(animation=file_url)
|
||||||
|
elif ext in ("png", "jpg", "jpeg", "webp"):
|
||||||
|
input_file = types.URLInputFile(file_url)
|
||||||
await message.answer_photo(photo=input_file, caption=caption)
|
await message.answer_photo(photo=input_file, caption=caption)
|
||||||
elif ext == "gif":
|
|
||||||
await message.answer_animation(animation=input_file, caption=caption)
|
|
||||||
elif ext in ("webm", "mp4"):
|
|
||||||
await message.answer_video(video=input_file, caption=caption)
|
|
||||||
else:
|
else:
|
||||||
|
input_file = types.URLInputFile(file_url)
|
||||||
await message.answer_document(document=input_file, caption=caption)
|
await message.answer_document(document=input_file, caption=caption)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
28
main.py
28
main.py
|
|
@ -1234,13 +1234,33 @@ async def handle_matches_cmd(message: Message):
|
||||||
raw_text = message.text or ""
|
raw_text = message.text or ""
|
||||||
parts = raw_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 not sport_alias:
|
||||||
|
labels = {
|
||||||
|
"epl": "⚽ EPL (Англия)",
|
||||||
|
"ucl": "⚽ Champions League",
|
||||||
|
"laliga": "⚽ La Liga (Испания)",
|
||||||
|
"bundesliga": "⚽ Bundesliga (Германия)",
|
||||||
|
"seriea": "⚽ Serie A (Италия)",
|
||||||
|
"ligue1": "⚽ Ligue 1 (Франция)",
|
||||||
|
"europa": "⚽ Europa League",
|
||||||
|
}
|
||||||
|
lines = ["🏆 Доступные лиги для ставок:\n"]
|
||||||
|
for alias, name in labels.items():
|
||||||
|
lines.append(f" {name} → /matches {alias}")
|
||||||
|
lines.append("\nПример: /matches epl")
|
||||||
|
await message.reply("\n".join(lines), parse_mode=None)
|
||||||
|
return
|
||||||
|
|
||||||
|
if sport_alias not in config.ODDS_SPORTS:
|
||||||
if message.from_user:
|
if message.from_user:
|
||||||
clear_user_sport_context(message.from_user.id)
|
clear_user_sport_context(message.from_user.id)
|
||||||
await message.reply("Неизвестный спорт. Доступно: cs / dota / football", parse_mode=None)
|
available = " / ".join(config.ODDS_SPORTS.keys())
|
||||||
|
await message.reply(f"Неизвестная лига. Доступно: {available}", parse_mode=None)
|
||||||
return
|
return
|
||||||
if message.from_user:
|
if message.from_user:
|
||||||
if sport_alias and sport_alias in config.ODDS_SPORTS:
|
if sport_alias in config.ODDS_SPORTS:
|
||||||
remember_user_sport_context(message.from_user.id, sport_alias)
|
remember_user_sport_context(message.from_user.id, sport_alias)
|
||||||
else:
|
else:
|
||||||
clear_user_sport_context(message.from_user.id)
|
clear_user_sport_context(message.from_user.id)
|
||||||
|
|
@ -1280,7 +1300,7 @@ async def handle_bet_cmd(message: Message):
|
||||||
sport_alias = get_user_sport_context(message.from_user.id)
|
sport_alias = get_user_sport_context(message.from_user.id)
|
||||||
if not sport_alias:
|
if not sport_alias:
|
||||||
await message.reply(
|
await message.reply(
|
||||||
"Сначала открой /matches cs, /matches dota или /matches football.\n"
|
"Сначала открой /matches с нужной лигой (epl, ucl, laliga...).\n"
|
||||||
"Либо пиши полный формат: /bet [спорт] [номер] [исход] [ставка]",
|
"Либо пиши полный формат: /bet [спорт] [номер] [исход] [ставка]",
|
||||||
parse_mode=None,
|
parse_mode=None,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue