diff --git a/requirements.txt b/requirements.txt index 4a9fb58..57b4a72 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,4 @@ Pillow==11.3.0 python-multipart==0.0.20 uvicorn[standard]==0.35.0 yt-dlp==2026.6.9 -instagrapi==2.1.2 +instagrapi==2.6.9 diff --git a/src/vk_parser_app/admin.py b/src/vk_parser_app/admin.py index cd346ec..e8f9549 100644 --- a/src/vk_parser_app/admin.py +++ b/src/vk_parser_app/admin.py @@ -37,7 +37,7 @@ from .workers.tg_poster import TelegramPoster from .workers.tg_reactor import TelegramReactor from .workers.vk_poster import VKPoster from .workers.vk_storage_uploader import TelegramStorageUploader -from .workers.insta_parser import InstaParserWorker, instagram_login +from .workers.insta_parser import InstaParserWorker, InstagramCodeRequired, instagram_login COOKIE_NAME = "vk_parser_admin" VK_OAUTH_VERIFIER_COOKIE = "vk_oauth_verifier" @@ -3623,6 +3623,8 @@ async def workers(request: Request): vk_schedule=await vk_poster_schedule_rows(), category_titles=CATEGORY_TITLES, prompt_hints=PROMPT_HINTS, + instagram_auth_status=setting_values.get("insta_auth_status") or "", + instagram_cooldown_until=setting_values.get("insta_cooldown_until") or "", ), ) @@ -3952,7 +3954,7 @@ async def worker_toggle(request: Request, worker_name: str, csrf_token: str = Fo @app.post("/instagram-auth/login") -async def instagram_auth_login(request: Request, csrf_token: str = Form(...)): +async def instagram_auth_login(request: Request, csrf_token: str = Form(...), verification_code: str = Form("")): user = await get_current_user(request) if not user: return redirect("/login") @@ -3966,7 +3968,7 @@ async def instagram_auth_login(request: Request, csrf_token: str = Form(...)): status_text = "missing login or password" else: try: - await asyncio.to_thread(instagram_login, login, password, proxy, session_path) + await asyncio.to_thread(instagram_login, login, password, proxy, session_path, verification_code.strip()) status_text = f"ok: session saved to {session_path or 'insta_session.json'} at {datetime.now(timezone.utc).isoformat()}" await pool.execute( """ @@ -3978,8 +3980,14 @@ async def instagram_auth_login(request: Request, csrf_token: str = Form(...)): updated_at=NOW() """ ) + except InstagramCodeRequired as exc: + status_text = f"code_required: {exc.choice}" except Exception as exc: - status_text = f"failed: {str(exc)[:1000]}" + exc_name = exc.__class__.__name__ + if exc_name in {"TwoFactorRequired", "ChallengeRequired"}: + status_text = f"code_required: {exc_name}" + else: + status_text = f"failed: {exc_name}: {str(exc)[:1000]}" await pool.execute( """ INSERT INTO app_settings(key, value_json, value_type, title, description, category, updated_by) @@ -3996,6 +4004,29 @@ async def instagram_auth_login(request: Request, csrf_token: str = Form(...)): return redirect("/workers") +@app.post("/instagram-auth/clear-cooldown") +async def instagram_auth_clear_cooldown(request: Request, csrf_token: str = Form(...)): + user = await get_current_user(request) + if not user: + return redirect("/login") + require_csrf(user, csrf_token) + pool = await get_pool() + await pool.execute( + """ + INSERT INTO app_settings(key, value_json, value_type, title, description, category, updated_by) + VALUES('insta_cooldown_until', '""'::jsonb, 'str', 'Cooldown until', '', 'Instagram Parser', $1) + ON CONFLICT (key) DO UPDATE + SET value_json='""'::jsonb, + description='manual reset', + updated_by=$1, + updated_at=NOW() + """, + user["id"], + ) + await audit(user["id"], "instagram.cooldown_reset", "setting", None) + return redirect("/workers") + + @app.post("/settings/save") async def settings_save(request: Request, csrf_token: str = Form(...), key: str = Form(...), value: str = Form(...)): user = await get_current_user(request) diff --git a/src/vk_parser_app/templates/workers.html b/src/vk_parser_app/templates/workers.html index 933df82..e138c72 100644 --- a/src/vk_parser_app/templates/workers.html +++ b/src/vk_parser_app/templates/workers.html @@ -8,25 +8,6 @@