Skip to content

Commit

Permalink
Address minor style/nitpicks (#305)
Browse files Browse the repository at this point in the history
* reference the filename in constants, delete them after download

* minor clean up

* minor formatting changes via black

* update image, readme updates & test updates
  • Loading branch information
SathyaBhat authored Oct 15, 2022
1 parent a0650f2 commit e7ad6e0
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 42 deletions.
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Downloads songs from any Spotify playlist, album or track.

### Tell me more!

I wanted an easy way to grab the songs present in my library so I can download it & use it offline. I no longer use this, but continue to maintain this. spotify-dl doesn't download anything from Spotify. It picks up the metadata from Spotify API and then uses [yt-dlp](https://github.com/yt-dlp/yt-dlp) to download the song.
I wanted an easy way to grab the songs present in my library so I can download it & use it offline. I no longer use this, but continue to maintain this. spotify-dl doesn't download anything from Spotify. It picks up the metadata from Spotify API and then uses [yt-dlp](https://github.com/yt-dlp/yt-dlp) to download the song.

### How do I get this thing running?

Expand All @@ -24,7 +24,11 @@ Install using pip

Run the program

spotify_dl -l spotify_playlist_link/s -o download_directory
spotify_dl -l spotify_playlist_link_1 spotify_playlist_link_2

If you want to make use of parallel download, pass `-mc <number>`, where `<number>` refers to number of cores. If this is too high, spotify-dl will set it to one lesser than max number of cores that you have.

spotify_dl -mc 4 -l spotify_playlist_link_1 spotify_playlist_link_2

For running in verbose mode, append `-V`

Expand All @@ -34,14 +38,9 @@ For more details and other arguments, issue `-h`

spotify_dl -h

For downloading using multiple cores


spotify_dl -l [link] -mc [number of cores to use]

See [the getting started guide](https://github.com/SathyaBhat/spotify-dl/blob/master/GETTING_STARTED.md) for more details.

### Demo
### Demo

[![asciicast](https://asciinema.org/a/488558.svg)](https://asciinema.org/a/488558)

Expand Down
Binary file modified images/spotify-playlist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions spotify_dl/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
SAVE_PATH = os.getenv("XDG_CACHE_HOME") + "/spotifydl"
else:
SAVE_PATH = str(Path.home()) + "/.cache/spotifydl"

DOWNLOAD_LIST = "download_list.log"
4 changes: 3 additions & 1 deletion spotify_dl/scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
)
console = Console()
log = logging.getLogger("sdl")
sentry_sdk.init("https://[email protected]/2383261")
sentry_sdk.init(
"https://[email protected]/2383261"
)


def get_tokens():
Expand Down
51 changes: 40 additions & 11 deletions spotify_dl/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ def fetch_tracks(sp, item_type, url):
offset=offset,
)
total_songs = items.get("total")
track_info_task = progress.add_task(description="Fetching track info", total=len(items["items"]))
track_info_task = progress.add_task(
description="Fetching track info", total=len(items["items"])
)
for item in items["items"]:
track_info = item.get("track")
# If the user has a podcast in their playlist, there will be no track
Expand All @@ -42,11 +44,15 @@ def fetch_tracks(sp, item_type, url):
track_num = track_info.get("track_number")
spotify_id = track_info.get("id")
track_name = track_info.get("name")
track_artist = ",".join([artist["name"] for artist in track_info.get("artists")])
track_artist = ",".join(
[artist["name"] for artist in track_info.get("artists")]
)
if track_album_info:
track_album = track_album_info.get("name")
track_year = (
track_album_info.get("release_date")[:4] if track_album_info.get("release_date") else ""
track_album_info.get("release_date")[:4]
if track_album_info.get("release_date")
else ""
)
album_total = track_album_info.get("total_tracks")
if len(item["track"]["album"]["images"]) > 0:
Expand All @@ -55,8 +61,14 @@ def fetch_tracks(sp, item_type, url):
cover = None

artists = track_info.get("artists")
main_artist_id = artists[0].get("uri", None) if len(artists) > 0 else None
genres = sp.artist(artist_id=main_artist_id).get("genres", []) if main_artist_id else []
main_artist_id = (
artists[0].get("uri", None) if len(artists) > 0 else None
)
genres = (
sp.artist(artist_id=main_artist_id).get("genres", [])
if main_artist_id
else []
)
if len(genres) > 0:
genre = genres[0]
else:
Expand Down Expand Up @@ -95,25 +107,38 @@ def fetch_tracks(sp, item_type, url):

elif item_type == "album":
with Progress() as progress:
album_songs_task = progress.add_task(description="Fetching songs from the album..")
album_songs_task = progress.add_task(
description="Fetching songs from the album.."
)
while True:
album_info = sp.album(album_id=url)
items = sp.album_tracks(album_id=url, offset=offset)
total_songs = items.get("total")
track_album = album_info.get("name")
track_year = album_info.get("release_date")[:4] if album_info.get("release_date") else ""
track_year = (
album_info.get("release_date")[:4]
if album_info.get("release_date")
else ""
)
album_total = album_info.get("total_tracks")
if len(album_info["images"]) > 0:
cover = album_info["images"][0]["url"]
else:
cover = None
if len(sp.artist(artist_id=album_info["artists"][0]["uri"])["genres"]) > 0:
genre = sp.artist(artist_id=album_info["artists"][0]["uri"])["genres"][0]
if (
len(sp.artist(artist_id=album_info["artists"][0]["uri"])["genres"])
> 0
):
genre = sp.artist(artist_id=album_info["artists"][0]["uri"])[
"genres"
][0]
else:
genre = ""
for item in items["items"]:
track_name = item.get("name")
track_artist = ", ".join([artist["name"] for artist in item["artists"]])
track_artist = ", ".join(
[artist["name"] for artist in item["artists"]]
)
track_num = item["track_number"]
spotify_id = item.get("id")
songs_list.append(
Expand Down Expand Up @@ -149,7 +174,11 @@ def fetch_tracks(sp, item_type, url):
track_artist = ", ".join([artist["name"] for artist in items["artists"]])
if album_info:
track_album = album_info.get("name")
track_year = album_info.get("release_date")[:4] if album_info.get("release_date") else ""
track_year = (
album_info.get("release_date")[:4]
if album_info.get("release_date")
else ""
)
album_total = album_info.get("total_tracks")
track_num = items["track_number"]
spotify_id = items["id"]
Expand Down
36 changes: 24 additions & 12 deletions spotify_dl/spotify_dl.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,15 @@ def spotify_dl():
args = parser.parse_args()
num_cores = os.cpu_count()
args.multi_core = int(args.multi_core)
console.log(f"Starting spotify_dl [bold green]v{VERSION}[/bold green]")
if args.verbose:
log.setLevel(DEBUG)
log.debug("Setting debug mode on spotify_dl")

if args.multi_core > (num_cores - 1):
print(f"[!] too many cores requested , reverting to {num_cores - 1} cores")
console.log(
f"Requested cores [bold red]{args.multi_core}[/bold red] exceeds available [bold green]{num_cores}[/bold green], using [bold green]{num_cores - 1}[/bold green] cores."
)
args.multi_core = num_cores - 1
if args.version:
console.print(f"spotify_dl [bold green]v{VERSION}[/bold green]")
Expand All @@ -127,20 +134,19 @@ def spotify_dl():
else:
setattr(args, key, value)

if args.verbose:
log.setLevel(DEBUG)
if not args.url:
raise (Exception("No playlist url provided:"))

console.log(f"Starting spotify_dl [bold green]v{VERSION}[/bold green]")
log.debug("Setting debug mode on spotify_dl")

tokens = get_tokens()
if tokens is None:
sys.exit(1)
C_ID, C_SECRET = tokens
client_id, client_secret = tokens

sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id=C_ID, client_secret=C_SECRET))
sp = spotipy.Spotify(
auth_manager=SpotifyClientCredentials(
client_id=client_id, client_secret=client_secret
)
)
log.debug("Arguments: %s ", args)

valid_urls = validate_spotify_urls(args.url)
Expand All @@ -153,9 +159,13 @@ def spotify_dl():
url_dict = {}
item_type, item_id = parse_spotify_url(url)
directory_name = get_item_name(sp, item_type, item_id)
url_dict["save_path"] = Path(PurePath.joinpath(Path(args.output), Path(directory_name)))
url_dict["save_path"] = Path(
PurePath.joinpath(Path(args.output), Path(directory_name))
)
url_dict["save_path"].mkdir(parents=True, exist_ok=True)
console.print(f"Saving songs to [bold green]{directory_name}[/bold green] directory")
console.print(
f"Saving songs to [bold green]{directory_name}[/bold green] directory"
)
url_dict["songs"] = fetch_tracks(sp, item_type, url)
url_data["urls"].append(url_dict.copy())
if args.download is True:
Expand All @@ -177,6 +187,8 @@ def spotify_dl():


if __name__ == "__main__":
starttime = time.time()
start_time = time.time()
spotify_dl()
print(f"[*] finished in {time.time() - starttime}")
console.log(
f"Download completed in [bold green]{time.time() - start_time} seconds.[/bold green]"
)
30 changes: 21 additions & 9 deletions spotify_dl/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
from mutagen.mp3 import MP3
from spotify_dl.scaffold import log
from spotify_dl.utils import sanitize
from spotify_dl.constants import DOWNLOAD_LIST


def default_filename(**kwargs):
"""name without number"""
return sanitize(f"{kwargs['artist']} - {kwargs['name']}", "#") # youtube-dl automatically replaces with #
return sanitize(
f"{kwargs['artist']} - {kwargs['name']}", "#"
) # youtube-dl automatically replaces with #


def playlist_num_filename(**kwargs):
Expand All @@ -30,8 +33,6 @@ def write_tracks(tracks_file, song_dict):
:param song_dict: the songs to be written to tracks_file
"""
track_db = []
if tracks_file != "All_Songs_For_This_Download.txt":
return "Invalid filename"

with open(tracks_file, "w+", encoding="utf-8", newline="") as file_out:
i = 0
Expand Down Expand Up @@ -81,14 +82,18 @@ def set_tags(temp, file_path, kwargs):
song_file = MP3(mp3filename, ID3=EasyID3)
except mutagen.MutagenError as e:
log.debug(e)
print(f"Failed to download: {mp3filename}, please ensure YouTubeDL is up-to-date. ")
print(
f"Failed to download: {mp3filename}, please ensure YouTubeDL is up-to-date. "
)

return
song_file["date"] = song.get("year")
if kwargs["keep_playlist_order"]:
song_file["tracknumber"] = str(song.get("playlist_num"))
else:
song_file["tracknumber"] = str(song.get("num")) + "/" + str(song.get("num_tracks"))
song_file["tracknumber"] = (
str(song.get("num")) + "/" + str(song.get("num_tracks"))
)

song_file["genre"] = song.get("genre")
song_file.save()
Expand Down Expand Up @@ -132,8 +137,12 @@ def find_and_download_songs(kwargs):
query = f"{artist} - {name} Lyrics".replace(":", "").replace('"', "")
print(f"Initiating download for {query}.")

file_name = kwargs["file_name_f"](name=name, artist=artist, track_num=kwargs["track_db"][i].get("num"))
sponsorblock_remove_list = ["music_offtopic"] if kwargs["skip_non_music_sections"] else []
file_name = kwargs["file_name_f"](
name=name, artist=artist, track_num=kwargs["track_db"][i].get("num")
)
sponsorblock_remove_list = (
["music_offtopic"] if kwargs["skip_non_music_sections"] else []
)

file_path = path.join(kwargs["track_db"][i]["save_path"], file_name)
outtmpl = f"{file_path}.%(ext)s"
Expand Down Expand Up @@ -214,7 +223,9 @@ def multicore_find_and_download_songs(kwargs):
processes = []
segment_index = 0
for segment in file_segments:
p = multiprocessing.Process(target=multicore_handler, args=(segment_index, segment, kwargs.copy()))
p = multiprocessing.Process(
target=multicore_handler, args=(segment_index, segment, kwargs.copy())
)
processes.append(p)
segment_index += 1

Expand Down Expand Up @@ -249,7 +260,7 @@ def download_songs(**kwargs):
"""
for url in kwargs["songs"]["urls"]:
log.debug("Downloading to %s", url["save_path"])
reference_file = "All_Songs_For_This_Download.txt"
reference_file = DOWNLOAD_LIST
track_db = write_tracks(reference_file, kwargs["songs"])
os.rename(reference_file, kwargs["output_dir"] + "/" + reference_file)
reference_file = str(kwargs["output_dir"]) + "/" + reference_file
Expand All @@ -259,3 +270,4 @@ def download_songs(**kwargs):
multicore_find_and_download_songs(kwargs)
else:
find_and_download_songs(kwargs)
os.remove(reference_file)
2 changes: 1 addition & 1 deletion tests/test_spotify_fetch_tracks.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def test_spotify_track_fetch_one():
assert {
"album": "Hell Freezes Over (Remaster 2018)",
"artist": "Eagles",
"cover": "https://i.scdn.co/image/ab67616d0000b27396d28597a5ae44ab66552183",
"cover": "https://i.scdn.co/image/ab67616d0000485196d28597a5ae44ab66552183",
"genre": "album rock",
"name": "Hotel California - Live On MTV, 1994",
"num": 6,
Expand Down

0 comments on commit e7ad6e0

Please sign in to comment.