From 44525895f65f76c157f70e79a0acfc7354e2bcde Mon Sep 17 00:00:00 2001 From: jbannon Date: Sun, 5 Jun 2022 15:24:26 +0000 Subject: [PATCH] soundcloud artist url --- src/ytdl_sub/validators/url_validator.py | 44 +++++++++++++++++++++ tests/unit/validators/test_url_validator.py | 24 +++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/ytdl_sub/validators/url_validator.py b/src/ytdl_sub/validators/url_validator.py index 98dcd3fd..20498f35 100644 --- a/src/ytdl_sub/validators/url_validator.py +++ b/src/ytdl_sub/validators/url_validator.py @@ -143,3 +143,47 @@ class YoutubeChannelUrlValidator(StringValidator): Full channel URL """ return self._channel_url + + +class SoundcloudArtistUrlValidator(StringValidator): + + _expected_value_type_name = "Soundcloud artist 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 + artist_name = query.path[1:].split("/")[0] # strip extra paths or slashes + artist_name = artist_name.split("?")[0] # strip extra arguments + return f"https://soundcloud.com/{artist_name}" + + return None + + def __init__(self, name: str, value: Any): + super().__init__(name, value) + + self._artist_url = self._get_channel_url(value) + if not self._artist_url: + raise self._validation_exception(f"'{value}' is not a valid Soundcloud artist url.") + + @property + def artist_url(self) -> str: + """ + Returns + ------- + Full artist URL + """ + return self._artist_url diff --git a/tests/unit/validators/test_url_validator.py b/tests/unit/validators/test_url_validator.py index 26c6870b..1f2ccc7c 100644 --- a/tests/unit/validators/test_url_validator.py +++ b/tests/unit/validators/test_url_validator.py @@ -3,6 +3,7 @@ import re import pytest from ytdl_sub.utils.exceptions import ValidationException +from ytdl_sub.validators.url_validator import SoundcloudArtistUrlValidator from ytdl_sub.validators.url_validator import YoutubeChannelUrlValidator from ytdl_sub.validators.url_validator import YoutubePlaylistUrlValidator from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator @@ -94,3 +95,26 @@ class TestYoutubeChannelUrlValidator: 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 TestSoundcloudArtistUrlValidator: + @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): + artist_url = SoundcloudArtistUrlValidator(name="unit test", value=url).artist_url + assert artist_url == "https://soundcloud.com/poop" + + def test_youtube_playlist_url_validator_fail(self): + bad_url = "soundcloud.com" + expected_error_msg = f"'{bad_url}' is not a valid Soundcloud artist url." + with pytest.raises(ValidationException, match=re.escape(expected_error_msg)): + SoundcloudArtistUrlValidator(name="unit test", value=bad_url)