-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
144 lines (117 loc) · 4.61 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Module Imports
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import sys
import subprocess
import re
import os
import shutil
from pathlib import Path
from tkinter import filedialog
import requests
# ChromeDriver Launch Options
launch_options = Options()
launch_options.add_argument("--headless")
launch_options.add_argument("--no-gpu")
# Regex for validating the URL
soundcloud_regex = re.compile(r'(?:https://)?(www\.)?soundcloud.com/([\w-]+)/([\w-]+)')
# Prompt user for SoundCloud URL
while True:
# Get URL from user
print("Welcome to the SoundCloud Downloader!")
print("Please enter the URL of the track you want to download:")
link = input(">")
# Logic for an emergency exit from the loop/program
if link == "!!exit":
sys.exit()
# Check if the entered URL is a valid SoundCloud URL
elif not soundcloud_regex.match(link):
print("Invalid URL")
# If the entered URL is a valid SoundCloud URL, break the loop
else:
break
# Open the browser
print("Warming up Selenium...")
driver = webdriver.Chrome(options=launch_options) # TODO: Add error handling
print("Seleneum is ready!")
# Open the SoundCloud page for the track
print("Opening SoundCloud...")
driver.get(link)
while True:
try:
# Get all network logs from the browser
log = driver.execute_script("var performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {}; var network = performance.getEntries() || {}; return network;")
# Search for the song title on the page
filename = driver.find_element(by='class name', value='soundTitle__title').find_element(by="tag name", value='span').text
break
except:
print("Chromedriver could not get the correct info, Selenium needs to reload the page")
driver.refresh()
# TODO: Get the album art from the page
# Define the variable for holding the link to the song's download
link = None
# Search all logs for "playlist.m3u8" (the audio data) and use the last instance
print("Finding Download Link...")
for item in log:
if "playlist.m3u8" in item['name']:
link = item['name']
break
# Show the user the download link
print("Link Found: " + link)
#Extract the album art from the link
print("Extracting Album Art...")
elements = driver.find_elements(by='class name', value='sc-artwork')
art = None
for element in elements:
if element.get_attribute("aria-role") != "img":
continue
style = element.get_attribute('style')
match = re.search(r'background-image: url\((.*)\)', style)
if match and "500x500" in match.group(1):
art = match.group(1).replace("\"", "")
break
if art is not None:
print("Album Art Found: " + art)
else:
print("Album Art Not Found")
# Close the browser
print("Cooling down Selenium...")
driver.quit()
# Use ffmpeg to download the audio and convert it to mp3
print("Downloading...")
# Delete the old file if it exists
if Path("file.mp3").exists():
os.remove("file.mp3")
if Path("file2.mp3").exists():
os.remove("file2.mp3")
subprocess.call("ffmpeg -protocol_whitelist file,http,https,tcp,tls -i \"{}\" -b:a 320k \"file.mp3\"".format(link), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True)
print("Download complete!")
print("Embedding Album Art...")
with open("embed1.log", "w") as log:
ext = subprocess.call("ffmpeg -i file.mp3 -protocol_whitelist file,http,https,tcp,tls -i \"{}\" -map 0:a -map 1:0 -c:a copy -id3v2_version 3 \"file2.mp3\"".format(art), stdout=log, stderr=log, shell=True)
print("Embedding Complete!") if ext == 0 else print("Embedding Failed! Using original file...")
if ext == 1:
print("Attempting different embed method...")
with requests.get(art, stream=True) as r:
r.raise_for_status()
with open("art.jpg", "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
os.remove("file2.mp3")
with open("embed2.log", "w") as log:
ext = subprocess.call("ffmpeg -i file.mp3 -i art.jpg -map 0:a -map 1:0 -c:a copy -id3v2_version 3 \"file2.mp3\"".format(art), stdout=log, stderr=log, shell=True)
print("Embedding Complete!") if ext == 0 else print("Embedding Failed! Using original file...")
os.remove("art.jpg")
# Prompt the user to select a directory to save the file
print("Please select a save location:")
target = filedialog.asksaveasfilename(defaultextension=".mp3", initialfile="{}.mp3".format(filename), title="Save as...", initialdir=Path.home() / "Desktop/")
# Move the file to the selected directory
print("Moving file...")
shutil.move("file2.mp3" if ext == 0 else "file.mp3", target)
# Remove the old file
print("Cleaning up...")
os.remove("file.mp3") if ext == 0 else None
os.remove("file2.mp3") if ext == 1 else None
# Done
print("Done!")