WIP, channel /user/ and /c/ should be valid
This commit is contained in:
parent
03700b998b
commit
73353a953a
2 changed files with 174 additions and 25 deletions
|
|
@ -3,12 +3,13 @@ from typing import Optional
|
|||
from urllib.parse import parse_qs
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from ytdl_sub.utils.exceptions import ValidationException
|
||||
from ytdl_sub.validators.validators import StringValidator
|
||||
|
||||
|
||||
class YoutubeVideoUrlValidator(StringValidator):
|
||||
|
||||
_expected_value_type_name = "youtube video url"
|
||||
_expected_value_type_name = "Youtube video url"
|
||||
|
||||
@classmethod
|
||||
def _get_video_id(cls, url: str) -> Optional[str]:
|
||||
|
|
@ -19,8 +20,8 @@ class YoutubeVideoUrlValidator(StringValidator):
|
|||
- https://www.youtube.com/embed/SA2iWivDJiE
|
||||
- https://www.youtube.com/v/SA2iWivDJiE?version=3&hl=en_US
|
||||
"""
|
||||
# If the url doesn't contain the 'youtu' substring, assume it is the video id
|
||||
if "youtu" not in url:
|
||||
# If the url doesn't contain youtube, assume it is the video id
|
||||
if "youtube.com" not in url and "youtu.be" not in url:
|
||||
return url
|
||||
|
||||
# If https:// is not present, urlparse will not work
|
||||
|
|
@ -56,3 +57,107 @@ class YoutubeVideoUrlValidator(StringValidator):
|
|||
ID of the video
|
||||
"""
|
||||
return 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 the ID
|
||||
if "youtube.com" not in url:
|
||||
return url
|
||||
|
||||
# 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)
|
||||
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 or ID.")
|
||||
|
||||
@property
|
||||
def playlist_id(self) -> str:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
ID of the channel
|
||||
"""
|
||||
return self._playlist_id
|
||||
|
||||
|
||||
class YoutubeChannelUrlValidator(StringValidator):
|
||||
|
||||
_expected_value_type_name = "Youtube channel url"
|
||||
|
||||
@classmethod
|
||||
def _get_channel_id(cls, url: str) -> Optional[str]:
|
||||
"""
|
||||
Examples:
|
||||
- https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw
|
||||
|
||||
NOT:
|
||||
- https://www.youtube.com/user/a_username_that_can_change
|
||||
- https://www.youtube.com/c/a_name_that_can_change
|
||||
|
||||
Raises
|
||||
------
|
||||
ValidationException
|
||||
If the url is for the user name
|
||||
"""
|
||||
# If the url doesn't contain youtube, assume it is the ID
|
||||
if "youtube.com" not in url:
|
||||
return url
|
||||
|
||||
# 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 == "/channel":
|
||||
parsed_q = parse_qs(query.query)
|
||||
return parsed_q["v"][0]
|
||||
if query.path in ("/user", "/c"):
|
||||
raise ValidationException('user or c not allowed since it can change')
|
||||
|
||||
return None
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name, value)
|
||||
|
||||
try:
|
||||
self._channel_id = self._get_channel_id(value)
|
||||
except ValidationException:
|
||||
raise self._validation_exception(
|
||||
f"{value} uses a deprecated Youtube url that which can change. "
|
||||
f"Use the /channel/ url instead."
|
||||
)
|
||||
|
||||
if not self._channel_id:
|
||||
raise self._validation_exception(f"'{value}' is not a valid Youtube channel url or ID.")
|
||||
|
||||
@property
|
||||
def channel_id(self) -> str:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
ID of the channel
|
||||
"""
|
||||
return self._channel_id
|
||||
|
|
|
|||
|
|
@ -1,29 +1,73 @@
|
|||
import pytest
|
||||
|
||||
from ytdl_sub.utils.exceptions import ValidationException
|
||||
from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator
|
||||
from ytdl_sub.validators.url_validator import YoutubeVideoUrlValidator, YoutubePlaylistUrlValidator
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"dQw4w9WgXcQ",
|
||||
"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",
|
||||
],
|
||||
)
|
||||
def test_youtube_video_validator_success(url):
|
||||
video_id = YoutubeVideoUrlValidator(name="unit test", value=url).video_id
|
||||
assert video_id == "dQw4w9WgXcQ"
|
||||
class TestYoutubeVideoUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"dQw4w9WgXcQ",
|
||||
"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",
|
||||
],
|
||||
)
|
||||
def test_youtube_video_validator_success(self, url):
|
||||
video_id = YoutubeVideoUrlValidator(name="unit test", value=url).video_id
|
||||
assert video_id == "dQw4w9WgXcQ"
|
||||
|
||||
|
||||
def test_youtube_video_validator_fail():
|
||||
bad_url = "youtube.cum/asdfd"
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube video url or ID."
|
||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
||||
def test_youtube_video_validator_fail(self):
|
||||
bad_url = "youtube.cum/asdfd"
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube video url or ID."
|
||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
||||
|
||||
|
||||
class TestYoutubePlaylistUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"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_video_validator_success(self, url):
|
||||
playlist_id = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_id
|
||||
assert playlist_id == "PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||
|
||||
def test_youtube_playlist_validator_fail(self):
|
||||
bad_url = "youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url or ID."
|
||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
||||
|
||||
class TestYoutubeChannelUrlValidator:
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc",
|
||||
"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_video_validator_success(self, url):
|
||||
playlist_id = YoutubePlaylistUrlValidator(name="unit test", value=url).playlist_id
|
||||
assert playlist_id == "PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||
|
||||
def test_youtube_playlist_validator_fail(self):
|
||||
bad_url = "youpoop.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
|
||||
expected_error_msg = f"'{bad_url}' is not a valid Youtube playlist url or ID."
|
||||
with pytest.raises(ValidationException, match=expected_error_msg):
|
||||
YoutubeVideoUrlValidator(name="unit test", value=bad_url)
|
||||
Loading…
Reference in a new issue