Giter Site home page Giter Site logo

glomatico / spotify-web-downloader Goto Github PK

View Code? Open in Web Editor NEW
299.0 9.0 35.0 198 KB

A Python CLI app for downloading songs/music videos/albums/playlists directly from Spotify.

Python 100.00%
spotify spotify-downloader music-downloader spotify-aac-downloader

spotify-web-downloader's Introduction

Spotify Web Downloader

A Python CLI app for downloading songs/music videos/albums/playlists directly from Spotify.

Discord Server: https://discord.gg/aBjMEZ9tnq

Features

  • Download songs in AAC 128kbps or in AAC 256kbps with a premium account
  • Download music videos with a premium account
  • Download synced lyrics with a premium account
  • Highly configurable

Prerequisites

Installation

  1. Install the package spotify-web-downloader using pip
    pip install spotify-web-downloader
  2. Place your cookies file in the directory from which you will be running spotify-web-downloader and name it cookies.txt.

Usage

spotify-web-downloader [OPTIONS] URLS...

Examples

  • Download a song
    spotify-web-downloader "https://open.spotify.com/track/18gqCQzqYb0zvurQPlRkpo"
  • Download an album
    spotify-web-downloader "https://open.spotify.com/album/0r8D5N674HbTXlR3zNxeU1"

Configuration

spotify-web-downloader can be configured using the command line arguments or the config file. The config file is created automatically when you run spotify-web-downloader for the first time at ~/.spotify-web-downloader/config.json on Linux and %USERPROFILE%\.spotify-web-downloader\config.json on Windows. Config file values can be overridden using command line arguments.

Command line argument / Config file key Description Default value
--download-music-video / download_music_video Attempt to download music videos from songs (can lead to incorrect results). false
--save-cover, -s / save_cover Save cover as a separate file. false
--overwrite / overwrite Overwrite existing files. false
--read-urls-as-txt, -r / - Interpret URLs as paths to text files containing URLs. false
--lrc-only, -l / lrc_only Download only the synced lyrics. false
--no-lrc / no_lrc Don't download the synced lyrics. false
--config-path / - Path to config file. <home>/.spotify-web-downloader/config.json
--log-level / log_level Log level. INFO
--print-exceptions / print_exceptions Print exceptions. false
--cookies-path, -c / cookies_path Path to .txt cookies file. ./cookies.txt
--output-path, -o / output_path Path to output directory. ./Spotify
--temp-path / temp_path Path to temporary directory. ./temp
--wvd-path / wvd_path Path to .wvd file. null
--ffmpeg-path / ffmpeg_path Path to FFmpeg binary. ffmpeg
--mp4box-path / mp4box_path Path to MP4Box binary. MP4Box
--mp4decrypt-path / mp4decrypt_path Path to mp4decrypt binary. mp4decrypt
--aria2c-path / aria2c_path Path to aria2c binary. aria2c
--nm3u8dlre-path / nm3u8dlre_path Path to N_m3u8DL-RE binary. N_m3u8DL-RE
--remux-mode / remux_mode Remux mode. ffmpeg
--date-tag-template / date_tag_template Date tag template. %Y-%m-%dT%H:%M:%SZ
--exclude-tags / exclude_tags Comma-separated tags to exclude. null
--truncate / truncate Maximum length of the file/folder names. 40
--template-folder-album / template_folder_album Template of the album folders as a format string. {album_artist}/{album}
--template-folder-compilation / template_folder_compilation Template of the compilation album folders as a format string. Compilations/{album}
--template-file-single-disc / template_file_single_disc Template of the song files for single-disc albums as a format string. {track:02d} {title}
--template-file-multi-disc / template_file_multi_disc Template of the song files for multi-disc albums as a format string. {disc}-{track:02d} {title}
--download-mode-song / download_mode_song Download mode for songs. ytdlp
--premium-quality, -p / premium_quality Download songs in premium quality. false
--template-folder-music-video / template_folder_music_video Template of the music video folders as a format string. {artist}/Unknown Album
--template-file-music-video / template_file_music_video Template of the music video files as a format string. {title}
--download-mode-video / download_mode_video Download mode for videos. ytdlp
--no-config-file, -n / - Do not use a config file. false

