spotifysaverdn 0.7.5.post1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spotifysaverdn-0.7.5.post1/LICENSE +8 -0
- spotifysaverdn-0.7.5.post1/PKG-INFO +556 -0
- spotifysaverdn-0.7.5.post1/README.md +507 -0
- spotifysaverdn-0.7.5.post1/pyproject.toml +143 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/__init__.py +46 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/__main__.py +8 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/README.md +365 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/__init__.py +5 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/app.py +291 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/config.py +105 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/examples.py +268 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/main.py +21 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/__init__.py +6 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/authentication.py +137 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/backups.py +316 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/channel_watcher.py +124 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/download.py +1522 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/jellyfin.py +59 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/notifications.py +35 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/spotify_settings.py +223 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/storage.py +32 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/routers/user_preferences.py +129 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/schemas.py +273 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/__init__.py +31 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/channel_watcher.py +1462 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/download_directory_store.py +148 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/download_limits_store.py +79 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/download_service.py +508 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/jellyfin_library_scan.py +406 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/notification_hub.py +69 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/security_store.py +318 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/storage_protection.py +243 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/video_download_service.py +425 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/api/services/youtube_confirmation_store.py +77 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/__init__.py +5 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/cli.py +36 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/__init__.py +11 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/download/__init__.py +5 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/download/album.py +161 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/download/download.py +128 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/download/playlist.py +123 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/download/track.py +109 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/init.py +76 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/inspect/__init__.py +7 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/inspect/album_info.py +38 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/inspect/inspect.py +52 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/inspect/playlist_info.py +36 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/inspect/track_info.py +30 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/log/__init__.py +5 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/log/log.py +68 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/cli/commands/version.py +19 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/config/__init__.py +3 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/config/setting_environment.py +81 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/download_limiter.py +46 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/downloader/__init__.py +13 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/downloader/image_downloader.py +61 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/downloader/soundcloud_downloader.py +350 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/downloader/trim_silence.py +187 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/downloader/youtube_downloader.py +766 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/downloader/youtube_downloader_for_cli.py +1204 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/enums/__init__.py +4 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/enums/audio_formats_enum.py +8 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/enums/bitrates_enum.py +9 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/metadata/__init__.py +9 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/metadata/music_file_metadata.py +179 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/metadata/nfo_generator.py +163 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/models/__init__.py +8 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/models/album.py +42 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/models/artist.py +44 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/models/playlist.py +41 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/models/track.py +90 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/__init__.py +9 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/audiodb_parser.py +212 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/errors/errors.py +83 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/lrclib_api.py +92 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/schemas/__init__.py +3 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/schemas/album_audiodb_schema.py +67 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/schemas/artist_audiodb_schema.py +63 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/schemas/track_audiodb_schema.py +39 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/score_match_calculator.py +251 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/spotify_api.py +496 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/the_audio_db_service.py +214 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/services/youtube_api.py +318 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/spotlog/__init__.py +7 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/spotlog/log_config.py +78 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/spotlog/logger.py +19 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/spotlog/ydd_logger.py +25 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/README.md +86 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/index.html +806 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/css/styles.css +1757 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/js/api-client.js +738 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/js/app.js +1931 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/js/channel-watcher-manager.js +398 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/js/download-manager.js +765 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/js/state-manager.js +75 -0
- spotifysaverdn-0.7.5.post1/spotifysaver/ui/static/js/ui-manager.js +871 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Copyright (c) 2025 Gabriel Baute
|
|
2
|
+
Copyright (c) 2026 Danilo Nishimura
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
5
|
+
|
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spotifysaverdn
|
|
3
|
+
Version: 0.7.5.post1
|
|
4
|
+
Summary: Download audio and video from YouTube Music to your media server.
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: spotify,youtube,youtube-music,soundcloud,music-downloader,jellyfin,metadata,cli-tool,audio-conversion,playlist-downloader
|
|
8
|
+
Author: Gabriel Baute
|
|
9
|
+
Author-email: gabrielbaute@gmail.com
|
|
10
|
+
Maintainer: Gabriel Baute
|
|
11
|
+
Maintainer-email: gabrielbaute@gmail.com
|
|
12
|
+
Requires-Python: >=3.10,<4.0
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Natural Language :: English
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
28
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
29
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion
|
|
30
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
31
|
+
Classifier: Topic :: Utilities
|
|
32
|
+
Provides-Extra: docs
|
|
33
|
+
Requires-Dist: click (>=8.1.8,<9.0.0)
|
|
34
|
+
Requires-Dist: fastapi (>=0.115.14,<0.116.0)
|
|
35
|
+
Requires-Dist: mutagen (>=1.47.0,<2.0.0)
|
|
36
|
+
Requires-Dist: pydantic (>=2.11.9,<3.0.0)
|
|
37
|
+
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
|
38
|
+
Requires-Dist: requests (>=2.32.5,<3.0.0)
|
|
39
|
+
Requires-Dist: spotipy (>=2.25.1,<3.0.0)
|
|
40
|
+
Requires-Dist: tzdata (>=2025.2,<2026.0)
|
|
41
|
+
Requires-Dist: uvicorn[standard] (>=0.34.0,<0.35.0)
|
|
42
|
+
Requires-Dist: yt-dlp (>=2026.8.19,<2027.0.0)
|
|
43
|
+
Requires-Dist: ytmusicapi (>=1.10.3,<2.0.0)
|
|
44
|
+
Project-URL: Documentation, https://deepwiki.com/danilonishi/spotify-saver
|
|
45
|
+
Project-URL: Homepage, https://github.com/danilonishi/spotify-saver
|
|
46
|
+
Project-URL: Repository, https://github.com/danilonishi/spotify-saver
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# SpotifySaver 🎵✨
|
|
50
|
+
|
|
51
|
+
[](https://www.python.org/)
|
|
52
|
+
[](https://pypi.org/project/spotifysaverdn/)
|
|
53
|
+
[](https://github.com/danilonishi/spotify-saver/pkgs/container/spotify-saver)
|
|
54
|
+
[](https://github.com/danilonishi/spotify-saver/pkgs/container/spotify-saver)
|
|
55
|
+
[](https://ffmpeg.org/)
|
|
56
|
+
[](https://github.com/yt-dlp/yt-dlp)
|
|
57
|
+
[](https://opensource.org/licenses/MIT)
|
|
58
|
+
[](https://github.com/psf/black)
|
|
59
|
+
|
|
60
|
+
[](https://developer.spotify.com/)
|
|
61
|
+
[](https://youtube.com/)
|
|
62
|
+
[](https://ytmusicapi.readthedocs.io/)
|
|
63
|
+
[](https://soundcloud.com)
|
|
64
|
+
|
|
65
|
+
> ⚠️This repository is a fork from gabrielbaute's SpotifySaver. It's being developed with quality of life features I missed when using his tool. You can easily see the changes made by clicking [here](https://github.com/gabrielbaute/spotify-saver/compare/main...danilonishi:spotify-saver:main).
|
|
66
|
+
|
|
67
|
+
All-in-one tool for downloading content for Jellyfin or similar media servers.
|
|
68
|
+
|
|
69
|
+
The app allows you to download content for your media server. It can connect to Spotify, Soundcloud and YouTube Music APIs, retrieve information, locate the media, download and extract the audio and/or video data and generate a Jellyfin-compatible .nfo file for libraries.
|
|
70
|
+
|
|
71
|
+
## Changes in this Fork
|
|
72
|
+
|
|
73
|
+
<p align="center">
|
|
74
|
+
<img src="screenshot.jpg" alt="SpotifySaver web interface" />
|
|
75
|
+
</p>
|
|
76
|
+
|
|
77
|
+
This fork packs many more features compared to the baseline:
|
|
78
|
+
|
|
79
|
+
- **Server-managed download queue:** Downloads continue if you refresh or close the browser.
|
|
80
|
+
- **Access control:** Protected UI and API to avoid unauthorized access.
|
|
81
|
+
- **Video support:** Downloads videos with configurable format, resolution and quality and generates NFO metadata.
|
|
82
|
+
- **SoundCloud support:** Direct downloads when download option is available.
|
|
83
|
+
- **Silence Trimming:** Option to automatically trim silence at the start and end of downloaded audio files.
|
|
84
|
+
- **Playlist support:** Download playlists from Spotify and YouTube.
|
|
85
|
+
- **Multiple parallel Downloads:** Useful when downloading large playlists or albums.
|
|
86
|
+
- **Channel Watcher:** Schedule channel checks and automatically download new uploads.
|
|
87
|
+
- **Jellyfin library scans:** Automatically triggers Jellyfin media scan after downloads are completed.
|
|
88
|
+
- **[Browser extension support](https://github.com/danilonishi/spotifyu-saver-browser-extension):** Trigger downloads from Spotify, YouTube, and SoundCloud pages, or watch channels.
|
|
89
|
+
- **Simplified download folders:** Browse and select download folders in the web interface.
|
|
90
|
+
- **UI improvements:** Dark mode and customizable interface.
|
|
91
|
+
- **Backup and restore:** Easier to migrate the server or share configurations.
|
|
92
|
+
- **Storage safeguards:** Set a minimum free space to avoid completely filling the storage.
|
|
93
|
+
- **Improved visibility:** Downloads are reported by the server to all connected clients.
|
|
94
|
+
- **Large Spotify playlists:** Large playlists were capped due to Spotify list being paginated. This is fixed here.
|
|
95
|
+
- **Overwrite control:** Keep existing files by default (skipping download), or choose to redownload and overwrite.
|
|
96
|
+
- **Notifications:** Browser and toaster notifications for events are available.
|
|
97
|
+
- **Download queue controls:** Pause/resume the queue and retry failed downloads.
|
|
98
|
+
- **Channel Watcher controls and filters:** Filter out uploads by keywords, duration, date, Shorts, and livestreams.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## 🌟 Features
|
|
102
|
+
|
|
103
|
+
| | Feature | Description |
|
|
104
|
+
|--------|--------------------------|--------------------------------------------|
|
|
105
|
+
||**General**||
|
|
106
|
+
| ✅ | Organization | Automatic folder structure: Artist/Album/Track or Channel/Video|
|
|
107
|
+
| ✅ | Metadata | Generate Jellyfin-compatible `.nfo` metadata for audio and video|
|
|
108
|
+
| ✅ | Audio Formats | M4A, MP3 and OPUS|
|
|
109
|
+
| ✅ | Audio Bitrates | 96, 128, 192 and 256 kbps|
|
|
110
|
+
| ✅ | Video Formats | MP4, MKV and WebM|
|
|
111
|
+
| ✅ | Video Resolution | 360p, 480p, 720p, 1080p, 1440p and 2460p (4K)|
|
|
112
|
+
||**Youtube/Youtube Music**||
|
|
113
|
+
| ✅ | Download | Download audio or video|
|
|
114
|
+
| ✅ | Playlists / Album Collections | Download and generate playlist file |
|
|
115
|
+
| ✅ | Channel Watcher | Watch channel and automatically downloads new content |
|
|
116
|
+
| ✅ | video with chapter markers | Not supported|
|
|
117
|
+
| ❌ | Lyrics | Not supported|
|
|
118
|
+
| ❌ | Captions | Planned|
|
|
119
|
+
||**Spotify**||
|
|
120
|
+
| ✅ | Tracks | Fetch metadata from Spotify and audio track from Youtube Music|
|
|
121
|
+
| ✅ | Playlists | Download tracks and saves playlist file|
|
|
122
|
+
| ✅ | Lyrics | Synchronized lyrics (.lrc) from LRC Lib|
|
|
123
|
+
| ❌ | Artist Watcher | Planned |
|
|
124
|
+
||**Soundcloud**||
|
|
125
|
+
| ✅ | Tracks | Direct download when available, Youtube Music as fallback|
|
|
126
|
+
| ❌ | Playlists | Planned |
|
|
127
|
+
| ❌ | Lyrics | Not supported|
|
|
128
|
+
| ❌ | Artist Watcher | Planned |
|
|
129
|
+
||**Browser Extension**||
|
|
130
|
+
| ✅ | API | Adapts interface when download is requested by browser extension|
|
|
131
|
+
||**Settings**||
|
|
132
|
+
| ✅ | UI | Control panel visibility|
|
|
133
|
+
| ✅ | Notifications | Enable browser and toaster notifications for events|
|
|
134
|
+
| ✅ | Storage | Define minimum free space for downloads|
|
|
135
|
+
| ✅ | Download limiter | Set number of simultaneous downloads and bandwidth|
|
|
136
|
+
| ✅ | Confirmation | Option to confirm queued downloads before they start downloading|
|
|
137
|
+
| ✅ | Backup & Restore | Generates `.json` file with server and client settings|
|
|
138
|
+
| ✅ | Jellyfin | Option to trigger library scan after all downloads are finished|
|
|
139
|
+
| ✅ | Spotify | Set up credentials to access the Spotify API|
|
|
140
|
+
| ✅ | Security | Password management|
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Installation
|
|
144
|
+
|
|
145
|
+
### Requirements
|
|
146
|
+
- Python 3.10+
|
|
147
|
+
- FFmpeg
|
|
148
|
+
- [Spotify Developer Account](https://developer.spotify.com/dashboard/) (only for Spotify URL downloads)
|
|
149
|
+
|
|
150
|
+
##
|
|
151
|
+
|
|
152
|
+
You can install using one of the three methods listed below.
|
|
153
|
+
|
|
154
|
+
### Method 1: Docker (recommended)
|
|
155
|
+
See [Docker support with auto-builds](#-docker-support)
|
|
156
|
+
|
|
157
|
+
### Method 2: Poetry (through Git)
|
|
158
|
+
```bash
|
|
159
|
+
git clone https://github.com/danilonishi/spotify-saver.git
|
|
160
|
+
cd spotify-saver
|
|
161
|
+
poetry install
|
|
162
|
+
```
|
|
163
|
+
Then proceed to [First-time sign-in](#first-time-sign-in)
|
|
164
|
+
|
|
165
|
+
### Method 3: Pip (through Git)
|
|
166
|
+
```bash
|
|
167
|
+
pip install git+https://github.com/danilonishi/spotify-saver.git
|
|
168
|
+
```
|
|
169
|
+
Then proceed to [First-time sign-in](#first-time-sign-in)
|
|
170
|
+
|
|
171
|
+
## 🐳 Docker Support
|
|
172
|
+
|
|
173
|
+
Docker images are published to
|
|
174
|
+
[GitHub Container Registry](https://github.com/danilonishi/spotify-saver/pkgs/container/spotify-saver)
|
|
175
|
+
from pushes to `main` and version tags (`v*`). `latest` tracks `main`; version
|
|
176
|
+
tags are also available for pinned deployments. The first successful workflow
|
|
177
|
+
run creates the package. Set its visibility to **Public** in GitHub Packages
|
|
178
|
+
if servers should be able to pull images without authenticating. Until the
|
|
179
|
+
first publish workflow has succeeded, use the local-build override below.
|
|
180
|
+
|
|
181
|
+
### Install with Docker Compose
|
|
182
|
+
|
|
183
|
+
Requirements: Docker Engine/Desktop with the Compose plugin. Clone this
|
|
184
|
+
repository, then create the host folders and environment file:
|
|
185
|
+
|
|
186
|
+
In **Windows PowerShell**, run:
|
|
187
|
+
|
|
188
|
+
```powershell
|
|
189
|
+
New-Item -ItemType Directory -Force data\music, data\videos, data\config
|
|
190
|
+
Copy-Item .env.docker.example .env
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
On **Linux/macOS**, run the equivalent commands in a terminal using Bash:
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
mkdir -p data/music data/videos data/config
|
|
197
|
+
cp .env.docker.example .env
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The container runs as user ID `1000` and needs write access to its config
|
|
201
|
+
folder. If you created the repository or its data folders with `sudo`, fix
|
|
202
|
+
ownership before starting the container:
|
|
203
|
+
|
|
204
|
+
```sh
|
|
205
|
+
sudo chown -R 1000:1000 data/config
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
If you set `CONFIG_DIR` in `.env` to a different host folder, use that folder
|
|
209
|
+
instead of `data/config`.
|
|
210
|
+
|
|
211
|
+
Before starting SpotifySaver, edit `.env` and set `MUSIC_DIR` and `VIDEO_DIR`
|
|
212
|
+
to the existing media folders on your server. For example, if your media
|
|
213
|
+
folders are `/media/Music` and `/media/Videos`, set:
|
|
214
|
+
|
|
215
|
+
```dotenv
|
|
216
|
+
MUSIC_DIR=/media/Music
|
|
217
|
+
VIDEO_DIR=/media/Videos
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
These are host paths, not the `/music` and `/videos` paths used inside the
|
|
221
|
+
container. Leave `CONFIG_DIR=./data/config` unless you want to store the app's
|
|
222
|
+
configuration elsewhere. On Linux, you can edit the file with `nano .env` from
|
|
223
|
+
the repository folder.
|
|
224
|
+
|
|
225
|
+
Direct YouTube downloads and the Channel Watcher do not need Spotify
|
|
226
|
+
credentials. Spotify URL-based downloads can be configured from **Settings →
|
|
227
|
+
Spotify Account** after signing in. The app asks Spotify to authorize in your
|
|
228
|
+
browser and receives the callback on the server; this works with a headless
|
|
229
|
+
Docker deployment.
|
|
230
|
+
|
|
231
|
+
Start the published image:
|
|
232
|
+
|
|
233
|
+
```sh
|
|
234
|
+
docker compose pull
|
|
235
|
+
docker compose up -d
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## First-time sign-in
|
|
239
|
+
|
|
240
|
+
On first launch, SpotifySaver writes a one-time administrator setup token to
|
|
241
|
+
the server logs. From the directory containing the Compose files, run:
|
|
242
|
+
|
|
243
|
+
```sh
|
|
244
|
+
docker compose logs --tail=100 spotifysaver
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Find the line beginning `First-run administrator setup token` and enter its
|
|
248
|
+
token in the setup page. If the container is restarting, use this same command
|
|
249
|
+
to inspect the startup error in the logs.
|
|
250
|
+
|
|
251
|
+
Open SpotifySaver in your browser, enter that token, and create an administrator
|
|
252
|
+
password of at least 12 characters. The token is generated again after a server
|
|
253
|
+
restart until the initial password has been set, and becomes invalid once it is
|
|
254
|
+
used. Do not share the logs while they contain the token. After setup, sign in
|
|
255
|
+
with the password you created. Login attempts are rate-limited.
|
|
256
|
+
|
|
257
|
+
The admin password, sessions, and Spotify app credentials are persisted in
|
|
258
|
+
`CONFIG_DIR` (the `data/config` folder by default); the database is readable
|
|
259
|
+
only by the container account on Linux. The Spotify OAuth token cache is stored
|
|
260
|
+
in the same config directory with restricted file permissions. Back up this
|
|
261
|
+
directory and protect access to it.
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
## Configure Spotify
|
|
265
|
+
|
|
266
|
+
1. Create an app in the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/).
|
|
267
|
+
2. In SpotifySaver, open **Settings → Spotify Account**. Copy the displayed
|
|
268
|
+
OAuth redirect URL into the app's allowed Redirect URIs in the Spotify
|
|
269
|
+
Developer Dashboard. It must match exactly; for a Caddy deployment it uses
|
|
270
|
+
the public HTTPS hostname.
|
|
271
|
+
3. Enter the app's Client ID and Client Secret and save them.
|
|
272
|
+
4. Select **Connect to Spotify** and approve access in Spotify.
|
|
273
|
+
|
|
274
|
+
The Client Secret is stored on the server and is never returned to the browser
|
|
275
|
+
after saving. The server-side security database is protected by filesystem
|
|
276
|
+
permissions, not encrypted; anyone with access to the server's config files or
|
|
277
|
+
Docker administrator access can read it. Keep those host files private.
|
|
278
|
+
|
|
279
|
+
To build and run the checked-out source instead of pulling GHCR, add the build
|
|
280
|
+
override:
|
|
281
|
+
|
|
282
|
+
```sh
|
|
283
|
+
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### CLI
|
|
287
|
+
|
|
288
|
+
If you're unable to browse to the settings view, run this command to save configuration to `~/.spotify-saver/.env`:
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
spotifysaver init
|
|
292
|
+
```
|
|
293
|
+
The app also checks for a `.env` file in the project directory as a fallback.
|
|
294
|
+
Supported environment variables include:
|
|
295
|
+
|
|
296
|
+
| Variable | Description | Default Value |
|
|
297
|
+
|---------------------------|--------------------------------------------|-----------------------------------|
|
|
298
|
+
| `SPOTIFY_CLIENT_ID` | ID of the Spotify app you created | - |
|
|
299
|
+
| `SPOTIFY_CLIENT_SECRET` | Secret key generated for your Spotify app | - |
|
|
300
|
+
| `SPOTIFY_REDIRECT_URI` | Spotify app redirect URI | `http://127.0.0.1:8888/callback` |
|
|
301
|
+
| `SPOTIFYSAVER_OUTPUT_DIR` | Audio download directory | `Music` |
|
|
302
|
+
| `SPOTIFYSAVER_VIDEO_DIR` | Video download directory | `Videos` |
|
|
303
|
+
| `YTDLP_COOKIES_PATH` | YouTube cookies file path (optional; for Docker, use a path inside the container such as `/config/cookies.txt`) | - |
|
|
304
|
+
| `SPOTIFY_AUTH_CACHE_PATH` | Spotify authorization cache path | `~/.spotify-saver/.spotify-cache` |
|
|
305
|
+
| `SPOTIFY_SCOPES` | Spotify permissions requested | `playlist-read-private playlist-read-collaborative` |
|
|
306
|
+
| `LOG_LEVEL` | Logging level | `info` |
|
|
307
|
+
|
|
308
|
+
The `init` wizard also writes `API_PORT` and `API_HOST`, but the standalone
|
|
309
|
+
server currently uses port `8000` and host `0.0.0.0`. For an example
|
|
310
|
+
configuration file, see [`.env.example`](.env.example).
|
|
311
|
+
|
|
312
|
+
# Updating
|
|
313
|
+
|
|
314
|
+
## Git/Poetry
|
|
315
|
+
|
|
316
|
+
For a source checkout installed with Poetry, update the checkout and reinstall:
|
|
317
|
+
|
|
318
|
+
```sh
|
|
319
|
+
git pull
|
|
320
|
+
poetry install
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Git/Pip
|
|
324
|
+
|
|
325
|
+
If installed from Git with pip, upgrade from the repository:
|
|
326
|
+
|
|
327
|
+
```sh
|
|
328
|
+
python -m pip install --upgrade "git+https://github.com/danilonishi/spotify-saver.git"
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Restart the SpotifySaver server after updating.
|
|
332
|
+
|
|
333
|
+
## Docker
|
|
334
|
+
|
|
335
|
+
For Docker, update to the latest published `main` image by running `git pull`
|
|
336
|
+
for the Compose files, then pull and start the service.
|
|
337
|
+
|
|
338
|
+
If Caddy runs in Docker, include the Caddy override on **both** commands so the container stays attached to Caddy's shared network:
|
|
339
|
+
|
|
340
|
+
```sh
|
|
341
|
+
docker compose -f docker-compose.yml -f docker-compose.caddy.yml pull
|
|
342
|
+
docker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
If you do **not** use the Docker Caddy override (for example, Caddy runs on the
|
|
346
|
+
host), use the base Compose file:
|
|
347
|
+
|
|
348
|
+
```sh
|
|
349
|
+
docker compose pull
|
|
350
|
+
docker compose up -d
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Docker images are published as latest when changes are pushed to main. To publish a versioned release image, push a new Git tag using the vX.Y.Z format (for example, v0.7.6). The workflow publishes versioned and major/minor tags. To pin your deployment to that release, set IMAGE_TAG=0.7.6 in .env instead of using latest.
|
|
354
|
+
|
|
355
|
+
Open `http://127.0.0.1:8000`. The API is also available at
|
|
356
|
+
`http://127.0.0.1:8000/docs`. The port is bound to loopback only; for access
|
|
357
|
+
over HTTPS or from other devices, configure a reverse proxy rather than
|
|
358
|
+
exposing the application port directly. See the optional
|
|
359
|
+
[Caddy reverse proxy guide](CADDY.md).
|
|
360
|
+
|
|
361
|
+
The UI's folder selectors operate on container paths. Audio downloads are
|
|
362
|
+
stored under `/music`, video and watched-channel downloads under `/videos`,
|
|
363
|
+
and both paths map to `data/music` and `data/videos` on the host by default.
|
|
364
|
+
You can set `MUSIC_DIR`, `VIDEO_DIR`, and `CONFIG_DIR` in `.env` to change the
|
|
365
|
+
host-side folders. Keep the config directory: it stores the watched-channel
|
|
366
|
+
database, channel download archives, cookies, and other home-directory app
|
|
367
|
+
state. Back up these folders before migrating or reinstalling:
|
|
368
|
+
|
|
369
|
+
```text
|
|
370
|
+
data/music/
|
|
371
|
+
data/videos/
|
|
372
|
+
data/config/
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
On Linux, make sure the mounted directories are writable by the container's
|
|
376
|
+
non-root user (UID 1000). For example, if these are dedicated directories:
|
|
377
|
+
|
|
378
|
+
```sh
|
|
379
|
+
sudo chown -R 1000:1000 data/music data/videos data/config
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Useful maintenance commands for a deployment without the Docker Caddy override:
|
|
383
|
+
|
|
384
|
+
```sh
|
|
385
|
+
docker compose logs -f spotifysaver
|
|
386
|
+
git pull
|
|
387
|
+
docker compose pull
|
|
388
|
+
docker compose up -d
|
|
389
|
+
docker compose down
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
For a Docker Caddy deployment, add
|
|
393
|
+
`-f docker-compose.yml -f docker-compose.caddy.yml` to each `docker compose`
|
|
394
|
+
command instead. Omitting the override can detach SpotifySaver from Caddy's
|
|
395
|
+
network when Compose recreates the container.
|
|
396
|
+
|
|
397
|
+
`docker compose down` stops and removes the container but leaves the bind
|
|
398
|
+
mounted data folders and named log volume intact. Do not use
|
|
399
|
+
`docker compose down -v` unless you intend to remove the named log volume as
|
|
400
|
+
well.
|
|
401
|
+
|
|
402
|
+
## Cookies
|
|
403
|
+
|
|
404
|
+
Cookies are disabled by default. **Only configure `YTDLP_COOKIES_PATH` if a video
|
|
405
|
+
requires authentication**, and use a fresh export: stale or incompatible YouTube
|
|
406
|
+
cookies can cause downloads to fail with HTTP 403. For Docker Compose, save the
|
|
407
|
+
cookies file under the configured `CONFIG_DIR` on the host (by default,
|
|
408
|
+
`./data/config/cookies.txt`) and set this in `.env`:
|
|
409
|
+
|
|
410
|
+
```dotenv
|
|
411
|
+
YTDLP_COOKIES_PATH=/config/cookies.txt
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
To disable cookies, remove or empty `YTDLP_COOKIES_PATH` in `.env`, then
|
|
415
|
+
recreate the container with `docker compose up -d --force-recreate spotifysaver`.
|
|
416
|
+
To back up or replace the file first, use the host path, for example:
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
cp ./data/config/cookies.txt ./data/config/cookies.txt.backup
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Do not share the cookie file; it contains session credentials. If the cookie
|
|
423
|
+
file is not present in your configured `CONFIG_DIR`, leave the setting disabled.
|
|
424
|
+
|
|
425
|
+
# 📚 Documentation
|
|
426
|
+
|
|
427
|
+
The **documentation for using the API**, on the other hand, can be found in this same repository here: [API Documentation](API_IMPLEMENTATION_SUMMARY.md)
|
|
428
|
+
|
|
429
|
+
## 💻 Using the CLI
|
|
430
|
+
|
|
431
|
+
### Available Commands
|
|
432
|
+
|
|
433
|
+
| Command | Description | Example |
|
|
434
|
+
|----------------------|--------------------------------------------|--------------------------------------------|
|
|
435
|
+
| `init` | Configure environment variables | `spotifysaver init"` |
|
|
436
|
+
| `download [URL]` | Download Spotify tracks/albums/playlists or YouTube albums/playlists | `spotifysaver download "URL"` |
|
|
437
|
+
| `inspect` | Shows Spotify metadata (album, playlist) | `spotifysaver inspect "URL_SPOTIFY"` |
|
|
438
|
+
| `show-log` | Shows the application log | `spotifysaver show-log` |
|
|
439
|
+
| `version` | Shows the installed version | `spotifysaver version` |
|
|
440
|
+
|
|
441
|
+
### Download Options
|
|
442
|
+
|
|
443
|
+
| Option | Description | Accepted Values |
|
|
444
|
+
|-------------------|-------------------------------------------------------|-------------------------|
|
|
445
|
+
| `--lyrics` | Download synchronized lyrics (.lrc) | Flag (no value) |
|
|
446
|
+
| `--output DIR` | Output directory | Valid path |
|
|
447
|
+
| `--format FORMAT` | Audio format | `m4a` (default), `mp3`, `opus` |
|
|
448
|
+
| `--bitrate KBPS` | Audio bitrate | `96`, `128` , `192`, `256`(default) |
|
|
449
|
+
| `--cover/--no-cover` | Save Spotify cover or embed YouTube thumbnail | Flag (no value) |
|
|
450
|
+
| `--nfo` | Generates a .nfo metadata file in the JellyFin format | Flag (no value) |
|
|
451
|
+
| `--explain` | Show score breakdown for each track without downloading (for error analysis) | Flag (no value) |
|
|
452
|
+
| `--dry-run` | Simulate download without saving files | Flag (no value) |
|
|
453
|
+
|
|
454
|
+
### show-log Options
|
|
455
|
+
|
|
456
|
+
| Option | Description | Accepted Values |
|
|
457
|
+
|-------------|-----------------------------------------|-------------------------------|
|
|
458
|
+
| `--lines` | Number of log lines to display | `--lines 25` --> `int` |
|
|
459
|
+
| `--level` | Filter by log level | INFO, WARNING, DEBUG, ERROR |
|
|
460
|
+
| `--path` | Displays the location of the log file | Flag (no value) |
|
|
461
|
+
|
|
462
|
+
## 💡 Usage Examples
|
|
463
|
+
```bash
|
|
464
|
+
# Set spotifysaver configuration
|
|
465
|
+
spotifysaver init
|
|
466
|
+
|
|
467
|
+
# Download album with synchronized lyrics
|
|
468
|
+
spotifysaver download "https://open.spotify.com/album/..." --lyrics
|
|
469
|
+
|
|
470
|
+
# Download album with metadata file; the cover is saved as cover.jpg by default
|
|
471
|
+
spotifysaver download "https://open.spotify.com/album/..." --nfo
|
|
472
|
+
|
|
473
|
+
# Download song in MP3 format
|
|
474
|
+
spotifysaver download "https://open.spotify.com/track/..." --format mp3
|
|
475
|
+
|
|
476
|
+
# Download a YouTube Music album or playlist with YouTube-provided tags
|
|
477
|
+
spotifysaver download "https://music.youtube.com/playlist?list=..."
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The CLI accepts Spotify tracks, albums, and playlists, and YouTube playlists or album collections. Direct YouTube video URLs are supported by the web interface and API, but not by the CLI. Spotify playlist tracks are saved under their canonical artist/album folders, with playlist files kept separately in a `Playlists/` directory beside the configured output directory. Existing files are skipped by default; set the web interface's overwrite option or the API's `overwrite_existing` field to replace them.
|
|
481
|
+
|
|
482
|
+
## Usage with API
|
|
483
|
+
|
|
484
|
+
To use the API, you need to have the API server running. You can start it with the following command:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
# Start the API server
|
|
488
|
+
spotifysaver-api
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
The server will run at `http://127.0.0.1:8000` by default. The API accepts Spotify track, album, and playlist URLs, as well as direct YouTube video and collection URLs. Active downloads can be cancelled with `POST /api/v1/download/{task_id}/cancel`. You can find the [API documentation here](API_IMPLEMENTATION_SUMMARY.md), which describes the technical aspects and usage in detail.
|
|
492
|
+
|
|
493
|
+
## 🖥️ Web Interface (UI)
|
|
494
|
+
|
|
495
|
+
Start the API server with web interface
|
|
496
|
+
```bash
|
|
497
|
+
spotifysaver-api
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
This will start the API server with an integrated web interface.
|
|
501
|
+
You can access at `http://127.0.0.1:8000` from the same machine or replace by your target ip or reverse-proxy address.
|
|
502
|
+
|
|
503
|
+
**Default Access:** (replace by your)
|
|
504
|
+
- Web Interface & API: `http://{address}:8000`
|
|
505
|
+
- API Documentation: `http://{address}:8000/docs`
|
|
506
|
+
|
|
507
|
+
The web interface and API **require an administrator password**. On first startup,
|
|
508
|
+
the server logs a one-time setup token; enter it in the browser to create the
|
|
509
|
+
password. Store and protect the server's configuration directory because it
|
|
510
|
+
contains the password hash, Spotify credentials, and authorization tokens.
|
|
511
|
+
Use **HTTPS** for remote access.
|
|
512
|
+
|
|
513
|
+
In **Settings → Backup & Restore**, download a JSON configuration backup before
|
|
514
|
+
migrating or reinstalling. The file includes watched channel URLs and server
|
|
515
|
+
paths, so keep it private. Restoring replaces the included settings on the
|
|
516
|
+
current instance. Passwords, Jellyfin API keys, Spotify client secrets, and
|
|
517
|
+
Spotify authorization tokens, active downloads, per-video watcher history, and
|
|
518
|
+
activity logs are not transferred; re-enter secrets and reconnect Spotify on
|
|
519
|
+
the destination if needed. Review media folder paths after restoring because
|
|
520
|
+
host and container paths can differ.
|
|
521
|
+
|
|
522
|
+
## 📂 Output Structure
|
|
523
|
+
```
|
|
524
|
+
.
|
|
525
|
+
├── Music/
|
|
526
|
+
│ ├── Artist/
|
|
527
|
+
│ │ └── Album (Year)/
|
|
528
|
+
│ │ ├── 01 - Song.mp3
|
|
529
|
+
│ │ ├── 01 - Song.lrc
|
|
530
|
+
│ │ ├── album.nfo
|
|
531
|
+
│ │ └── cover.jpg
|
|
532
|
+
│ └── YouTube/
|
|
533
|
+
│ └── Collection Name/
|
|
534
|
+
│ └── 01 - Video Title.mp3
|
|
535
|
+
├── Videos/
|
|
536
|
+
│ └── Channel Name/
|
|
537
|
+
│ └── Video Title.mp4
|
|
538
|
+
└── Playlists/
|
|
539
|
+
└── Playlist Name/
|
|
540
|
+
└── Playlist Name.m3u
|
|
541
|
+
```
|
|
542
|
+
Videos are saved under a folder named for the YouTube channel or uploader within
|
|
543
|
+
the selected video folder (default: `Videos`). Playlist video filenames include
|
|
544
|
+
their position in the playlist, such as `01 - Video Title.mp4`.
|
|
545
|
+
|
|
546
|
+
## 🤝 Contributions
|
|
547
|
+
1. Fork the project
|
|
548
|
+
2. Create your branch (`git checkout -b feature/new-feature`)
|
|
549
|
+
3. Commit your changes (`git commit -m 'Add awesome feature'`)
|
|
550
|
+
4. Push to the branch (`git push origin feature/new-feature`)
|
|
551
|
+
5. Open a Pull Request
|
|
552
|
+
|
|
553
|
+
## 📄 License
|
|
554
|
+
|
|
555
|
+
MIT © [TGabriel Baute](https://github.com/gabrielbaute)
|
|
556
|
+
|