#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 咪咕短剧 flows.cdyylkj.com/miguSM/home 接口: - POST /api/submit_phone 传入电话号码 → 新建 TgeBrowser → 输入手机号、点击发送验证码 → 返回成功 - POST /api/submit_code 传入验证码 → 在对应会话中填写验证码并提交 每个电话号码对应一个新建的 TgeBrowser 浏览器会话。 """ from __future__ import annotations import threading import uuid from typing import Any, Optional from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from migu_miguSM_dp import ( MIGU_HOME_URL, connect_dp_to_tgebrowser, connect_dp_to_ws, input_code_and_submit, input_phone_and_send_code, ) from tgebrowser_client import TgeBrowserClient app = FastAPI(title="咪咕短剧 miguSM 自动化 API", description="TgeBrowser + DrissionPage 手机号与验证码提交流程") # 会话存储:session_id -> {page, env_id, client} _sessions: dict[str, dict[str, Any]] = {} _sessions_lock = threading.Lock() class SubmitPhoneRequest(BaseModel): phone: str = Field(..., description="手机号码") url: str = Field(MIGU_HOME_URL, description="目标页面 URL") class SubmitPhoneResponse(BaseModel): success: bool = True session_id: str = Field(..., description="会话 ID,submit_code 时需传入") message: str = "输入电话号码成功" class SubmitCodeRequest(BaseModel): session_id: str = Field(..., description="submit_phone 返回的会话 ID") code: str = Field(..., description="短信验证码") class SubmitCodeResponse(BaseModel): success: bool = True message: str = "" @app.post("/api/submit_phone", response_model=SubmitPhoneResponse) def api_submit_phone(req: SubmitPhoneRequest): """ 步骤一:传入电话号码。 新建 TgeBrowser 浏览器 → 打开 miguSM 页面 → 输入手机号 → 点击发送验证码。 返回 session_id,用于后续 submit_code。 """ try: client = TgeBrowserClient() # 每次输入电话号码新建一个浏览器 start_data = client.create_and_start( browser_name=f"miguSM_{req.phone[-4:]}", start_page_url=req.url, ) port = start_data.get("port") ws = start_data.get("ws") env_id = start_data.get("envId") # 优先用端口连接(DrissionPage 对端口支持更好) if port: page = connect_dp_to_tgebrowser(port) elif ws: page = connect_dp_to_ws(ws) else: raise HTTPException(status_code=500, detail="TgeBrowser 未返回 port 或 ws") input_phone_and_send_code(page, req.phone, url=req.url) session_id = str(uuid.uuid4()) with _sessions_lock: _sessions[session_id] = { "page": page, "env_id": env_id, "client": client, } return SubmitPhoneResponse(success=True, session_id=session_id, message="输入电话号码成功") except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.post("/api/submit_code", response_model=SubmitCodeResponse) def api_submit_code(req: SubmitCodeRequest): """ 步骤二:传入验证码。 在 submit_phone 创建的会话中填写验证码并提交。 """ with _sessions_lock: sess = _sessions.get(req.session_id) if not sess: raise HTTPException(status_code=404, detail=f"会话不存在或已过期: {req.session_id}") page = sess["page"] try: result = input_code_and_submit(page, req.code) return SubmitCodeResponse(success=True, message=result.get("message", "验证码已填写")) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.delete("/api/session/{session_id}") def close_session(session_id: str): """关闭并清理指定会话(可选,用于释放浏览器)。""" with _sessions_lock: sess = _sessions.pop(session_id, None) if not sess: return {"success": False, "message": "会话不存在"} try: client = sess.get("client") env_id = sess.get("env_id") if client and env_id is not None: client.stop_browser(env_id=env_id) except Exception: pass return {"success": True, "message": "会话已关闭"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8001)