Coder Social home page Coder Social logo

zspotify's Introduction

ZSpotify

Docker CI GPLv3

ZSpotify is a Spotify downloader that enables users to find and download songs.

Installation

Install ZSpotify using either pip or Docker

pip

  1. Install required dependencies:

    ⚠️ To install Python and FFmpeg on Linux, use the preferred package manager for your distribution.

  2. Install ZSpotify:

pip install git+https://github.com/jsavargas/zspotify

Docker

docker pull jsavargas/zspotify
docker run -v ${HOME}/.zspotify:/root/.zspotify -v ${HOME}/Music:/root/Music -it jsavargas/zspotify

PLEASE NOTE πŸ—’οΈ You must first run zspotify locally and authenticate. Migrate your authentication file (credentials.json) into the .zspotify volume on your docker system so that it can be used on start.
Otherwise your Docker run will fail due to it trying to recieve a username input that it will never get.

Usage

usage: zspotify [-h] [-ap] [-sp] [-ls] [-pl PLAYLIST] [-tr TRACK] [-al ALBUM] [-ar ARTIST] [-ep EPISODE]
                [-fs FULL_SHOW] [-cd CONFIG_DIR] [--archive ARCHIVE] [-d DOWNLOAD_DIR] [-md MUSIC_DIR]
                [-pd EPISODES_DIR] [-v] [-af {mp3,ogg}] [--album-in-filename] [--antiban-time ANTIBAN_TIME]
                [--antiban-album ANTIBAN_ALBUM] [--limit LIMIT] [-f] [-ns] [-s] [-cf CREDENTIALS_FILE]
                [-bd BULK_DOWNLOAD]
                [search]

positional arguments:
  search                Searches for a track, album, artist or playlist or download by url

options:
  -h, --help            Show this help message and exit
  -v, --version         Shows the current version of ZSpotify
  -ap, --all-playlists  Downloads all saved playlist from your library
  -sp, --select-playlists
                        Downloads a saved playlist from your library
  -ls, --liked-songs    Downloads your liked songs
  -pl PLAYLIST, --playlist PLAYLIST
                        Download playlist by id or url
  -tr TRACK, --track TRACK
                        Downloads a track from their id or url
  -al ALBUM, --album ALBUM
                        Downloads an album from their id or url
  -ar ARTIST, --artist ARTIST
                        Downloads an artist from their id or url
  -ep EPISODE, --episode EPISODE
                        Downloads a episode from their id or url
  -fs FULL_SHOW, --full-show FULL_SHOW
                        Downloads all show episodes from id or url
  -cd CONFIG_DIR, --config-dir CONFIG_DIR
                        Folder to save the config files  
                        Default: *nix => $HOME/.zspotify Windows => (%homepath%)/.zspotify
  --archive ARCHIVE     File to save the downloaded files
  -d DOWNLOAD_DIR, --download-dir DOWNLOAD_DIR
                        Folder to save the downloaded files
  -md MUSIC_DIR, --music-dir MUSIC_DIR
                        Folder to save the downloaded music files
  -pd EPISODES_DIR, --episodes-dir EPISODES_DIR
                        Folder to save the downloaded episodes files
  -af {mp3,ogg}, --audio-format {mp3,ogg}
                        Audio format to download the tracks
  --album-in-filename   Adds the album name to the filename
  --antiban-time ANTIBAN_TIME
                        Time (seconds) to wait between downloads to avoid Ban
  --antiban-album ANTIBAN_ALBUM
                        Time (seconds) to wait between album downloads to avoid Ban
  --limit LIMIT         Search Limit (seconds)
                        Imposes a search limit that is overridable with the environment variable LIMIT_RESULTS
                        Default: 10
  -f, --force-premium   Force premium account
  -ns, --not-skip-existing
                        If flag setted NOT Skip existing already downloaded tracks
  -s, --skip-downloaded
                        Skip already downloaded songs if exist in archive even it is doesn't exist in the filesystem
  -cf CREDENTIALS_FILE, --credentials-file CREDENTIALS_FILE
                        File to save the credentials  
                        Run once to create this file with your terminal input username and password.   
                        Then move the file and change the directory with this argument.
  -bd BULK_DOWNLOAD, --bulk-download BULK_DOWNLOAD
                        Bulk download from file with urls

Changelog

View changelog here

Disclaimer

We recommend using a burner account to avoid any possible account bans.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Acknowledgements

zspotify's People

Contributors

amnemonic avatar atahabaki avatar bionded avatar cbackas avatar example123 avatar jlsalvador avatar joonas-fi avatar jsavargas avatar jzinkweg avatar kaitallaoua avatar krowvin avatar mauritzfunke avatar merlinscholz avatar niclimcy avatar nopeless avatar scarlettekk avatar screeper11 avatar seut avatar tjmurray avatar vicdominguez 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  avatar  avatar  avatar  avatar  avatar  avatar

zspotify's Issues

[Suggestion] Use something like argparse to parse arguments

Hi,
I'm trying to contribute regularly to this repository and I'm currently implementing a feature to read urls and files from files to download.
I noticed that its nearly impossible to use more than one argument with the way arguments are currently implemented.

I didn't want to "waste" my resources and implement it without your approval.

-ls parameter returns error

How to reproduce

python zspotify -ls

ERROR

Traceback (most recent call last):
  File "/home/pi/zspotify/zspotify.py", line 892, in <module>
    main()
  File "/home/pi/zspotify/zspotify.py", line 888, in main
    client()
  File "/home/pi/zspotify/zspotify.py", line 141, in client
    for song in get_saved_tracks(token):
  File "/home/pi/zspotify/zspotify.py", line 693, in get_saved_tracks
    songs.extend(resp['items'])
KeyError: 'items'

Podcast episode failed to download

Attempting to download podcast episode with the following command:
python .\main.py -ep "https://open.spotify.com/episode/5JplhUbKVqtTzZtdvj2MaQ" -d "C:\Users<USER>\Music\zspotify\downloads" -cd "C:\Users<USER>\Music\zspotify\config" -pd "C:\Users<USER>\Music\zspotify\Podcasts"

Using Windows Powershell.

The following is the console output:

β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ    β–ˆβ–ˆ
   β–ˆβ–ˆβ–ˆ  β–ˆβ–ˆ      β–ˆβ–ˆ   β–ˆβ–ˆ β–ˆβ–ˆ    β–ˆβ–ˆ    β–ˆβ–ˆ    β–ˆβ–ˆ β–ˆβ–ˆ       β–ˆβ–ˆ  β–ˆβ–ˆ
  β–ˆβ–ˆβ–ˆ   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  β–ˆβ–ˆ    β–ˆβ–ˆ    β–ˆβ–ˆ    β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ     β–ˆβ–ˆβ–ˆβ–ˆ
 β–ˆβ–ˆβ–ˆ         β–ˆβ–ˆ β–ˆβ–ˆ      β–ˆβ–ˆ    β–ˆβ–ˆ    β–ˆβ–ˆ    β–ˆβ–ˆ β–ˆβ–ˆ         β–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ       β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ     β–ˆβ–ˆ    β–ˆβ–ˆ β–ˆβ–ˆ         β–ˆβ–ˆ

version: 2.0.0_alpha
Migration complete from file: C:\Users<USER>\Music\zspotify\config.song_archive
Migration complete from file: C:\Users<USER>\Music\zspotify\downloads.song_archive
Migration complete from file: C:\Users<USER>\Music\zspotify\downloads\ZSpotify Music.song_archive
Migration complete from file: C:\Users<USER>\Music\zspotify\Podcasts.song_archive
Downloading What Happened To The Neandertals episode
Couldn't resolve redirect!
Eons Mysteries of Deep Time - What Happened To The Neandertals.mp3: 31.8MB [00:21, 1.58MB/s]
Converting What Happened To The Neandertals episode

download_track - FAILED TO DOWNLOAD

Decoding failed. ffmpeg returned error code: 1

Output from ffmpeg/avlib:

