trackfetch 2.0.0__tar.gz → 2.2.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trackfetch
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Turn a text file of songs into tagged MP3s: Spotify metadata and cover art, best-match YouTube audio via yt-dlp.
5
5
  Author: ByteMe6
6
6
  License-Expression: GPL-3.0-or-later
@@ -30,20 +30,21 @@ Requires-Dist: pytest-cov>=5; extra == "test"
30
30
  Dynamic: license-file
31
31
 
32
32
  <picture>
33
- <source media="(prefers-color-scheme: dark)" srcset=".github/assets/banner-dark.svg">
34
- <img alt="trackfetch: a text file of songs in, tagged MP3s with cover art out" src=".github/assets/banner-light.svg" width="100%">
33
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ByteMe6/trackfetch/master/.github/assets/banner-dark.svg">
34
+ <img alt="trackfetch: a text file of songs in, tagged MP3s with cover art out" src="https://raw.githubusercontent.com/ByteMe6/trackfetch/master/.github/assets/banner-light.svg" width="100%">
35
35
  </picture>
36
36
 
37
37
  <p align="center">
38
38
  <a href="https://github.com/ByteMe6/trackfetch/releases/latest"><img alt="Latest release" src="https://img.shields.io/github/v/release/ByteMe6/trackfetch?style=flat-square&label=release&labelColor=15122B&color=FFB547"></a>
39
+ <a href="https://pypi.org/project/trackfetch/"><img alt="PyPI" src="https://img.shields.io/pypi/v/trackfetch?style=flat-square&label=pypi&labelColor=15122B&color=FFB547"></a>
39
40
  <a href="https://github.com/ByteMe6/trackfetch/actions/workflows/release.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/ByteMe6/trackfetch/release.yml?branch=master&style=flat-square&label=build&labelColor=15122B"></a>
40
41
  <a href="#install"><img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-FFB547?style=flat-square&labelColor=15122B"></a>
41
42
  <a href="#standalone-binary"><img alt="Linux, macOS and Windows on x86_64 and ARM64" src="https://img.shields.io/badge/linux%20%C2%B7%20macos%20%C2%B7%20windows-x86__64%20%2B%20arm64-FFB547?style=flat-square&labelColor=15122B"></a>
42
- <a href="LICENSE"><img alt="License: GPL-3.0-or-later" src="https://img.shields.io/badge/license-GPL--3.0--or--later-FFB547?style=flat-square&labelColor=15122B"></a>
43
+ <a href="https://github.com/ByteMe6/trackfetch/blob/master/LICENSE"><img alt="License: GPL-3.0-or-later" src="https://img.shields.io/badge/license-GPL--3.0--or--later-FFB547?style=flat-square&labelColor=15122B"></a>
43
44
  </p>
44
45
 
45
46
  <p align="center">
46
- <b>English</b> · <a href="README.uk.md">Українська</a> · <a href="README.ru.md">Русский</a>
47
+ <b>English</b> · <a href="https://github.com/ByteMe6/trackfetch/blob/master/README.uk.md">Українська</a> · <a href="https://github.com/ByteMe6/trackfetch/blob/master/README.ru.md">Русский</a>
47
48
  </p>
48
49
 
49
50
  <p align="center">
@@ -57,7 +58,7 @@ Dynamic: license-file
57
58
 
58
59
  <br>
59
60
 
60
- <img alt="Terminal recording: trackfetch skips two songs that are already downloaded, finds Daft Punk - One More Time on Spotify, scores five YouTube results, downloads the best one and saves a tagged MP3" src=".github/assets/demo.svg" width="100%">
61
+ <img alt="Terminal recording: trackfetch skips two songs that are already downloaded, finds Daft Punk - One More Time on Spotify, scores five YouTube results, downloads the best one and saves a tagged MP3" src="https://raw.githubusercontent.com/ByteMe6/trackfetch/master/.github/assets/demo.svg" width="100%">
61
62
 
62
63
  <br>
63
64
 
@@ -66,7 +67,7 @@ trackfetch reads a plain text file with one `Artist - Title` per line. For every
66
67
  - **Exact metadata.** The title, every credited artist, album, album artist, track number and release date come from Spotify, not from a YouTube video title.
67
68
  - **Album art.** The largest Spotify cover is embedded in every file.
68
69
  - **The right upload.** trackfetch scores five YouTube results per song. Official audio wins; covers, karaoke, nightcore, sped-up, slowed, remix and reaction videos lose.
69
- - **Best quality.** yt-dlp extracts the audio as the highest-quality VBR MP3.
70
+ - **Your choice of format.** MP3 for any player, or Opus and M4A that keep YouTube's original audio without re-encoding.
70
71
  - **Resumable.** Finished songs are logged in `done.txt` and skipped next time. Failures go to `failed.txt` with the reason.
