Platform: ThinkPAD laptop / windows11 / Microsoft Visual Studio Code
Python version: Python 3.13.1
I was trying to download tracks from Spotify Music, I got all the album links stored in a text file. I hope the following code will download all the tracks, the links of which is stored in the urls.txt file.
import subprocess
import os
import time
import re
from spotipy import Spotify
from spotipy.oauth2 import SpotifyClientCredentials
def get_album_tracks(album_url, spotify_client):
"""Retrieve all track URLs from an album URL."""
try:
# Extract album ID from the URL
match = re.match(r"https?://open\.spotify\/album/([a-zA-Z0-9]+)", album_url)
if not match:
print(f"Invalid album URL: {album_url}")
return []
album_id = match.group(1)
# Fetch album tracks
tracks = spotify_client.album_tracks(album_id)
track_links = [track['external_urls']['spotify'] for track in tracks['items']]
return track_links
except Exception as e:
print(f"Error retrieving tracks for album {album_url}: {e}")
return []
def download_songs_from_file(file_path, download_directory, client_id, client_secret, max_retries=3):
try:
# Ensure the download directory exists
os.makedirs(download_directory, exist_ok=True)
# Authenticate with Spotify API
spotify_client = Spotify(client_credentials_manager=SpotifyClientCredentials(client_id, client_secret))
# Read album links from the file
with open(file_path, 'r') as file:
album_links = [link.strip() for link in file if link.strip()] # Remove empty lines and whitespace
total_albums = len(album_links)
total_tracks = 0
successful_downloads = 0
print(f"Total albums to process: {total_albums}")
for album_index, album_link in enumerate(album_links, start=1):
print(f"\nProcessing album ({album_index}/{total_albums}): {album_link}")
# Get all track links from the album
track_links = get_album_tracks(album_link, spotify_client)
track_count = len(track_links)
total_tracks += track_count
print(f"Found {track_count} tracks in album: {album_link}")
for track_index, track_link in enumerate(track_links, start=1):
print(f"Downloading track ({track_index}/{track_count}): {track_link}")
retries = 0
while retries < max_retries:
try:
# Run the spotdl command
subprocess.run(
["spotdl", "download", track_link, "--path", download_directory],
check=True
)
print(f"Downloaded successfully: {track_link}")
successful_downloads += 1
break
except subprocess.CalledProcessError as e:
retries += 1
print(f"Error downloading: {track_link} (Attempt {retries}/{max_retries}) - {e}")
if retries >= max_retries:
print(f"Skipping after {max_retries} attempts.")
else:
time.sleep(2) # Short delay before retrying
# Count the actual files in the download directory
downloaded_files = len([f for f in os.listdir(download_directory) if os.path.isfile(os.path.join(download_directory, f))])
print(f"\nDownload summary:")
print(f"Total albums in list: {total_albums}")
print(f"Total tracks found: {total_tracks}")
print(f"Successfully downloaded: {successful_downloads}")
print(f"Failed downloads: {total_tracks - successful_downloads}")
print(f"Total files in '{download_directory}': {downloaded_files}")
except FileNotFoundError:
print(f"The file {file_path} was not found.")
except Exception as e:
print(f"An error occurred: {e}")
# Example usage
file_path = "C:\\Users\\myname\\Music\\BEYOND\\urls.txt" # File containing album links
download_directory = "C:\\Users\\myname\\Music\\BEYOND" # Directory for downloads
client_id = "my_client_id" # Spotify API Client ID
client_secret = "my_client_sectet" # Spotify API Client Secret
download_songs_from_file(file_path, download_directory, client_id, client_secret)
The output:
Processing album (1/50):
Found 12 tracks in album:
Downloading track (1/12):
The file C:\Users\myname\Music\BEYOND\urls.txt was not found.
One thing clear is that the code already read the file, right?
But why it gave the file not found message?
Any advice to correct/improve this code will be highly appreciated.
Thanks!
Platform: ThinkPAD laptop / windows11 / Microsoft Visual Studio Code
Python version: Python 3.13.1
I was trying to download tracks from Spotify Music, I got all the album links stored in a text file. I hope the following code will download all the tracks, the links of which is stored in the urls.txt file.
import subprocess
import os
import time
import re
from spotipy import Spotify
from spotipy.oauth2 import SpotifyClientCredentials
def get_album_tracks(album_url, spotify_client):
"""Retrieve all track URLs from an album URL."""
try:
# Extract album ID from the URL
match = re.match(r"https?://open\.spotify\.com/album/([a-zA-Z0-9]+)", album_url)
if not match:
print(f"Invalid album URL: {album_url}")
return []
album_id = match.group(1)
# Fetch album tracks
tracks = spotify_client.album_tracks(album_id)
track_links = [track['external_urls']['spotify'] for track in tracks['items']]
return track_links
except Exception as e:
print(f"Error retrieving tracks for album {album_url}: {e}")
return []
def download_songs_from_file(file_path, download_directory, client_id, client_secret, max_retries=3):
try:
# Ensure the download directory exists
os.makedirs(download_directory, exist_ok=True)
# Authenticate with Spotify API
spotify_client = Spotify(client_credentials_manager=SpotifyClientCredentials(client_id, client_secret))
# Read album links from the file
with open(file_path, 'r') as file:
album_links = [link.strip() for link in file if link.strip()] # Remove empty lines and whitespace
total_albums = len(album_links)
total_tracks = 0
successful_downloads = 0
print(f"Total albums to process: {total_albums}")
for album_index, album_link in enumerate(album_links, start=1):
print(f"\nProcessing album ({album_index}/{total_albums}): {album_link}")
# Get all track links from the album
track_links = get_album_tracks(album_link, spotify_client)
track_count = len(track_links)
total_tracks += track_count
print(f"Found {track_count} tracks in album: {album_link}")
for track_index, track_link in enumerate(track_links, start=1):
print(f"Downloading track ({track_index}/{track_count}): {track_link}")
retries = 0
while retries < max_retries:
try:
# Run the spotdl command
subprocess.run(
["spotdl", "download", track_link, "--path", download_directory],
check=True
)
print(f"Downloaded successfully: {track_link}")
successful_downloads += 1
break
except subprocess.CalledProcessError as e:
retries += 1
print(f"Error downloading: {track_link} (Attempt {retries}/{max_retries}) - {e}")
if retries >= max_retries:
print(f"Skipping after {max_retries} attempts.")
else:
time.sleep(2) # Short delay before retrying
# Count the actual files in the download directory
downloaded_files = len([f for f in os.listdir(download_directory) if os.path.isfile(os.path.join(download_directory, f))])
print(f"\nDownload summary:")
print(f"Total albums in list: {total_albums}")
print(f"Total tracks found: {total_tracks}")
print(f"Successfully downloaded: {successful_downloads}")
print(f"Failed downloads: {total_tracks - successful_downloads}")
print(f"Total files in '{download_directory}': {downloaded_files}")
except FileNotFoundError:
print(f"The file {file_path} was not found.")
except Exception as e:
print(f"An error occurred: {e}")
# Example usage
file_path = "C:\\Users\\myname\\Music\\BEYOND\\urls.txt" # File containing album links
download_directory = "C:\\Users\\myname\\Music\\BEYOND" # Directory for downloads
client_id = "my_client_id" # Spotify API Client ID
client_secret = "my_client_sectet" # Spotify API Client Secret
download_songs_from_file(file_path, download_directory, client_id, client_secret)
The output:
Processing album (1/50): https://open.spotify.com/album/6oGvml3VgdRhNCTRX32Tbs
Found 12 tracks in album: https://open.spotify.com/album/6oGvml3VgdRhNCTRX32Tbs
Downloading track (1/12): https://open.spotify.com/track/466cmnbIuOeQ3aKpijfvmf
The file C:\Users\myname\Music\BEYOND\urls.txt was not found.
One thing clear is that the code already read the file, right?
But why it gave the file not found message?
Any advice to correct/improve this code will be highly appreciated.
Thanks!
Share Improve this question asked Jan 19 at 11:51 beesunsbeesuns 211 silver badge7 bronze badges 2 |1 Answer
Reset to default 0subprocess.run without argument shell=True
tries to run your application without a shell and if the app is not found, it will throw FileNotFound as essentially your python code doesn't know where to find it. See:
>>> subprocess.run(["spotydl"])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python312\Lib\subprocess.py", line 548, in run
with Popen(*popenargs, **kwargs) as process:
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python312\Lib\subprocess.py", line 1026, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Python312\Lib\subprocess.py", line 1538, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [WinError 2] The system cannot find the file specified
>>>
versus with shell:
>>> subprocess.run(["spotydl"], shell=True)
'spotydl' is not recognized as an internal or external command,
operable program or batch file.
CompletedProcess(args=['spotydl'], returncode=1)
>>>
So, the issue is that your subprocess call doesnt find spotdl
. I'd just use absolute path to the spotdl executable to fix this.
subprocess.run
was not executed, so probably the error is within this line. Maybe printing all the trace error will show you what is really happening. – Iran Ribeiro Commented Jan 19 at 12:23file_path
is the thing the exception referred to as not being findable) then you wouldn't have needed to come here in the first place. – Charles Duffy Commented Jan 19 at 12:50