forked from zovos/bot_tg
Add Magnit prices command
This commit is contained in:
parent
682fc7422c
commit
75a63bb6fc
2 changed files with 117 additions and 55 deletions
11
config.py
11
config.py
|
|
@ -21,6 +21,15 @@ PENIS_TOP_LIMIT = 10
|
||||||
# --- Казино ---
|
# --- Казино ---
|
||||||
CASINO_MAX_BET = 1.0
|
CASINO_MAX_BET = 1.0
|
||||||
|
|
||||||
|
# --- Magnit API ---
|
||||||
|
MAGNIT_API_BASE_URL = os.getenv("MAGNIT_API_BASE_URL", "https://mirror.porno4free.ru/magnit")
|
||||||
|
MAGNIT_STORE_CODE = os.getenv("MAGNIT_STORE_CODE", "618224")
|
||||||
|
MAGNIT_REQUEST_TIMEOUT = int(os.getenv("MAGNIT_REQUEST_TIMEOUT", "15"))
|
||||||
|
# Можно указывать просто строку с названием или словарь с query/label/store_code.
|
||||||
|
MAGNIT_PRODUCTS = [
|
||||||
|
"RedBull",
|
||||||
|
]
|
||||||
|
|
||||||
# --- Конфигурация макетов ---
|
# --- Конфигурация макетов ---
|
||||||
TEMPLATES = {
|
TEMPLATES = {
|
||||||
"1": {
|
"1": {
|
||||||
|
|
@ -103,6 +112,6 @@ def get_hint_text(templates_str: str) -> str:
|
||||||
"• /penis_casino [ставка] — казино на размер.\n"
|
"• /penis_casino [ставка] — казино на размер.\n"
|
||||||
"• /gadanie [тема] — гадание на фене с мемом.\n"
|
"• /gadanie [тема] — гадание на фене с мемом.\n"
|
||||||
"• /ebalnik — включить/выключить автоответы в чате.\n"
|
"• /ebalnik — включить/выключить автоответы в чате.\n"
|
||||||
"• /prices /fetch — цены.\n"
|
"• /prices /fetch — цены и остатки Магнита.\n"
|
||||||
"Подсказка: в группах пиши /команда@username_бота."
|
"Подсказка: в группах пиши /команда@username_бота."
|
||||||
)
|
)
|
||||||
|
|
|
||||||
149
main.py
149
main.py
|
|
@ -388,6 +388,62 @@ def minutes_until_next_lesson(now: datetime | None = None) -> str:
|
||||||
minutes = (total_seconds % 3600) // 60
|
minutes = (total_seconds % 3600) // 60
|
||||||
return f"Твой мозг окончательно сгниет, а очко порвется через: {days} дн {hours} ч {minutes} мин"
|
return f"Твой мозг окончательно сгниет, а очко порвется через: {days} дн {hours} ч {minutes} мин"
|
||||||
|
|
||||||
|
def _prepare_magnit_query(value: str) -> str:
|
||||||
|
value = re.sub(r"(?<=[a-zа-яё])(?=[A-ZА-ЯЁ])", " ", value)
|
||||||
|
value = re.sub(r"[_-]+", " ", value)
|
||||||
|
return re.sub(r"\s+", " ", value).strip()
|
||||||
|
|
||||||
|
def _normalize_magnit_product(entry) -> dict[str, str]:
|
||||||
|
if isinstance(entry, str):
|
||||||
|
raw_query = entry.strip()
|
||||||
|
if not raw_query:
|
||||||
|
raise ValueError("Пустой query в MAGNIT_PRODUCTS.")
|
||||||
|
return {
|
||||||
|
"query": _prepare_magnit_query(raw_query),
|
||||||
|
"label": raw_query,
|
||||||
|
"store_code": config.MAGNIT_STORE_CODE,
|
||||||
|
}
|
||||||
|
|
||||||
|
if isinstance(entry, dict):
|
||||||
|
raw_query = str(entry.get("query", "")).strip()
|
||||||
|
if not raw_query:
|
||||||
|
raise ValueError("У товара в MAGNIT_PRODUCTS отсутствует query.")
|
||||||
|
return {
|
||||||
|
"query": _prepare_magnit_query(raw_query),
|
||||||
|
"label": str(entry.get("label") or raw_query).strip() or raw_query,
|
||||||
|
"store_code": str(entry.get("store_code") or config.MAGNIT_STORE_CODE).strip(),
|
||||||
|
}
|
||||||
|
|
||||||
|
raise ValueError("MAGNIT_PRODUCTS должен содержать строки или словари.")
|
||||||
|
|
||||||
|
def _pick_magnit_item(data: dict):
|
||||||
|
best_match = data.get("best_match")
|
||||||
|
if isinstance(best_match, dict):
|
||||||
|
return best_match
|
||||||
|
|
||||||
|
items = data.get("items")
|
||||||
|
if isinstance(items, list) and items:
|
||||||
|
return items[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _format_money(value) -> str | None:
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
amount = f"{float(value):.2f}".rstrip("0").rstrip(".")
|
||||||
|
return f"{amount} ₽"
|
||||||
|
|
||||||
|
def _format_magnit_price(item: dict) -> str:
|
||||||
|
new_price = _format_money(item.get("price"))
|
||||||
|
old_price = _format_money(item.get("old_price"))
|
||||||
|
if old_price and new_price and item.get("old_price") and item.get("old_price") != item.get("price"):
|
||||||
|
return f"{old_price} -> {new_price}"
|
||||||
|
return new_price or "нет цены"
|
||||||
|
|
||||||
|
def _format_magnit_quantity(value) -> str:
|
||||||
|
if value is None:
|
||||||
|
return "нет данных"
|
||||||
|
return f"{value} шт."
|
||||||
|
|
||||||
# --- Игровая логика (/penis) ---
|
# --- Игровая логика (/penis) ---
|
||||||
|
|
||||||
def play_penis(user_id: int, user_name: str | None = None, now: datetime | None = None) -> tuple[bool, str]:
|
def play_penis(user_id: int, user_name: str | None = None, now: datetime | None = None) -> tuple[bool, str]:
|
||||||
|
|
@ -542,61 +598,58 @@ async def handle_zvetok_cmd(message: Message):
|
||||||
await message.answer(minutes_until_next_lesson())
|
await message.answer(minutes_until_next_lesson())
|
||||||
|
|
||||||
async def handle_prices_cmd(message: Message):
|
async def handle_prices_cmd(message: Message):
|
||||||
|
try:
|
||||||
|
products = [_normalize_magnit_product(entry) for entry in config.MAGNIT_PRODUCTS]
|
||||||
|
except ValueError as exc:
|
||||||
|
await message.answer(f"Проверь MAGNIT_PRODUCTS в config.py: {exc}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not products:
|
||||||
|
await message.answer("Список MAGNIT_PRODUCTS пуст. Добавь товары в config.py.")
|
||||||
|
return
|
||||||
|
|
||||||
|
async def fetch_product(product_cfg: dict[str, str]) -> str:
|
||||||
def fetch():
|
def fetch():
|
||||||
return requests.get(
|
return requests.get(
|
||||||
"https://bebrik.xyz/magnit/products",
|
f"{config.MAGNIT_API_BASE_URL.rstrip('/')}/price",
|
||||||
headers={"X-Token": "sisi"},
|
params={
|
||||||
timeout=10,
|
"store_code": product_cfg["store_code"],
|
||||||
|
"query": product_cfg["query"],
|
||||||
|
},
|
||||||
|
timeout=config.MAGNIT_REQUEST_TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
label = product_cfg["label"] or product_cfg["query"] or "товар"
|
||||||
try:
|
try:
|
||||||
resp = await asyncio.to_thread(fetch)
|
resp = await asyncio.to_thread(fetch)
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
await message.answer("пошел нахуй")
|
logger.warning("Magnit API returned %s for %s", resp.status_code, product_cfg["query"])
|
||||||
return
|
return f"{label}, ошибка API ({resp.status_code}), -"
|
||||||
|
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
if not data:
|
if not isinstance(data, dict):
|
||||||
await message.answer("иди нахуй")
|
return f"{label}, битый ответ API, -"
|
||||||
return
|
|
||||||
text = "смерть в 25:\n\n"
|
item = _pick_magnit_item(data)
|
||||||
for item in data:
|
if not isinstance(item, dict):
|
||||||
name = item.get("name")
|
return f"{label}, товар не найден, -"
|
||||||
price = item.get("price")
|
|
||||||
text += f"{name} — {price} ₽\n"
|
name = str(item.get("name") or label).strip() or label
|
||||||
await message.answer(text[:4000])
|
price = _format_magnit_price(item)
|
||||||
except Exception:
|
quantity = _format_magnit_quantity(item.get("quantity"))
|
||||||
await message.answer("unable to connect x-server гандон")
|
return f"{name}, {price}, {quantity}"
|
||||||
|
except requests.RequestException:
|
||||||
|
logger.exception("Failed to fetch Magnit product: %s", product_cfg["query"])
|
||||||
|
return f"{label}, ошибка запроса, -"
|
||||||
|
except ValueError:
|
||||||
|
logger.exception("Magnit API returned invalid JSON for %s", product_cfg["query"])
|
||||||
|
return f"{label}, битый JSON, -"
|
||||||
|
|
||||||
|
lines = await asyncio.gather(*(fetch_product(product) for product in products))
|
||||||
|
await message.answer("\n".join(lines)[:4000])
|
||||||
|
|
||||||
async def handle_fetch_cmd(message: Message):
|
async def handle_fetch_cmd(message: Message):
|
||||||
def fetch():
|
await handle_prices_cmd(message)
|
||||||
return requests.get(
|
|
||||||
"https://mirror.porno4free.ru/magnit/magnit/prices/all",
|
|
||||||
headers={"x-token": "secret_token"},
|
|
||||||
timeout=10,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
resp = await asyncio.to_thread(fetch)
|
|
||||||
if resp.status_code != 200:
|
|
||||||
await message.reply("пошел нахуй")
|
|
||||||
return
|
|
||||||
data = resp.json()
|
|
||||||
if not isinstance(data, dict) or not data:
|
|
||||||
await message.reply("иди нахуй")
|
|
||||||
return
|
|
||||||
lines = ["смерть в 25:"]
|
|
||||||
for group in sorted(data.keys()):
|
|
||||||
items = data.get(group)
|
|
||||||
lines.append(f"\n{group}:")
|
|
||||||
if not isinstance(items, list):
|
|
||||||
continue
|
|
||||||
for item in items:
|
|
||||||
name = item.get("name")
|
|
||||||
price = item.get("price")
|
|
||||||
if not name or price is None:
|
|
||||||
continue
|
|
||||||
lines.append(f"{name} — {price} ₽")
|
|
||||||
await message.answer("\n".join(lines)[:4000])
|
|
||||||
except Exception:
|
|
||||||
await message.answer("unable to connect x-server гандон")
|
|
||||||
|
|
||||||
async def handle_svodka_cmd(message: Message):
|
async def handle_svodka_cmd(message: Message):
|
||||||
data = await asyncio.to_thread(get_military_data, "creamy_caprice", 5)
|
data = await asyncio.to_thread(get_military_data, "creamy_caprice", 5)
|
||||||
|
|
@ -790,8 +843,8 @@ def main():
|
||||||
BotCommand(command="size", description="хуй"),
|
BotCommand(command="size", description="хуй"),
|
||||||
BotCommand(command="penis", description="миниигра 1 раз в 24ч"),
|
BotCommand(command="penis", description="миниигра 1 раз в 24ч"),
|
||||||
BotCommand(command="top_penis", description="топ по длине"),
|
BotCommand(command="top_penis", description="топ по длине"),
|
||||||
BotCommand(command="prices", description="цены x-server"),
|
BotCommand(command="prices", description="цены и остатки Магнита"),
|
||||||
BotCommand(command="fetch", description="цены (новый источник)"),
|
BotCommand(command="fetch", description="alias для /prices"),
|
||||||
BotCommand(command="zvetok", description="Цветянский бля"),
|
BotCommand(command="zvetok", description="Цветянский бля"),
|
||||||
BotCommand(command="talk", description="Побазарить"),
|
BotCommand(command="talk", description="Побазарить"),
|
||||||
BotCommand(command="ebalnik", description="вкл/выкл автответов"),
|
BotCommand(command="ebalnik", description="вкл/выкл автответов"),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue