166 lines
5.8 KiB
Python
166 lines
5.8 KiB
Python
"""
|
|
发布管理 API (支持用户认证)
|
|
"""
|
|
from fastapi import APIRouter, HTTPException, BackgroundTasks, Depends, Request
|
|
from fastapi.responses import FileResponse
|
|
from pydantic import BaseModel
|
|
from typing import List, Optional
|
|
from datetime import datetime
|
|
import re
|
|
from loguru import logger
|
|
from app.services.publish_service import PublishService
|
|
from app.core.response import success_response
|
|
from app.core.config import settings
|
|
from app.core.deps import get_current_user
|
|
|
|
router = APIRouter()
|
|
publish_service = PublishService()
|
|
|
|
class PublishRequest(BaseModel):
|
|
"""Video publish request model"""
|
|
video_path: str
|
|
platform: str
|
|
title: str
|
|
tags: List[str] = []
|
|
description: str = ""
|
|
publish_time: Optional[datetime] = None
|
|
|
|
class PublishResponse(BaseModel):
|
|
"""Video publish response model"""
|
|
success: bool
|
|
message: str
|
|
platform: str
|
|
url: Optional[str] = None
|
|
|
|
# Supported platforms for validation
|
|
SUPPORTED_PLATFORMS = {"bilibili", "douyin", "xiaohongshu", "weixin"}
|
|
|
|
|
|
def _get_user_id(request: Request) -> Optional[str]:
|
|
"""从请求中获取用户 ID (兼容未登录场景)"""
|
|
try:
|
|
from app.core.security import decode_access_token
|
|
token = request.cookies.get("access_token")
|
|
if token:
|
|
token_data = decode_access_token(token)
|
|
if token_data:
|
|
return token_data.user_id
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
|
|
@router.post("")
|
|
async def publish_video(request: PublishRequest, req: Request, background_tasks: BackgroundTasks):
|
|
"""发布视频到指定平台"""
|
|
# Validate platform
|
|
if request.platform not in SUPPORTED_PLATFORMS:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"不支持的平台: {request.platform}。支持的平台: {', '.join(SUPPORTED_PLATFORMS)}"
|
|
)
|
|
|
|
# 获取用户 ID (可选)
|
|
user_id = _get_user_id(req)
|
|
|
|
try:
|
|
result = await publish_service.publish(
|
|
video_path=request.video_path,
|
|
platform=request.platform,
|
|
title=request.title,
|
|
tags=request.tags,
|
|
description=request.description,
|
|
publish_time=request.publish_time,
|
|
user_id=user_id
|
|
)
|
|
message = result.get("message", "")
|
|
return success_response(result, message=message)
|
|
except Exception as e:
|
|
logger.error(f"发布失败: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.get("/platforms")
|
|
async def list_platforms():
|
|
return success_response({"platforms": [{**pinfo, "id": pid} for pid, pinfo in publish_service.PLATFORMS.items()]})
|
|
|
|
@router.get("/accounts")
|
|
async def list_accounts(req: Request):
|
|
user_id = _get_user_id(req)
|
|
return success_response({"accounts": publish_service.get_accounts(user_id)})
|
|
|
|
@router.post("/login/{platform}")
|
|
async def login_platform(platform: str, req: Request):
|
|
"""触发平台QR码登录"""
|
|
if platform not in SUPPORTED_PLATFORMS:
|
|
raise HTTPException(status_code=400, detail=f"不支持的平台: {platform}")
|
|
|
|
user_id = _get_user_id(req)
|
|
result = await publish_service.login(platform, user_id)
|
|
|
|
message = result.get("message", "")
|
|
return success_response(result, message=message)
|
|
|
|
@router.post("/logout/{platform}")
|
|
async def logout_platform(platform: str, req: Request):
|
|
"""注销平台登录"""
|
|
if platform not in SUPPORTED_PLATFORMS:
|
|
raise HTTPException(status_code=400, detail=f"不支持的平台: {platform}")
|
|
|
|
user_id = _get_user_id(req)
|
|
result = publish_service.logout(platform, user_id)
|
|
message = result.get("message", "")
|
|
return success_response(result, message=message)
|
|
|
|
@router.get("/login/status/{platform}")
|
|
async def get_login_status(platform: str, req: Request):
|
|
"""检查登录状态 (优先检查活跃的扫码会话)"""
|
|
if platform not in SUPPORTED_PLATFORMS:
|
|
raise HTTPException(status_code=400, detail=f"不支持的平台: {platform}")
|
|
|
|
user_id = _get_user_id(req)
|
|
result = publish_service.get_login_session_status(platform, user_id)
|
|
message = result.get("message", "")
|
|
return success_response(result, message=message)
|
|
|
|
@router.post("/cookies/save/{platform}")
|
|
async def save_platform_cookie(platform: str, cookie_data: dict, req: Request):
|
|
"""
|
|
保存从客户端浏览器提取的Cookie
|
|
|
|
Args:
|
|
platform: 平台ID
|
|
cookie_data: {"cookie_string": "document.cookie的内容"}
|
|
"""
|
|
if platform not in SUPPORTED_PLATFORMS:
|
|
raise HTTPException(status_code=400, detail=f"不支持的平台: {platform}")
|
|
|
|
cookie_string = cookie_data.get("cookie_string", "")
|
|
if not cookie_string:
|
|
raise HTTPException(status_code=400, detail="cookie_string 不能为空")
|
|
|
|
user_id = _get_user_id(req)
|
|
result = await publish_service.save_cookie_string(platform, cookie_string, user_id)
|
|
|
|
message = result.get("message", "")
|
|
return success_response(result, message=message)
|
|
|
|
|
|
@router.get("/screenshot/{filename}")
|
|
async def get_publish_screenshot(
|
|
filename: str,
|
|
current_user: dict = Depends(get_current_user),
|
|
):
|
|
if not re.match(r"^[A-Za-z0-9_.-]+$", filename):
|
|
raise HTTPException(status_code=400, detail="非法文件名")
|
|
|
|
user_id = str(current_user.get("id") or "")
|
|
if not user_id:
|
|
raise HTTPException(status_code=401, detail="未登录")
|
|
|
|
user_dir = re.sub(r"[^A-Za-z0-9_-]", "_", user_id)[:64] or "legacy"
|
|
file_path = settings.PUBLISH_SCREENSHOT_DIR / user_dir / filename
|
|
if not file_path.exists() or not file_path.is_file():
|
|
raise HTTPException(status_code=404, detail="截图不存在")
|
|
|
|
return FileResponse(path=str(file_path), media_type="image/png")
|