33 lines
1 KiB
Python
33 lines
1 KiB
Python
|
|
"""Confirm whether a video is a Short by probing youtube.com/shorts/<id>.
|
||
|
|
|
||
|
|
A real Short returns HTTP 200 at that URL; a regular video redirects to /watch.
|
||
|
|
This uses no API quota."""
|
||
|
|
import httpx
|
||
|
|
|
||
|
|
SHORTS_URL = "https://www.youtube.com/shorts/{video_id}"
|
||
|
|
# The SOCS cookie skips YouTube's cookie-consent interstitial, which otherwise
|
||
|
|
# redirects every server-side request to consent.youtube.com.
|
||
|
|
_HEADERS = {
|
||
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
|
||
|
|
"Cookie": "SOCS=CAI",
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def probe_is_short(client: httpx.Client, video_id: str) -> bool | None:
|
||
|
|
"""True if a Short, False if a regular video, None if undetermined (retry later)."""
|
||
|
|
try:
|
||
|
|
resp = client.get(
|
||
|
|
SHORTS_URL.format(video_id=video_id), follow_redirects=False
|
||
|
|
)
|
||
|
|
except httpx.HTTPError:
|
||
|
|
return None
|
||
|
|
if resp.status_code == 200:
|
||
|
|
return True
|
||
|
|
if resp.status_code in (301, 302, 303, 307, 308):
|
||
|
|
return False
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def make_client() -> httpx.Client:
|
||
|
|
return httpx.Client(timeout=10.0, headers=_HEADERS)
|