document.getElementById('addModal').addEventListener('click', function(e) { if (e.target === this) this.style.display='none'; }); """ @app.get("/channel-media", response_class=HTMLResponse) async def channel_media_page(_: str = Depends(panel_auth)) -> str: return layout("频道媒体", channel_media_page_html()) @app.get("/api/groups") async def api_groups(_: str = Depends(panel_auth), q: str = "", limit: int = 500) -> dict[str, Any]: if not user_session_ready(): return {"groups": [], "error": "TG user session not configured"} if q.strip(): groups = await telethon_search_dialogs(q.strip(), limit=min(limit, 200)) else: groups = await telethon_list_dialogs(limit=min(limit, 500)) groups = [g for g in groups if g.get("type") in ("group", "channel")] return {"groups": groups} @app.post("/api/monitors/create") async def api_monitor_create( _: str = Depends(panel_auth), channel_id: str = Form(...), channel_title: str = Form(""), channel_username: str = Form(""), media_types: str = Form("video,document"), keywords: str = Form(""), max_file_size_mb: int = Form(2000), download_dir: str = Form(""), notify_telegram: str | None = Form(None), proxy: str = Form(""), date_from: str = Form(""), date_to: str = Form(""), max_concurrent: int = Form(3), forward_mode: str | None = Form(None), forward_to: str = Form("admin"), ) -> RedirectResponse: try: cid = int(channel_id.strip()) except (ValueError, TypeError): raise HTTPException(400, "invalid channel_id") channel_media_monitor_create( cid, channel_title.strip() or str(cid), channel_username.strip(), media_types.strip() or "video,document", keywords.strip(), max(1, max_file_size_mb), download_dir.strip(), bool(notify_telegram), proxy.strip(), date_from.strip(), date_to.strip(), max(1, min(10, max_concurrent)), bool(forward_mode), forward_to.strip() or "admin", ) return RedirectResponse("/channel-media", status_code=303) @app.get("/channel-media/{monitor_id}/pause") async def channel_media_pause(monitor_id: int, _: str = Depends(panel_auth)) -> RedirectResponse: channel_media_monitor_update(monitor_id, status="paused") return RedirectResponse("/channel-media", status_code=303) @app.get("/channel-media/{monitor_id}/resume") async def channel_media_resume(monitor_id: int, _: str = Depends(panel_auth)) -> RedirectResponse: channel_media_monitor_update(monitor_id, status="active") return RedirectResponse("/channel-media", status_code=303) @app.get("/channel-media/{monitor_id}/delete") async def channel_media_delete_route(monitor_id: int, _: str = Depends(panel_auth)) -> RedirectResponse: channel_media_monitor_delete(monitor_id) return RedirectResponse("/channel-media", status_code=303) @app.get("/channel-media/{monitor_id}/check", response_class=HTMLResponse) async def channel_media_check(monitor_id: int, _: str = Depends(panel_auth)) -> str: count = await telethon_download_from_channel(monitor_id) monitor = channel_media_monitor_get(monitor_id) name = monitor.get("channel_title", "") if monitor else "" return layout("检查完成", f"
已检查频道 {html_escape(name)},新增 {count} 个文件。

返回

") @app.get("/channel-media/{monitor_id}/download", response_class=HTMLResponse) async def channel_media_download_history(monitor_id: int, _: str = Depends(panel_auth)) -> str: monitor = channel_media_monitor_get(monitor_id) if not monitor: raise HTTPException(404) downloads = channel_media_downloads_list(monitor_id, limit=200) rows = "" for d in downloads: size_mb = f"{(d.get('file_size', 0) or 0) / 1024 / 1024:.1f} MB" rows += f"{d.get('id')}{html_escape(d.get('media_type',''))}" rows += f"{html_escape(d.get('file_name',''))}
{html_escape(d.get('caption','')[:100])}" rows += f"{size_mb}{html_escape(d.get('created_at',''))}" total = monitor.get("total_downloaded", 0) size_mb = (monitor.get("total_size_bytes", 0) or 0) // 1024 // 1024 body = f"""

下载记录 - {html_escape(monitor.get('channel_title',''))}

累计:{total} 个文件,{size_mb} MB

立即下载新内容 返回列表
{rows}
ID类型文件名/说明大小时间
""" return layout("下载记录", body) return app