{"id":14458154,"url":"https://github.com/LaurenceRawlings/savify","last_synced_at":"2025-08-28T15:30:52.539Z","repository":{"id":37440211,"uuid":"203842922","full_name":"LaurenceRawlings/savify","owner":"LaurenceRawlings","description":"Download Spotify songs to mp3 with full metadata and cover art!","archived":false,"fork":false,"pushed_at":"2023-06-22T09:46:58.000Z","size":579,"stargazers_count":1144,"open_issues_count":47,"forks_count":79,"subscribers_count":17,"default_branch":"main","last_synced_at":"2024-08-17T11:05:31.831Z","etag":null,"topics":["album-artwork","cover-art","downloads-songs","ffmpeg","id3v2","metadata","mp3","playlists","podcasts","spotify","spotify-alternative","spotify-api","spotify-downloader","spotify-playlist","spotify-playlist-downloader","spotify-to-mp3","spotify-web-api","tags","youtube","youtube-dl"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LaurenceRawlings.png","metadata":{"files":{"readme":"README.rst","changelog":"HISTORY.rst","contributing":"CONTRIBUTING.rst","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"LaurenceRawlings","ko_fi":"LaurenceRawlings"}},"created_at":"2019-08-22T17:32:52.000Z","updated_at":"2024-08-16T20:04:14.000Z","dependencies_parsed_at":"2022-07-17T14:30:47.171Z","dependency_job_id":null,"html_url":"https://github.com/LaurenceRawlings/savify","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaurenceRawlings%2Fsavify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaurenceRawlings%2Fsavify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaurenceRawlings%2Fsavify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaurenceRawlings%2Fsavify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LaurenceRawlings","download_url":"https://codeload.github.com/LaurenceRawlings/savify/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":217591175,"owners_count":16201437,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["album-artwork","cover-art","downloads-songs","ffmpeg","id3v2","metadata","mp3","playlists","podcasts","spotify","spotify-alternative","spotify-api","spotify-downloader","spotify-playlist","spotify-playlist-downloader","spotify-to-mp3","spotify-web-api","tags","youtube","youtube-dl"],"created_at":"2024-09-01T18:00:53.960Z","updated_at":"2024-09-01T18:02:38.260Z","avatar_url":"https://github.com/LaurenceRawlings.png","language":"Python","funding_links":["https://github.com/sponsors/LaurenceRawlings","https://ko-fi.com/LaurenceRawlings","https://ko-fi.com/laurencerawlings"],"categories":["Python"],"sub_categories":[],"readme":"======\nSavify\n======\n\n.. image:: images/banner.png\n     :alt: Savify\n\n.. image:: https://img.shields.io/pypi/v/savify.svg?style=for-the-badge\n     :target: https://pypi.python.org/pypi/savify\n     :alt: PyPi\n\n.. image:: https://img.shields.io/travis/LaurenceRawlings/savify.svg?style=for-the-badge\n     :target: https://travis-ci.org/github/LaurenceRawlings/savify\n     :alt: Build\n\n.. image:: https://img.shields.io/readthedocs/savify?style=for-the-badge\n     :target: https://savify.readthedocs.io\n     :alt: Documentation Status\n\n.. image:: https://img.shields.io/github/v/release/laurencerawlings/savify?include_prereleases\u0026style=for-the-badge\n     :target: https://github.com/laurencerawlings/savify/releases\n     :alt: Release\n\n.. image:: https://img.shields.io/github/downloads-pre/laurencerawlings/savify/latest/total?style=for-the-badge\n     :target: https://github.com/laurencerawlings/savify/releases\n     :alt: Downloads\n\n.. image:: https://img.shields.io/discord/701075588466737312?style=for-the-badge\n     :target: https://discordapp.com/invite/SPuPEda\n     :alt: Discord\n\n.. image:: https://img.shields.io/github/stars/laurencerawlings/savify?style=for-the-badge\n     :target: https://github.com/laurencerawlings/savify/stargazers\n     :alt: Stars\n\n.. image:: https://img.shields.io/github/contributors/laurencerawlings/savify?style=for-the-badge\n     :target: https://github.com/laurencerawlings/savify/graphs/contributors\n     :alt: Contributors\n\n.. image:: https://pyup.io/repos/github/LaurenceRawlings/savify/shield.svg?style=for-the-badge\n     :target: https://pyup.io/repos/github/LaurenceRawlings/savify/\n     :alt: Updates\n\n\n`Savify \u003chttps://github.com/LaurenceRawlings/savify\u003e`__ is a python\nlibrary that downloads songs from a selected provider (by default YouTube),\nand then scrapes the meta information from Spotify. Given a query, Savify will find\nand download songs to mp3 format with quality as high as **320 kb/s**!\nThe application will also scrape and write **id3v2 tags** to all your\nsongs. Tags include **title, artists, year, album and even cover-art!**\n\nSavify supports all Spotify track, album, and playlist links. Additionally,\nthere is an **integrated search function** so even if you do not have the\nSpotify link you can simply enter song name and Savify will download it!\n\nAs well as mp3, Savify can also download and convert to other file types.\nInside the application, you can specify which format and quality you would\nlike to download the song in for maximum compatibility across all your\ndevices. Available formats: mp3, aac, flac, m4a, opus, vorbis, and wav.\n**Tags and cover art will only be applied to songs downloaded in mp3 format.**\n\nPlease note this library does not go against Spotify TOS in any way, songs\nare not ripped directly from Spotify, but are instead downloaded from other\nsources such as YouTube and Soundcloud using the youtube-dl python library.\nSpotify is only used to gather accurate meta information to be embedded into\nthe downloaded song files.\n\n**Visit our official Docker Hub image repository and get the latest Docker image: https://hub.docker.com/repository/docker/laurencerawlings/savify**\n\n**Any questions or feedback join the** `Discord Server \u003chttps://discordapp.com/invite/SPuPEda\u003e`__\n\n\n.. image:: https://ko-fi.com/img/githubbutton_sm.svg\n     :target: https://ko-fi.com/laurencerawlings\n     :alt: Donate\n\nFFmpeg\n======\n\nSavify relies on the open source FFmpeg library to convert and\nwrite metadata to the songs it downloads. Please make sure FFmpeg is\ninstalled on your computer and added to the System PATH. Follow the tutorial\n`here \u003chttps://github.com/adaptlearning/adapt_authoring/wiki/Installing-FFmpeg\u003e`__.\n\nPlaylists\n=========\n\nIf you want to use Savify to download personal Spotify playlists, ensure their\nvisibility is set to 'Public'. This is so Savify can use the Spotify API to\nretrieve the song details from your playlist.\n\nInstallation\n============\n\nIf you are on Windows you can download the latest pre-packed executable\npackage (which I recommend as you will not have to provide a Savify API key),\nor you can download the python library and run the module directly using the CLI.\n\nDownload the latest release\n---------------------------\n\nGo `here \u003chttps://github.com/LaurenceRawlings/savify/releases\u003e`__ to download\nthe latest Savify.exe then make sure you have:\n\n- FFmpeg downloaded and it added to your Path\n- Spotify API credentials added to your environment variables\n\nThat is it, you should be good to go! See some usage examples below.\n\nUsing the Python module\n-----------------------\n\n``$ pip install -U savify``\n\nBuild Savify as Docker container\n--------------------------------\n\nClone the repository and make sure you are in the root directory.\nExecute the following build command:\n\n``$ docker build -t savify:dev .``\n\nUsage\n=====\n\nCurrently Savify only supports Spotify URLs and search queries,\nhowever support for Spotify URIs will be added in the future.\n\nCLI\n---\n\nIf you have downloaded the latest Savify.exe from the releases page\nopen your terminal and navigate to the same directory as the binary,\nthen you can run:\n\n``$ Savify.exe``\n\nIf you are using the Python package and savify is installed to your\nsite-packages and your pip folder is in your PATH (which it should be\nby default), from anywhere you can simply run:\n\n``$ savify``\n\nFor help run:\n\n``$ savify --help``\n\nGeneral usage\n~~~~~~~~~~~~~\n\nUsing the default above:\n\n``$ savify \"https://open.spotify.com/track/4Dju9g4NCz0LDxwcjonSvI\"``\n\nSpecifying your own options:\n\n``$ savify \"https://open.spotify.com/track/4Dju9g4NCz0LDxwcjonSvI\" -q best -f mp3 -o \"/path/to/downloads\" -g \"%artist%/%album%\"``\n\nWith a search query:\n\n``$ savify \"You \u0026 I - Bru-C\" -t track -q best -f mp3 -o \"/path/to/downloads\" -g \"%artist%/%album%\"``\n\nGrouping\n~~~~~~~~\n\nAvailable variables: ``%artist%, %album%, %playlist%``\n\nFor example:\n\n``$ savify \"You \u0026 I - Bru-C\" -o /path/to/downloads -g \"%artist%/%album%\"``\n\nWould download in the following directory structure:\n\n.. code-block:: python\n\n     /path/to/downloads\n          |\n          |- /Bru-C\n               |\n               |- /Original Sounds\n                    |\n                    |- Bru-C - You \u0026 I.mp3\n\nDownload Defaults\n-----------------\n\n:Query Type: track\n:Quality: best\n:Format: mp3\n:Path:\n     Windows: HOME/AppData/Roaming/Savify/downloads\n\n     Linux: HOME/.local/share/Savify/downloads\n\n     MacOS: HOME/Library/Application Support/Savify/downloads\n:Grouping: no grouping\n\nFor more usage examples read the `docs \u003chttps://savify.readthedocs.io\u003e`__.\n\nDocker\n------\n\nRun savify inside a container which can also be attached to other\ncontainer's networks. This is handy if you want to run multiple instances\nof savify and/or want to use VPNs for downloading.\nYou can use your self-built Docker image or the official one. Make sure to\nuse the right Docker image name and tag.\n\n``$ docker run laurencerawlings/savify:latest``\n\nIf no argument is specified, the container will print the help page. Simply\nappend your arguments, make sure you mount a folder from your host so\ndownloads are persistent (``-v``) - ``pwd`` is used to mount the current directory\nyou are in - and remove the container when done (``--rm``). You have to specify your\nSpotify client ID and secret by using environment variables (``-e``):\n\n.. code-block:: bash\n\n    $ docker run --rm -v \"`pwd`:/root/.local/share/Savify/downloads\" \\\n               -e SPOTIPY_CLIENT_ID=client_id \\\n               -e SPOTIPY_CLIENT_SECRET=client_secret \\\n               laurencerawlings/savify:latest \"https://open.spotify.com/playlist/...\"\n\nIf you want to preserve your logs, you can mount the logging directory by simply\nadding the following argument to the docker run command: ``-v \"./logs:/root/.local/share/Savify/logs\"``\n\nAutomate with a shell script:\n\n``$ nano savify.sh``\n\n.. code-block:: sh\n\n    #!/bin/bash\n    docker run --rm -v \"`pwd`:/root/.local/share/Savify/downloads\" \\\n               -e SPOTIPY_CLIENT_ID=client_id \\\n               -e SPOTIPY_CLIENT_SECRET=client_secret \\\n               laurencerawlings/savify:latest $1\n\nThen run with:\n\n``$ sh savify.sh \"https://open.spotify.com/track/4Dju9g4NCz0LDxwcjonSvI\"``\n\nYou also have the option to quickstart using our docker script which have an integrated VPN-check\nto see if there are any VPN containers the script can connect to. The script is perfect for being\nscheduled with cron:\n\n.. code-block:: sh\n\n    $ wget https://github.com/laurencerawlings/savify/latest/download/savify-docker-scripts.zip\n    $ unzip savify-docker-scripts.zip \u0026\u0026 rm savify-docker-scripts.zip\n    $ cd savify-docker-scripts/\n\nYou then have to edit the configuration file with your preferred text editor (we prefer nano),\nsave it (Ctrl + X, Y for saving changes in nano) and rename it to ``config.sh``.\n\n.. code-block:: sh\n\n    $ nano template.config.sh\n    $ mv template.config.sh config.sh\n\nYou can then run the script:\n\n.. code-block:: sh\n\n    $ bash bulk-download.sh\n\n\nSpotify Application\n-------------------\n\nTo use the Savify Python module you will need your own Spotify\ndeveloper application to access their API. To do this sign up\n`here \u003chttps://developer.spotify.com/\u003e`__. When you have made a new\napplication take note of your client id and secret. You can pass\nthe id and secret to Savify in two ways:\n\nEnvironment variables (recommended)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNow you need to add 2 environment variables to your system:\n\n``SPOTIPY_CLIENT_ID``\n\n``SPOTIPY_CLIENT_SECRET``\n\nTo find out how to do this find a tutorial online for your specific\noperating system. Once you have done this make sure to restart your\nshell.\n\nDuring object instantiation\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYou can pass in your id and secret using a tuple when creating your\nSavify object:\n\n.. code-block:: python\n\n     s = Savify(api_credentials=(\"CLIENT_ID\",\"CLIENT_SECRET\"))\n\n\nUse in your Python project\n--------------------------\n\nInstall the package to your environment:\n\n``$ pip install savify``\n\n\nImport and use Savify:\n\n.. code-block:: python\n\n     from savify import Savify\n     from savify.types import Type, Format, Quality\n\n     s = Savify()\n     # Spotify URL\n     s.download(\"SPOTIFY URL\")\n\n     # Search Query\n     # Types: TRACK, ALBUM, PLAYLIST\n     s.download(\"QUERY\", query_type=Type.TRACK)\n\nSavify optional constructor arguments (see above for defaults):\n\n.. code-block:: python\n\n    import logging\n\n     from savify import Savify\n     from savify.types import Type, Format, Quality\n     from savify.utils import PathHolder\n\n     # Quality Options: WORST, Q32K, Q96K, Q128K, Q192K, Q256K, Q320K, BEST\n     # Format Options: MP3, AAC, FLAC, M4A, OPUS, VORBIS, WAV\n     Savify(api_credentials=None, quality=Quality.BEST, download_format=Format.MP3, path_holder=PathHolder(downloads_path='path/for/downloads'), group='%artist%/%album%', quiet=False, skip_cover_art=False, log_level=logging.INFO)\n\nManually customising youtube-dl options:\n\n.. code-block:: python\n\n     from savify import Savify\n\n     options = {\n         'cookiefile': 'cookies.txt'\n     }\n\n     Savify(ydl_options=options)\n\nPassing in your own logger:\n\n.. code-block:: python\n\n     from savify import Savify\n     from savify.logger import Logger\n\n     logger = Logger(log_location='path/for/logs', log_level=None) # Silent output\n\n     Savify(logger=logger)\n\nThe group argument is used to sort you downloaded songs inside the\noutput path. Possible variables for the path string are: %artist%, %album%,\nand %playlist%. The variables are replaced with the songs metadata.\nFor example, a song downloaded with the above Savify object would\nsave to a path like this:\n`path/for/downloads/Example Artist/Example Album/Example Song.mp3`\n\nFor Developers\n==============\n\nIf you want to try your hand at adding to Savify use the instructions\n`here \u003cCONTRIBUTING.rst\u003e`__. From there you can make any additions you\nthink would make Savify better.\n\nTip\n---\n\nIf you are developing Savify, install the pip package locally so you\ncan make and test your changes. From the root directory run:\n\n``$ pip install -e .``\n\nYou can then run the Python module:\n\n``$ savify``\n\nCredits\n=======\n\nThis package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.\n\n.. _Cookiecutter: https://github.com/audreyr/cookiecutter\n.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLaurenceRawlings%2Fsavify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLaurenceRawlings%2Fsavify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLaurenceRawlings%2Fsavify/lists"}