Tag variables

The following variables can be used in the template folder/file and/or in the exclude_tags list:

  • album
  • album_artist
  • artist
  • compilation
  • composer
  • copyright
  • cover
  • disc
  • disc_total
  • isrc
  • label
  • lyrics
  • media_type
  • producer
  • rating
  • release_date
  • release_year
  • title
  • track
  • track_total
  • url

Remux modes

The following remux modes are available:

Music videos quality

Music videos will be downloaded in the highest quality available in H.264/AAC, up to 1080p.

Download modes

The following modes are available for songs:

The following modes are available for videos:

spotify-web-downloader's People

Contributors

glomatico avatar kyrluckechuck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spotify-web-downloader's Issues

Program crashes when track metadata is not found

Error:

Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.11/site-packages/spotify_web_downloader/cli.py", line 361, in main
    logger.info(f'({queue_progress}) Downloading "{track["name"]}"')
                                                   ~~~~~^^^^^^^^
TypeError: 'NoneType' object is not subscriptable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/homebrew/bin/spotify-web-downloader", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/spotify_web_downloader/cli.py", line 556, in main
    f'({queue_progress}) Failed to download "{track["name"]}"',
                                              ~~~~~^^^^^^^^
TypeError: 'NoneType' object is not subscriptable

Possible fix to check if track is None within the main function after initializing track:

track = queue_item.metadata
if track is None:
    logger.warning(f'({queue_progress}) No track information available for download.')
    continue

Question on download quality with Premium Mini plan

So I'm unsure if all countries have this, but there is a Premium Mini plan which is a day/week plan from Spotify. Think this plan as Spotify free plan without its usual restrictions, except it will retain the quality of free plan — so AAC 128kbit/s on web browser and max 160kbit/s OGG in phone. Now, when I use this Premium Mini plan to download a song using your downloader and then see its info using https://mediaarea.net/en/MediaInfo, I see 256 kbps AAC. I want to know if the downloader is falsely converting the audio from 128 to 256 in this case, or is this a loose restriction that the downloader is able to bypass.

I haven't listened to the downloaded songs and compared them yet so I can't tell you auditory difference.

Feature Request: Ability to download by ID

Add command-line arguments to download albums and tracks by ID:

COMMAND-LINE ARGUMENT DESCRIPTION
--album-id Download album by ID.
--track-id Download track by ID.
EXAMPLES
spotify-web-downloader --album-id 3Id3VUk9jSKBD1guNo1buF
spotify-web-downloader --track-id 1BLfQ6dPXmuDrFmbdfW7Jl
ERROR/WARNING MESSAGE ALTERNATIVES
Spotify ID is unavailable or does not exist.
Spotify ID is incorrect or does not exist.

Output log to file

Is there anyway to output the log to a txt file? I have a large 9000 song playlist that I'm going through, but I want to identify any errors so I can manually grab the tracks, without having to parse everything again. The scroll bar in cmd/powershell only seems to go back so far. Thanks.

Attempt to download video when i want a track?

Hello, i have created the cookies.txt already, i tried with an artist and a track, both yield the same result, i also checked the settings, please see below.

PS C:\temp\SpotifyDownloader> spotify-web-downloader https://open.spotify.com/artist/78tfBR026VhVUGCBiZMX06
[CRITICAL 09:13:02] Cannot download music videos with a free account
PS C:\temp\SpotifyDownloader> spotify-web-downloader https://open.spotify.com/track/7FuyeSPssuLmWG4fNNTiNa?si=c9f371d0711f4a49
[CRITICAL 09:17:25] Cannot download music videos with a free account

config.json

exclude_tags

first of all BIG thanks for this amazing tool. W-O-N-D-E-R-FU-L

but i've issue to exclude some tags: i don't want add lyrics, comment, disc
so i've open config.json and edit with "exclude_tags": "lyrics, comment, disc",
but work only for lyrics ...
comment and disc (number) still present ...

cookies.txt not found

FileNotFoundError: [Errno 2] No such file or directory: 'cookies.txt'FileNotFoundError: [Errno 2] No such file or directory: 'cookies.txt'
i did as you said and i get this error
plzs help me