71
72
  - **Plays everywhere.** Tags are written as ID3v2.3, which Windows Explorer, Apple Music, Android, car stereos and most other players read.
72
73
  - **Any alphabet.** Cyrillic and other non-Latin titles are matched correctly and kept in filenames. Characters that are illegal in filenames are replaced.
@@ -74,13 +75,32 @@ trackfetch reads a plain text file with one `Artist - Title` per line. For every
74
75
 
75
76
  ## Install
76
77
 
77
- trackfetch needs these tools on your `PATH`, plus a free Spotify API key ([set it up below](#spotify-credentials)):
78
+ Pick one. Homebrew and Nix also install yt-dlp, FFmpeg and Deno for you; with the other methods, install them yourself ([see below](#dependencies)). Every method needs a free Spotify API key ([set it up below](#spotify-credentials)).
78
79
 
79
- | Tool | Used for | Install |
80
- | --- | --- | --- |
81
- | [yt-dlp](https://github.com/yt-dlp/yt-dlp) | Searching and downloading from YouTube | `pipx install yt-dlp` · `brew install yt-dlp` · `winget install yt-dlp` |
82
- | [FFmpeg](https://ffmpeg.org/) | Converting the audio to MP3 | `sudo apt install ffmpeg` · `brew install ffmpeg` · `winget install ffmpeg` |
83
- | [Deno](https://deno.com/) | JavaScript runtime that yt-dlp needs for YouTube | `curl -fsSL https://deno.land/install.sh \| sh` · `brew install deno` · `winget install DenoLand.Deno` |
80
+ ### Homebrew
81
+
82
+ macOS and Linux:
83
+
84
+ ```bash
85
+ brew install ByteMe6/tap/trackfetch
86
+ ```
87
+
88
+ On Intel Macs, Homebrew builds the dependencies from source, so the first install takes a while.
89
+
90
+ ### Nix
91
+
92
+ Linux and Apple Silicon Macs, with flakes enabled:
93
+
94
+ ```bash
95
+ nix run github:ByteMe6/trackfetch -- songs.txt # run without installing
96
+ nix profile install github:ByteMe6/trackfetch # install
97
+ ```
98
+
99
+ ### pipx
100
+
101
+ ```bash
102
+ pipx install trackfetch
103
+ ```
84
104
 
85
105
  ### Standalone binary
86
106
 
@@ -101,12 +121,6 @@ sudo mv trackfetch-linux-x86_64 /usr/local/bin/trackfetch
101
121
 
102
122
  On macOS, if Gatekeeper blocks the unsigned binary, run `xattr -d com.apple.quarantine trackfetch-macos-*` once. Checksums are in `SHA256SUMS.txt` on each release.
103
123
 
104
- ### pipx
105
-
106
- ```bash
107
- pipx install git+https://github.com/ByteMe6/trackfetch.git
108
- ```
109
-
110
124
  ### From source
111
125
 
112
126
  ```bash
@@ -116,6 +130,16 @@ python -m venv .venv && source .venv/bin/activate
116
130
  pip install -e .
117
131
  ```
118
132
 
133
+ ### Dependencies
134
+
135
+ With pipx, a standalone binary or a source install, put these on your `PATH`:
136
+
137
+ | Tool | Used for | Install |
138
+ | --- | --- | --- |
139
+ | [yt-dlp](https://github.com/yt-dlp/yt-dlp) | Searching and downloading from YouTube | `pipx install yt-dlp` · `brew install yt-dlp` · `winget install yt-dlp` |
140
+ | [FFmpeg](https://ffmpeg.org/) | Converting the audio to MP3 | `sudo apt install ffmpeg` · `brew install ffmpeg` · `winget install ffmpeg` |
141
+ | [Deno](https://deno.com/) | JavaScript runtime that yt-dlp needs for YouTube | `curl -fsSL https://deno.land/install.sh \| sh` · `brew install deno` · `winget install DenoLand.Deno` |
142
+
119
143
  ## Spotify credentials
120
144
 
121
145
  trackfetch uses Spotify's Client Credentials flow: no Spotify login, no access to your account.
@@ -171,7 +195,7 @@ EOF
171
195
  trackfetch songs.txt
172
196
  ```
173
197
 
174
- The files land in `~/Music/trackfetch/`.
198
+ The files land in the current directory.
175
199
 
176
200
  ## Playlists from streaming services
177
201
 
@@ -189,22 +213,90 @@ trackfetch "My Playlist.txt" -o ~/Music/"My Playlist"
189
213
  ## Usage
190
214
 
191
215
  ```text
192
- trackfetch [-h] [-o OUTPUT] [--title-only] [--delay DELAY] input
216
+ trackfetch [-h] [-o OUTPUT] [--config CONFIG] [-f {mp3,m4a,opus}] [--title-only] [--delay DELAY] [--spotify-client-id ID] [--spotify-client-secret SECRET] [input]
193
217
  ```
194
218
 
195
219
  | Option | Default | What it does |
196
220
  | --- | --- | --- |
197
- | `input` | required | Text file with one `Artist - Title` per line |
198
- | `-o`, `--output` | `~/Music/trackfetch` | Folder to save the MP3s in. It's created if it doesn't exist. |
199
- | `--title-only` | off | Name files `Title.mp3` instead of `Artist - Title.mp3` |
221
+ | `input` | required | Text file with one `Artist - Title` per line. Can also be set in the [config file](#configuration-file). |
222
+ | `-o`, `--output` | current directory | Folder to save the files in. It's created if it doesn't exist. |
223
+ | `--config` | auto-detected | Path to a [config file](#configuration-file). |
224
+ | `-f`, `--format` | `m4a` | Audio format: `mp3`, `m4a` or `opus`. See [Audio formats](#audio-formats). |
225
+ | `--title-only` | off | Name files `Title.m4a` instead of `Artist - Title.m4a` |
200
226
  | `--delay` | `1.0` | Seconds to wait between songs. Raise it for long lists. |
227
+ | `--spotify-client-id` | `$SPOTIFY_CLIENT_ID` | Spotify API client ID. See [Spotify credentials](#spotify-credentials). |
228
+ | `--spotify-client-secret` | `$SPOTIFY_CLIENT_SECRET` | Spotify API client secret. |
201
229
 
202
230
  ```bash
203
231
  trackfetch songs.txt -o ~/Music/RoadTrip # save to a specific folder
204
232
  trackfetch songs.txt -o /media/usb --title-only # short names for a car stereo
205
233
  trackfetch big-list.txt --delay 3 # go easy on rate limits
234
+ trackfetch songs.txt --format opus # original YouTube audio, no re-encode
235
+ ```
236
+
237
+ ### Configuration file
238
+
239
+ Put your defaults in an INI file and forget the flags:
240
+
241
+ ```ini
242
+ [trackfetch]
243
+ output = ~/Music/trackfetch
244
+ format = m4a
245
+ title_only = false
246
+ delay = 1.0
247
+ input = ~/songs.txt
248
+ spotify_client_id = your-client-id
249
+ spotify_client_secret = your-client-secret
206
250
  ```
207
251
 
252
+ Every option above can be set there, under the `[trackfetch]` section. The
253
+ precedence is always the same:
254
+
255
+ 1. the command-line flag,
256
+ 2. the config file,
257
+ 3. the built-in default (the current directory for the output folder).
258
+
259
+ trackfetch looks for the config file in this order: the path given with
260
+ `--config`, the path in `$TRACKFETCH_CONFIG`, `trackfetch.ini` in the current
261
+ directory, `$XDG_CONFIG_HOME/trackfetch/trackfetch.ini` (usually
262
+ `~/.config/trackfetch/trackfetch.ini`) and `~/.trackfetch.ini`.
263
+
264
+ ### Spotify credentials
265
+
266
+ trackfetch needs a Spotify client ID and secret to read the metadata. Give
267
+ them in whichever way suits you:
268
+
269
+ ```bash
270
+ # in the config file
271
+ [trackfetch]
272
+ spotify_client_id = your-client-id
273
+ spotify_client_secret = your-client-secret
274
+ ```
275
+
276
+ ```bash
277
+ # in the environment
278
+ export SPOTIFY_CLIENT_ID='your-client-id'
279
+ export SPOTIFY_CLIENT_SECRET='your-client-secret'
280
+ ```
281
+
282
+ ```bash
283
+ # on the command line
284
+ trackfetch songs.txt --spotify-client-id your-id --spotify-client-secret your-secret
285
+ ```
286
+
287
+ The flag wins over the config file, and the config file wins over the
288
+ environment variable.
289
+
290
+ ### Audio formats
291
+
292
+ | Format | What you get | Plays on |
293
+ | --- | --- | --- |
294
+ | `m4a` (default) | YouTube's **original** AAC audio when available, copied without re-encoding | Apple devices, iTunes, most players |
295
+ | `opus` | YouTube's **original** Opus audio, copied without re-encoding. The best quality you can get | most modern players, Android, browsers; not iTunes or older devices |
296
+ | `mp3` | YouTube's audio **re-encoded** to the best VBR MP3. A second lossy encode, so slightly below the source | everything, including old players and car stereos |
297
+
298
+ All three get the same tags and embedded cover art. `done.txt` doesn't track the format, so use a separate `-o` folder for each format.
299
+
208
300
  ### Input file
209
301
 
210
302
  ```text
@@ -213,14 +305,14 @@ Daft Punk - One More Time
213
305
  Sufjan Stevens - Mystery of Love - Remastered ← only the first " - " separates artist and title
214
306
  ```
215
307
 
216
- The separator is space, hyphen, space (` - `). Lines without it are skipped. See [`examples/songs.txt`](examples/songs.txt).
308
+ The separator is space, hyphen, space (` - `). Lines without it are skipped. See [`examples/songs.txt`](https://github.com/ByteMe6/trackfetch/blob/master/examples/songs.txt).
217
309
 
218
310
  ### Output folder
219
311
 
220
312
  ```text
221
- ~/Music/trackfetch/
222
- ├── Daft Punk - One More Time.mp3
223
- ├── Radiohead - Paranoid Android.mp3
313
+ ./
314
+ ├── Daft Punk - One More Time.m4a
315
+ ├── Radiohead - Paranoid Android.m4a
224
316
  ├── done.txt ← finished songs, skipped on the next run
225
317
  └── failed.txt ← "Artist - Title | reason" for each song that failed
226
318
  ```
@@ -228,7 +320,7 @@ The separator is space, hyphen, space (` - `). Lines without it are skipped. See
228
320
  **Retry failures** by stripping the reasons from `failed.txt` and running it again:
229
321
 
230
322
  ```bash
231
- cut -d '|' -f 1 ~/Music/trackfetch/failed.txt > retry.txt
323
+ cut -d '|' -f 1 ./failed.txt > retry.txt
232
324
  trackfetch retry.txt
233
325
  ```
234
326
 
@@ -236,7 +328,7 @@ trackfetch retry.txt
236
328
 
237
329
  ### Cheat sheet
238
330
 
239
- A [tldr](https://tldr.sh/) page is in [`docs/tldr/trackfetch.md`](docs/tldr/trackfetch.md). To use it with [tealdeer](https://github.com/tealdeer-rs/tealdeer), copy it into your custom pages folder as `trackfetch.page.md`.
331
+ A [tldr](https://tldr.sh/) page is in [`docs/tldr/trackfetch.md`](https://github.com/ByteMe6/trackfetch/blob/master/docs/tldr/trackfetch.md). To use it with [tealdeer](https://github.com/tealdeer-rs/tealdeer), copy it into your custom pages folder as `trackfetch.page.md`.
240
332
 
241
333
  ## How it works
242
334
 
@@ -313,11 +405,11 @@ pytest --cov=trackfetch
313
405
 
314
406
  The tests stub every network and subprocess call, so they run offline in under a second. To build a standalone binary yourself, run `pip install pyinstaller && pyinstaller trackfetch.spec`; it ends up in `dist/`.
315
407
 
316
- See [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.
408
+ See [CONTRIBUTING.md](https://github.com/ByteMe6/trackfetch/blob/master/CONTRIBUTING.md) before opening a pull request.
317
409
 
318
410
  ### Releasing
319
411
 
320
- Every push to `master` runs the tests on Linux, macOS and Windows. When `version` in [`pyproject.toml`](pyproject.toml) has no matching `vX.Y.Z` tag yet, the [Build & Release](.github/workflows/release.yml) workflow also builds all six binaries and publishes a release, using that version's section of [`CHANGELOG.md`](CHANGELOG.md) as the notes.
412
+ Every push to `master` runs the tests on Linux, macOS and Windows. When `version` in [`pyproject.toml`](https://github.com/ByteMe6/trackfetch/blob/master/pyproject.toml) has no matching `vX.Y.Z` tag yet, the [Build & Release](https://github.com/ByteMe6/trackfetch/blob/master/.github/workflows/release.yml) workflow also builds all six binaries and publishes a release, using that version's section of [`CHANGELOG.md`](https://github.com/ByteMe6/trackfetch/blob/master/CHANGELOG.md) as the notes.
321
413
 
322
414
  To release, move the changes under `[Unreleased]` in the changelog to a new `## [X.Y.Z] - YYYY-MM-DD` section, bump `version`, and push.
323
415
 
@@ -330,4 +422,4 @@ trackfetch is for personal use with content you have the right to download. You
330
422
 
331
423
  ## License
332
424
 
333
- trackfetch is free software, released under the [GNU General Public License v3.0 or later](LICENSE). You can use, study, change and share it. If you distribute a modified version, it must stay under the same license.
425
+ trackfetch is free software, released under the [GNU General Public License v3.0 or later](https://github.com/ByteMe6/trackfetch/blob/master/LICENSE). You can use, study, change and share it. If you distribute a modified version, it must stay under the same license.
@@ -1,18 +1,19 @@
1
1
  <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset=".github/assets/banner-dark.svg">
3
- <img alt="trackfetch: a text file of songs in, tagged MP3s with cover art out" src=".github/assets/banner-light.svg" width="100%">
2
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ByteMe6/trackfetch/master/.github/assets/banner-dark.svg">
3
+ <img alt="trackfetch: a text file of songs in, tagged MP3s with cover art out" src="https://raw.githubusercontent.com/ByteMe6/trackfetch/master/.github/assets/banner-light.svg" width="100%">
4
4
  </picture>
5
5
 
6
6
  <p align="center">
7
7
  <a href="https://github.com/ByteMe6/trackfetch/releases/latest"><img alt="Latest release" src="https://img.shields.io/github/v/release/ByteMe6/trackfetch?style=flat-square&label=release&labelColor=15122B&color=FFB547"></a>
8
+ <a href="https://pypi.org/project/trackfetch/"><img alt="PyPI" src="https://img.shields.io/pypi/v/trackfetch?style=flat-square&label=pypi&labelColor=15122B&color=FFB547"></a>
8
9
  <a href="https://github.com/ByteMe6/trackfetch/actions/workflows/release.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/ByteMe6/trackfetch/release.yml?branch=master&style=flat-square&label=build&labelColor=15122B"></a>
9
10
  <a href="#install"><img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-FFB547?style=flat-square&labelColor=15122B"></a>
10
11
  <a href="#standalone-binary"><img alt="Linux, macOS and Windows on x86_64 and ARM64" src="https://img.shields.io/badge/linux%20%C2%B7%20macos%20%C2%B7%20windows-x86__64%20%2B%20arm64-FFB547?style=flat-square&labelColor=15122B"></a>
11
- <a href="LICENSE"><img alt="License: GPL-3.0-or-later" src="https://img.shields.io/badge/license-GPL--3.0--or--later-FFB547?style=flat-square&labelColor=15122B"></a>
12
+ <a href="https://github.com/ByteMe6/trackfetch/blob/master/LICENSE"><img alt="License: GPL-3.0-or-later" src="https://img.shields.io/badge/license-GPL--3.0--or--later-FFB547?style=flat-square&labelColor=15122B"></a>
12
13
  </p>
13
14
 
14
15
  <p align="center">
15
- <b>English</b> · <a href="README.uk.md">Українська</a> · <a href="README.ru.md">Русский</a>
16
+ <b>English</b> · <a href="https://github.com/ByteMe6/trackfetch/blob/master/README.uk.md">Українська</a> · <a href="https://github.com/ByteMe6/trackfetch/blob/master/README.ru.md">Русский</a>
16
17
  </p>
17
18
 
18
19
  <p align="center">
@@ -26,7 +27,7 @@
26
27
 
27
28
  <br>
28
29
 
29
- <img alt="Terminal recording: trackfetch skips two songs that are already downloaded, finds Daft Punk - One More Time on Spotify, scores five YouTube results, downloads the best one and saves a tagged MP3" src=".github/assets/demo.svg" width="100%">
30
+ <img alt="Terminal recording: trackfetch skips two songs that are already downloaded, finds Daft Punk - One More Time on Spotify, scores five YouTube results, downloads the best one and saves a tagged MP3" src="https://raw.githubusercontent.com/ByteMe6/trackfetch/master/.github/assets/demo.svg" width="100%">
30
31
 
31
32
  <br>
32
33
 
@@ -35,7 +36,7 @@ trackfetch reads a plain text file with one `Artist - Title` per line. For every
35
36
  - **Exact metadata.** The title, every credited artist, album, album artist, track number and release date come from Spotify, not from a YouTube video title.
36
37
  - **Album art.** The largest Spotify cover is embedded in every file.
37
38
  - **The right upload.** trackfetch scores five YouTube results per song. Official audio wins; covers, karaoke, nightcore, sped-up, slowed, remix and reaction videos lose.
38
- - **Best quality.** yt-dlp extracts the audio as the highest-quality VBR MP3.
39
+ - **Your choice of format.** MP3 for any player, or Opus and M4A that keep YouTube's original audio without re-encoding.
39
40
  - **Resumable.** Finished songs are logged in `done.txt` and skipped next time. Failures go to `failed.txt` with the reason.
40
41
  - **Plays everywhere.** Tags are written as ID3v2.3, which Windows Explorer, Apple Music, Android, car stereos and most other players read.
41
42
  - **Any alphabet.** Cyrillic and other non-Latin titles are matched correctly and kept in filenames. Characters that are illegal in filenames are replaced.
@@ -43,13 +44,32 @@ trackfetch reads a plain text file with one `Artist - Title` per line. For every
43
44
 
44
45
  ## Install
45
46
 
46
- trackfetch needs these tools on your `PATH`, plus a free Spotify API key ([set it up below](#spotify-credentials)):
47
+ Pick one. Homebrew and Nix also install yt-dlp, FFmpeg and Deno for you; with the other methods, install them yourself ([see below](#dependencies)). Every method needs a free Spotify API key ([set it up below](#spotify-credentials)).
47
48
 
48
- | Tool | Used for | Install |
49
- | --- | --- | --- |
50
- | [yt-dlp](https://github.com/yt-dlp/yt-dlp) | Searching and downloading from YouTube | `pipx install yt-dlp` · `brew install yt-dlp` · `winget install yt-dlp` |
51
- | [FFmpeg](https://ffmpeg.org/) | Converting the audio to MP3 | `sudo apt install ffmpeg` · `brew install ffmpeg` · `winget install ffmpeg` |
52
- | [Deno](https://deno.com/) | JavaScript runtime that yt-dlp needs for YouTube | `curl -fsSL https://deno.land/install.sh \| sh` · `brew install deno` · `winget install DenoLand.Deno` |
49
+ ### Homebrew
50
+
51
+ macOS and Linux:
52
+
53
+ ```bash
54
+ brew install ByteMe6/tap/trackfetch
55
+ ```
56
+
57
+ On Intel Macs, Homebrew builds the dependencies from source, so the first install takes a while.
58
+
59
+ ### Nix
60
+
61
+ Linux and Apple Silicon Macs, with flakes enabled:
62
+
63
+ ```bash
64
+ nix run github:ByteMe6/trackfetch -- songs.txt # run without installing
65
+ nix profile install github:ByteMe6/trackfetch # install
66
+ ```
67
+
68
+ ### pipx
69
+
70
+ ```bash
71
+ pipx install trackfetch
72
+ ```
53
73
 
54
74
  ### Standalone binary
55
75
 
@@ -70,12 +90,6 @@ sudo mv trackfetch-linux-x86_64 /usr/local/bin/trackfetch
70
90
 
71
91
  On macOS, if Gatekeeper blocks the unsigned binary, run `xattr -d com.apple.quarantine trackfetch-macos-*` once. Checksums are in `SHA256SUMS.txt` on each release.
72
92
 
73
- ### pipx
74
-
75
- ```bash
76
- pipx install git+https://github.com/ByteMe6/trackfetch.git
77
- ```
78
-
79
93
  ### From source
80
94
 
81
95
  ```bash
@@ -85,6 +99,16 @@ python -m venv .venv && source .venv/bin/activate
85
99
  pip install -e .
86
100
  ```
87
101
 
102
+ ### Dependencies
103
+
104
+ With pipx, a standalone binary or a source install, put these on your `PATH`:
105
+
106
+ | Tool | Used for | Install |
107
+ | --- | --- | --- |
108
+ | [yt-dlp](https://github.com/yt-dlp/yt-dlp) | Searching and downloading from YouTube | `pipx install yt-dlp` · `brew install yt-dlp` · `winget install yt-dlp` |
109
+ | [FFmpeg](https://ffmpeg.org/) | Converting the audio to MP3 | `sudo apt install ffmpeg` · `brew install ffmpeg` · `winget install ffmpeg` |
110
+ | [Deno](https://deno.com/) | JavaScript runtime that yt-dlp needs for YouTube | `curl -fsSL https://deno.land/install.sh \| sh` · `brew install deno` · `winget install DenoLand.Deno` |
111
+
88
112
  ## Spotify credentials
89
113
 
90
114
  trackfetch uses Spotify's Client Credentials flow: no Spotify login, no access to your account.
@@ -140,7 +164,7 @@ EOF
140
164
  trackfetch songs.txt
141
165
  ```
142
166
 
143
- The files land in `~/Music/trackfetch/`.
167
+ The files land in the current directory.
144
168
 
145
169
  ## Playlists from streaming services
146
170
 
@@ -158,22 +182,90 @@ trackfetch "My Playlist.txt" -o ~/Music/"My Playlist"
158
182
  ## Usage
159
183
 
160
184
  ```text
161
- trackfetch [-h] [-o OUTPUT] [--title-only] [--delay DELAY] input
185
+ trackfetch [-h] [-o OUTPUT] [--config CONFIG] [-f {mp3,m4a,opus}] [--title-only] [--delay DELAY] [--spotify-client-id ID] [--spotify-client-secret SECRET] [input]
162
186
  ```
163
187
 
164
188
  | Option | Default | What it does |
165
189
  | --- | --- | --- |
166
- | `input` | required | Text file with one `Artist - Title` per line |
167
- | `-o`, `--output` | `~/Music/trackfetch` | Folder to save the MP3s in. It's created if it doesn't exist. |
168
- | `--title-only` | off | Name files `Title.mp3` instead of `Artist - Title.mp3` |
190
+ | `input` | required | Text file with one `Artist - Title` per line. Can also be set in the [config file](#configuration-file). |
191
+ | `-o`, `--output` | current directory | Folder to save the files in. It's created if it doesn't exist. |
192
+ | `--config` | auto-detected | Path to a [config file](#configuration-file). |
193
+ | `-f`, `--format` | `m4a` | Audio format: `mp3`, `m4a` or `opus`. See [Audio formats](#audio-formats). |
194
+ | `--title-only` | off | Name files `Title.m4a` instead of `Artist - Title.m4a` |
169
195
  | `--delay` | `1.0` | Seconds to wait between songs. Raise it for long lists. |
196
+ | `--spotify-client-id` | `$SPOTIFY_CLIENT_ID` | Spotify API client ID. See [Spotify credentials](#spotify-credentials). |
197
+ | `--spotify-client-secret` | `$SPOTIFY_CLIENT_SECRET` | Spotify API client secret. |
170
198
 
171
199
  ```bash
172
200
  trackfetch songs.txt -o ~/Music/RoadTrip # save to a specific folder
173
201
  trackfetch songs.txt -o /media/usb --title-only # short names for a car stereo
174
202
  trackfetch big-list.txt --delay 3 # go easy on rate limits
203
+ trackfetch songs.txt --format opus # original YouTube audio, no re-encode
204
+ ```
205
+
206
+ ### Configuration file
207
+
208
+ Put your defaults in an INI file and forget the flags:
209
+
210
+ ```ini
211
+ [trackfetch]
212
+ output = ~/Music/trackfetch
213
+ format = m4a
214
+ title_only = false
215
+ delay = 1.0
216
+ input = ~/songs.txt
217
+ spotify_client_id = your-client-id
218
+ spotify_client_secret = your-client-secret
175
219
  ```
176
220
 
221
+ Every option above can be set there, under the `[trackfetch]` section. The
222
+ precedence is always the same:
223
+
224
+ 1. the command-line flag,
225
+ 2. the config file,
226
+ 3. the built-in default (the current directory for the output folder).
227
+
228
+ trackfetch looks for the config file in this order: the path given with
229
+ `--config`, the path in `$TRACKFETCH_CONFIG`, `trackfetch.ini` in the current
230
+ directory, `$XDG_CONFIG_HOME/trackfetch/trackfetch.ini` (usually
231
+ `~/.config/trackfetch/trackfetch.ini`) and `~/.trackfetch.ini`.
232
+
233
+ ### Spotify credentials
234
+
235
+ trackfetch needs a Spotify client ID and secret to read the metadata. Give
236
+ them in whichever way suits you:
237
+
238
+ ```bash
239
+ # in the config file
240
+ [trackfetch]
241
+ spotify_client_id = your-client-id
242
+ spotify_client_secret = your-client-secret
243
+ ```
244
+
245
+ ```bash
246
+ # in the environment
247
+ export SPOTIFY_CLIENT_ID='your-client-id'
248
+ export SPOTIFY_CLIENT_SECRET='your-client-secret'
249
+ ```
250
+
251
+ ```bash
252
+ # on the command line
253
+ trackfetch songs.txt --spotify-client-id your-id --spotify-client-secret your-secret
254
+ ```
255
+
256
+ The flag wins over the config file, and the config file wins over the
257
+ environment variable.
258
+
259
+ ### Audio formats
260
+
261
+ | Format | What you get | Plays on |
262
+ | --- | --- | --- |
263
+ | `m4a` (default) | YouTube's **original** AAC audio when available, copied without re-encoding | Apple devices, iTunes, most players |
264
+ | `opus` | YouTube's **original** Opus audio, copied without re-encoding. The best quality you can get | most modern players, Android, browsers; not iTunes or older devices |
265
+ | `mp3` | YouTube's audio **re-encoded** to the best VBR MP3. A second lossy encode, so slightly below the source | everything, including old players and car stereos |
266
+
267
+ All three get the same tags and embedded cover art. `done.txt` doesn't track the format, so use a separate `-o` folder for each format.
268
+
177
269
  ### Input file
178
270
 
179
271
  ```text
@@ -182,14 +274,14 @@ Daft Punk - One More Time
182
274
  Sufjan Stevens - Mystery of Love - Remastered ← only the first " - " separates artist and title
183
275
  ```
184
276
 
185
- The separator is space, hyphen, space (` - `). Lines without it are skipped. See [`examples/songs.txt`](examples/songs.txt).
277
+ The separator is space, hyphen, space (` - `). Lines without it are skipped. See [`examples/songs.txt`](https://github.com/ByteMe6/trackfetch/blob/master/examples/songs.txt).
186
278
 
187
279
  ### Output folder
188
280
 
189
281
  ```text
190
- ~/Music/trackfetch/
191
- ├── Daft Punk - One More Time.mp3
192
- ├── Radiohead - Paranoid Android.mp3
282
+ ./
283
+ ├── Daft Punk - One More Time.m4a
284
+ ├── Radiohead - Paranoid Android.m4a
193
285
  ├── done.txt ← finished songs, skipped on the next run
194
286
  └── failed.txt ← "Artist - Title | reason" for each song that failed
195
287
  ```
@@ -197,7 +289,7 @@ The separator is space, hyphen, space (` - `). Lines without it are skipped. See
197
289
  **Retry failures** by stripping the reasons from `failed.txt` and running it again:
198
290
 
199
291
  ```bash
200
- cut -d '|' -f 1 ~/Music/trackfetch/failed.txt > retry.txt
292
+ cut -d '|' -f 1 ./failed.txt > retry.txt
201
293
  trackfetch retry.txt
202
294
  ```
203
295
 
@@ -205,7 +297,7 @@ trackfetch retry.txt
205
297
 
206
298
  ### Cheat sheet
207
299
 
208
- A [tldr](https://tldr.sh/) page is in [`docs/tldr/trackfetch.md`](docs/tldr/trackfetch.md). To use it with [tealdeer](https://github.com/tealdeer-rs/tealdeer), copy it into your custom pages folder as `trackfetch.page.md`.
300
+ A [tldr](https://tldr.sh/) page is in [`docs/tldr/trackfetch.md`](https://github.com/ByteMe6/trackfetch/blob/master/docs/tldr/trackfetch.md). To use it with [tealdeer](https://github.com/tealdeer-rs/tealdeer), copy it into your custom pages folder as `trackfetch.page.md`.
209
301
 
210
302
  ## How it works
211
303
 
@@ -282,11 +374,11 @@ pytest --cov=trackfetch
282
374
 
283
375
  The tests stub every network and subprocess call, so they run offline in under a second. To build a standalone binary yourself, run `pip install pyinstaller && pyinstaller trackfetch.spec`; it ends up in `dist/`.
284
376
 
285
- See [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.
377
+ See [CONTRIBUTING.md](https://github.com/ByteMe6/trackfetch/blob/master/CONTRIBUTING.md) before opening a pull request.
286
378
 
287
379
  ### Releasing
288
380
 
289
- Every push to `master` runs the tests on Linux, macOS and Windows. When `version` in [`pyproject.toml`](pyproject.toml) has no matching `vX.Y.Z` tag yet, the [Build & Release](.github/workflows/release.yml) workflow also builds all six binaries and publishes a release, using that version's section of [`CHANGELOG.md`](CHANGELOG.md) as the notes.
381
+ Every push to `master` runs the tests on Linux, macOS and Windows. When `version` in [`pyproject.toml`](https://github.com/ByteMe6/trackfetch/blob/master/pyproject.toml) has no matching `vX.Y.Z` tag yet, the [Build & Release](https://github.com/ByteMe6/trackfetch/blob/master/.github/workflows/release.yml) workflow also builds all six binaries and publishes a release, using that version's section of [`CHANGELOG.md`](https://github.com/ByteMe6/trackfetch/blob/master/CHANGELOG.md) as the notes.
290
382
 
291
383
  To release, move the changes under `[Unreleased]` in the changelog to a new `## [X.Y.Z] - YYYY-MM-DD` section, bump `version`, and push.
292
384
 
@@ -299,4 +391,4 @@ trackfetch is for personal use with content you have the right to download. You
299
391
 
300
392
  ## License
301
393
 
302
- trackfetch is free software, released under the [GNU General Public License v3.0 or later](LICENSE). You can use, study, change and share it. If you distribute a modified version, it must stay under the same license.
394
+ trackfetch is free software, released under the [GNU General Public License v3.0 or later](https://github.com/ByteMe6/trackfetch/blob/master/LICENSE). You can use, study, change and share it. If you distribute a modified version, it must stay under the same license.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "trackfetch"
7
- version = "2.0.0"
7
+ version = "2.2.0"
8
8
  description = "Turn a text file of songs into tagged MP3s: Spotify metadata and cover art, best-match YouTube audio via yt-dlp."
9
9
  readme = "README.md"
10
10
  license = "GPL-3.0-or-later"