62 lines
1.9 KiB
Python
62 lines
1.9 KiB
Python
from typing import Dict, Optional
|
|
from pathlib import Path
|
|
from urllib.parse import quote
|
|
|
|
|
|
def _parse_proxy_line(line: str) -> Optional[str]:
|
|
# Формат: scheme:ip:port[:login[:pass]]
|
|
# Примеры:
|
|
# socks5:127.0.0.1:9050
|
|
# socks5:127.0.0.1:9050:user:pass
|
|
# http:127.0.0.1:8888
|
|
parts = [p.strip() for p in line.strip().split(":")]
|
|
if len(parts) < 3:
|
|
return None
|
|
scheme, host, port = parts[0], parts[1], parts[2]
|
|
user = parts[3] if len(parts) >= 4 and parts[3] else None
|
|
password = parts[4] if len(parts) >= 5 and parts[4] else None
|
|
auth = ""
|
|
if user:
|
|
auth = quote(user)
|
|
if password:
|
|
auth += f":{quote(password)}"
|
|
auth += "@"
|
|
# Исправление для socks5: httpx ожидает схему socks5:// (не socks://)
|
|
if scheme == "socks":
|
|
scheme = "socks5"
|
|
# Явно проверяем протокол, чтобы был http://, https:// или socks5://
|
|
if not scheme.startswith(("http", "socks")):
|
|
scheme = "http"
|
|
return f"{scheme}://{auth}{host}:{port}"
|
|
|
|
|
|
def _read_proxy_from_file() -> Optional[str]:
|
|
file_path = Path("proxy.txt")
|
|
if not file_path.exists():
|
|
return None
|
|
try:
|
|
for raw in file_path.read_text(encoding="utf-8").splitlines():
|
|
line = raw.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
url = _parse_proxy_line(line)
|
|
if url:
|
|
return url
|
|
except Exception:
|
|
return None
|
|
return None
|
|
|
|
|
|
def build_httpx_proxies() -> Optional[Dict[str, str]]:
|
|
# Читаем только из proxy.txt (без переменных окружения)
|
|
url = _read_proxy_from_file()
|
|
if not url:
|
|
return None
|
|
# Для httpx корректнее указывать схемы явно
|
|
return {
|
|
"http://": url,
|
|
"https://": url,
|
|
}
|
|
|
|
|