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")
|
logger = logging.getLogger("streamrip")
|
||||||
URL_REGEX = re.compile(
|
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:/]+")
|
SOUNDCLOUD_URL_REGEX = re.compile(r"https://soundcloud.com/[-\w:/]+")
|
||||||
LASTFM_URL_REGEX = re.compile(r"https://www.last.fm/user/\w+/playlists/\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