216 lines
5.1 KiB
Python
216 lines
5.1 KiB
Python
|
|
"""
|
|||
|
|
平台适配器基类
|
|||
|
|
定义了所有平台适配器的通用接口。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from abc import ABC, abstractmethod
|
|||
|
|
from typing import Optional, Dict, Any
|
|||
|
|
from playwright.async_api import Page
|
|||
|
|
|
|||
|
|
from ..core.models import (
|
|||
|
|
PlatformType,
|
|||
|
|
AccountInfo,
|
|||
|
|
Content,
|
|||
|
|
PublishResult,
|
|||
|
|
UploadStatus,
|
|||
|
|
PublishStatus
|
|||
|
|
)
|
|||
|
|
from ..auth.base_auth import BaseAuth
|
|||
|
|
|
|||
|
|
|
|||
|
|
class BaseAdapter(ABC):
|
|||
|
|
"""平台适配器基类"""
|
|||
|
|
|
|||
|
|
def __init__(self, platform: PlatformType):
|
|||
|
|
self.platform = platform
|
|||
|
|
self.platform_name = platform.value
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
async def login(self, account_info: AccountInfo, headless: bool = False) -> bool:
|
|||
|
|
"""
|
|||
|
|
登录平台
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
account_info: 账号信息
|
|||
|
|
headless: 是否使用无头模式
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
登录是否成功
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
async def publish_content(self, page: Page, content: Content, account_info: AccountInfo) -> PublishResult:
|
|||
|
|
"""
|
|||
|
|
发布内容
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
page: Playwright页面对象
|
|||
|
|
content: 要发布的内容
|
|||
|
|
account_info: 账号信息
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
发布结果
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
async def check_login_status(self, page: Page) -> bool:
|
|||
|
|
"""
|
|||
|
|
检查登录状态
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
page: Playwright页面对象
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
是否已登录
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@abstractmethod
|
|||
|
|
def get_authenticator(self) -> BaseAuth:
|
|||
|
|
"""
|
|||
|
|
获取认证器实例
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
认证器实例
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
async def validate_content(self, content: Content) -> tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证内容是否符合平台要求
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
content: 要验证的内容
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
# 基础验证
|
|||
|
|
if not content.title.strip():
|
|||
|
|
return False, "标题不能为空"
|
|||
|
|
|
|||
|
|
if not content.description.strip():
|
|||
|
|
return False, "内容描述不能为空"
|
|||
|
|
|
|||
|
|
if len(content.title) > 100:
|
|||
|
|
return False, "标题过长,最多100个字符"
|
|||
|
|
|
|||
|
|
if len(content.description) > 1000:
|
|||
|
|
return False, "内容过长,最多1000个字符"
|
|||
|
|
|
|||
|
|
return True, ""
|
|||
|
|
|
|||
|
|
async def wait_for_upload_complete(
|
|||
|
|
self,
|
|||
|
|
page: Page,
|
|||
|
|
timeout: int = 300,
|
|||
|
|
check_interval: float = 2.0
|
|||
|
|
) -> bool:
|
|||
|
|
"""
|
|||
|
|
等待上传完成
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
page: Playwright页面对象
|
|||
|
|
timeout: 超时时间(秒)
|
|||
|
|
check_interval: 检查间隔(秒)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
上传是否完成
|
|||
|
|
"""
|
|||
|
|
import asyncio
|
|||
|
|
start_time = asyncio.get_event_loop().time()
|
|||
|
|
|
|||
|
|
while asyncio.get_event_loop().time() - start_time < timeout:
|
|||
|
|
if await self._check_upload_status(page):
|
|||
|
|
return True
|
|||
|
|
await asyncio.sleep(check_interval)
|
|||
|
|
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
async def _check_upload_status(self, page: Page) -> bool:
|
|||
|
|
"""
|
|||
|
|
检查上传状态(子类实现)
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
page: Playwright页面对象
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
上传是否完成
|
|||
|
|
"""
|
|||
|
|
# 默认实现,子类应该重写
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
async def wait_for_publish_complete(
|
|||
|
|
self,
|
|||
|
|
page: Page,
|
|||
|
|
timeout: int = 60,
|
|||
|
|
check_interval: float = 2.0
|
|||
|
|
) -> bool:
|
|||
|
|
"""
|
|||
|
|
等待发布完成
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
page: Playwright页面对象
|
|||
|
|
timeout: 超时时间(秒)
|
|||
|
|
check_interval: 检查间隔(秒)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
发布是否完成
|
|||
|
|
"""
|
|||
|
|
import asyncio
|
|||
|
|
start_time = asyncio.get_event_loop().time()
|
|||
|
|
|
|||
|
|
while asyncio.get_event_loop().time() - start_time < timeout:
|
|||
|
|
if await self._check_publish_status(page):
|
|||
|
|
return True
|
|||
|
|
await asyncio.sleep(check_interval)
|
|||
|
|
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
async def _check_publish_status(self, page: Page) -> bool:
|
|||
|
|
"""
|
|||
|
|
检查发布状态(子类实现)
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
page: Playwright页面对象
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
发布是否完成
|
|||
|
|
"""
|
|||
|
|
# 默认实现,子类应该重写
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
def create_publish_result(
|
|||
|
|
self,
|
|||
|
|
success: bool,
|
|||
|
|
message: str,
|
|||
|
|
task_id: str,
|
|||
|
|
account: str,
|
|||
|
|
error_details: Optional[Dict[str, Any]] = None,
|
|||
|
|
duration: Optional[float] = None
|
|||
|
|
) -> PublishResult:
|
|||
|
|
"""
|
|||
|
|
创建发布结果对象
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
success: 是否成功
|
|||
|
|
message: 结果消息
|
|||
|
|
task_id: 任务ID
|
|||
|
|
account: 账号名称
|
|||
|
|
error_details: 错误详情
|
|||
|
|
duration: 执行耗时
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
发布结果对象
|
|||
|
|
"""
|
|||
|
|
return PublishResult(
|
|||
|
|
task_id=task_id,
|
|||
|
|
platform=self.platform,
|
|||
|
|
account=account,
|
|||
|
|
success=success,
|
|||
|
|
message=message,
|
|||
|
|
error_details=error_details,
|
|||
|
|
duration=duration
|
|||
|
|
)
|