| from abc import ABC, abstractmethod
|
| from typing import List
|
| import asyncio
|
| from app.models.proxy import Proxy
|
| from app.models.source import SourceConfig, SourceType
|
| from app.grabber.patterns import ProxyPatterns
|
| from app.grabber.parsers import VMessParser, VLESSParser, TrojanParser, SSParser
|
| from app.utils.base64_decoder import SubscriptionDecoder
|
|
|
|
|
| class BaseGrabber(ABC):
|
| def __init__(
|
| self, max_retries: int = 3, retry_delay: float = 1.0, timeout: int = 30
|
| ):
|
| self.max_retries = max_retries
|
| self.retry_delay = retry_delay
|
| self.timeout = timeout
|
|
|
| @abstractmethod
|
| async def fetch_content(self, source: SourceConfig) -> str:
|
| pass
|
|
|
| async def extract_proxies(self, source: SourceConfig) -> List[Proxy]:
|
| content = await self.fetch_content(source)
|
|
|
| if source.selector:
|
| proxies = await self._try_exact_selector(content, source)
|
| if proxies:
|
| return proxies
|
|
|
| proxies = await self.parse_content(content, source.type)
|
|
|
| return proxies
|
|
|
| async def _try_exact_selector(
|
| self, content: str, source: SourceConfig
|
| ) -> List[Proxy]:
|
| return []
|
|
|
| async def parse_content(self, content: str, source_type: SourceType) -> List[Proxy]:
|
| proxies = []
|
|
|
| if source_type == SourceType.SUBSCRIPTION_BASE64:
|
| try:
|
| content = SubscriptionDecoder.decode(content)
|
| except ValueError:
|
| pass
|
|
|
| http_matches = ProxyPatterns.extract_http_proxies(content)
|
| for ip, port in http_matches:
|
| proxies.append(
|
| Proxy(ip=ip, port=int(port), protocol="http", source=str(source_type))
|
| )
|
|
|
| vmess_urls = ProxyPatterns.extract_vmess_urls(content)
|
| for url in vmess_urls:
|
| try:
|
| proxy = VMessParser.parse(url)
|
| proxies.append(proxy)
|
| except ValueError:
|
| continue
|
|
|
| vless_urls = ProxyPatterns.extract_vless_urls(content)
|
| for url in vless_urls:
|
| try:
|
| proxy = VLESSParser.parse(url)
|
| proxies.append(proxy)
|
| except ValueError:
|
| continue
|
|
|
| trojan_urls = ProxyPatterns.extract_trojan_urls(content)
|
| for url in trojan_urls:
|
| try:
|
| proxy = TrojanParser.parse(url)
|
| proxies.append(proxy)
|
| except ValueError:
|
| continue
|
|
|
| ss_urls = ProxyPatterns.extract_ss_urls(content)
|
| for url in ss_urls:
|
| try:
|
| proxy = SSParser.parse(url)
|
| proxies.append(proxy)
|
| except ValueError:
|
| continue
|
|
|
| return proxies
|
|
|