From 2cd4902ef0080ff09d1c58b2d52fdfbacc12c112 Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Tue, 8 Apr 2025 23:11:07 +0200 Subject: [PATCH 1/8] Added functionality that allows you to set a max length on a track --- scdl/scdl.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/scdl/scdl.py b/scdl/scdl.py index 7ce7d48..2fa4e71 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -9,7 +9,7 @@ [--original-name][--original-metadata][--no-original][--only-original] [--name-format ][--strict-playlist][--playlist-name-format ] [--client-id ][--auth-token ][--overwrite][--no-playlist][--opus] - [--add-description] + [--add-description][--max-length ] scdl -h | --help scdl --version @@ -45,6 +45,7 @@ --hidewarnings Hide Warnings. (use with precaution) --max-size [max-size] Skip tracks larger than size (k/m/g) --min-size [min-size] Skip tracks smaller than size (k/m/g) + --max-length [max-length] Skip tracks audio length smaller then length (s) --no-playlist-folder Download playlist tracks into main directory, instead of making a playlist subfolder --onlymp3 Download only mp3 files @@ -194,6 +195,7 @@ class SCDLArgs(TypedDict): sync: Optional[str] s: Optional[str] t: bool + max_length: Optional[int] class PlaylistInfo(TypedDict): @@ -1082,6 +1084,10 @@ def download_track( if track.policy == "BLOCK": raise RegionBlockError + # Skip if track length is longer than given max length + if is_exceeded_max_duration(track, kwargs): + raise SoundCloudException(f"{title} length is longer than passed max allowed length {kwargs.get("max_length")}") + # Get user_id from the client me = client.get_me() if kwargs["auth_token"] else None client_user_id = me and me.id @@ -1191,6 +1197,15 @@ def create_description_file(description: Optional[str], filename: str) -> None: logger.error("Error trying to write description txt file...") logger.error(ioe) +def is_exceeded_max_duration( + track: Union[BasicTrack, Track], + kwargs: SCDLArgs +) -> bool: + max_length_ms = int(kwargs.get("max_length")) * 1000 + is_exceeded = max_length_ms < track.full_duration + + return is_exceeded + def already_downloaded( track: Union[BasicTrack, Track], From f2d4ab16351fe5c7735e2873d32312020a0de314 Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Tue, 8 Apr 2025 23:18:00 +0200 Subject: [PATCH 2/8] Created test for max track length functionality --- tests/test_track.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_track.py b/tests/test_track.py index 86347b9..f31c282 100644 --- a/tests/test_track.py +++ b/tests/test_track.py @@ -402,3 +402,24 @@ def test_description_file(tmp_path: Path) -> None: assert desc_file.exists() with open(desc_file, encoding="utf-8") as f: assert f.read().splitlines() == ["test description:", "9439290883"] + + +def test_max_length(tmp_path: Path) -> None: + os.chdir(tmp_path) + r = call_scdl_with_auth( + "-l", + "https://soundcloud.com/one-thousand-and-one/test-track", + "--onlymp3", + "--max-length=0", + ) + assert r.returncode == 1 + assert "length is longer than passed max allowed length" in r.stderr + + r = call_scdl_with_auth( + "-l", + "https://soundcloud.com/one-thousand-and-one/test-track", + "--onlymp3", + "--max-length=10", + ) + assert r.returncode == 1 + assert not "length is longer than passed max allowed length" in r.stderr From 833456b8b8a044b4487e2237203b39b50b470546 Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Wed, 9 Apr 2025 20:18:31 +0200 Subject: [PATCH 3/8] Created min-length functionality --- scdl/scdl.py | 48 ++++++++++++++++++++++++++++++++++++++------- tests/test_track.py | 20 +++++++++++++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/scdl/scdl.py b/scdl/scdl.py index 2fa4e71..bbe97fc 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -9,7 +9,7 @@ [--original-name][--original-metadata][--no-original][--only-original] [--name-format ][--strict-playlist][--playlist-name-format ] [--client-id ][--auth-token ][--overwrite][--no-playlist][--opus] - [--add-description][--max-length ] + [--add-description][--min-length ][--max-length ] scdl -h | --help scdl --version @@ -45,7 +45,8 @@ --hidewarnings Hide Warnings. (use with precaution) --max-size [max-size] Skip tracks larger than size (k/m/g) --min-size [min-size] Skip tracks smaller than size (k/m/g) - --max-length [max-length] Skip tracks audio length smaller then length (s) + --min-length [min-length] Skip track smaller than length (s) + --max-length [max-length] Skip track longer than length (s) --no-playlist-folder Download playlist tracks into main directory, instead of making a playlist subfolder --onlymp3 Download only mp3 files @@ -195,6 +196,7 @@ class SCDLArgs(TypedDict): sync: Optional[str] s: Optional[str] t: bool + min_length: Optional[int] max_length: Optional[int] @@ -387,6 +389,28 @@ def main() -> None: sys.exit(1) logger.debug("max-size: %d", arguments["--max-size"]) + if arguments["--min-length"] is not None: + try: + if int(arguments["--min-length"]) <= 0: + logger.error("Min length should be an integer and be greater than 0") + sys.exit(1) + except Exception: + logger.exception(f"Error trying to convert --min-length {arguments["--min-length"]} to integer") + sys.exit(1) + + if arguments["--max-length"] is not None: + try: + if int(arguments["--max-length"]) <= 0: + logger.error("Max length should be an integer and be greater than 0") + sys.exit(1) + except Exception: + logger.exception(f"Error trying to convert {arguments["--max-length"]} --max-length to integer") + sys.exit(1) + + if arguments.get("--min-length") and arguments.get("--max-length") and arguments.get("--min-length") >= arguments.get("--max-length"): + logger.error(f"min_length {arguments.get("--min-length")} cannot be equal or greater than max_length {arguments.get("--max-length")}") + sys.exit(1) + if arguments["--hidewarnings"]: warnings.filterwarnings("ignore") @@ -1084,9 +1108,15 @@ def download_track( if track.policy == "BLOCK": raise RegionBlockError + # Skip if track length is shorter than given min length + if kwargs.get("min_length"): + if is_shorter__min_duration(track, kwargs): + raise SoundCloudException(f"{title} length is shorter than minimum length {kwargs.get("min_length")}s") + # Skip if track length is longer than given max length - if is_exceeded_max_duration(track, kwargs): - raise SoundCloudException(f"{title} length is longer than passed max allowed length {kwargs.get("max_length")}") + if kwargs.get("max_length"): + if is_exceeded_max_duration(track, kwargs): + raise SoundCloudException(f"{title} length is longer than maximum length {kwargs.get("max_length")}s") # Get user_id from the client me = client.get_me() if kwargs["auth_token"] else None @@ -1202,10 +1232,14 @@ def is_exceeded_max_duration( kwargs: SCDLArgs ) -> bool: max_length_ms = int(kwargs.get("max_length")) * 1000 - is_exceeded = max_length_ms < track.full_duration - - return is_exceeded + return max_length_ms < track.full_duration +def is_shorter__min_duration( + track: Union[BasicTrack, Track], + kwargs: SCDLArgs +) -> bool: + min_length_ms = int(kwargs.get("min_length")) * 1000 + return min_length_ms > track.full_duration def already_downloaded( track: Union[BasicTrack, Track], diff --git a/tests/test_track.py b/tests/test_track.py index f31c282..fd71712 100644 --- a/tests/test_track.py +++ b/tests/test_track.py @@ -423,3 +423,23 @@ def test_max_length(tmp_path: Path) -> None: ) assert r.returncode == 1 assert not "length is longer than passed max allowed length" in r.stderr + +def test_min_length(tmp_path: Path) -> None: + os.chdir(tmp_path) + r = call_scdl_with_auth( + "-l", + "https://soundcloud.com/one-thousand-and-one/test-track", + "--onlymp3", + "--min-length=10", + ) + assert r.returncode == 1 + assert "length is shorter than minimum length" in r.stderr + + r = call_scdl_with_auth( + "-l", + "https://soundcloud.com/one-thousand-and-one/test-track", + "--onlymp3", + "--min-length=0", + ) + assert r.returncode == 1 + assert not "length is shorter than minimum length" in r.stderr From 6c8159699b7766143ecf683c919d84608ccb2dbf Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Wed, 9 Apr 2025 20:42:32 +0200 Subject: [PATCH 4/8] Created min-length functionality --- scdl/scdl.py | 16 ++++++++-------- tests/test_track.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scdl/scdl.py b/scdl/scdl.py index bbe97fc..5293c58 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -391,20 +391,20 @@ def main() -> None: if arguments["--min-length"] is not None: try: - if int(arguments["--min-length"]) <= 0: - logger.error("Min length should be an integer and be greater than 0") + if int(arguments["--min-length"]) < 0: + logger.error("Min length should be greater than 0") sys.exit(1) except Exception: - logger.exception(f"Error trying to convert --min-length {arguments["--min-length"]} to integer") + logger.exception("Min-length should be an integer") sys.exit(1) if arguments["--max-length"] is not None: try: - if int(arguments["--max-length"]) <= 0: - logger.error("Max length should be an integer and be greater than 0") + if int(arguments["--max-length"]) < 0: + logger.error("Max length should be greater than 0") sys.exit(1) except Exception: - logger.exception(f"Error trying to convert {arguments["--max-length"]} --max-length to integer") + logger.exception("Max length should be an integer") sys.exit(1) if arguments.get("--min-length") and arguments.get("--max-length") and arguments.get("--min-length") >= arguments.get("--max-length"): @@ -1111,12 +1111,12 @@ def download_track( # Skip if track length is shorter than given min length if kwargs.get("min_length"): if is_shorter__min_duration(track, kwargs): - raise SoundCloudException(f"{title} length is shorter than minimum length {kwargs.get("min_length")}s") + raise SoundCloudException(f"Skipping track... {title} length is shorter than minimum length {kwargs.get("min_length")}s") # Skip if track length is longer than given max length if kwargs.get("max_length"): if is_exceeded_max_duration(track, kwargs): - raise SoundCloudException(f"{title} length is longer than maximum length {kwargs.get("max_length")}s") + raise SoundCloudException(f"Skipping track... {title} length is longer than maximum length {kwargs.get("max_length")}s") # Get user_id from the client me = client.get_me() if kwargs["auth_token"] else None diff --git a/tests/test_track.py b/tests/test_track.py index fd71712..ac4e50d 100644 --- a/tests/test_track.py +++ b/tests/test_track.py @@ -413,7 +413,7 @@ def test_max_length(tmp_path: Path) -> None: "--max-length=0", ) assert r.returncode == 1 - assert "length is longer than passed max allowed length" in r.stderr + assert "length is longer than maximum length" in r.stderr r = call_scdl_with_auth( "-l", @@ -422,7 +422,7 @@ def test_max_length(tmp_path: Path) -> None: "--max-length=10", ) assert r.returncode == 1 - assert not "length is longer than passed max allowed length" in r.stderr + assert not "length is longer than maximum length" in r.stderr def test_min_length(tmp_path: Path) -> None: os.chdir(tmp_path) From cbc243d80bc6b10bdfe0ff8e5db92c04aabcd506 Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Wed, 9 Apr 2025 20:45:30 +0200 Subject: [PATCH 5/8] Created min-length functionality --- scdl/scdl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scdl/scdl.py b/scdl/scdl.py index 5293c58..f988df4 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -1234,7 +1234,7 @@ def is_exceeded_max_duration( max_length_ms = int(kwargs.get("max_length")) * 1000 return max_length_ms < track.full_duration -def is_shorter__min_duration( +def is_shorter_min_duration( track: Union[BasicTrack, Track], kwargs: SCDLArgs ) -> bool: From 48357eefcf248b6f395e58e8bff37e82e6f125a5 Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Wed, 9 Apr 2025 20:46:33 +0200 Subject: [PATCH 6/8] Name change --- scdl/scdl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scdl/scdl.py b/scdl/scdl.py index f988df4..1bd5b14 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -1110,7 +1110,7 @@ def download_track( # Skip if track length is shorter than given min length if kwargs.get("min_length"): - if is_shorter__min_duration(track, kwargs): + if is_shorter_than_min_duration(track, kwargs): raise SoundCloudException(f"Skipping track... {title} length is shorter than minimum length {kwargs.get("min_length")}s") # Skip if track length is longer than given max length @@ -1234,7 +1234,7 @@ def is_exceeded_max_duration( max_length_ms = int(kwargs.get("max_length")) * 1000 return max_length_ms < track.full_duration -def is_shorter_min_duration( +def is_shorter_than_min_duration( track: Union[BasicTrack, Track], kwargs: SCDLArgs ) -> bool: From 1bbc18b2897db9ff56034a6e35e706d1cb98a32b Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Wed, 9 Apr 2025 22:39:33 +0200 Subject: [PATCH 7/8] Updated argument description --- scdl/scdl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scdl/scdl.py b/scdl/scdl.py index 1bd5b14..d6b16ad 100644 --- a/scdl/scdl.py +++ b/scdl/scdl.py @@ -45,8 +45,8 @@ --hidewarnings Hide Warnings. (use with precaution) --max-size [max-size] Skip tracks larger than size (k/m/g) --min-size [min-size] Skip tracks smaller than size (k/m/g) - --min-length [min-length] Skip track smaller than length (s) - --max-length [max-length] Skip track longer than length (s) + --min-length [min-length] Skip tracks shorter than minimum length in seconds + --max-length [max-length] Skip tracks longer than maximum length in seconds --no-playlist-folder Download playlist tracks into main directory, instead of making a playlist subfolder --onlymp3 Download only mp3 files From 651922f1aff71fe60653615a8262dc21327ec0b1 Mon Sep 17 00:00:00 2001 From: Thijs Goettsch Date: Fri, 11 Apr 2025 17:37:33 +0200 Subject: [PATCH 8/8] Updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bff7897..29d6a4b 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ scdl me -f --hidewarnings Hide Warnings. (use with precaution) --max-size [max-size] Skip tracks larger than size (k/m/g) --min-size [min-size] Skip tracks smaller than size (k/m/g) +--min-length [min-length] Skip tracks shorter than minimum length in seconds +--max-length [max-length] Skip tracks longer than maximum length in seconds --no-playlist-folder Download playlist tracks into main directory, instead of making a playlist subfolder --onlymp3 Download only mp3 files