Paralell downloads

It is possible to download the songs in parallel? Downloading a playlist with 800 songs is taken forever because its being done sequentially. Im using aria2c, but this did'nt help.

If not, how hard is to add this feature?

Cannot download music videos with a free account

$ spotify-web-downloader "https://open.spotify.com/track/3iXU8Appg61ZtkAe09FCTq?si=nlVafQ7VQmiEkf9r1gMc7Q"
[CRITICAL 13:47:48] Cannot download music videos with a free account

Getting this, even after setting the "download video to false" (default config)

TypeError: argument of type 'WindowsPath' is not iterable

Hello,

Thank you very much for the application. I have followed the steps for its installation and configuration, but this error is generated when I try to download any content (song, album, etc.)

$ spotify-aac-downloader https://open.spotify.com/album/35dut3ICqF3NEDkjxfzJJ1 -p -e
Downloading "Starboy (feat. Daft Punk)" (track 1/21 from URL 1/1)
Failed to download "Starboy (feat. Daft Punk)" (track 1/21 from URL 1/1)
Traceback (most recent call last):
File "c:\users\manu\appdata\local\programs\python\python37\lib\site-packages\spotify_aac_downloader_init_.py", line 139, in main
dl.fixup(decryption_key, encrypted_location, fixed_location)
File "c:\users\manu\appdata\local\programs\python\python37\lib\site-packages\spotify_aac_downloader\spotify_aac_downloader.py", line 245, in fixup
check=True
File "c:\users\manu\appdata\local\programs\python\python37\lib\subprocess.py", line 488, in run
with Popen(*popenargs, **kwargs) as process:
File "c:\users\manu\appdata\local\programs\python\python37\lib\subprocess.py", line 800, in init
restore_signals, start_new_session)
File "c:\users\manu\appdata\local\programs\python\python37\lib\subprocess.py", line 1148, in _execute_child
args = list2cmdline(args)
File "c:\users\manu\appdata\local\programs\python\python37\lib\subprocess.py", line 555, in list2cmdline
needquote = (" " in arg) or ("\t" in arg) or not arg
TypeError: argument of type 'WindowsPath' is not iterable

You can help me?. Thank you so much. A greeting.

InvalidLicenseMessage: Cannot parse an empty license_message

Hello,
#16
294229254-56f1a709-68d4-4115-a467-60e5818d5a67
I didnt want to open a seperate issue but apparently have to because I ran into this error too.
It happens when I am downloading from a -r *.txt file and happens randomly after 50-100 songs. If I restart the program it works again until a few songs but then this error occurs again.
Whats the matter?
Thanks!

lrc file lyrics timestamp issue

Issue

The timestamp in lrc file are getting stored according to local timezone and not using UTC time so i am getting different results in lrc files.

Problem

At line 188 in get_lyrics_synced_timestamp_lrc function its not using UTC timezone and using my local timezone by default thus output is

Screenshot 2024-01-19 at 4 16 43 PM Screenshot 2024-01-19 at 4 15 08 PM

Fix

Instead of using

lrc_timestamp = datetime.datetime.fromtimestamp(time / 1000.0)

Output

1970-01-01 05:30:02.380000

Full Output

30:02.38

You can use

lrc_timestamp = datetime.datetime.fromtimestamp(time / 1000.0,tz=datetime.timezone.utc)

Output

1970-01-01 00:00:02.380000+00:00

Full Output

00:02.38

Feature Request: Add Options for Default Language Selection and Playlist Title-Based Directory Creation

Hello,

I am currently using the spotify-web-downloader tool and have found it to be incredibly useful for my music downloading needs. However, I believe the addition of a couple of features could greatly enhance its functionality and user experience. Below are the details of the features I am proposing:

  1. Default Language Selection for Songs:

    • Problem: Currently, when downloading songs from Spotify, the tool does not allow the user to specify the default language for the tracks. This can be inconvenient for users who prefer songs in specific languages, especially in regions with multiple languages.
    • Proposed Feature: I suggest adding a command-line argument (e.g., --default-language or in the config file as default_language) that allows users to set their preferred language for song downloads. This setting should influence the metadata and lyrics language (if available).
  2. Playlist Title-Based Directory Creation:

    • Problem: When downloading playlists, all files are saved directly to the specified output path, without creating a subdirectory named after the playlist title. This can lead to disorganization, especially when downloading multiple playlists.
    • Proposed Feature: It would be highly beneficial if the tool could automatically create a new directory based on the playlist title for storing the downloaded files. This could be an optional feature enabled via a command-line switch (e.g., --use-playlist-title-for-folder) or a configurable setting in the config file.

