mirror of
https://github.com/nathom/streamrip.git
synced 2025-05-09 14:11:55 -04:00
Fix deezer dynamic link parsing (#824)
* Fix links issues due tu recent PR * Add tests for URL parsing --------- Co-authored-by: Nathan Thomas <nathanthomas707@gmail.com>
This commit is contained in:
parent
db52d493b8
commit
5bcadd3c6a
2 changed files with 156 additions and 1 deletions
|
@ -18,7 +18,7 @@ from ..media import (
|
|||
|
||||
logger = logging.getLogger("streamrip")
|
||||
URL_REGEX = re.compile(
|
||||
r"https?://(?:www|open|play|listen)?\.?(qobuz|tidal|deezer|dzr)\.?(com|page.link)(?:(?:/(album|artist|track|playlist|video|label))|(?:\/[-\w]+?))+\/([-\w]+)",
|
||||
r"https?://(?:www|open|play|listen)?\.?(qobuz|tidal|deezer)\.com?(?:(?:/(album|artist|track|playlist|video|label))|(?:\/[-\w]+?))+\/([-\w]+)",
|
||||
)
|
||||
SOUNDCLOUD_URL_REGEX = re.compile(r"https://soundcloud.com/[-\w:/]+")
|
||||
LASTFM_URL_REGEX = re.compile(r"https://www.last.fm/user/\w+/playlists/\w+")
|
||||
|
|
155
tests/test_parse_url.py
Normal file
155
tests/test_parse_url.py
Normal file
|
@ -0,0 +1,155 @@
|
|||
import unittest
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from streamrip.rip.parse_url import (
|
||||
DeezerDynamicURL,
|
||||
GenericURL,
|
||||
SoundcloudURL,
|
||||
parse_url,
|
||||
)
|
||||
|
||||
|
||||
class TestParseURL(unittest.TestCase):
|
||||
def test_deezer_dynamic_url(self):
|
||||
"""Test that Deezer dynamic URLs are matched correctly."""
|
||||
url = "https://dzr.page.link/SnV6hCyHihkmCCwUA"
|
||||
result = parse_url(url)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertIsInstance(result, DeezerDynamicURL)
|
||||
self.assertEqual(result.source, "deezer")
|
||||
|
||||
def test_qobuz_album_url(self):
|
||||
"""Test that Qobuz album URLs are matched correctly."""
|
||||
url = "https://www.qobuz.com/fr-fr/album/bizarre-ride-ii-the-pharcyde-the-pharcyde/0066991040005"
|
||||
result = parse_url(url)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertIsInstance(result, GenericURL)
|
||||
self.assertEqual(result.source, "qobuz")
|
||||
|
||||
# Verify the regex match groups
|
||||
groups = result.match.groups()
|
||||
self.assertEqual(len(groups), 3)
|
||||
self.assertEqual(groups[0], "qobuz") # source
|
||||
self.assertEqual(groups[1], "album") # media_type
|
||||
self.assertEqual(groups[2], "0066991040005") # item_id
|
||||
|
||||
def test_tidal_track_url(self):
|
||||
"""Test that Tidal track URLs are matched correctly."""
|
||||
url = "https://tidal.com/browse/track/3083287"
|
||||
result = parse_url(url)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertIsInstance(result, GenericURL)
|
||||
self.assertEqual(result.source, "tidal")
|
||||
|
||||
# Verify the regex match groups
|
||||
groups = result.match.groups()
|
||||
self.assertEqual(len(groups), 3)
|
||||
self.assertEqual(groups[0], "tidal") # source
|
||||
self.assertEqual(groups[1], "track") # media_type
|
||||
self.assertEqual(groups[2], "3083287") # item_id
|
||||
|
||||
def test_deezer_track_url(self):
|
||||
"""Test that Deezer track URLs are matched correctly."""
|
||||
url = "https://www.deezer.com/track/4195713"
|
||||
result = parse_url(url)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertIsInstance(result, GenericURL)
|
||||
self.assertEqual(result.source, "deezer")
|
||||
|
||||
# Verify the regex match groups
|
||||
groups = result.match.groups()
|
||||
self.assertEqual(len(groups), 3)
|
||||
self.assertEqual(groups[0], "deezer") # source
|
||||
self.assertEqual(groups[1], "track") # media_type
|
||||
self.assertEqual(groups[2], "4195713") # item_id
|
||||
|
||||
def test_invalid_url(self):
|
||||
"""Test that invalid URLs return None."""
|
||||
urls = [
|
||||
"https://example.com",
|
||||
"not a url",
|
||||
"https://spotify.com/track/123456", # Unsupported source
|
||||
"https://tidal.com/invalid/3083287", # Invalid media type
|
||||
]
|
||||
|
||||
for url in urls:
|
||||
result = parse_url(url)
|
||||
self.assertIsNone(result, f"URL should not parse: {url}")
|
||||
|
||||
def test_alternate_url_formats(self):
|
||||
"""Test various URL formats that should be valid."""
|
||||
# Test with different domain prefixes
|
||||
url1 = "https://open.tidal.com/track/3083287"
|
||||
url2 = "https://play.qobuz.com/album/0066991040005"
|
||||
url3 = "https://listen.tidal.com/track/3083287"
|
||||
|
||||
for url in [url1, url2, url3]:
|
||||
result = parse_url(url)
|
||||
self.assertIsNotNone(result, f"Should parse URL: {url}")
|
||||
self.assertIsInstance(result, GenericURL)
|
||||
|
||||
def test_url_with_language_code(self):
|
||||
"""Test URLs with different language codes."""
|
||||
urls = [
|
||||
"https://www.qobuz.com/us-en/album/name/id123456",
|
||||
"https://www.qobuz.com/gb-en/album/name/id123456",
|
||||
"https://www.deezer.com/en/track/4195713",
|
||||
"https://www.deezer.com/fr/track/4195713",
|
||||
]
|
||||
|
||||
for url in urls:
|
||||
result = parse_url(url)
|
||||
self.assertIsNotNone(result, f"Should parse URL: {url}")
|
||||
self.assertIsInstance(result, GenericURL)
|
||||
|
||||
def test_soundcloud_url(self):
|
||||
"""Test that Soundcloud URLs are matched correctly."""
|
||||
urls = [
|
||||
"https://soundcloud.com/artist-name/track-name",
|
||||
"https://soundcloud.com/artist-name/sets/playlist-name",
|
||||
]
|
||||
|
||||
for url in urls:
|
||||
result = parse_url(url)
|
||||
self.assertIsNotNone(result, f"Should parse URL: {url}")
|
||||
self.assertIsInstance(result, SoundcloudURL)
|
||||
self.assertEqual(result.source, "soundcloud")
|
||||
|
||||
|
||||
class TestDeezerDynamicURL(unittest.TestCase):
|
||||
@patch("streamrip.rip.parse_url.DeezerDynamicURL._extract_info_from_dynamic_link")
|
||||
def test_into_pending_album(self, mock_extract):
|
||||
"""Test conversion of Deezer dynamic URL to a PendingAlbum."""
|
||||
import asyncio
|
||||
|
||||
async def run_test():
|
||||
url = "https://dzr.page.link/SnV6hCyHihkmCCwUA"
|
||||
result = parse_url(url)
|
||||
|
||||
# Mock the extract method to return album type and ID
|
||||
mock_extract.return_value = ("album", "12345")
|
||||
|
||||
# Mock the client, config, db
|
||||
mock_client = AsyncMock()
|
||||
mock_client.source = "deezer"
|
||||
mock_config = AsyncMock()
|
||||
mock_db = AsyncMock()
|
||||
|
||||
# Call into_pending
|
||||
pending = await result.into_pending(mock_client, mock_config, mock_db)
|
||||
|
||||
# Verify the correct pending type was created
|
||||
self.assertEqual(pending.__class__.__name__, "PendingAlbum")
|
||||
self.assertEqual(pending.id, "12345")
|
||||
|
||||
# Run the coroutine
|
||||
asyncio.run(run_test())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue