From bf2bbea7c4569dc571e29731763c78103f5186be Mon Sep 17 00:00:00 2001 From: bob-jones-cs <23340069+bob-jones-cs@users.noreply.github.com> Date: Tue, 2 Jun 2026 08:41:40 -0700 Subject: [PATCH 1/5] Populate the artists field in the SoundCloud audio provider results (the uploader is very commonly the artist on SoundCloud) --- spotdl/providers/audio/soundcloud.py | 1 + 1 file changed, 1 insertion(+) diff --git a/spotdl/providers/audio/soundcloud.py b/spotdl/providers/audio/soundcloud.py index db797a0b7..9098321a9 100644 --- a/spotdl/providers/audio/soundcloud.py +++ b/spotdl/providers/audio/soundcloud.py @@ -83,6 +83,7 @@ def get_results(self, search_term: str, *_args, **_kwargs) -> List[Result]: verified=result.user.verified, duration=result.full_duration, author=result.user.username, + artists=(result.user.username,), result_id=str(result.id), isrc_search=False, search_query=search_term, From f8095cbbe3a94b9888b6da251fdce0c8078829ab Mon Sep 17 00:00:00 2001 From: bob-jones-cs <23340069+bob-jones-cs@users.noreply.github.com> Date: Tue, 2 Jun 2026 08:46:23 -0700 Subject: [PATCH 2/5] Fall back to result.author in calc_main_artist_match when artists is None --- spotdl/utils/matching.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spotdl/utils/matching.py b/spotdl/utils/matching.py index 5b8f11f5a..ca47e3224 100644 --- a/spotdl/utils/matching.py +++ b/spotdl/utils/matching.py @@ -299,9 +299,13 @@ def calc_main_artist_match(song: Song, result: Result) -> float: main_artist_match = 0.0 - # Result has no artists, return 0.0 + # Result has no artists, fall back to author + # If no author either, return 0.0 if not result.artists: - return main_artist_match + if not result.author: + return main_artist_match + + return ratio(slugify(song.artists[0]), slugify(result.author)) song_artists, result_artists = list(map(slugify, song.artists)), list( map(slugify, result.artists) From 81add61e4ac33a6723ec742fdf56a4508a0a647e Mon Sep 17 00:00:00 2001 From: bob-jones-cs <23340069+bob-jones-cs@users.noreply.github.com> Date: Tue, 2 Jun 2026 09:02:05 -0700 Subject: [PATCH 3/5] Fix copy-pasted slider.kz docstrings in SoundCloud and BandCamp providers --- spotdl/providers/audio/bandcamp.py | 4 ++-- spotdl/providers/audio/soundcloud.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spotdl/providers/audio/bandcamp.py b/spotdl/providers/audio/bandcamp.py index 114ddee8f..917407e4b 100644 --- a/spotdl/providers/audio/bandcamp.py +++ b/spotdl/providers/audio/bandcamp.py @@ -170,7 +170,7 @@ class BandCamp(AudioProvider): def get_results(self, search_term: str, *_args, **_kwargs) -> List[Result]: """ - Get results from slider.kz + Get results from BandCamp ### Arguments - search_term: The search term to search for. @@ -178,7 +178,7 @@ def get_results(self, search_term: str, *_args, **_kwargs) -> List[Result]: - kwargs: Unused. ### Returns - - A list of slider.kz results if found, None otherwise. + - A list of BandCamp results if found, None otherwise. """ try: diff --git a/spotdl/providers/audio/soundcloud.py b/spotdl/providers/audio/soundcloud.py index 9098321a9..ce0d1131c 100644 --- a/spotdl/providers/audio/soundcloud.py +++ b/spotdl/providers/audio/soundcloud.py @@ -40,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def get_results(self, search_term: str, *_args, **_kwargs) -> List[Result]: """ - Get results from slider.kz + Get results from SoundCloud ### Arguments - search_term: The search term to search for. @@ -48,7 +48,7 @@ def get_results(self, search_term: str, *_args, **_kwargs) -> List[Result]: - kwargs: Unused. ### Returns - - A list of slider.kz results if found, None otherwise. + - A list of SoundCloud results if found, None otherwise. """ results = list(islice(self.client.search(search_term), 20)) From 7069948e9ce07e9dcc607ce3774869fde06d34c3 Mon Sep 17 00:00:00 2001 From: bob-jones-cs <23340069+bob-jones-cs@users.noreply.github.com> Date: Tue, 2 Jun 2026 09:15:22 -0700 Subject: [PATCH 4/5] Fix calc_main_artist_match docstring (wrong param names and return type) --- spotdl/utils/matching.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spotdl/utils/matching.py b/spotdl/utils/matching.py index ca47e3224..f5e9d178c 100644 --- a/spotdl/utils/matching.py +++ b/spotdl/utils/matching.py @@ -287,14 +287,15 @@ def get_best_matches( def calc_main_artist_match(song: Song, result: Result) -> float: """ - Check if main artist is present in list of artists + Calculate how well the main artist of the song matches the result. + Falls back to result.author if result.artists is not populated. ### Arguments - - main_artist: main artist to check - - artists: list of artists to check + - song: song to match + - result: result to match ### Returns - - True if main artist is present in list of artists, False otherwise + - artist match percentage (0.0 to 100.0) """ main_artist_match = 0.0 From fc6f3a50c61bd923ebf0564614caa25bbf26cbba Mon Sep 17 00:00:00 2001 From: bob-jones-cs <23340069+bob-jones-cs@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:20:23 -0700 Subject: [PATCH 5/5] Add unit tests for calc_main_artist_match author fallback --- tests/test_matching.py | 92 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/test_matching.py b/tests/test_matching.py index b76b6f450..e6aa3b411 100644 --- a/tests/test_matching.py +++ b/tests/test_matching.py @@ -2,7 +2,9 @@ from spotdl.providers.audio.base import AudioProviderError from spotdl.providers.audio.ytmusic import YouTubeMusic +from spotdl.types.result import Result from spotdl.types.song import Song +from spotdl.utils.matching import calc_main_artist_match from spotdl.utils.spotify import SpotifyClient from tests.conftest import new_initialize @@ -429,3 +431,93 @@ def test_ytmusic_matching(monkeypatch, query, expected, capsys): except AudioProviderError: pytest.skip("YouTube Music search failed") + + +SONG_DICT = { + "name": "流転の果て", + "artists": ["tokiwa"], + "artist": "tokiwa", + "album_id": "test", + "album_name": "勿忘", + "album_artist": "tokiwa", + "album_type": "album", + "genres": [], + "disc_number": 1, + "disc_count": 1, + "duration": 222, + "year": 2023, + "date": "2023-01-01", + "track_number": 1, + "tracks_count": 1, + "isrc": "", + "song_id": "7yfMsNxODzSIysdZ47JrlG", + "cover_url": "https://example.com/cover.jpg", + "explicit": False, + "publisher": "test", + "url": "https://open.spotify.com/track/7yfMsNxODzSIysdZ47JrlG", + "copyright_text": "", +} + + +def test_calc_main_artist_match_with_artists(): + song = Song.from_dict(SONG_DICT) + result = Result( + source="soundcloud", + url="https://soundcloud.com/tokiwa_anka/pnog8medav1f", + verified=False, + name="流転の果て", + duration=222041, + author="tokiwa", + artists=("tokiwa",), + result_id="941283319", + ) + + assert calc_main_artist_match(song, result) == 100.0 + + +def test_calc_main_artist_match_falls_back_to_author(): + song = Song.from_dict(SONG_DICT) + result = Result( + source="soundcloud", + url="https://soundcloud.com/tokiwa_anka/pnog8medav1f", + verified=False, + name="流転の果て", + duration=222041, + author="tokiwa", + result_id="941283319", + ) + + assert result.artists is None + assert calc_main_artist_match(song, result) == 100.0 + + +def test_calc_main_artist_match_no_artists_no_author(): + song = Song.from_dict(SONG_DICT) + result = Result( + source="soundcloud", + url="https://soundcloud.com/unknown/test", + verified=False, + name="流転の果て", + duration=222041, + author="", + result_id="000", + ) + + assert result.artists is None + assert calc_main_artist_match(song, result) == 0.0 + + +def test_calc_main_artist_match_author_fuzzy(): + song = Song.from_dict({**SONG_DICT, "artists": ["Carly Rae Jepsen"], "artist": "Carly Rae Jepsen"}) + result = Result( + source="youtube", + url="https://www.youtube.com/watch?v=abc", + verified=False, + name="I Really Like You", + duration=200, + author="Carly Rae Jepsen - Topic", + result_id="abc", + ) + + assert result.artists is None + assert calc_main_artist_match(song, result) > 70.0