fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed flag, scheduled refinement (migration 0005) - Search: match title + channel name only (descriptions caused noisy results) - Faceted tag filtering: AND across categories (language AND topic narrows), OR within a category; any/all toggle applies to topics - Language detection: majority vote over individual titles (fixes misdetections like multipoleguy -> English; drops bogus Polish/Romanian) - Login: drop forced consent so returning sign-in is quick (select_account) - Feed cards: clickable channel name (opens channel), persistent saved badge, undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
This commit is contained in:
parent
e56502789f
commit
8c245e986f
17 changed files with 306 additions and 35 deletions
32
backend/app/youtube/shorts.py
Normal file
32
backend/app/youtube/shorts.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue