| 154 | |
| 155 | @dataclass(frozen=True) |
| 156 | class Strategy: |
| 157 | id: str # stable identifier for stats |
| 158 | impersonate: str # curl_cffi browser profile (TLS / HTTP/2 fingerprint) |
| 159 | proxy: str # "env" (use HTTPS_PROXY) or "direct" |
| 160 | ua: str # User-Agent that matches impersonate |
| 161 | transport: str = "html" # "html" /watch or "innertube" /player |
| 162 | innertube_client: Optional[str] = None # key in INNERTUBE_CLIENTS |
| 163 | |
| 164 | def ua_for_warmup(self) -> dict: |
| 165 | return {**BASE_HEADERS, "User-Agent": self.ua} |
| 166 | |
| 167 | def ua_for_watch(self) -> dict: |
| 168 | return {**BASE_HEADERS, "User-Agent": self.ua, |
| 169 | "Referer": "https://www.youtube.com/", |
| 170 | "Sec-Fetch-Site": "same-origin"} |
| 171 | |
| 172 | def proxies_arg(self): |
| 173 | # None ⇒ curl_cffi reads HTTPS_PROXY from env. |
| 174 | if self.proxy == "direct": |
| 175 | return {"http": None, "https": None} |
| 176 | return None |
| 177 | |
| 178 | |
| 179 | # Three independent axes: TLS family × transport endpoint × proxy mode. |