"""Build detailed progress messages shown to the admin in Telegram — per-stage.""" from __future__ import annotations from models.schemas import DownloadProgress from utils.file_utils import format_size as _fmt_size _PROGRESS_BAR_LENGTH = 20 def _bar(percent: float) -> str: filled = int(percent / 100 * _PROGRESS_BAR_LENGTH) empty = _PROGRESS_BAR_LENGTH - filled return "█" * filled + "░" * empty def _eta(seconds: float) -> str: m, s = divmod(int(seconds), 60) h, m = divmod(m, 60) if h: return f"{h}h {m}m" if m: return f"{m}m {s}s" return f"{s}s" def _speed_line(bps: float) -> str: mb_s = bps / 1_048_576 return f"{mb_s:.1f} MB/s ({mb_s * 8:.1f} Mbps)" def _header(status: str) -> str: headers = { "downloading": "⬇️ **تحميل الملف من تلغرام**", "processing": "🔄 **معالجة الفيديو (FFmpeg)**", "uploading": "☁️ **رفع الملف إلى StreamTape**", "telegram_upload": "📤 **رفع نسخ احتياطية إلى تلغرام**", "archiving": "🗄️ **أرشفة في قاعدة البيانات**", "done": "✅ **اكتمل بنجاح! 🎉**", "error": "❌ **حدث خطأ!**", } return headers.get(status, "⏳ **جاري العمل...**") def format_progress_message(p: DownloadProgress) -> str: title = _header(p.status) lines: list[str] = [ "━" * 28, title, "━" * 28, ] # ── downloading ────────────────────────────────────────────────── if p.status == "downloading": lines.append("") lines.append(f"📦 **الحجم الكلي:** `{_fmt_size(p.total)}`") if p.downloaded > 0: lines.append(f"⬇️ **تم التحميل:** `{_fmt_size(p.downloaded)}` من `{_fmt_size(p.total)}`") if p.total > 0: lines.append(f"\n📊 `{_bar(p.percent)}` `{p.percent:.1f}%`") if p.speed > 0: lines.append(f"🚀 **السرعة:** `{_speed_line(p.speed)}`") lines.append(f"⏱️ **الوقت المتبقي:** ~`{_eta(p.eta_seconds)}`") if p.elapsed > 0: lines.append(f"⏱️ **الوقت المنقضي:** `{_eta(p.elapsed)}`") if p.bandwidth_total > 0: lines.append("") lines.append("─" * 28) lines.append(f"🌐 **إجمالي الباندويث:** `{_fmt_size(p.bandwidth_total)}`") # ── processing ─────────────────────────────────────────────────── elif p.status == "processing": lines.append("") lines.append(f"📦 **الحجم الكلي:** `{_fmt_size(p.total)}`") if p.stage_detail: lines.append(f"🔧 **مرحلة FFmpeg:** `{p.stage_detail}`") if p.sub_stage: lines.append(f"⚙️ **العملية:** `{p.sub_stage}`") if p.total > 0: lines.append(f"\n📊 `{_bar(p.percent)}` `{p.percent:.1f}%`") if p.elapsed > 0: lines.append(f"⏱️ **الوقت المنقضي:** `{_eta(p.elapsed)}`") # ── uploading (StreamTape) ────────────────────────────────────── elif p.status == "uploading": lines.append("") lines.append(f"📦 **الحجم الكلي:** `{_fmt_size(p.total)}`") if p.stage_detail: lines.append(f"👤 **الحساب:** `{p.stage_detail}`") if p.sub_stage: lines.append(f"⚙️ **المرحلة الفرعية:** `{p.sub_stage}`") if p.total_items > 0: cur = p.current_item tot = p.total_items lines.append(f"📌 **تقدم الحسابات:** `{cur}` من `{tot}`") pct = cur / tot * 100 lines.append(f"\n📊 `{_bar(pct)}` `{pct:.1f}%`") if p.elapsed > 0: lines.append(f"⏱️ **الوقت المنقضي:** `{_eta(p.elapsed)}`") # ── telegram_upload ───────────────────────────────────────────── elif p.status == "telegram_upload": lines.append("") lines.append(f"📦 **الحجم الكلي:** `{_fmt_size(p.total)}`") if p.total_items > 0: cur = p.current_item tot = p.total_items lines.append(f"📤 **النسخة:** `{cur}/{tot}`") pct = cur / tot * 100 lines.append(f"\n📊 `{_bar(pct)}` `{pct:.1f}%`") if p.elapsed > 0: lines.append(f"⏱️ **الوقت المنقضي:** `{_eta(p.elapsed)}`") # ── archiving ──────────────────────────────────────────────────── elif p.status == "archiving": lines.append("") if p.stage_detail: lines.append(f"🗄️ **الجدول:** `{p.stage_detail}`") if p.sub_stage: lines.append(f"✅ **الحالة:** `{p.sub_stage}`") if p.total_items > 0: lines.append(f"📌 **التقدم:** `{p.current_item}` من `{p.total_items}`") lines.append("") lines.append("✅ **تمت الأرشفة بنجاح!**") lines.append("") lines.append("━" * 28) lines.append("✅ **تمت العملية بنجاح!**") return "\n".join(lines) # ── done ──────────────────────────────────────────────────────── elif p.status == "done": lines.append("") lines.append("🎉 **🎊 تم بنجاح! 🎊**") lines.append("") lines.append(f"📦 **الحجم الكلي:** `{_fmt_size(p.total)}`") if p.elapsed > 0: lines.append(f"⏱️ **الوقت المستغرق:** `{_eta(p.elapsed)}`") if p.bandwidth_total > 0: lines.append(f"🌐 **إجمالي الباندويث:** `{_fmt_size(p.bandwidth_total)}`") lines.append("") lines.append("━" * 28) lines.append("✅ **تمت العملية بنجاح!**") return "\n".join(lines) # ── error ─────────────────────────────────────────────────────── elif p.status == "error": lines.append("") if p.stage_detail: lines.append(f"⚠️ **المرحلة:** `{p.stage_detail}`") if p.sub_stage: lines.append(f"🔴 **الخطأ:** `{p.sub_stage}`") lines.append("") lines.append("━" * 28) lines.append("❌ **فشلت العملية!**") return "\n".join(lines) lines.append("") lines.append("━" * 28) lines.append("⏳ **يرجى الانتظار...**") return "\n".join(lines)