diff --git a/services/youtube/youtube_handler.py b/services/youtube/youtube_handler.py index 810aee6..b36989e 100644 --- a/services/youtube/youtube_handler.py +++ b/services/youtube/youtube_handler.py @@ -66,6 +66,8 @@ def is_youtube_url(url: str) -> bool: def extract_youtube_id(url: str) -> Optional[str]: """Extract YouTube video ID from various URL formats.""" + if not isinstance(url, str): + return None parsed = urllib.parse.urlparse(url) if parsed.hostname in ("www.youtube.com", "youtube.com", "m.youtube.com"): if parsed.path == "/watch": diff --git a/tests/test_youtube_extract_id_nonstring.py b/tests/test_youtube_extract_id_nonstring.py new file mode 100644 index 0000000..e512b81 --- /dev/null +++ b/tests/test_youtube_extract_id_nonstring.py @@ -0,0 +1,15 @@ +from services.youtube.youtube_handler import extract_youtube_id + + +def test_extract_youtube_id_handles_non_string_url(): + # urllib.parse.urlparse raises AttributeError on a non-string, so a non-str + # url (e.g. from a JSON-decoded request body) crashed the extractor instead + # of being treated as "not a YouTube URL". + assert extract_youtube_id(123) is None + assert extract_youtube_id({"bad": 1}) is None + assert extract_youtube_id(["https://youtu.be/x"]) is None + + +def test_extract_youtube_id_still_parses_real_urls(): + assert extract_youtube_id("https://youtu.be/dQw4w9WgXcQ") == "dQw4w9WgXcQ" + assert extract_youtube_id("https://www.youtube.com/watch?v=abc123") == "abc123"