ffmpeg version 5.1.2-full_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 12.1.0 (Rev2, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 57. 28.100 / 57. 28.100
libavcodec 59. 37.100 / 59. 37.100
libavformat 59. 27.100 / 59. 27.100
libavdevice 59. 7.100 / 59. 7.100
libavfilter 8. 44.100 / 8. 44.100
libswscale 6. 7.100 / 6. 7.100
libswresample 4. 7.100 / 4. 7.100
libpostproc 56. 6.100 / 56. 6.100
[ogg @ 0000015de9316900] cannot find sync word
[cache @ 0000015de9316ec0] Statistics, cache hits:0 cache misses:3
cache:pipe:0: Invalid data found when processing input

5JplhUbKVqtTzZtdvj2MaQ C:\Users<USER>\Music\zspotify\Podcasts\Eons Mysteries of Deep Time - What Happened To The Neandertals.mp3
Added to archive: Eons Mysteries of Deep Time - What Happened To The Neandertals
Set audiotags What Happened To The Neandertals
[!] ERROR [Errno 2] No such file or directory: 'C:\Users\\Music\zspotify\Podcasts\Eons Mysteries of Deep Time - What Happened To The Neandertals.mp3'

Songs only get downloaded partially

Everything works fine except all the songs except it only downloads up to 90% and moves to next song. The songs are playable but skip whenever it reaches near the end !

Script fails when song title is too long for filename

Traceback (most recent call last):
File "/home/username/dev/zspotify/zspotify.py", line 754, in download_track
with open(filename, 'wb') as file, tqdm(
OSError: [Errno 36] File name too long: '/home/username/Music/ZSpotify Music/Jnr Choi - TO THE MOON (feat. Fivio Foreign, Russ Millions & Sam Tompkins) [Drill Remix] - TO THE MOON (feat. Fivio Foreign, Russ Millions & Sam Tompkins) - Drill Remix.mp3'

Songs only get downloaded partally

Hello, first of all thanks for your great software

Currently I have an issue regarding song downloads.
For example Wait For Me from Hablot Brown is only downloading 3:33 when the song is originally 4:06 long

Converts only first 2 minutes

I didn't do much testing and correct me if I'm wrong, but my downloads were capped at 2 minutes.
Also, the progress bar didn't go to 100%.

Crash only when downloading specific playlists

The script seems to crash at some specific songs only. Some playlists download without issues but this for example doesn't.

The crash message:
Traceback (most recent call last): File "C:\Users\sandro\Desktop\zspotify-master\zspotify.py", line 892, in <module> main() File "C:\Users\sandro\Desktop\zspotify-master\zspotify.py", line 888, in main client() File "C:\Users\sandro\Desktop\zspotify-master\zspotify.py", line 187, in client download_track(song['track']['id'], TypeError: 'NoneType' object is not subscriptable

I also tried running it in an elevated instance of PS, but the samme issue occured again.

Start playlist downloading from a specific song instead of from the beginning

I faced a problem while downloading from a huge playlist that contains 1000 songs (lofi if you wish to know), a few times I get an error which leads me to restart downloading and it's good that it skips already downloaded files but having to wait for it to skip like 600+ songs for it to continue is not very efficient. How about having the option to set a parameter where you don't have to download a playlist from its beginning, but it'd be something like passing the track number from which you wish to start downloading till the end.

It could also come in handy if there's a playlist and you want to download the latest added songs, so you specify your interval, from 1-20 instead of the whole playlist.

'Year' ('Date') is missing from ID3 tags

ID3 tags are missing the 'Year' data (I believe the tag name in ID3 is 'Date', even though it stores a year value). I notice that the ID3 tags do contain an "Original Date" tag, however most Music softwares do not recognise this (e.g. iTunes / Apple Music), so would be great to set the regular 'Date' value as well.

Screenshot 2022-10-14 at 19 43 57

Download for podcast fails

When I’m running zspotify with

zspotify --episode 2knf2lQkB9Bwim2t2Nkahz

it fails, probably somewhere in the API code that I don’t currently understand, with this output:

Downloading BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3 episode
Using OGG_VORBIS_96 because preferred AudioQuality.HIGH couldn't be found.
Unlocking Us with BrenΓ© Brown - BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3.mp3:  98%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–Š| 27.4M/27.9M [00:06<00:00, 3.98MB/s]###   download_track - FAILED TO DOWNLOAD   ###
Expecting value: line 1 column 1 (char 0)
2knf2lQkB9Bwim2t2Nkahz /Users/jan/Music/ZSpotify Podcast/Unlocking Us with BrenΓ© Brown - BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3.mp3
Unlocking Us with BrenΓ© Brown - BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3.mp3: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 27.9M/27.9M [00:07<00:00, 4.07MB/s]
Converting BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3 episode
Added to archive: Unlocking Us with BrenΓ© Brown - BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3
Set audiotags BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3
Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/_util.py", line 250, in _openfile
    fileobj = open(filename, "rb+" if writable else "rb")
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/Users/jan/Music/ZSpotify Podcast/Unlocking Us with BrenΓ© Brown - BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3.mp3'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/homebrew/bin/zspotify", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/zspotify/__main__.py", line 934, in main
    zs.start()
  File "/opt/homebrew/lib/python3.11/site-packages/zspotify/__main__.py", line 900, in start
    self.download_episode(episode)
  File "/opt/homebrew/lib/python3.11/site-packages/zspotify/__main__.py", line 761, in download_episode
    self.set_audio_tags(fullpath,
  File "/opt/homebrew/lib/python3.11/site-packages/zspotify/__main__.py", line 341, in set_audio_tags
    tags = id3.ID3(filename)
           ^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/id3/_file.py", line 76, in __init__
    super(ID3, self).__init__(*args, **kwargs)
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/id3/_tags.py", line 172, in __init__
    super(ID3Tags, self).__init__(*args, **kwargs)
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/_util.py", line 533, in __init__
    super(DictProxy, self).__init__(*args, **kwargs)
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/_tags.py", line 110, in __init__
    self.load(*args, **kwargs)
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/_util.py", line 184, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/_util.py", line 153, in wrapper
    with _openfile(self, filething, filename, fileobj,
  File "/opt/homebrew/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/contextlib.py", line 137, in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/mutagen/_util.py", line 271, in _openfile
    raise MutagenError(e)
mutagen.MutagenError: [Errno 2] No such file or directory: '/Users/jan/Music/ZSpotify Podcast/Unlocking Us with BrenΓ© Brown - BrenΓ© with Dr. John Gottman and Dr. Julie Schwartz Gottman on The Love Prescription, Part 1 of 3.mp3'

I think that the important hint is the Expecting value: line 1 column 1 (char 0). The rest may just be knock-on effects.

Can you help figuring this out?

os.getenv("PUID") returns None

Traceback (most recent call last):
  File "C:\Users\Miran\Desktop\zspotify-master\zspotify.py", line 85, in <module>
    PUID = int(os.getenv("PUID")) or 0
           ^^^^^^^^^^^^^^^^^^^^^^
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

Album numbers do not increment when downloading multiple albums from artist.

for album in albums:

            for album in albums:
                if artists_choice['id'] == album['artists'][0]['id'] and album['album_type'] != 'single' :
                    i += 1
                    year = re.search('(\d{4})', album['release_date']).group(1)
                    print(f"\n\n\n{i}/{total_albums_downloads} {album['artists'][0]['name']} - ({year}) {album['name']} [{album['total_tracks']}]")
                    download_album(album['id'])
                    for i in range(ANTI_BAN_WAIT_TIME_ALBUMS)[::-1]:
                        print("\rWait for Next Download in %d second(s)..." % (i + 1), end="")
                        time.sleep(1)

i += 1 is never more than 1 when printed as "i" gets trashed in the ANTI_BAN_WAIT_TIME_ALBUMS loop further down.

For giggles I changed the "i" to "p" in the loop and it resolved the issue.

                    for p in range(ANTI_BAN_WAIT_TIME_ALBUMS)[::-1]:
                        print("\rWait for Next Download in %d second(s)..." % (p + 1), end="")
                        time.sleep(1)

Pardon the hack and the lack of a decent description. I have zero python experience and have no idea the lingo :)

Idea: Re-use existing downloads, export m3u8

Hello! First of all, thank you for this great tool.

I have an improvement idea for people wishing to archive many playlists. It would probably require a different mode of operation and some major refactoring, though.
Given a playlist, the tool could download tracks into a standard directory structure (artist/album) and export an m3u8 file referencing these files. A subsequent run of the tool with a different playlist could look up if the track already exists and skip downloading it, but again reference it in an m3u8 file. This would provide the following advantages:

  1. Faster archival of many playlists with overlaps due to making use of the local library.
  2. The m3u8 files can be imported into software like Subsonic/Navidrome, enabling users to stream their backup copies easily.

update doc to require python 3.9?

with python 3.8 i got the error

python zspotify.py
Traceback (most recent call last):
  File "zspotify.py", line 941, in <module>
    def get_previously_downloaded() -> list[str]:
TypeError: 'type' object is not subscriptable

with python 3.9 it works

Need a setting to control Spotify Volume Normalisation

My understanding is that by default, Spotify sets volume normalisation to "Normal" mode (not off by default), and that this is a per-client setting (not a per-account setting), thus would need to be configured directly in ZSpotify. Since their normalisation impacts the actual audio / audio quality, possibly introducing artefacts due to use of compressors/limiters, it would be very useful to be able to turn this setting off when using ZSpotify so that the pure audio can be streamed.

I'm not totally sure yet whether it's on or off when using current ZSpotify, but either way this is a setting we should be able to control.

Some further reading/references:

https://support.spotify.com/us/article/audio-normalization/

https://artists.spotify.com/en/help/article/loudness-normalization

Handle filename too long error

On many OSes (at least linux lol), the max filename length is 255 bytes. There are some songs with names longer than this, when "Include album name in title" is enabled (one example here https://open.spotify.com/track/0zK8Em4hCWACv0BeAVGRcr)

Zspotify should probably handle these cases and truncate the filename to be shorter - in my case, downloading liked songs, when the download fails it tries again indefinitely until the script crashes due to recursion depth limits.

incorrect api tokens "read-user-email"

Hello I'm getting an error when downloading my like songs

zspotify

which is really just a 503 insufficient authorization response because the request isn't being made with the right token.

the tokens that fixed the issue for me:

  • "playlist-read-private" for the download_playlist() & download_from_user_playlist() function
  • "user-library-read" for the client() function

Let me know if I missed anything, and I hope you have a great week!

zspotify docker tag 2.0.3 PremiumAccountRequired error

Using the docker container tagged as 2.0.3

docker run -v ${HOME}/.zspotify:/root/.zspotify -v ${HOME}/Music:/root/Music -it jsavargas/zspotify -v
ZSpotify 2.0.3

When I run the container (or also pass the -f flag for 'force premium') I always receive

docker run -v ${HOME}/.zspotify:/root/.zspotify -v ${HOME}/Music:/root/Music -it jsavargas/zspotify
Traceback (most recent call last):
  File "/usr/local/bin/zspotify", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/zspotify/__main__.py", line 934, in main
    zs.start()
  File "/usr/local/lib/python3.9/site-packages/zspotify/__main__.py", line 859, in start
    while not self.login():
  File "/usr/local/lib/python3.9/site-packages/zspotify/__main__.py", line 317, in login
    return self.zs_api.login(username, password)
  File "/usr/local/lib/python3.9/site-packages/zspotify/zspotify_api.py", line 78, in login
    Session.Builder().user_pass(
  File "/usr/local/lib/python3.9/site-packages/librespot/core.py", line 1287, in create
    session.authenticate(self.login_credentials)
  File "/usr/local/lib/python3.9/site-packages/librespot/core.py", line 709, in authenticate
    self.__authenticate_partial(credential, False)
  File "/usr/local/lib/python3.9/site-packages/librespot/core.py", line 1067, in __authenticate_partial
    raise Session.SpotifyAuthenticationException(ap_login_failed)
librespot.core.Session.SpotifyAuthenticationException: PremiumAccountRequired

Using https://api.spotify.com/v1/me to interrogate my account I indeed have a premium:

{
  "country": "US",
  "display_name": "redacted",
  "email": "redacted",
  "explicit_content": {
    "filter_enabled": false,
    "filter_locked": false
  },
  "external_urls": {
    "spotify": "https://open.spotify.com/user/redacted"
  },
  "followers": {
    "href": null,
    "total": 1
  },
  "href": "https://api.spotify.com/v1/users/redacted",
  "id": "redacted",
  "images": [],
  "product": "premium",
  "type": "user",
  "uri": "spotify:user:redacted"
}

Thank you

Can't log in.

I didn't want to use my main acccount, so I created a new one. I can log in with my main account just fine, but my alt doesn't work for some reason. I can log into the website just fine with the same credentials. What could be the problem here?

Limit to Number of Albums to Download?

Hi! I'd like to download an entire artist's discography but am running into an issue where it stops around 20 albums in. Running via the Docker image using a link to artist:
https://open.spotify.com/artist/2aaLAng2L2aWD2FClzwiep?si=OjA40YyrSZKNIQArZhmO6Q
image
For some reason, it just stops at 2013 (right as I was getting to their good stuff!). I've tried re-running with it stopping at the same location. Is there some configuration issue? They have a few dozen more albums, is there a way to get the rest?

File name too long

Songs with long names crash and halt the program.

Error message:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.11/bin/zspotify", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/zspotify/__main__.py", line 933, in main
    zs.start()
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/zspotify/__main__.py", line 916, in start
    self.download_by_url(url)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/zspotify/__main__.py", line 684, in download_by_url
    ret = self.download_playlist(parsed_url['playlist'])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/zspotify/__main__.py", line 561, in download_playlist
    self.download_track(song['id'], basepath, "playlist")
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/zspotify/__main__.py", line 507, in download_track
    if self.not_skip_existing and fullpath.exists():
                                  ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/pathlib.py", line 1235, in exists
    self.stat()
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/pathlib.py", line 1013, in stat
    return os.stat(self, follow_symlinks=follow_symlinks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 63] File name too long

Error while parsing metadata for podcast

I've used this software to successfully download a few tracks and, upon attempting to download a podcast, found an error.

The podcasts in question are the episodes of "Hideo Kojima presents Brain Structure".
I made a playlist and added a few of the episodes to it.
After that I tried to download the tracks through the command line interface of zspotify.

The results follow below:

###   get_song_info - FAILED TO QUERY METADATA   ###
'NoneType' object is not subscriptable
6OFp3XvZVHtdKl94ybdUW7 {'tracks': [None]}
###   SKIPPING SONG - FAILED TO QUERY METADATA   ###
 download_track FAILED: [6OFp3XvZVHtdKl94ybdUW7][Hideo Kojima/][False][][False]
SKIPPING SONG:  cannot unpack non-iterable NoneType object
[!] ERROR local variable 'artists' referenced before assignment

Perhaps the format of the metadata is different for podcasts compared with regular tracks?

I hope this issue report is useful to increase the functionality of the software.

Best regards.

When using -ls flag it raises an error

in zspotify/zspotify_api.py on line 454, it raises an error of key not found, the response from the api is: {'error': {'status': 403, 'message': 'Forbidden.'}}

From the documentation this error is:
Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won't help here.

specify search type, page search results

Would be fantastic if one could specify search type (artist/album/track/etc) and also more search results, page by page? At least in interactive search mode.

Javascript variant of zspotify

Hi, i think that everything is said in the title, would it be possible to create a zspotify js variant / node.js variant ?

Thanks and have a nice day. πŸ‘

SKIP_EXISTING_FILES / SKIP_PREVIOUSLY_DOWNLOADED not working

As the title says - even if the files already exist, they still download and overwrite.

This is what I'm downloading: https://open.spotify.com/show/30IEdePodyRarA7JsbGFaz

It seems .song_archive doesn't exist/isn't created, which might explain why SKIP_PREVIOUSLY_DOWNLOADED doesn't work. I tried manually adding .song_archive in my ROOT_PATH but that didn't seem to do anything. I also added some print()s and it seems get_previously_downloaded() and add_to_archive is never called.

Songs end a few seconds early

It happens when I download any song. The issue I found was that it appears to ignore the last chunk, so I reduced the chunk size from 50000 to 50 to minimize the drop to the point where it didn't impede on the songs. I did this by adding the argument --chunk-size 50 to the command. This can also be accomplished permanently by editing the zs_config.json file.

Sanitization: only sanitize filenames, not song metadata, otherwise metadata gets spoiled (currently missing apostrophes, colons, etc)

Title says it all. Sanitization of filenames is of course sensible and necessary, however sanitisation of song metadata (the metadata baked into the MP3 file like track name, artist, album artist, date, album name etc) is unnecessary and means users have to manually check/correct the metadata for every song that is downloaded, to reinsert missing characters.

All software that handles MP3s is fine with special characters in the metadata. My entire library is full of apostrophes, colons, etc in track names, and I've never had a single issue handling these MP3s on any piece of software.

What would make sense would be to separate the filename sanitisation from the rest of the data handling, so that MP3 metadata can be preserved in pure form.

API rate limit exceed when skipping too many files.

Hi,

Using zspotify in docker container v1.9.4.
I face an issue with Spotify API rate limit exceed caused by too many get_song_info calls sent in a short time.
Happens about after 130 consecutive skipped tracks.

###   get_song_info - FAILED TO QUERY METADATA   ###
'tracks'
xyz {'error': {'status': 429, 'message': 'API rate limit exceeded'}}
###   SKIPPING SONG - FAILED TO QUERY METADATA   ###
 download_track FAILED: [xyz][xyz/][False][][False]
SKIPPING SONG:  cannot unpack non-iterable NoneType object
[!] ERROR local variable 'artists' referenced before assignment 

Absence of feature to set a delay, or hardcoded delay, between two requests blocks the restart of sync for large playlist.

Taking the opportunity to thank you for this great tool.

stops download of playlist after every song

user\anaconda3\lib\site-packages\pydub\utils.py:198: RuntimeWarning: Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work
warn("Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work", RuntimeWarning)

SKIPPING: Arch Enemy - Doomsday Machine - Nemesis.mp3 (GENERAL DOWNLOAD ERROR) ### [WinError 2] The system cannot find the file specified

[!] ERROR [WinError 32] The process cannot access the file because it is being used by another process: 'C:\Users\Ramses/Music/ZSpotify Music/General/Arch Enemy - Doomsday Machine - Nemesis.mp3'

pls help

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.