Spaces:
No application file
No application file
Update bot/handlers.py
Browse files- bot/handlers.py +107 -29
bot/handlers.py
CHANGED
|
@@ -1,5 +1,9 @@
|
|
| 1 |
# PATH: bot/handlers.py
|
| 2 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
from typing import Dict
|
| 4 |
|
| 5 |
from hydrogram import Client, filters
|
|
@@ -14,9 +18,23 @@ from bot.core.auth import is_owner_id, require_allowed
|
|
| 14 |
from bot.core.progress import SpeedETA, human_bytes, human_eta
|
| 15 |
from bot.core.tasks import create_task, set_task
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
from bot.integrations.cf_worker1 import profile_add, profile_list, profile_set_default
|
| 18 |
from bot.integrations.cf_worker2 import (
|
| 19 |
-
allow_user,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
)
|
| 21 |
|
| 22 |
from bot.telegram.media import download_to_temp
|
|
@@ -32,6 +50,10 @@ from bot.integrations.http import fetch_status
|
|
| 32 |
# ---------- in-memory auth state (simple FSM) ----------
|
| 33 |
_AWAIT_AUTH: Dict[int, str] = {}
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
def _pick_login_url(j: dict) -> str:
|
| 37 |
"""Accept login_url from either top-level OR nested {data:{...}} shapes."""
|
|
@@ -57,7 +79,6 @@ def _pick_login_url(j: dict) -> str:
|
|
| 57 |
|
| 58 |
|
| 59 |
def setup_handlers(app: Client) -> None:
|
| 60 |
-
|
| 61 |
@app.on_message(filters.command(["start"]) & filters.private)
|
| 62 |
async def start_handler(_: Client, m: Message):
|
| 63 |
await safe_reply(m, texts.START_TEXT)
|
|
@@ -71,6 +92,54 @@ def setup_handlers(app: Client) -> None:
|
|
| 71 |
uid = m.from_user.id if m.from_user else None
|
| 72 |
await safe_reply(m, f"👤 Your ID: `{uid}`")
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
# -------- OWNER allow/disallow via forward OR id --------
|
| 75 |
@app.on_message(filters.command(["allow"]) & filters.private)
|
| 76 |
async def allow_cmd(_: Client, m: Message):
|
|
@@ -128,7 +197,7 @@ def setup_handlers(app: Client) -> None:
|
|
| 128 |
f"W2={Workers.WORKER2_URL} -> {r2}\n\n"
|
| 129 |
f"DNS W1 -> {dns_check(Workers.WORKER1_URL)}\n"
|
| 130 |
f"DNS W2 -> {dns_check(Workers.WORKER2_URL)}\n"
|
| 131 |
-
f"DNS google -> {dns_check('https://www.google.com')}\n"
|
| 132 |
)
|
| 133 |
|
| 134 |
# -------- AUTH UI --------
|
|
@@ -184,7 +253,25 @@ def setup_handlers(app: Client) -> None:
|
|
| 184 |
await q.answer("OK")
|
| 185 |
|
| 186 |
# message sink for auth states
|
| 187 |
-
@app.on_message(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
async def auth_sink(_: Client, m: Message):
|
| 189 |
uid = m.from_user.id if m.from_user else 0
|
| 190 |
mode = _AWAIT_AUTH.get(uid)
|
|
@@ -294,38 +381,29 @@ def setup_handlers(app: Client) -> None:
|
|
| 294 |
|
| 295 |
file_path = ""
|
| 296 |
file_size = 0
|
|
|
|
| 297 |
|
| 298 |
try:
|
| 299 |
-
# ---------------- Download
|
| 300 |
set_task(task_id, "downloading", "")
|
| 301 |
|
| 302 |
-
|
| 303 |
-
|
|
|
|
| 304 |
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
txt = (
|
| 312 |
-
f"⬇️ Downloading…\n"
|
| 313 |
-
f"{human_bytes(done)}/{human_bytes(total)}\n"
|
| 314 |
-
f"speed: {human_bytes(snap['speed_bps'])}/s | eta: {human_eta(snap['eta_sec'])}"
|
| 315 |
-
)
|
| 316 |
-
await safe_edit(status, txt)
|
| 317 |
|
| 318 |
-
|
| 319 |
-
app_, m,
|
| 320 |
-
progress=dl_prog,
|
| 321 |
-
progress_args=(),
|
| 322 |
-
)
|
| 323 |
-
dl_avg_bps = int((file_size or 0) / max(dl_sec, 0.001))
|
| 324 |
|
| 325 |
# parse title/desc after download
|
| 326 |
title, desc = extract_title_description(m, file_name)
|
| 327 |
|
| 328 |
-
# ---------------- Upload
|
| 329 |
set_task(task_id, "uploading", "")
|
| 330 |
up_t0 = time.time()
|
| 331 |
|
|
@@ -355,7 +433,7 @@ def setup_handlers(app: Client) -> None:
|
|
| 355 |
)
|
| 356 |
|
| 357 |
up_sec = max(0.001, time.time() - up_t0)
|
| 358 |
-
up_avg_bps = int((file_size or 0) / up_sec)
|
| 359 |
|
| 360 |
await record_upload(uid, use_profile_id)
|
| 361 |
|
|
@@ -366,7 +444,7 @@ def setup_handlers(app: Client) -> None:
|
|
| 366 |
f"🎬 {title}\n"
|
| 367 |
f"🔗 {yt_url}\n\n"
|
| 368 |
f"⬇️ Download: {human_eta(int(dl_sec))} | avg {human_bytes(dl_avg_bps)}/s\n"
|
| 369 |
-
f"⬆️ Upload: {human_eta(int(up_sec))} | avg {human_bytes(up_avg_bps)}/s"
|
| 370 |
)
|
| 371 |
|
| 372 |
except Exception as e:
|
|
|
|
| 1 |
# PATH: bot/handlers.py
|
| 2 |
+
import asyncio
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
import re
|
| 6 |
+
import time
|
| 7 |
from typing import Dict
|
| 8 |
|
| 9 |
from hydrogram import Client, filters
|
|
|
|
| 18 |
from bot.core.progress import SpeedETA, human_bytes, human_eta
|
| 19 |
from bot.core.tasks import create_task, set_task
|
| 20 |
|
| 21 |
+
from bot.core.speedtest import (
|
| 22 |
+
ping_ms,
|
| 23 |
+
net_download_test,
|
| 24 |
+
net_upload_test,
|
| 25 |
+
disk_total_free,
|
| 26 |
+
bytes_to_mb,
|
| 27 |
+
bytes_per_sec_to_mb_s,
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
from bot.integrations.cf_worker1 import profile_add, profile_list, profile_set_default
|
| 31 |
from bot.integrations.cf_worker2 import (
|
| 32 |
+
allow_user,
|
| 33 |
+
disallow_user,
|
| 34 |
+
pick_profile,
|
| 35 |
+
access_token,
|
| 36 |
+
record_upload,
|
| 37 |
+
stats_today,
|
| 38 |
)
|
| 39 |
|
| 40 |
from bot.telegram.media import download_to_temp
|
|
|
|
| 50 |
# ---------- in-memory auth state (simple FSM) ----------
|
| 51 |
_AWAIT_AUTH: Dict[int, str] = {}
|
| 52 |
|
| 53 |
+
# uptime + speedtest cooldown
|
| 54 |
+
_STARTED_AT = time.time()
|
| 55 |
+
_SPEED_COOLDOWN: dict[int, float] = {}
|
| 56 |
+
|
| 57 |
|
| 58 |
def _pick_login_url(j: dict) -> str:
|
| 59 |
"""Accept login_url from either top-level OR nested {data:{...}} shapes."""
|
|
|
|
| 79 |
|
| 80 |
|
| 81 |
def setup_handlers(app: Client) -> None:
|
|
|
|
| 82 |
@app.on_message(filters.command(["start"]) & filters.private)
|
| 83 |
async def start_handler(_: Client, m: Message):
|
| 84 |
await safe_reply(m, texts.START_TEXT)
|
|
|
|
| 92 |
uid = m.from_user.id if m.from_user else None
|
| 93 |
await safe_reply(m, f"👤 Your ID: `{uid}`")
|
| 94 |
|
| 95 |
+
# -------------------- SPEEDTEST (any user) --------------------
|
| 96 |
+
@app.on_message(filters.command(["speedtest"]) & filters.private)
|
| 97 |
+
async def speedtest_cmd(_: Client, m: Message):
|
| 98 |
+
uid = m.from_user.id if m.from_user else 0
|
| 99 |
+
|
| 100 |
+
now = time.time()
|
| 101 |
+
last = _SPEED_COOLDOWN.get(uid, 0.0)
|
| 102 |
+
if now - last < 30:
|
| 103 |
+
return await safe_reply(m, "⏳ Wait 30s then try again.")
|
| 104 |
+
_SPEED_COOLDOWN[uid] = now
|
| 105 |
+
|
| 106 |
+
msg = await safe_reply(m, "⚡ Running speedtest…")
|
| 107 |
+
|
| 108 |
+
# uptime
|
| 109 |
+
up_sec = int(max(0, time.time() - _STARTED_AT))
|
| 110 |
+
up_txt = human_eta(up_sec)
|
| 111 |
+
|
| 112 |
+
# disk
|
| 113 |
+
d = disk_total_free("/")
|
| 114 |
+
total_gb = d["total"] / (1024**3)
|
| 115 |
+
free_gb = d["free"] / (1024**3)
|
| 116 |
+
|
| 117 |
+
# run parallel
|
| 118 |
+
dl_task = asyncio.create_task(net_download_test())
|
| 119 |
+
up_task = asyncio.create_task(net_upload_test())
|
| 120 |
+
p_task = asyncio.create_task(ping_ms())
|
| 121 |
+
|
| 122 |
+
dl = await dl_task
|
| 123 |
+
up = await up_task
|
| 124 |
+
p = await p_task
|
| 125 |
+
|
| 126 |
+
ping_line = f"{p:.0f} ms" if p is not None else "N/A"
|
| 127 |
+
|
| 128 |
+
dl_mb_s = bytes_per_sec_to_mb_s(dl["bps"])
|
| 129 |
+
up_mb_s = bytes_per_sec_to_mb_s(up["bps"])
|
| 130 |
+
|
| 131 |
+
txt = (
|
| 132 |
+
"⚡ **Speedtest**\n\n"
|
| 133 |
+
f"🕒 Uptime: **{up_txt}**\n"
|
| 134 |
+
f"📶 Ping: **{ping_line}**\n"
|
| 135 |
+
f"💾 Disk: **{total_gb:.1f} GB total**, **{free_gb:.1f} GB free**\n\n"
|
| 136 |
+
f"⬇️ Download: **{dl_mb_s:.2f} MB/s** "
|
| 137 |
+
f"({bytes_to_mb(dl['bytes']):.2f} MB in {dl['seconds']:.2f}s)\n"
|
| 138 |
+
f"⬆️ Upload: **{up_mb_s:.2f} MB/s** "
|
| 139 |
+
f"({bytes_to_mb(up['bytes']):.2f} MB in {up['seconds']:.2f}s)\n"
|
| 140 |
+
)
|
| 141 |
+
await safe_edit(msg, txt)
|
| 142 |
+
|
| 143 |
# -------- OWNER allow/disallow via forward OR id --------
|
| 144 |
@app.on_message(filters.command(["allow"]) & filters.private)
|
| 145 |
async def allow_cmd(_: Client, m: Message):
|
|
|
|
| 197 |
f"W2={Workers.WORKER2_URL} -> {r2}\n\n"
|
| 198 |
f"DNS W1 -> {dns_check(Workers.WORKER1_URL)}\n"
|
| 199 |
f"DNS W2 -> {dns_check(Workers.WORKER2_URL)}\n"
|
| 200 |
+
f"DNS google -> {dns_check('https://www.google.com')}\n",
|
| 201 |
)
|
| 202 |
|
| 203 |
# -------- AUTH UI --------
|
|
|
|
| 253 |
await q.answer("OK")
|
| 254 |
|
| 255 |
# message sink for auth states
|
| 256 |
+
@app.on_message(
|
| 257 |
+
filters.private
|
| 258 |
+
& filters.text
|
| 259 |
+
& ~filters.command(
|
| 260 |
+
[
|
| 261 |
+
"start",
|
| 262 |
+
"ping",
|
| 263 |
+
"me",
|
| 264 |
+
"auth",
|
| 265 |
+
"cancel",
|
| 266 |
+
"profiles",
|
| 267 |
+
"speedtest",
|
| 268 |
+
"stats",
|
| 269 |
+
"allow",
|
| 270 |
+
"disallow",
|
| 271 |
+
"diag",
|
| 272 |
+
]
|
| 273 |
+
)
|
| 274 |
+
)
|
| 275 |
async def auth_sink(_: Client, m: Message):
|
| 276 |
uid = m.from_user.id if m.from_user else 0
|
| 277 |
mode = _AWAIT_AUTH.get(uid)
|
|
|
|
| 381 |
|
| 382 |
file_path = ""
|
| 383 |
file_size = 0
|
| 384 |
+
file_name = "video.bin"
|
| 385 |
|
| 386 |
try:
|
| 387 |
+
# ---------------- Download (Telegram) ----------------
|
| 388 |
set_task(task_id, "downloading", "")
|
| 389 |
|
| 390 |
+
dl_t0 = time.time()
|
| 391 |
+
file_path, file_size, file_name = await download_to_temp(app_, m)
|
| 392 |
+
dl_sec = max(0.001, time.time() - dl_t0)
|
| 393 |
|
| 394 |
+
# fallback size from disk if TG didn't give it
|
| 395 |
+
if not file_size and file_path and os.path.exists(file_path):
|
| 396 |
+
try:
|
| 397 |
+
file_size = os.path.getsize(file_path)
|
| 398 |
+
except Exception:
|
| 399 |
+
file_size = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 400 |
|
| 401 |
+
dl_avg_bps = int((file_size or 0) / dl_sec) if file_size else 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
|
| 403 |
# parse title/desc after download
|
| 404 |
title, desc = extract_title_description(m, file_name)
|
| 405 |
|
| 406 |
+
# ---------------- Upload (YouTube) ----------------
|
| 407 |
set_task(task_id, "uploading", "")
|
| 408 |
up_t0 = time.time()
|
| 409 |
|
|
|
|
| 433 |
)
|
| 434 |
|
| 435 |
up_sec = max(0.001, time.time() - up_t0)
|
| 436 |
+
up_avg_bps = int((file_size or 0) / up_sec) if file_size else 0
|
| 437 |
|
| 438 |
await record_upload(uid, use_profile_id)
|
| 439 |
|
|
|
|
| 444 |
f"🎬 {title}\n"
|
| 445 |
f"🔗 {yt_url}\n\n"
|
| 446 |
f"⬇️ Download: {human_eta(int(dl_sec))} | avg {human_bytes(dl_avg_bps)}/s\n"
|
| 447 |
+
f"⬆️ Upload: {human_eta(int(up_sec))} | avg {human_bytes(up_avg_bps)}/s",
|
| 448 |
)
|
| 449 |
|
| 450 |
except Exception as e:
|