From e03b2f47547113169045eb960daeb9cfabf8ca34 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Sat, 14 Jan 2023 16:18:56 -0800 Subject: [PATCH] remove url validators --- src/ytdl_sub/validators/url_validator.py | 204 -------------------- tests/e2e/conftest.py | 8 - tests/unit/validators/test_url_validator.py | 155 --------------- 3 files changed, 367 deletions(-) delete mode 100644 src/ytdl_sub/validators/url_validator.py delete mode 100644 tests/unit/validators/test_url_validator.py diff --git a/src/ytdl_sub/validators/url_validator.py b/src/ytdl_sub/validators/url_validator.py deleted file mode 100644 index 828c2e3f..00000000 --- a/src/ytdl_sub/validators/url_validator.py +++ /dev/null @@ -1,204 +0,0 @@ -from typing import Any -from typing import Optional -from urllib.parse import parse_qs -from urllib.parse import urlparse - -from ytdl_sub.validators.validators import StringValidator - - -class YoutubeVideoUrlValidator(StringValidator): - - _expected_value_type_name = "Youtube video url" - - @classmethod - def _get_video_id(cls, url: str) -> Optional[str]: - """ - Examples: - - https://youtu.be/SA2iWivDJiE - https://www.youtube.com/watch?v=_oPAwA_Udwc&feature=feedu - https://www.youtube.com/embed/SA2iWivDJiE - https://www.youtube.com/v/SA2iWivDJiE?version=3&hl=en_US - https://www.youtube.com/shorts/ucYmEqmlhFw - - Returns - ------- - The video id if it is parsed correctly. None if parsing fails - """ - # If the url doesn't contain youtube or youtu.be, assume it is invalid - if "youtube.com" not in url and "youtu.be" not in url: - return None - - # If https:// is not present, urlparse will not work - if not url.startswith("https://"): - url = f"https://{url}" - - query = urlparse(url) - if query.hostname in ("youtu.be", "www.youtu.be"): - return query.path[1:] - if query.hostname in ("youtube.com", "www.youtube.com"): - if query.path == "/watch": - parsed_q = parse_qs(query.query) - if "v" in parsed_q: - return parsed_q["v"][0] - if query.path.startswith(("/embed/", "/v/", "/shorts/")): - return query.path.split("/")[2] - - return None - - def __init__(self, name: str, value: Any): - super().__init__(name, value) - - self._video_id = self._get_video_id(value) - if not self._video_id: - raise self._validation_exception(f"'{value}' is not a valid Youtube video url.") - - @property - def video_url(self) -> str: - """ - Returns - ------- - Full video URL - """ - return f"https://youtube.com/watch?v={self._video_id}" - - -class YoutubePlaylistUrlValidator(StringValidator): - - _expected_value_type_name = "Youtube playlist url" - - @classmethod - def _get_playlist_id(cls, url: str) -> Optional[str]: - """ - Examples: - - https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc - """ - # If the url doesn't contain youtube, assume it is invalid - if "youtube.com" not in url: - return None - - # If https:// is not present, urlparse will not work - if not url.startswith("https://"): - url = f"https://{url}" - - query = urlparse(url) - if query.hostname in ("youtube.com", "www.youtube.com"): - if query.path == "/playlist": - parsed_q = parse_qs(query.query) - if "list" in parsed_q: - return parsed_q["list"][0] - - return None - - def __init__(self, name: str, value: Any): - super().__init__(name, value) - - self._playlist_id = self._get_playlist_id(value) - if not self._playlist_id: - raise self._validation_exception(f"'{value}' is not a valid Youtube playlist url.") - - @property - def playlist_url(self) -> str: - """ - Returns - ------- - Full playlist URL - """ - return f"https://youtube.com/playlist?list={self._playlist_id}" - - -class YoutubeChannelUrlValidator(StringValidator): - - _expected_value_type_name = "Youtube channel url" - - @classmethod - def _get_channel_url(cls, url: str) -> Optional[str]: - """ - Examples: - - https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw - - https://www.youtube.com/user/username - - https://www.youtube.com/c/channel_name - - https://youtube.com/channel_name - """ - # If the url doesn't contain youtube, assume it is invalid - if "youtube.com" not in url: - return None - - # If https:// is not present, urlparse will not work - if not url.startswith("https://"): - url = f"https://{url}" - - query = urlparse(url) - if query.hostname in ("youtube.com", "www.youtube.com"): - query_path_split = query.path.split("/") - if any(query.path.startswith(qpath) for qpath in ("/channel/", "/user/", "/c/")): - # Ensure there is "/path/id".split('/') = ['', 'path', 'id'] at least three - if len(query_path_split) < 3 or len(query_path_split[2]) == 0: - return None - return f"https://youtube.com{query.path}" - if len(query_path_split) == 2 and len(query_path_split[1]) > 0: - # For channels that do not feature a 'c' or 'channel' - # Ensure length of channel string is at least one - return f"https://youtube.com{query.path}" - - return None - - def __init__(self, name: str, value: Any): - super().__init__(name, value) - - self._channel_url = self._get_channel_url(value) - if not self._channel_url: - raise self._validation_exception(f"'{value}' is not a valid Youtube channel url.") - - @property - def channel_url(self) -> str: - """ - Returns - ------- - Full channel URL - """ - return self._channel_url - - -class SoundcloudUsernameUrlValidator(StringValidator): - - _expected_value_type_name = "Soundcloud username url" - - @classmethod - def _get_channel_url(cls, url: str) -> Optional[str]: - """ - Examples: - - https://www.soundcloud.com/artist_name - """ - # If the url doesn't contain soundcloud, assume it is invalid - if "soundcloud.com" not in url: - return None - - # If https:// is not present, urlparse will not work - if not url.startswith("https://"): - url = f"https://{url}" - - query = urlparse(url) - if query.hostname in ("soundcloud.com", "www.soundcloud.com"): - if len(query.path) > 2: # /artist_name - username = query.path[1:].split("/")[0] # strip extra paths or slashes - username = username.split("?")[0] # strip extra arguments - return f"https://soundcloud.com/{username}" - - return None - - def __init__(self, name: str, value: Any): - super().__init__(name, value) - - self._username_url = self._get_channel_url(value) - if not self._username_url: - raise self._validation_exception(f"'{value}' is not a valid Soundcloud username url.") - - @property - def username_url(self) -> str: - """ - Returns - ------- - Full artist URL - """ - return self._username_url diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py index 803d38a1..1e387f0f 100644 --- a/tests/e2e/conftest.py +++ b/tests/e2e/conftest.py @@ -79,14 +79,6 @@ def channel_as_tv_show_config(working_directory) -> ConfigFile: ) -@pytest.fixture -def soundcloud_discography_config(working_directory) -> ConfigFile: - return _load_config( - config_path="examples/soundcloud_discography_config.yaml", - working_directory=working_directory, - ) - - @pytest.fixture() def music_audio_config(working_directory) -> ConfigFile: return _load_config( diff --git a/tests/unit/validators/test_url_validator.py b/tests/unit/validators/test_url_validator.py deleted file mode 100644 index e592e231..00000000 --- a/tests/unit/validators/test_url_validator.py +++ /dev/null @@ -1,155 +0,0 @@ -import re - -import pytest - -from ytdl_sub.utils.exceptions import ValidationException -from ytdl_sub.validators.url_validator import SoundcloudUsernameUrlValidator -from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator -from ytdl_sub.validators.url_validator import YoutubePlaylistUrlValidator -from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator - - -class TestYoutubeVideoUrlValidator: - @pytest.mark.parametrize( - "url", - [ - "youtu.be/dQw4w9WgXcQ", - "www.youtu.be/dQw4w9WgXcQ", - "https://youtu.be/dQw4w9WgXcQ", - "https://www.youtu.be/dQw4w9WgXcQ", - "https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=feedu", - "https://www.youtube.com/embed/dQw4w9WgXcQ", - "https://www.youtube.com/v/dQw4w9WgXcQ?version=3&hl=en_US", - "https://www.youtube.com/shorts/dQw4w9WgXcQ", - ], - ) - def test_youtube_video_url_validator_success(self, url): - video_url = YoutubeVideoUrlValidator(name="unit test", value=url).video_url - assert video_url == "https://youtube.com/watch?v=dQw4w9WgXcQ" - - @pytest.mark.parametrize( - "bad_url", - [ - "utube.com/watch?v=sdfsadf", - "youtube.com/nope?v=sdfsadf", - "youtube.com", - "youtube.com/watch", - "youtube.com/watch?v=", - "youtu.be/", - "youtu.be", - "youtube.com/shorts", - ], - ) - def test_youtube_video_url_validator_fail(self, bad_url): - expected_error_msg = f"'{bad_url}' is not a valid Youtube video url." - with pytest.raises(ValidationException, match=re.escape(expected_error_msg)): - YoutubeVideoUrlValidator(name="unit test", value=bad_url) - - -class TestYoutubePlaylistUrlValidator: - @pytest.mark.parametrize( - "url", - [ - "youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", - "www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", - "https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", - "https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", - ], - ) - def test_youtube_playlist_url_validator_success(self, url): - playlist_url = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_url - assert ( - playlist_url == "https://youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc" - ) - - @pytest.mark.parametrize( - "bad_url", - [ - "youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", - "youtube.com/playlistlist=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc", - "youtube.com", - "youtube.com/playlist/asdfsdfsdf", - "youtube.com/playlist?list=", - "youtube.com/playlist", - ], - ) - def test_youtube_playlist_url_validator_fail(self, bad_url): - expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url." - with pytest.raises(ValidationException, match=re.escape(expected_error_msg)): - YoutubePlaylistUrlValidator(name="unit test", value=bad_url) - - -class TestYoutubeChannelUrlValidator: - @pytest.mark.parametrize( - "url, expected_url", - [ - ( - "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - "https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - ), - ( - "https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - "https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - ), - ( - "youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - "https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - ), - ( - "www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - "https://youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", - ), - ( - "https://www.youtube.com/c/RickastleyCoUkOfficial", - "https://youtube.com/c/RickastleyCoUkOfficial", - ), - ( - "https://www.youtube.com/user/videogamedunkey", - "https://youtube.com/user/videogamedunkey", - ), - ( - "https://youtube.com/extracredits", - "https://youtube.com/extracredits", - ), - ], - ) - def test_youtube_channel_url_validator_success(self, url, expected_url): - channel_url = YoutubeChannelUrlValidator(name="unit test", value=url).channel_url - assert channel_url == expected_url - - @pytest.mark.parametrize( - "bad_url", - [ - "www.youtube.com/cha/UCuAXFkgsw1L7xaCfnd5JJOw", - "www.nopetube.com/channel/asdfdsf", - "www.youtube.com/channel/", - "www.youtube.com/channell/asdfasdf", - ], - ) - def test_youtube_channel_url_validator_fail(self, bad_url): - expected_error_msg = f"'{bad_url}' is not a valid Youtube channel url." - with pytest.raises(ValidationException, match=re.escape(expected_error_msg)): - YoutubeChannelUrlValidator(name="unit test", value=bad_url) - - -class TestSoundcloudUsernameUrlValidator: - @pytest.mark.parametrize( - "url", - [ - "soundcloud.com/poop", - "www.soundcloud.com/poop", - "https://soundcloud.com/poop", - "https://www.soundcloud.com/poop", - "https://www.soundcloud.com/poop/albums", - "https://www.soundcloud.com/poop?link=clipboard_share", - ], - ) - def test_soundcloud_artist_url_validator_success(self, url): - username_url = SoundcloudUsernameUrlValidator(name="unit test", value=url).username_url - assert username_url == "https://soundcloud.com/poop" - - @pytest.mark.parametrize("bad_url", ["soundcloud.com", "soundnope.lol", "soundcloud.comm/"]) - def test_youtube_playlist_url_validator_fail(self, bad_url): - expected_error_msg = f"'{bad_url}' is not a valid Soundcloud username url." - with pytest.raises(ValidationException, match=re.escape(expected_error_msg)): - SoundcloudUsernameUrlValidator(name="unit test", value=bad_url)