Last active
November 15, 2023 03:05
-
-
Save Zetaphor/82cd8fff2d18da7b6e8fae3a074a7f8e to your computer and use it in GitHub Desktop.
Music download automation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
docker pull selenium/standalone-chrome | |
docker run -d -p 4444:4444 --shm-size=2g selenium/standalone-chrome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
spotdl | |
pytube | |
pydub | |
selenium | |
webdriver_manager |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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