Skip to content

Instantly share code, notes, and snippets.

@Zetaphor
Last active November 15, 2023 03:05
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zetaphor/82cd8fff2d18da7b6e8fae3a074a7f8e to your computer and use it in GitHub Desktop.
Save Zetaphor/82cd8fff2d18da7b6e8fae3a074a7f8e to your computer and use it in GitHub Desktop.
Music download automation
docker pull selenium/standalone-chrome
docker run -d -p 4444:4444 --shm-size=2g selenium/standalone-chrome
import os
import re
import datetime
from pytube import YouTube
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
username = 'LastFMUsername'
password = 'LastFMPassword'
def sanitize_filename(name):
unsafe_characters = ['<', '>', ':', '"', '/', '\\', '|', '?', '*']
for char in unsafe_characters:
name = name.replace(char, '')
return name
def login_to_website():
# Define the Chrome options
chrome_options = Options()
chrome_options.set_capability("browserName", "chrome")
driver = None
tracks = [] # List to store the track information
try:
# Setting up Remote Webdriver to connect to the Selenium standalone Chrome Docker container
driver = webdriver.Remote(
command_executor='http://localhost:4444/wd/hub',
options=chrome_options)
# Opening the website
driver.get("https://www.last.fm/login")
username_field = driver.find_element(By.NAME, 'username_or_email')
username_field.send_keys(username)
password_field = driver.find_element(By.NAME, 'password')
password_field.send_keys(password)
login_button = driver.find_element(By.NAME, 'submit')
login_button.click()
WebDriverWait(driver, 10).until(EC.url_changes("https://www.last.fm/login"))
driver.get("https://www.last.fm/home/tracks")
recs_feed_items = WebDriverWait(driver, 10).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".recs-feed-item")))
for item in recs_feed_items:
try:
recs_feed_playlink = item.find_element(By.CSS_SELECTOR, ".recs-feed-playlink").get_attribute("href")
except NoSuchElementException:
print("Playlink selector missing")
continue # Skip this item if the playlink is missing
track_name_dirty = item.find_element(By.CSS_SELECTOR, ".recs-feed-title a").text
# Here we clean up the track_name by removing the duration using regex
track_name = re.sub(r'\s\(\d+:\d+\)$', '', track_name_dirty)
artist_name = item.find_element(By.CSS_SELECTOR, ".recs-feed-description a").text
print(f"Playlink: {recs_feed_playlink}, Track Name: {track_name}, Artist Name: {artist_name}")
# Add the track information to the list
tracks.append((recs_feed_playlink, track_name, artist_name))
except Exception as e:
print(f"An error occurred: {e}")
finally:
if driver is not None:
driver.quit()
# After quitting the driver, download each track
parent_dir = 'LastFM Recommendations'
if not os.path.exists(parent_dir):
os.makedirs(parent_dir)
dir_name = 'LFM - ' + datetime.datetime.now().strftime('%m-%d-%y')
dir_path = os.path.join(parent_dir, dir_name)
if not os.path.exists(dir_path):
os.makedirs(dir_path)
playlist = [] # List to store the filenames for the M3U playlist
for playlink, track_name, artist_name in tracks:
try:
youtube = YouTube(playlink)
stream = youtube.streams.get_audio_only()
sanitized_track_name = sanitize_filename(track_name)
sanitized_artist_name = sanitize_filename(artist_name)
filename = f"{sanitized_artist_name} - {sanitized_track_name}.mp3"
output_file = stream.download(output_path=dir_path, filename=filename) # Downloads the video
# Add the filename to the playlist
playlist.append(output_file)
except Exception as e:
print(f"An error occurred while downloading {playlink}: {e}")
# Create the M3U playlist
with open(os.path.join(dir_path, f"{dir_name}.m3u"), 'w') as f:
for filename in playlist:
f.write(os.path.basename(filename) + '\n')
if __name__ == "__main__":
login_to_website()
spotdl
pytube
pydub
selenium
webdriver_manager
import os
import subprocess
import smtplib
from datetime import datetime
from email.mime.text import MIMEText
def create_m3u_playlist(directory):
# Get the list of MP3 files in the directory
mp3_files = [file for file in os.listdir(directory) if file.endswith(".mp3")]
# Create the M3U playlist file
today = datetime.now().strftime("%m-%d-%Y")
playlist_name = f"DW - {today}.m3u"
playlist_path = os.path.join(directory, playlist_name)
with open(playlist_path, "w") as playlist_file:
# Write the header
playlist_file.write("#EXTM3U\n")
# Write each MP3 file path as a playlist entry
for mp3_file in mp3_files:
mp3_path = os.path.join(mp3_file)
playlist_file.write(f"#EXTINF:0,{mp3_file}\n")
playlist_file.write(f"{mp3_path}\n")
print(f"M3U playlist created: {playlist_path}")
def create_folder_with_current_date(subfolder):
current_date = datetime.now().strftime("%m-%d-%Y")
folder_path = os.path.join(os.getcwd(), subfolder, current_date)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
return folder_path
def execute_bash_command(command, folder_path):
try:
# Change directory to the created folder
os.chdir(folder_path)
# Execute the bash command
# process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
# stdout, stderr = process.communicate()
# print(process.stdout)
print(process.stderr)
if process.returncode == 0:
send_email(f"Discover Weekly List Updated", f"A new discover weekly playlist has been downloaded to ${folder_path}")
print("Command executed successfully.")
else:
error_message = f"Command execution error:\n{process.stderr}"
print(error_message) # Print the error message on the console
send_email(f"${script_name} - Command Execution Error", error_message)
except Exception as e:
print(e)
send_email(f"${script_name} - Command Execution Error", str(e))
def send_email(subject, message):
# Gmail SMTP configuration
smtp_server = 'smtp.gmail.com'
smtp_port = 587
sender_email = 'username@gmail.com'
# If you're using 2FA you need an app password
# You're using 2FA right? 🤨
sender_app_password = 'app_password'
recipient_email = 'receipient@example.com'
# Email content
email_subject = subject
email_body = message
# Create email message
msg = MIMEText(email_body)
msg['Subject'] = email_subject
msg['From'] = sender_email
msg['To'] = recipient_email
try:
# Connect to the SMTP server and send the email
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(sender_email, sender_app_password)
server.send_message(msg)
print("Email sent successfully.")
except Exception as e:
print(f"Failed to send email: {str(e)}")
script_name = 'Discover Weekly'
subfolder = 'Discover Weekly'
command_to_execute = ['spotdl', 'download', 'DISCOVER_WEEKLY_PLAYLIST_URL']
folder_path = create_folder_with_current_date(subfolder)
execute_bash_command(command_to_execute, folder_path)
create_m3u_playlist(folder_path)
import os
import subprocess
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
# Get the absolute path of the current script
script_directory = os.path.dirname(os.path.abspath(__file__))
# Create or define the Albums directory
albums_directory = os.path.join(script_directory, "Albums")
os.makedirs(albums_directory, exist_ok=True)
def parse_spotify_album(url):
# Extract the album ID from the URL
album_id = url.split('/')[-1].split('?')[0]
# Authenticate with the Spotify API using client credentials
client_id = 'CLIENT_ID'
client_secret = 'CLIENT_SECRET'
auth_manager = SpotifyClientCredentials(client_id=client_id, client_secret=client_secret)
sp = spotipy.Spotify(auth_manager=auth_manager)
# Get the album details from the API
album = sp.album(album_id)
# Extract the artist and album name
artist = album['artists'][0]['name']
album_name = album['name']
return artist, album_name
# Read the file containing the list of URLs
file_path = os.path.join(script_directory, 'urls.txt')
with open(file_path, 'r') as file:
urls = file.read().splitlines()
# Process each URL
for url in urls:
artist, album_name = parse_spotify_album(url)
# Create the artist folder inside the Albums folder
artist_folder = os.path.join(albums_directory, artist)
os.makedirs(artist_folder, exist_ok=True)
# Create the album folder inside the artist folder
album_folder = os.path.join(artist_folder, album_name)
os.makedirs(album_folder, exist_ok=True)
# Run a bash command inside the album folder
os.chdir(album_folder)
os.system(f"spotdl download '{url}'") # Added single quotes around the URL
# Move back to the Albums directory after each iteration
os.chdir(albums_directory)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment