Code Monkey home page Code Monkey logo

zotify's Introduction

Zotify

A highly customizable music and podcast downloader.

Zotify logo

Features

  • Downloads at up to 320kbps*
  • Downloads directly from the source**
  • Downloads podcasts, playlists, liked songs, albums, artists, singles.
  • Downloads synced lyrics from the source
  • Option to download in real time to appear more legitimate***
  • Supports multiple audio formats
  • Download directly from URL or use built-in in search
  • Bulk downloads from a list of URLs in a text file or parsed directly as arguments

*Free accounts are limited to 160kbps.
**Audio files are NOT substituted with ones from other sources such as YouTube or Deezer, they are sourced directly.
***'real time' refers to downloading at the speed it would normally be streamed at (the duration of the track).

Install

Dependencies:

- Python 3.9 or greater
- FFmpeg

Installation:

python -m pip install git+https://zotify.xyz/zotify/zotify.git

See INSTALLATION for a more detailed and opinionated installation walkthrough.

Command line usage

Basic command line usage:
  zotify <track/album/playlist/episode/artist url>   Downloads the track, album, playlist or podcast episode specified as a command line argument. If an artist url is given, all albums by specified artist will be downloaded. Can take multiple urls.

Basic options:
  (nothing)        Download the tracks/albums/playlists URLs from the parameter
  -d, --download   Download all tracks/albums/playlists URLs from the specified file
  -p, --playlist   Downloads a saved playlist from your account
  -l, --liked      Downloads all the liked songs from your account
  -f, --followed   Downloads all songs by all artists you follow
  -s, --search     Searches for specified track, album, artist or playlist, loads search prompt if none are given.  
  -h, --help       See this message.

Options

All these options can either be configured in the config or via the commandline, in case of both the commandline-option has higher priority.
Be aware you have to set boolean values in the commandline like this: --download-real-time=True

Key (config) Commandline parameter Defaults Description
CREDENTIALS_LOCATION --credentials-location The location of the credentials.json
OUTPUT --output The output location/format (see below)
SONG_ARCHIVE --song-archive The song_archive file for SKIP_PREVIOUSLY_DOWNLOADED
ROOT_PATH --root-path Directory where Zotify saves music
ROOT_PODCAST_PATH --root-podcast-path Directory where Zotify saves podcasts
SPLIT_ALBUM_DISCS --split-album-discs False Saves each disk in its own folder
DOWNLOAD_LYRICS --download-lyrics True Downloads synced lyrics in .lrc format, uses unsynced as fallback.
MD_ALLGENRES --md-allgenres False Save all relevant genres in metadata
MD_GENREDELIMITER --md-genredelimiter , Delimiter character used to split genres in metadata
DOWNLOAD_FORMAT --download-format ogg The download audio format (aac, fdk_aac, m4a, mp3, ogg, opus, vorbis)
DOWNLOAD_QUALITY --download-quality auto Audio quality of downloaded songs (normal, high, very_high*)
TRANSCODE_BITRATE --transcode-bitrate auto Overwrite the bitrate for ffmpeg encoding
SKIP_EXISTING_FILES --skip-existing True Skip songs with the same name
SKIP_PREVIOUSLY_DOWNLOADED --skip-previously-downloaded False Use a song_archive file to skip previously downloaded songs
RETRY_ATTEMPTS --retry-attempts 1 Number of times Zotify will retry a failed request
BULK_WAIT_TIME --bulk-wait-time 1 The wait time between bulk downloads
OVERRIDE_AUTO_WAIT --override-auto-wait False Totally disable wait time between songs with the risk of instability
CHUNK_SIZE --chunk-size 20000 Chunk size for downloading
DOWNLOAD_REAL_TIME --download-real-time False Downloads songs as fast as they would be played, should prevent account bans.
LANGUAGE --language en Language for spotify metadata
PRINT_SPLASH --print-splash False Show the Zotify logo at startup
PRINT_SKIPS --print-skips True Show messages if a song is being skipped
PRINT_DOWNLOAD_PROGRESS --print-download-progress True Show download/playlist progress bars
PRINT_ERRORS --print-errors True Show errors
PRINT_DOWNLOADS --print-downloads False Print messages when a song is finished downloading
TEMP_DOWNLOAD_DIR --temp-download-dir Download tracks to a temporary directory first

*very-high is limited to premium only

Configuration

You can find the configuration file in following locations:

OS Location
Windows C:\Users\<USERNAME>\AppData\Roaming\Zotify\config.json
MacOS /Users/<USERNAME>/Library/ApplicationSupport/Zotify/config.json
Linux /home/<USERNAME>/.config/zotify/config.json

To log out, just remove the configuration file. Uninstalling Zotify does not remove the config file.

Output format

With the option OUTPUT (or the commandline parameter --output) you can specify the output location and format.
The value is relative to the ROOT_PATH/ROOT_PODCAST_PATH directory and can contain the following placeholder:

Placeholder Description
{artist} The song artist
{album} The song album
{song_name} The song name
{release_year} The song release year
{disc_number} The disc number
{track_number} The track_number
{id} The song id
{track_id} The track id
{ext} The file extension
{album_id} (only when downloading albums) ID of the album
{album_num} (only when downloading albums) Incrementing track number
{playlist} (only when downloading playlists) Name of the playlist
{playlist_num} (only when downloading playlists) Incrementing track number

Example values could be:

{playlist}/{artist} - {song_name}.{ext}
{playlist}/{playlist_num} - {artist} - {song_name}.{ext}
{artist} - {song_name}.{ext}
{artist}/{album}/{album_num} - {artist} - {song_name}.{ext}

Docker Usage

Build the docker image from the Dockerfile:
  docker build -t zotify .
Create and run a container from the image:
  docker run --rm -v "$PWD/Zotify Music:/root/Music/Zotify Music" -v "$PWD/Zotify Podcasts:/root/Music/Zotify Podcasts" -it zotify

What do I do if I see "Your session has been terminated"?

If you see this, don't worry! Just try logging back in. If you see the incorrect username or password error, reset your password and you should be able to log back in.

Will my account get banned if I use this tool?

Currently no user has reported their account getting banned after using Zotify.

It is recommended you use Zotify with a burner account. Alternatively, there is a configuration option labeled DOWNLOAD_REAL_TIME, this limits the download speed to the duration of the song being downloaded thus appearing less suspicious. This option is much slower and is only recommended for premium users who wish to download songs in 320kbps without buying premium on a burner account.

Disclaimer

Zotify is intended to be used in compliance with DMCA, Section 1201, for educational, private and fair use.
Zotify contributors are not responsible for any misuse of the program or source code.

Contributing

Please refer to CONTRIBUTING

Changelog

Please refer to CHANGELOG

zotify's People

Contributors

datnohand avatar logykk avatar simseslab avatar user20342 avatar zotify-dev 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

zotify's Issues

incomplete escape \U at position 3

having this issue when downloading from this link: https://open.spotify.com/album/7D2DrBRs922elDgsyNrqjA?si=GZAHGHmhTwOe6j2bozmutQ

incomplete escape \U at position 3

Traceback (most recent call last):
  File "C:\Python311\Lib\site-packages\zotify\track.py", line 190, in download_track
    c = len([file for file in Path(filedir).iterdir() if re.search(f'^{filename}_', str(file))]) + 1
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\site-packages\zotify\track.py", line 190, in <listcomp>
    c = len([file for file in Path(filedir).iterdir() if re.search(f'^{filename}_', str(file))]) + 1
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\__init__.py", line 176, in search
    return _compile(pattern, flags).search(string)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\__init__.py", line 294, in _compile
    p = _compiler.compile(pattern, flags)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\_compiler.py", line 743, in compile
    p = _parser.parse(p, flags)
        ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\_parser.py", line 980, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\_parser.py", line 455, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\_parser.py", line 539, in _parse
    code = _escape(source, this, state)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\re\_parser.py", line 393, in _escape
    raise source.error("incomplete escape %s" % escape, len(escape))
re.error: incomplete escape \U at position 3

Error while downloading

HTTPSConnectionPool(host='audio-gm-fb.spotifycdn.com', port=443): Max retries exceeded with url: /audio/5d9238e56e52d82388d8c69a4368ea1fcc9b3ea0?Expires=1700354581FullPathhmac=iuWP8dynSfSurm31le1a2zDxsTixGof1h40oBjWxUBI= (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio-gm-fb.spotifycdn.com'. (_ssl.c:1006)")))

Traceback (most recent call last):
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connectionpool.py", line 468, in _make_request
self._validate_conn(conn)
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connectionpool.py", line 1097, in _validate_conn
conn.connect()
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connection.py", line 642, in connect
sock_and_verified = _ssl_wrap_socket_and_match_hostname(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connection.py", line 783, in ssl_wrap_socket_and_match_hostname
ssl_sock = ssl_wrap_socket(
^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/util/ssl
.py", line 471, in ssl_wrap_socket
ssl_sock = ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/util/ssl
.py", line 515, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/ssl.py", line 517, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/ssl.py", line 1108, in _create
self.do_handshake()
File "/data/data/com.termux/files/usr/lib/python3.11/ssl.py", line 1379, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio-gm-fb.spotifycdn.com'. (_ssl.c:1006)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connectionpool.py", line 791, in urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connectionpool.py", line 492, in _make_request
raise new_e
urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio-gm-fb.spotifycdn.com'. (_ssl.c:1006)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/requests/adapters.py", line 486, in send
resp = conn.urlopen(
^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/connectionpool.py", line 845, in urlopen
retries = retries.increment(
^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/urllib3/util/retry.py", line 515, in increment
raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='audio-gm-fb.spotifycdn.com', port=443): Max retries exceeded with url: /audio/5d9238e56e52d82388d8c69a4368ea1fcc9b3ea0?Expires=1700354581FullPathhmac=iuWP8dynSfSurm31le1a2zDxsTixGof1h40oBjWxUBI= (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio-gm-fb.spotifycdn.com'. (_ssl.c:1006)")))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/zotify/track.py", line 224, in download_track
stream = Zotify.get_content_stream(track, Zotify.DOWNLOAD_QUALITY)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/zotify/zotify.py", line 53, in get_content_stream
return cls.SESSION.content_feeder().load(content_id, VorbisOnlyAudioQuality(quality), False, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 739, in load
return self.load_track(playable_id, audio_quality_picker, preload,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 800, in load_track
return self.load_stream(file, track, None, preload, halt_listener)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 754, in load_stream
return CdnFeedHelper.load_track(self.__session, track, file,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 342, in load_track
streamer = session.cdn().stream_file(file, key, url, halt_listener)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 441, in stream_file
return CdnManager.Streamer(
^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 578, in init
response = self.request(range_start=0,
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/librespot/audio/init.py", line 632, in request
response = self.__session.client().get(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/requests/sessions.py", line 602, in get
return self.request("GET", url, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/requests/sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/requests/sessions.py", line 703, in send
r = adapter.send(request, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/requests/adapters.py", line 517, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='audio-gm-fb.spotifycdn.com', port=443): Max retries exceeded with url: /audio/5d9238e56e52d82388d8c69a4368ea1fcc9b3ea0?Expires=1700354581FullPathhmac=iuWP8dynSfSurm31le1a2zDxsTixGof1h40oBjWxUBI= (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio-gm-fb.spotifycdn.com'. (_ssl.c:1006)")))

Why am I getting this error

Error Message when Running Zotify

I keep on getting these long strings of code when running Zotify. This is what I typed into Powershell:

zotify -l --download-lyrics=True --download-quality=high --md-allgenres=True --skip-existing=true

Then, it showed the following as the download was going on.

`incomplete escape \U at position 3

Traceback (most recent call last):
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\site-packages\zotify\track.py", line 190, in download_track
c = len([file for file in Path(filedir).iterdir() if re.search(f'^{filename}', str(file))]) + 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\site-packages\zotify\track.py", line 190, in
c = len([file for file in Path(filedir).iterdir() if re.search(f'^{filename}
', str(file))]) + 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_init_.py", line 176, in search
return compile(pattern, flags).search(string)
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_init
.py", line 294, in _compile
p = _compiler.compile(pattern, flags)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_compiler.py", line 743, in compile
p = _parser.parse(p, flags)
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_parser.py", line 980, in parse
p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_parser.py", line 455, in _parse_sub
itemsappend(_parse(source, state, verbose, nested + 1,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_parser.py", line 539, in _parse
code = _escape(source, this, state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Tong\AppData\Local\Programs\Python\Python311\Lib\re_parser.py", line 393, in _escape
raise source.error("incomplete escape %s" % escape, len(escape))
re.error: incomplete escape \U at position 3`

Incomplete lyrics

I get skipping lyrics error for 90% of songs even when lyrics are available. It will still download lyrics but they will always be incomplete. Error still occurs when I use "--download-lyrics=true"

Skipping lyrics for Enter Shikari - A Kiss for the Whole World x: lyrics not available

Skipping lyrics for Enter Shikari - (pls) set me on fire: lyrics not available

Skipping lyrics for Enter Shikari - It Hurts: lyrics not available

Skipping lyrics for Enter Shikari - Leap into the Lightning: lyrics not available

Skipping lyrics for Enter Shikari - feed yøur søul: lyrics not available

Skipping lyrics for Enter Shikari - Dead Wood: lyrics not available

Skipping lyrics for Enter Shikari - Jailbreak: lyrics not available

Skipping lyrics for Enter Shikari - Bloodshot: lyrics not available

Skipping lyrics for Enter Shikari - giant pacific octopus swirling off into infinity…: lyrics not available

100%|██████████████████████████████████████████████████████████████████████████████████████████| 12.0/12.0 [00:30<00:00, 2.51s/Song]

Change config path

can it be allowed to change the config path via command line for a custom config location? something like --config-path or something of that sort will be really helpful. Thank you so much.

BadCredentials

I keep getting this error no matter what:

 File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\librespot\core.py", line 1317, in create
    session.authenticate(self.login_credentials)
  File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\librespot\core.py", line 711, in authenticate
    self.__authenticate_partial(credential, False)
  File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\librespot\core.py", line 1077, in __authenticate_partial
    raise Session.SpotifyAuthenticationException(ap_login_failed)
librespot.core.Session.SpotifyAuthenticationException: BadCredentials

I have uninstalled and reinstalled multiple times. Zotify used to work perfectly, then I switched to a different user account, and then switched to the old one again but since then this error has always occurred.

[Bug] Handling duplicate files

I'm getting the following error when I attempt to re-download an existing song with the --skip-existing=False and --skip-previously-downloaded=False.

EDIT: I realize now that it works when I don't delete the .song_ids file. Not sure if it's supposed to work without it so I'm leaving the issue open for now.

P.S. The readme needs to be updated from --skip-existing-files to --skip-existing

Output
zotify --skip-existing=False --skip-previously-downloaded=False https://open.spotify.com/track/0Ic42kynfrSAJjTlOr0dWR?si=12b93981e9c8416d

C:\Users\piano\Music\zotify
Tinashe - Needs: 100%|████████████████████████████████████████████████████████████████████████████████████████████▉| 2.69M/2.69M [00:00<00:00, 3.60MB/s]

C:\Users\piano\Music\zotify\music
zotify --skip-existing=False --skip-previously-downloaded=False https://open.spotify.com/track/0Ic42kynfrSAJjTlOr0dWR?si=12b93981e9c8416d

###   SKIPPING SONG - FAILED TO QUERY METADATA   ###
Track_ID: 0Ic42kynfrSAJjTlOr0dWR

bad escape \T at position 6

Traceback (most recent call last):
  File "C:\Python\Python311\Lib\site-packages\zotify\track.py", line 190, in download_track
    c = len([file for file in Path(filedir).iterdir() if re.search(f'^{filename}_', str(file))]) + 1
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\site-packages\zotify\track.py", line 190, in <listcomp>
    c = len([file for file in Path(filedir).iterdir() if re.search(f'^{filename}_', str(file))]) + 1
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\__init__.py", line 176, in search
    return _compile(pattern, flags).search(string)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\__init__.py", line 294, in _compile
    p = _compiler.compile(pattern, flags)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\_compiler.py", line 743, in compile
    p = _parser.parse(p, flags)
        ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\_parser.py", line 980, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\_parser.py", line 455, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\_parser.py", line 539, in _parse
    code = _escape(source, this, state)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\re\_parser.py", line 438, in _escape
    raise source.error("bad escape %s" % escape, len(escape))
re.error: bad escape \T at position 6

SpotifyAuthenticationException: PremiumAccountRequired Problem

I've been using zotify in the past, but then changed my Spotify password and can't seem to login again.
there's no config.json file, and whenever I try to setup username, password or credentials location, a long error ending with the line SpotifyAuthenticationException: PremiumAccountRequired appears.

needless to say, I have a Spotify premium account. also tried to set up a json file on my own.

what am I doing wrong?

--skip-previously-downloaded should read .song_ids as well as .song_archive

Title.

.song_archive is apparently only written if --skip-previously-downloaded is set, but that doesn't make much sense to set on your first download. If you then later set that flag it looks for the archive, which isn't there, and wants to re-download everything.

.song_ids are also a source of downloaded info, so Zotify should use that as well.

I personally just populated the .song_archive file per below, but IMO this shouldn't be necessary

for f in **/.song_ids; do cat "$f" >> ~/Library/Application\ Support/Zotify/.song_archive; done

[bug] Bulk download delay not working

I get rate-limited when downloading a big playlist. The sleep after downloading a song doesn't work.
I believe there is a small bug in track.py (line 283).

if not Zotify.CONFIG.get_bulk_wait_time():
    time.sleep(Zotify.CONFIG.get_bulk_wait_time())

That condition is only true if BULK_WAIT_TIME is equal to 0. Removing the negation from it fixes it.

if Zotify.CONFIG.get_bulk_wait_time():
    time.sleep(Zotify.CONFIG.get_bulk_wait_time())

[Question] How to log out of Zotify?

I logged in with my main account, but after thoroughly reading the README file, I wanted to log out of Zotify immediately. However, there is no documentation on how to log out of Zotify. So, how do I log out?

Some songs are saved as ._1.ogg

It happens multiple times while downloading a larger list, it seems the ._1.ogg file gets overwritten and there are multiple entries in .song_ids all with the ._1.ogg name. If I delete ._1.ogg and clean up .song_ids to remove these entries and download again it seems to work so it feels like some sort of an edge bug.

#52 might be related.

This might also be because the Liked Songs playlist has duplicates with the same artist/track name but different track URIs, e.g. same song is liked from both the album and a single release.

I don't want any metadata.

Love this tool, genuinely.

But, there is no option to just - not - download the metadata. I don't want any cover art. I don't want the album its in. I don't care about that, and it adds unnecessary data into the files.

Such a simple thing, really, but I'm forced to remove all the metadata using another tool, and that takes a lot of extra time.

If this could be implemented, I'd use this tool a lot more. Usually I find myself converting all my playlists over to YouTube and downloading it with yt-dlp.

i signed up my spotify using google

i signed up my spotify using google and this way i dont have a password
so i created a password

but when i am putting my username and password
it returns this error

Traceback (most recent call last): File "<frozen runpy>", line 198, in _run_module_as_main File "<frozen runpy>", line 88, in _run_code File "C:\Users\moham\AppData\Roaming\Python\Python311\Scripts\zotify.exe\__main__.py", line 7, in <module> File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\zotify\__main__.py", line 64, in main args.func(args) File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\zotify\app.py", line 21, in client Zotify(args) File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\zotify\zotify.py", line 21, in __init__ Zotify.login(args) File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\zotify\zotify.py", line 46, in login cls.SESSION = Session.Builder(conf).user_pass(user_name, password).create() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\librespot\core.py", line 1634, in create session.authenticate(self.login_credentials) File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\librespot\core.py", line 939, in authenticate self.__authenticate_partial(credential, False) File "C:\Users\moham\AppData\Roaming\Python\Python311\site-packages\librespot\core.py", line 1350, in __authenticate_partial raise Session.SpotifyAuthenticationException(ap_login_failed) librespot.core.Session.SpotifyAuthenticationException: TravelRestriction

Track #'s should be forced as 2-digit values

Depending on the system used to list directory contents, having track 1 as "1" in the filename instead of "01" could cause some systems to output the directory listing with an incorrect track order. Having track 1 start with 1 might then result in the next track in the directory listing be track 10. By forcing the track numbers to always be 2 digits, then every system should display the tracks in the correct order when retrieving the directory listing as "01" "02" etc.

Hope that makes sense. I'm not aware of any albums that are 10-discs +, but maybe having disc numbers be 2 digit as well might be prudent.

--skip-existing does not work with Podcasts

zotify --root-podcast-path $downloadPath --skip-existing=True $url

Already downloaded episodes will be downloaded again.

also an option to just download the most recent episode would be awsome. Nice project overall 👍

unable to write metadata

so this is working in Termux Android
its working fine.
but downloaded songs does not include thumbnail,
i do have ffmpeg installed
Screenshot_20231014-104947_Trebuchet
Screenshot_20231014-105555_Trebuchet
Screenshot_20231014-105748_Trebuchet

Cant download Zotify

PS C:\Users\NoYou> pipx install https://get.zotify.xyz
ERROR: Could not install packages due to an OSError: HTTPSConnectionPool(host='zotify.xyz', port=443): Max retries exceeded with url: /zotify/zotify/archive/main.zip (Caused by ResponseError('too many 500 error responses'))

Cannot determine package name from spec 'https://get.zotify.xyz'. Check package spec for errors.

zpotify.command not showing up

i am unable to find the zpotify.command file and the app launcher is no where to be find in neither my applications or the zpotify folder. Also zpotify folder is not showing up via application support but although it is in my library. i have encountered several errors during the installations.

Changing configuration, not working

Im a newbie to this so forgive me:

I tried to change the config file in Python to set the audio format to 'm4a' and the download lyrics to 'False' but they are still downloading in OGG with lyric files. I also tried to type 'zotify --download-lyrics=False' and 'zotify --download-format=m4a' into terminal but it just gives me a search prompt.

How to fix this?

How do i use this ?

Like where do i put the URL for the playlist i want to download and how do i set up those config options

When downloading a playlist, progress of each song download is not shown

I have "PRINT_DOWNLOAD_PROGRESS": "True" and "PRINT_PROGRESS_INFO": "True" enabled but when downloading a saved playlist there is no progress shown as each song is downloaded. If I just point to a single file download via a URL I get a progress bar.

The progress bar only shows up for the very last song in the playlist.

On the --liked playlist it seems to behave as expected, only --playlist seems to be broken, not sure whether it has anything to do with the interactive mode.

This is on macOS, iTerm2 if it makes a difference.

Misses a lot of tracks

First, I love this, thank you for creating it.

I need to run zotify 3-4+ times to get it to download everything, especially with longer download lists (1,000+ tracks). The problem is that when it fails because of an API error or what not, it just continues along, but there's no good way to know if it snagged somewhere or not other than scrolling through all the output and looking for errors.

2 suggestions:

  • Add a timeout after error option. I think it's often erroring because of a rate limit. Telling it to pause for 60 seconds whenever it snags might help
  • Add a summary, e.g.:
Downloaded Tracks: 856
Skipped Tracks (Song Already Exists): 80
Failed Tracks: 64

SKIPPING SONG - FAILED TO QUERY METADATA

Hi!

I tried downloading a song with zotify and got this error (see below) and I'm not really sure what to do with it.

SKIPPING SONG - FAILED TO QUERY METADATA

Track_ID: 3yfqSUWxFvZELEM4PmlwIR

replace() argument 2 must be str, not None

Traceback (most recent call last):
File "C:\Users\alexa\scoop\apps\python\current\Lib\site-packages\zotify\track.py", line 175, in download_track
output_template = output_template.replace("{ext}", ext)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: replace() argument 2 must be str, not None

in the config I changed the output to: "OUTPUT": "{artist} - {song_name}.{ext}", this was shown as an example, but since I changed this I am not able to download any songs no more.

I'm new to github, so I'm not really sure how to fix this

[Feature Request] Config entry for additional FFMPEG arguments

This could be helpful for those who want to more finely tune their audio libraries, and could help slightly more advanced users get access to features they don't know how to implement themselves.

Converting to mono (#41) or removing metadata entirely (#40 somewhat relevant, though removing metadata after doesn't save on bandwidth) could both be via FFMPEG arguments, and sometimes you want to change options on the encoder (e.g. opus compression).

Podcast Downloading Does Not Respect OUTPUT and DOWNLOAD_FORMAT in config.json

Description

Summary:
When downloading podcasts, the OUTPUT and DOWNLOAD_FORMAT settings in config.json are not respected. However, these settings work as expected for music downloads. Is this feature not yet developed for podcast downloads, or am I missing something in the configuration?

Steps to Reproduce:
Set OUTPUT to {id}.{ext} and DOWNLOAD_FORMAT to mp3 in config.json.
Download a podcast episode.
Observe the downloaded file's name and format.

Expected Behavior:
The podcast file should be named according to the id and should be in mp3 format as specified in config.json.

Actual Behavior:
The podcast file is named according to the podcast and episode name and is in ogg format.

"Failed fetching audio key" error

Recently when I try and download an album or song I get this GENERAL DOWNLOAD ERROR that seems related to a failure to fetch audio keys:

###   SKIPPING: Ravi Shankar - Offering (GENERAL DOWNLOAD ERROR)   ###
Track_ID: 1SrrZO8GYMR44gNiopTxbS
album_num: 01
artist: Philip Glass
album: Passages
album_id: 2PD9WIFJ91puhlzPPkcU6I


Failed fetching audio key! gid: 3db5715f0301495db6c0b43c5856f83c, fileId: d63771a1d7db80f8ca12bd4856ca2621887e9c8a

Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.11/site-packages/zotify/track.py", line 224, in download_track
    stream = Zotify.get_content_stream(track, Zotify.DOWNLOAD_QUALITY)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/zotify/zotify.py", line 53, in get_content_stream
    return cls.SESSION.content_feeder().load(content_id, VorbisOnlyAudioQuality(quality), False, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/librespot/audio/__init__.py", line 739, in load
    return self.load_track(playable_id, audio_quality_picker, preload,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/librespot/audio/__init__.py", line 800, in load_track
    return self.load_stream(file, track, None, preload, halt_listener)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/librespot/audio/__init__.py", line 754, in load_stream
    return CdnFeedHelper.load_track(self.__session, track, file,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/librespot/audio/__init__.py", line 339, in load_track
    key = session.audio_key().get_audio_key(track.gid, file.file_id)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/librespot/audio/__init__.py", line 277, in get_audio_key
    return self.get_audio_key(gid, file_id, False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/librespot/audio/__init__.py", line 278, in get_audio_key
    raise RuntimeError(
RuntimeError: Failed fetching audio key! gid: 3db5715f0301495db6c0b43c5856f83c, fileId: d63771a1d7db80f8ca12bd4856ca2621887e9c8a

Generate m3u playlist files and reuse existing downloads across playlists

It is nice that zotify can detect tracks that have already been downloaded, but it would be nice to generate m3u playlists that point to common files.

Or on platforms that support it (Linux, macOS, maybe even Windows) use symlinks to point to the existing downloads. Many playlists have overlaps, in particular with the Liked Songs, so it would be nice to preserve the playlist structure in some form.

Or have a command line flag to just fetch a playlist metadata and save it as an m3u file. Then one could download all playlists in a single folder and just reconstruct the playlists with m3u files.

Fwiw, EXTM3U or PLS might be better formats than M3U, though not sure how well supported by players they are. Of course, zotify could output all/either of them, user's choice.

Audiobook download fails due to `\'/episode/podcast/name\' was declared as a non null type` error

When trying to download an audiobook the correct episode data is parsed but when the episode download is attempted the JSON response is:

('{"errors":[{"message":"The field at path \'/episode/podcast/name\' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is \'String\' within parent type \'Podcast\'","path":["episode","podcast","name"],"extensions":{"classification":"NullValueInNonNullableField"}},{"message":"The field at path \'/episode/podcast/showTypes\' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is \'[ShowType!]\' within parent type \'Podcast\'","path":["episode","podcast","showTypes"],"extensions":{"classification":"NullValueInNonNullableField"}}],"data":{"episode":null},"extensions":{}}', {'errors': [{'message': "The field at path '/episode/podcast/name' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is 'String' within parent type 'Podcast'", 'path': ['episode', 'podcast', 'name'], 'extensions': {'classification': 'NullValueInNonNullableField'}}, {'message': "The field at path '/episode/podcast/showTypes' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is '[ShowType!]' within parent type 'Podcast'", 'path': ['episode', 'podcast', 'showTypes'], 'extensions': {'classification': 'NullValueInNonNullableField'}}], 'data': {'episode': None}, 'extensions': {}})

Has anyone seen this before and know how to resolve?

KeyError: 'items'

I run into Errors when trying to download a playlist and they look as following:

Downloading Playlist
Traceback (most recent call last):
File "", line 198, in run_module_as_main
File "", line 88, in run_code
File "c:\users\U.local\bin\zotify.exe_main
.py", line 7, in
File "C:\Users\U.local\pipx\venvs\zotify\Lib\site-packages\zotify_main
.py", line 64, in main
args.func(args)
File "C:\Users\U.local\pipx\venvs\zotify\Lib\site-packages\zotify\app.py", line 52, in client
download_from_user_playlist()
File "C:\Users\U.local\pipx\venvs\zotify\Lib\site-packages\zotify\playlist.py", line 81, in download_from_user_playlist
download_playlist(playlist)
File "C:\Users\U.local\pipx\venvs\zotify\Lib\site-packages\zotify\playlist.py", line 52, in download_playlist
playlist_songs = [song for song in get_playlist_songs(playlist[ID]) if song[TRACK][ID]]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\U.local\pipx\venvs\zotify\Lib\site-packages\zotify\playlist.py", line 36, in get_playlist_songs
songs.extend(resp[ITEMS])
~~~~^^^^^^^
KeyError: 'items'

my config looks as following:
{ "SAVE_CREDENTIALS": "True", "CREDENTIALS_LOCATION": "", "OUTPUT": "", "SONG_ARCHIVE": "True", "ROOT_PATH": "", "ROOT_PODCAST_PATH": "", "SPLIT_ALBUM_DISCS": "False", "DOWNLOAD_LYRICS": "False", "MD_SAVE_GENRES": "True", "MD_ALLGENRES": "True", "MD_GENREDELIMITER": " ; ", "DOWNLOAD_FORMAT": "mp3", "DOWNLOAD_QUALITY": "very_high", "TRANSCODE_BITRATE": "320kbps", "SKIP_EXISTING": "True", "SKIP_PREVIOUSLY_DOWNLOADED": "True", "RETRY_ATTEMPTS": "3", "BULK_WAIT_TIME": "1", "OVERRIDE_AUTO_WAIT": "False", "CHUNK_SIZE": "20000", "DOWNLOAD_REAL_TIME": "False", "LANGUAGE": "en", "PRINT_SPLASH": "False", "PRINT_SKIPS": "True", "PRINT_DOWNLOAD_PROGRESS": "True", "PRINT_ERRORS": "True", "PRINT_DOWNLOADS": "True", "PRINT_API_ERRORS": "True", "PRINT_PROGRESS_INFO": "True", "PRINT_WARNINGS": "True", "TEMP_DOWNLOAD_DIR": "" }

Hope someone can help me, kind regards,
Towny

Downloaded Podcasts don't get any Metadata

When you download a Podcast episode, it doesn't get any Metadata applied to it.

It would be pretty nice to to get the Podcast name as an Album Name & the creators names as Artist tags.

Handle Windows Directory Paths with Backslashes

Description

Windows default directory paths use backslashes instead of forward slashes ("/"). While entering directory paths in the config file, I encountered an error due to the interpretation of backslashes as escape sequences in Python.

Steps to Reproduce:

  1. Enter a Windows directory path with backslashes in the config file.
  2. Run the program

Expected Behavior:

The program should correctly interpret and handle Windows directory paths specified in the config file without triggering escape sequence errors.

Why this matter

When you right-click on a folder in Windows while holding down SHIFT, there is an option to copy the folder path, and it retrieves the path with backslashes.

SSL Certificate issue.

getting the following when downloading music. Appears randomly. Some songs download , some don't. If I retry it enough times it eventually works? Just extremely annoying. Issue:

HTTPSConnectionPool(host='audio4-gm-fb.spotifycdn.com', port=443): Max retries exceeded with url: /audio/3d90279a75e9c37be75fc75989e4ef9257590efb?Expires=1698359610FullPathhmac=YjbTTh1pW5ZoLsCN1SqAZvgG8ZqMzs4UZuuzK2UWLAA= (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio4-gm-fb.spotifycdn.com'. (_ssl.c:1000)")))

Traceback (most recent call last):
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connectionpool.py", line 468, in _make_request
self._validate_conn(conn)
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connectionpool.py", line 1097, in _validate_conn
conn.connect()
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connection.py", line 642, in connect
sock_and_verified = _ssl_wrap_socket_and_match_hostname(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connection.py", line 783, in ssl_wrap_socket_and_match_hostname
ssl_sock = ssl_wrap_socket(
^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\util\ssl
.py", line 471, in ssl_wrap_socket
ssl_sock = ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\util\ssl
.py", line 515, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\ssl.py", line 455, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\ssl.py", line 1046, in _create
self.do_handshake()
File "C:\Users\Bwall\scoop\apps\python\current\Lib\ssl.py", line 1317, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio4-gm-fb.spotifycdn.com'. (_ssl.c:1000)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connectionpool.py", line 791, in urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connectionpool.py", line 492, in _make_request
raise new_e
urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio4-gm-fb.spotifycdn.com'. (_ssl.c:1000)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\requests\adapters.py", line 486, in send
resp = conn.urlopen(
^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\connectionpool.py", line 845, in urlopen
retries = retries.increment(
^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\urllib3\util\retry.py", line 515, in increment
raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='audio4-gm-fb.spotifycdn.com', port=443): Max retries exceeded with url: /audio/3d90279a75e9c37be75fc75989e4ef9257590efb?Expires=1698359610FullPathhmac=YjbTTh1pW5ZoLsCN1SqAZvgG8ZqMzs4UZuuzK2UWLAA= (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio4-gm-fb.spotifycdn.com'. (_ssl.c:1000)")))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\zotify\track.py", line 224, in download_track
stream = Zotify.get_content_stream(track, Zotify.DOWNLOAD_QUALITY)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\zotify\zotify.py", line 53, in get_content_stream
return cls.SESSION.content_feeder().load(content_id, VorbisOnlyAudioQuality(quality), False, None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init_.py", line 736, in load
return self.load_track(playable_id, audio_quality_picker, preload,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init_.py", line 797, in load_track
return self.load_stream(file, track, None, preload, halt_listener)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init_.py", line 751, in load_stream
return CdnFeedHelper.load_track(self.session, track, file,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init
.py", line 339, in load_track
streamer = session.cdn().stream_file(file, key, url, halt_listener)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init
.py", line 438, in stream_file
return CdnManager.Streamer(
^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init_.py", line 575, in init
response = self.request(range_start=0,
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\librespot\audio_init_.py", line 629, in request
response = self.__session.client().get(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\requests\sessions.py", line 602, in get
return self.request("GET", url, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\requests\sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\requests\sessions.py", line 703, in send
r = adapter.send(request, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Bwall\scoop\apps\python\current\Lib\site-packages\requests\adapters.py", line 517, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='audio4-gm-fb.spotifycdn.com', port=443): Max retries exceeded with url: /audio/3d90279a75e9c37be75fc75989e4ef9257590efb?Expires=1698359610FullPathhmac=YjbTTh1pW5ZoLsCN1SqAZvgG8ZqMzs4UZuuzK2UWLAA= (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'audio4-gm-fb.spotifycdn.com'. (_ssl.c:1000)")))

.song_ids format?

When I make download of the playlsit, in the output folder I always find the .song_ids file with mysterious numbers in the first column

7fd3ufuESeBC8kyqo7Lzbs	2023-08-14 09:07:44	Proyal	1001 Nights - Original Mix	Proyal - 1001 Nights - Original Mix.mp3
1VpoazEusm1ki8hoSK49ua	2023-08-14 09:07:55	Paolo Pellegrino	'74 - '75 (feat. Susan Tyler) - Radio Edit	Paolo Pellegrino - '74 - '75 (feat. Susan Tyler) - Radio Edit.mp3
3leKR9bTU8RGm1VnwJV1CS	2023-08-14 09:08:20	Menno de Jong	Abhyasa	Menno de Jong - Abhyasa.mp3
3VWh4Gs34HeTBUvv9bnLQL	2023-08-14 09:08:31	BiXX	Above The Clouds	BiXX - Above The Clouds.mp3

This doesn't correspond to the ID of the song when I copy its link via Spotify app, not Youtube IDs.
Where the come from?

Download location of music not changing

Hi, what is the correct way of changing the music output directory of the downloaded music folder? I wish to save them in my SSD drive instead of the default Zotify Music folder.

I've tried the following methods which didn't work for me:

  1. Editing the .config file and inserting the desired output address within:
    "ROOT_PATH": "D:\User\Users Music\Custom Zotify Music Folder",

  2. Using this command within the powershell:
    zotify --root-path D:\User\Users Music\Custom Zotify Music Folder

Please let me know if I'm missing something. TIA!

Download lyrics LRC files for existing tracks

If DOWNLOAD_LYRICS is initially False and then switched to True, zotify doesn't attempt to download the .lrc files for existing tracks.

Could you please add an option to force it to download missing lrc files only, if that's possible?

Also, not sure whether it's possible to just embed the lyrics as a tag, rather than having another lrc file which some apps do not support.

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.