121 lines
3.1 KiB
Python
121 lines
3.1 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
下载策略基础类和接口定义
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass, field
|
|
from typing import Dict, List, Optional, Any
|
|
from enum import Enum
|
|
import time
|
|
|
|
|
|
class TaskType(Enum):
|
|
"""任务类型枚举"""
|
|
VIDEO = "video"
|
|
IMAGE = "image"
|
|
MUSIC = "music"
|
|
USER = "user"
|
|
MIX = "mix"
|
|
LIVE = "live"
|
|
|
|
|
|
class TaskStatus(Enum):
|
|
"""任务状态枚举"""
|
|
PENDING = "pending"
|
|
PROCESSING = "processing"
|
|
COMPLETED = "completed"
|
|
FAILED = "failed"
|
|
RETRYING = "retrying"
|
|
|
|
|
|
@dataclass
|
|
class DownloadTask:
|
|
"""下载任务数据类"""
|
|
task_id: str
|
|
url: str
|
|
task_type: TaskType
|
|
priority: int = 0
|
|
retry_count: int = 0
|
|
max_retries: int = 3
|
|
status: TaskStatus = TaskStatus.PENDING
|
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
created_at: float = field(default_factory=time.time)
|
|
updated_at: float = field(default_factory=time.time)
|
|
error_message: Optional[str] = None
|
|
|
|
def increment_retry(self) -> bool:
|
|
"""增加重试次数,返回是否还能重试"""
|
|
self.retry_count += 1
|
|
self.updated_at = time.time()
|
|
return self.retry_count < self.max_retries
|
|
|
|
def to_dict(self) -> Dict:
|
|
"""转换为字典"""
|
|
return {
|
|
'task_id': self.task_id,
|
|
'url': self.url,
|
|
'task_type': self.task_type.value,
|
|
'priority': self.priority,
|
|
'retry_count': self.retry_count,
|
|
'max_retries': self.max_retries,
|
|
'status': self.status.value,
|
|
'metadata': self.metadata,
|
|
'created_at': self.created_at,
|
|
'updated_at': self.updated_at,
|
|
'error_message': self.error_message
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class DownloadResult:
|
|
"""下载结果数据类"""
|
|
success: bool
|
|
task_id: str
|
|
file_paths: List[str] = field(default_factory=list)
|
|
error_message: Optional[str] = None
|
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
duration: float = 0.0
|
|
retry_count: int = 0
|
|
|
|
def to_dict(self) -> Dict:
|
|
"""转换为字典"""
|
|
return {
|
|
'success': self.success,
|
|
'task_id': self.task_id,
|
|
'file_paths': self.file_paths,
|
|
'error_message': self.error_message,
|
|
'metadata': self.metadata,
|
|
'duration': self.duration,
|
|
'retry_count': self.retry_count
|
|
}
|
|
|
|
|
|
class IDownloadStrategy(ABC):
|
|
"""下载策略抽象基类"""
|
|
|
|
@abstractmethod
|
|
async def can_handle(self, task: DownloadTask) -> bool:
|
|
"""判断是否可以处理该任务"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def download(self, task: DownloadTask) -> DownloadResult:
|
|
"""执行下载任务"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_priority(self) -> int:
|
|
"""获取策略优先级,数值越大优先级越高"""
|
|
pass
|
|
|
|
@property
|
|
@abstractmethod
|
|
def name(self) -> str:
|
|
"""策略名称"""
|
|
pass
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.name} (Priority: {self.get_priority()})" |