Stuck while working on a script that downloads entire youtube playlists as individual songs, while the songs are downloading fine, i want the files to have their respective cover arts as well, however the program is unable to do the same
below is the entire python script I’m using
Embeds cover art into the MP3 file.
Args:
mp3_path (str): Path to the MP3 file.
entry (dict): Entry dictionary from YoutubeDL.
Returns:
bool: True if cover art was successfully embedded, False otherwise.
def embed_cover_art(mp3_path, entry):
thumbnail_url = entry.get('thumbnail', '')
if not thumbnail_url:
logging.warning(f"No thumbnail URL found for {mp3_path}")
return False
try:
logging.info(f"Downloading thumbnail from {thumbnail_url}")
response = get(thumbnail_url, timeout=5) # Set a timeout
response.raise_for_status()
# Use a more descriptive temporary filename
thumbnail_file_path = f"{mp3_path}.tmp_thumbnail.jpg"
with open(thumbnail_file_path, 'wb') as thumbnail_file:
thumbnail_file.write(response.content)
logging.info(f"Thumbnail downloaded and saved to {thumbnail_file_path}")
try:
audio = ID3(mp3_path)
except ID3NoHeaderError:
audio = ID3()
logging.info(f"No ID3 header found for {mp3_path}, creating new ID3 tag")
with open(thumbnail_file_path, 'rb') as thumbnail_file:
audio.add(APIC(
encoding=3, # 3 is for utf-8
mime='image/jpeg', # or 'image/png'
type=3, # 3 is for the cover image
desc='Cover',
data=thumbnail_file.read()
))
audio.save(mp3_path)
logging.info(f"Cover art embedded successfully for {mp3_path}")
os.remove(thumbnail_file_path)
return True
except (RequestException, ConnectionError) as e:
logging.error(f"Failed to download thumbnail for {mp3_path}: {e}")
return False
except Exception as e:
logging.error(f"Error embedding cover art for {mp3_path}: {e}")
return False
Downloads playlist videos as MP3 with embedded thumbnails.
Args:
url (str): URL of the YouTube playlist.
destination_folder (str): Path to the destination folder.
Returns:
None
def download_and_process_playlist(url, destination_folder):
logging.info(f"Starting to process playlist: {url}")
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': os.path.join(destination_folder, '%(title)s.%(ext)s'),
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
'quiet': False, # Set to False to see download progress
'noplaylist': False, # Set to False to download the entire playlist
}
with YoutubeDL(ydl_opts) as ydl:
try:
info = ydl.extract_info(url, download=True)
logging.info(f"Playlist info extracted successfully.")
for entry in info['entries']:
title = extract_title(entry.get('description', ''), entry.get('title', 'Unknown Title'))
mp3_path = os.path.join(destination_folder, f"{title}.mp3")
webm_path = os.path.join(destination_folder, f"{title}.webm")
logging.info(f"Processing entry: {title}")
logging.info(f"MP3 path: {mp3_path}")
if not os.path.exists(mp3_path):
logging.error(f"MP3 file not found: {mp3_path}")
continue
# Embed cover art and then delete the original file if successful
for attempt in range(MAX_RETRIES):
try:
if embed_cover_art(mp3_path, entry):
# Delete the original file after successful embedding
if os.path.exists(webm_path):
os.remove(webm_path)
break
else:
raise Exception("Cover art embedding failed.")
except Exception as e:
logging.error(f"Attempt {attempt + 1} failed for {title}: {e}", exc_info=True)
if attempt < MAX_RETRIES - 1:
logging.info(f"Retrying in {RETRY_DELAY} seconds...")
time.sleep(RETRY_DELAY)
else:
logging.error(f"Failed to process {title} after {MAX_RETRIES} attempts.")
except Exception as e:
logging.error(f"Error processing playlist {url}: {e}", exc_info=True)