goofish / src /rotation.py
host1syan's picture
Upload 212 files
5378afe verified
import os
import random
import time
from dataclasses import dataclass
from typing import Dict, List, Optional
@dataclass
class RotationItem:
value: str
last_error: Optional[str] = None
class RotationPool:
def __init__(self, items: List[str], blacklist_ttl: int = 300, name: str = ""):
self.items = [RotationItem(value=item) for item in items if item]
self.blacklist_ttl = max(0, int(blacklist_ttl))
self.name = name or "rotation"
self._blacklist: Dict[str, float] = {}
def _cleanup_blacklist(self) -> None:
now = time.time()
expired = [key for key, ts in self._blacklist.items() if ts <= now]
for key in expired:
self._blacklist.pop(key, None)
def available_items(self) -> List[RotationItem]:
self._cleanup_blacklist()
return [item for item in self.items if item.value not in self._blacklist]
def pick_random(self) -> Optional[RotationItem]:
candidates = self.available_items()
if not candidates:
return None
return random.choice(candidates)
def mark_bad(self, item: Optional[RotationItem], reason: str = "") -> None:
if not item:
return
item.last_error = reason
if self.blacklist_ttl <= 0:
return
self._blacklist[item.value] = time.time() + self.blacklist_ttl
def parse_proxy_pool(value: Optional[str]) -> List[str]:
if not value:
return []
if isinstance(value, list):
return [str(item).strip() for item in value if str(item).strip()]
return [entry.strip() for entry in str(value).split(",") if entry.strip()]
def load_state_files(state_dir: str) -> List[str]:
if not state_dir:
return []
if not os.path.isdir(state_dir):
return []
files = []
for name in os.listdir(state_dir):
if name.endswith(".json"):
files.append(os.path.join(state_dir, name))
return sorted(files)