I believe these features will make spotify-web-downloader even more robust and convenient for users. Thank you for considering these enhancements. I look forward to the potential implementation of these features and am excited to see how they will improve the overall functionality of the tool.

Best regards,
Andre Ho

Use slashes to separate multiple artists in ‘album_artist’ and ‘artist’ fields

On Spotify, multiple artists are separated in a way that makes each one clickable. However, the current implementation of spotify-web-downloader combines all artists into a single string. This approach can make browsing in music players cumbersome.

To improve user experience, I suggest separating multiple artists with slashes (“/”), as recommended in the ID3 tag documentation. This change should apply to both the ‘artist’ and ‘album_artist’ fields.

Additionally, when downloading files, it would be beneficial to store them in the folder of the first credited artist. This adjustment would simplify file management for users.

Question

hey is there a way to download songs into one folder instead of it creating subfolders. ? i downloaded a playlist and every artist has a folder.

Can't download next track

~ $ spotify-web-downloader https://open.spotify.com/album/3EkmvTqyKrnMw1WiVpsSwF?si=z9HUKMkLSGGFSD9018yahQ&context=spotify%3Aalbum%3A3EkmvTqyKrnMw1WiVpsSwF
[4] 6135
~ $ [INFO 09:24:38] (Track 1/6 from URL 1/1) Downloading "Galliyan"

[4]+ Stopped spotify-web-downloader https://open.spotify.com/album/3EkmvTqyKrnMw1WiVpsSwF?si=z9HUKMkLSGGFSD9018yahQ

~ $ ls temp/ 3ySVdXje5nm31d7vL3jNV3_encrypted.m4a ~ $

I am using this in termux after downloading on track it can not download the other one in the album

“truncate” should apply to file names only, not folder names

In the current implementation, when the “truncate” option is set to 40 and “template_folder_album” is configured as “{album_artist}/{album} ({release_year})”, album folders are named in the format ‘Album Title XXXXXXXXXXXXXXXXXXXXXXXXXXX (197’. This truncation applies to both file and folder names, which can lead to confusion.

A more logical approach would be to apply the “truncate” function solely to file names, which are more likely to exceed the length limit than album folder names. This modification would improve the readability and organization of the album folders. The length of the file name should be calculated from the full path of the file, and then truncated if necessary. This change would ensure that the truncation process does not inadvertently affect the structure and readability of the album folders.

Playlist downloads stops

Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/spotify_aac_downloader/cli.py", line 278, in main
logger.info(f'({current_track}) Downloading "{track["name"]}"')
TypeError: 'NoneType' object is not subscriptable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/local/bin/spotify-aac-downloader", line 8, in
sys.exit(main())
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 1157, in call
return self.main(*args, **kwargs)
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "/usr/local/lib/python3.10/dist-packages/spotify_aac_downloader/cli.py", line 348, in main
f'({current_track}) Failed to download "{track["name"]}"',
TypeError: 'NoneType' object is not subscriptable

Error when trying to download one track

Track: https://open.spotify.com/track/1pXvHzvQ1sUHIwvN50wJWp
Error:

Traceback (most recent call last):
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\site-packages\requests\models.py", line 971, in json
    return complexjson.loads(self.text, **kwargs)
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\json\__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\site-packages\spotify_aac_downloader\cli.py", line 273, in main
    pssh = dl.get_pssh(file_id)
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\site-packages\spotify_aac_downloader\dl.py", line 158, in get_pssh
    return self.session.get(
  File "C:\Users\smirn\AppData\Local\Programs\Python\Python39\lib\site-packages\requests\models.py", line 975, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.