diff --git a/scdl/scdl.py b/scdl/scdl.py index 6738598..da3f75f 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -1,7 +1,7 @@ """scdl allows you to download music from Soundcloud Usage: - scdl (-l | me) [-a | -f | -C | -t | -p | -r][-c | --force-metadata] + scdl (-l | -s | me) [-a | -f | -C | -t | -p | -r][-c | --force-metadata] [-n ][-o ][--hidewarnings][--debug | --error][--path ] [--addtofile][--addtimestamp][--onlymp3][--hide-progress][--min-size ] [--max-size ][--remove][--no-album-tag][--no-playlist-folder] @@ -19,6 +19,7 @@ -h --help Show this screen --version Show version -l [url] URL can be track/playlist/user + -s [search_query] Search for a track/playlist/user and use the first result -n [maxtracks] Download the n last tracks of a playlist according to the creation date -a Download all tracks of user (including reposts) @@ -191,6 +192,7 @@ class SCDLArgs(TypedDict): remove: bool strict_playlist: bool sync: Optional[str] + s: Optional[str] t: bool @@ -366,6 +368,14 @@ def main() -> None: assert me is not None arguments["-l"] = me.permalink_url + if arguments["-s"]: + url = search_soundcloud(client, arguments["-s"]) + if url: + arguments["-l"] = url + else: + logger.error("Search failed. Exiting...") + sys.exit(1) + arguments["-l"] = validate_url(client, arguments["-l"]) if arguments["--download-archive"]: @@ -438,6 +448,21 @@ def validate_url(client: SoundCloud, url: str) -> str: logger.error("URL is not valid") sys.exit(1) +def search_soundcloud(client: SoundCloud, query: str) -> Optional[str]: + """Search SoundCloud and return the URL of the first result.""" + try: + results = list(client.search(query, limit=1)) + if results: + item = results[0] + logger.info(f"Search resolved to url {item.permalink_url}") + if isinstance(item, (Track, AlbumPlaylist, User)): + return item.permalink_url + logger.warning(f"Unexpected search result type: {type(item)}") + logger.error(f"No results found for query: {query}") + return None + except Exception as e: + logger.error(f"Error searching SoundCloud: {e}") + return None def get_config(config_file: pathlib.Path) -> configparser.ConfigParser: """Gets config from scdl.cfg""" diff --git a/tests/test_search.py b/tests/test_search.py new file mode 100644 index 0000000..1c74f35 --- /dev/null +++ b/tests/test_search.py @@ -0,0 +1,44 @@ +import os +from pathlib import Path + +from tests.utils import assert_track, call_scdl_with_auth + + +def test_search(tmp_path: Path) -> None: + os.chdir(tmp_path) + r = call_scdl_with_auth( + "-s", + "7x11x13-testing test track", + "--name-format", + "track", + "--onlymp3", + ) + assert r.returncode == 0 + assert_track(tmp_path, "track.mp3") + + +def test_search_no_results(tmp_path: Path) -> None: + os.chdir(tmp_path) + r = call_scdl_with_auth( + "-s", + "this query should not return any results xyzabc123", + "--name-format", + "track", + "--onlymp3", + ) + assert r.returncode == 1 + assert "No results found for query" in r.stderr + + +def test_search_playlist(tmp_path: Path) -> None: + os.chdir(tmp_path) + r = call_scdl_with_auth( + "-s", + "playlist1 7x11x13-testing", + "--playlist-name-format", + "{playlist[tracknumber]}_{title}", + "--onlymp3", + ) + assert r.returncode == 0 + assert_track(tmp_path / "playlist1", "1_OK Bye.mp3", check_metadata=False) + assert_track(tmp_path / "playlist1", "2_Wan Bushi - Eurodance Vibes (part 1+2+3).mp3", check_metadata=False) \ No newline at end of file