fix request metadata issue
Browse files- src/pages/_home_page.py +6 -7
- src/utils/helpers.py +45 -0
src/pages/_home_page.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from typing import Any, Dict, List, Tuple
|
| 4 |
-
|
| 5 |
-
import requests
|
| 6 |
import streamlit as st
|
| 7 |
|
| 8 |
from utils.helpers import (
|
|
@@ -11,6 +9,7 @@ from utils.helpers import (
|
|
| 11 |
fetch_job_status,
|
| 12 |
fetch_quiz,
|
| 13 |
fetch_summary,
|
|
|
|
| 14 |
get_image_base64,
|
| 15 |
get_remote_image_url,
|
| 16 |
list_cached_videos,
|
|
@@ -135,12 +134,12 @@ def _render_api_status() -> None:
|
|
| 135 |
def _fetch_youtube_metadata(video_url: str) -> Dict[str, Any] | None:
|
| 136 |
if not video_url:
|
| 137 |
return None
|
| 138 |
-
oembed_url = f"https://www.youtube.com/oembed?url={video_url}&format=json"
|
| 139 |
try:
|
| 140 |
-
|
| 141 |
-
if
|
| 142 |
-
return
|
| 143 |
-
except
|
|
|
|
| 144 |
return None
|
| 145 |
return None
|
| 146 |
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from typing import Any, Dict, List, Tuple
|
|
|
|
|
|
|
| 4 |
import streamlit as st
|
| 5 |
|
| 6 |
from utils.helpers import (
|
|
|
|
| 9 |
fetch_job_status,
|
| 10 |
fetch_quiz,
|
| 11 |
fetch_summary,
|
| 12 |
+
fetch_youtube_metadata_v3,
|
| 13 |
get_image_base64,
|
| 14 |
get_remote_image_url,
|
| 15 |
list_cached_videos,
|
|
|
|
| 134 |
def _fetch_youtube_metadata(video_url: str) -> Dict[str, Any] | None:
|
| 135 |
if not video_url:
|
| 136 |
return None
|
|
|
|
| 137 |
try:
|
| 138 |
+
metadata = fetch_youtube_metadata_v3(video_url)
|
| 139 |
+
if metadata:
|
| 140 |
+
return metadata
|
| 141 |
+
except RuntimeError as exc:
|
| 142 |
+
st.warning(str(exc))
|
| 143 |
return None
|
| 144 |
return None
|
| 145 |
|
src/utils/helpers.py
CHANGED
|
@@ -26,6 +26,7 @@ _API_KEY_ENV_KEY = "CHAPTLY_API_KEY"
|
|
| 26 |
_HMAC_SECRET_ENV_KEY = "CHAPTLY_API_SECRET"
|
| 27 |
_S3_BUCKET_ENV_KEY = "CHAPTLY_S3_BUCKET"
|
| 28 |
_AWS_REGION_ENV_KEY = "AWS_REGION"
|
|
|
|
| 29 |
_SIG_HEADER = "X-Signature"
|
| 30 |
_TS_HEADER = "X-Timestamp"
|
| 31 |
|
|
@@ -33,6 +34,7 @@ DEFAULT_S3_BUCKET = "chaptly-rag"
|
|
| 33 |
DEFAULT_AWS_REGION = "ap-southeast-1"
|
| 34 |
IMAGE_REQUEST_TIMEOUT = 10
|
| 35 |
_IMG_DIR = Path(__file__).resolve().parents[2] / "img"
|
|
|
|
| 36 |
|
| 37 |
|
| 38 |
@dataclass(frozen=True)
|
|
@@ -315,3 +317,46 @@ def list_cached_videos() -> list[Dict[str, Any]]:
|
|
| 315 |
metadata = _load_video_metadata(video_id)
|
| 316 |
items.append(metadata)
|
| 317 |
return sorted(items, key=lambda item: item.get("title", ""))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
_HMAC_SECRET_ENV_KEY = "CHAPTLY_API_SECRET"
|
| 27 |
_S3_BUCKET_ENV_KEY = "CHAPTLY_S3_BUCKET"
|
| 28 |
_AWS_REGION_ENV_KEY = "AWS_REGION"
|
| 29 |
+
_YOUTUBE_API_KEY_ENV = "YOUTUBE_V3_DATA_API_KEY"
|
| 30 |
_SIG_HEADER = "X-Signature"
|
| 31 |
_TS_HEADER = "X-Timestamp"
|
| 32 |
|
|
|
|
| 34 |
DEFAULT_AWS_REGION = "ap-southeast-1"
|
| 35 |
IMAGE_REQUEST_TIMEOUT = 10
|
| 36 |
_IMG_DIR = Path(__file__).resolve().parents[2] / "img"
|
| 37 |
+
YOUTUBE_API_URL = "https://www.googleapis.com/youtube/v3/videos"
|
| 38 |
|
| 39 |
|
| 40 |
@dataclass(frozen=True)
|
|
|
|
| 317 |
metadata = _load_video_metadata(video_id)
|
| 318 |
items.append(metadata)
|
| 319 |
return sorted(items, key=lambda item: item.get("title", ""))
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
def extract_youtube_video_id(url: str) -> Optional[str]:
|
| 323 |
+
"""Best-effort extraction of the YouTube video ID from a URL."""
|
| 324 |
+
if not url:
|
| 325 |
+
return None
|
| 326 |
+
url = url.strip()
|
| 327 |
+
if "v=" in url:
|
| 328 |
+
return url.split("v=")[1].split("&")[0]
|
| 329 |
+
if "youtu.be" in url:
|
| 330 |
+
return url.rsplit("/", 1)[-1].split("?")[0]
|
| 331 |
+
return None
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
def fetch_youtube_metadata_v3(video_url: str) -> Optional[Dict[str, Any]]:
|
| 335 |
+
"""Fetch video metadata using the YouTube Data API v3."""
|
| 336 |
+
video_id = extract_youtube_video_id(video_url)
|
| 337 |
+
if not video_id:
|
| 338 |
+
return None
|
| 339 |
+
api_key = _get_secret_or_env(_YOUTUBE_API_KEY_ENV)
|
| 340 |
+
if not api_key:
|
| 341 |
+
raise RuntimeError("YOUTUBE_V3_DATA_API_KEY is not configured in this environment.")
|
| 342 |
+
params = {
|
| 343 |
+
"part": "snippet",
|
| 344 |
+
"id": video_id,
|
| 345 |
+
"key": api_key,
|
| 346 |
+
}
|
| 347 |
+
try:
|
| 348 |
+
response = requests.get(YOUTUBE_API_URL, params=params, timeout=DEFAULT_TIMEOUT)
|
| 349 |
+
response.raise_for_status()
|
| 350 |
+
payload = response.json()
|
| 351 |
+
except requests.RequestException as exc:
|
| 352 |
+
raise RuntimeError(f"Unable to contact YouTube Data API: {exc}") from exc
|
| 353 |
+
items = payload.get("items") or []
|
| 354 |
+
if not items:
|
| 355 |
+
return None
|
| 356 |
+
snippet = items[0].get("snippet", {})
|
| 357 |
+
return {
|
| 358 |
+
"title": snippet.get("title"),
|
| 359 |
+
"author_name": snippet.get("channelTitle"),
|
| 360 |
+
"thumbnail_url": (snippet.get("thumbnails", {}).get("high", {}) or snippet.get("thumbnails", {}).get("default", {})).get("url"),
|
| 361 |
+
"video_id": video_id,
|
| 362 |
+
}
|