audiolibrarian 0.16.3__tar.gz → 0.16.4__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.
Files changed (39) hide show
  1. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/.gitignore +2 -0
  2. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/CONTRIBUTING.md +2 -2
  3. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/Makefile +4 -1
  4. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/PKG-INFO +114 -109
  5. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/README.md +113 -108
  6. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/git_hooks/README.md +0 -1
  7. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/pyproject.toml +7 -0
  8. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/__init__.py +1 -1
  9. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/picard_src/README.md +3 -3
  10. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/uv.lock +80 -0
  11. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/.github/workflows/main.yml +0 -0
  12. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/.python-version +0 -0
  13. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/COPYING +0 -0
  14. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/LICENSE +0 -0
  15. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/git_hooks/pre-push +0 -0
  16. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/scripts/update_links.sh +0 -0
  17. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/__init__.py +0 -0
  18. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/audiofile.py +0 -0
  19. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/__init__.py +0 -0
  20. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/flac.py +0 -0
  21. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/m4a.py +0 -0
  22. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/mp3.py +0 -0
  23. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/tags.py +0 -0
  24. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiosource.py +0 -0
  25. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/base.py +0 -0
  26. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/cli.py +0 -0
  27. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/commands.py +0 -0
  28. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/genremanager.py +0 -0
  29. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/musicbrainz.py +0 -0
  30. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/output.py +0 -0
  31. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/records.py +0 -0
  32. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/settings.py +0 -0
  33. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/sh.py +0 -0
  34. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/text.py +0 -0
  35. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/picard_src/__init__.py +0 -0
  36. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/picard_src/textencoding.py +0 -0
  37. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/tools/__init__.py +0 -0
  38. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/tools/diff.py +0 -0
  39. {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/tools/show_tags.py +0 -0
@@ -14,3 +14,5 @@ library/
14
14
  new_library/
15
15
  workdir/
16
16
  venv/
17
+
18
+ NOTES.md
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Git Hooks
4
4
 
5
- The project includes a git_hooks directory with a pre-push hook that verifies that all code is
5
+ The project includes a git_hooks directory with a pre-push hook that verifies that all code is
6
6
  linted and tests pass. To have git use the hooks in this directory, run:
7
7
 
8
8
  ```bash
9
9
  git config core.hooksPath git_hooks
10
- ```
10
+ ```
@@ -4,6 +4,7 @@
4
4
  PRESET_VARS := $(.VARIABLES)
5
5
 
6
6
  # Project variables
7
+ MD_FILES := $(shell find . -name '*.md' | grep -v "/.venv/" | grep -v "/dist/")
7
8
  PROJECT_NAME := $(shell grep -e '^name =' pyproject.toml | cut -d'"' -f2)
8
9
  PY_FILES := $(shell find . -name '*.py' | grep -v "/.venv/" | grep -v "/dist/")
9
10
  PYTHON_VERSION_ := $(shell cat .python-version)
@@ -15,6 +16,7 @@ BROWSER := $(shell command -v chromium || command -v google-chrome-stable || co
15
16
  PYTHON := $(shell command -v python$(PYTHON_VERSION_))
16
17
  UV := $(shell command -v uv)
17
18
  COVERAGE := $(UV) run coverage
19
+ MDLINT := $(UV) run pymarkdownlnt
18
20
  MYPY := $(UV) run mypy
19
21
  PIP := $(UV) pip
20
22
  PYTEST := $(UV) run pytest
@@ -71,6 +73,7 @@ lint: format ## Lint the code.
71
73
  @$(RUFF) format --check src
72
74
  @$(RUFF) check src
73
75
  @$(MYPY) --non-interactive $(PY_FILES)
76
+ @$(MDLINT) scan $(MD_FILES)
74
77
 
75
78
  .PHONY: publish
76
79
  publish: $(WHEEL) ## Publish the package to PyPI.
@@ -107,7 +110,7 @@ ifndef PYTHON_VERSION
107
110
  endif
108
111
  endif
109
112
 
110
- uv.lock:
113
+ uv.lock: pyproject.toml
111
114
  @$(UV) lock
112
115
 
113
116
  $(WHEEL): $(PY_FILES) pyproject.toml uv.lock dep
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: audiolibrarian
3
- Version: 0.16.3
3
+ Version: 0.16.4
4
4
  Summary: Manage my audio library.
5
5
  Project-URL: Repository, https://github.com/toadstule/audiolibrarian
6
6
  Author-email: Steve Jibson <steve@jibson.com>
@@ -27,8 +27,9 @@ Description-Content-Type: text/markdown
27
27
 
28
28
  ## Overview ##
29
29
 
30
- `audiolibrarian` is a powerful command-line tool for managing digital music libraries. It provides a streamlined
31
- workflow for ripping, converting, organizing, and tagging audio files with high-quality metadata from MusicBrainz.
30
+ `audiolibrarian` is a command-line tool for ripping audio from CDs (or taking
31
+ high-quality audio from local files), tagging them with comprehensive metadata from MusicBrainz,
32
+ converting them to multiple formats, and organizing them in a clean directory structure.
32
33
 
33
34
  ### Key Features ###
34
35
 
@@ -45,28 +46,32 @@ workflow for ripping, converting, organizing, and tagging audio files with high-
45
46
  - **Consistent Quality**: Maintains audio quality through the conversion process
46
47
  - **Accurate Metadata**: Leverages MusicBrainz for comprehensive music information
47
48
  - **Automated Workflow**: Reduces manual work in organizing and tagging music
48
- - **Scriptable**: Perfect for automating large music library management tasks
49
49
  - **Open Source**: Free to use and modify under the GPL-3.0 license
50
50
 
51
- Whether you're digitizing a CD collection, organizing existing music files, or managing a large digital library,
52
- `audiolibrarian` provides the tools you need to keep your music collection well-organized and properly tagged.
53
-
51
+ Whether you're digitizing a CD collection, organizing existing music files, or managing a large
52
+ digital library, `audiolibrarian` provides the tools you need to keep your music collection
53
+ well-organized and properly tagged.
54
54
 
55
55
  ## Installation ##
56
56
 
57
+ > **NOTE:** This library has only been tested on Linux. It may not work on other operating
58
+ > systems.
59
+
57
60
  ### External Requirements ###
58
61
 
59
62
  `audiolibrarian` uses a few command-line tools to run:
60
63
 
61
- * `cd-paranoia`: [cd-paranoia](https://www.gnu.org/software/libcdio/)
62
- * `eject`: [util-linux](https://github.com/util-linux/util-linux)
63
- * `faad`: [faad2](https://github.com/knik0/faad2)
64
- * `fdkaac`: [fdkaac](https://github.com/nu774/fdkaac)
65
- * `flac`: [flac](https://github.com/xiph/flac)
66
- * `lame`: [lame](https://lame.sourceforge.io/)
67
- * `mpg123`: [mpg123](https://www.mpg123.de/)
68
- * `sndfile-convert`: [libsndfile](https://github.com/libsndfile/libsndfile)
69
- * `wavegain`: [wavegain](https://rarewares.org/others.php)
64
+ - [cd-paranoia](https://www.gnu.org/software/libcdio/)
65
+ - [util-linux](https://github.com/util-linux/util-linux)
66
+ - [faad2](https://github.com/knik0/faad2)
67
+ - [fdkaac](https://github.com/nu774/fdkaac)
68
+ - [flac](https://github.com/xiph/flac)
69
+ - [lame](https://lame.sourceforge.io/)
70
+ - [mpg123](https://www.mpg123.de/)
71
+ - [libsndfile](https://github.com/libsndfile/libsndfile)
72
+ - [wavegain](https://github.com/MestreLion/wavegain)
73
+
74
+ It also requires the [libdiscid](https://musicbrainz.org/doc/libdiscid) library.
70
75
 
71
76
  ### Install from PyPI ###
72
77
 
@@ -78,38 +83,41 @@ pip install audiolibrarian
78
83
 
79
84
  ## Configuration ##
80
85
 
81
- `audiolibrarian` uses a flexible configuration system that supports multiple configuration sources, listed in order of precedence:
86
+ `audiolibrarian` uses a flexible configuration system that supports multiple configuration sources,
87
+ listed in order of precedence:
82
88
 
83
89
  1. **Environment Variables** (highest precedence)
84
90
  - Prefix: `AUDIOLIBRARIAN__`
85
91
  - Nested fields: Use `__` as delimiter (e.g., `AUDIOLIBRARIAN__MUSICBRAINZ__USERNAME`)
86
92
  - Example:
93
+
87
94
  ```bash
88
- # Override library directory
95
+ # Override library directory (library_dir)
89
96
  export AUDIOLIBRARIAN__LIBRARY_DIR="/mnt/music/library"
90
97
 
91
- # Set MusicBrainz credentials
98
+ # Set MusicBrainz credentials (musicbrainz.username and musicbrainz.password)
92
99
  export AUDIOLIBRARIAN__MUSICBRAINZ__USERNAME="your_username"
93
100
  export AUDIOLIBRARIAN__MUSICBRAINZ__PASSWORD="your_password"
94
101
  ```
95
102
 
96
- 2. **YAML Configuration File**
97
- - Location: `~/.config/audiolibrarian/config.yaml` (or `$XDG_CONFIG_HOME/audiolibrarian/config.yaml` if set)
103
+ 2. **YAML Configuration File** (medium precedence)
104
+ - Default location: `~/.config/audiolibrarian/config.yaml`
98
105
  - Example:
106
+
99
107
  ```yaml
100
108
  # Base directory for your music library
101
109
  library_dir: "~/music/library"
102
-
110
+
103
111
  # Cache and working directory
104
112
  work_dir: "~/.cache/audiolibrarian"
105
-
113
+
106
114
  # CD/DVD device path (use null for default device)
107
115
  discid_device: null
108
-
116
+
109
117
  # Audio normalization settings
110
118
  normalize_gain: 5 # dB gain for normalization
111
119
  normalize_preset: "radio" # "album" or "radio"
112
-
120
+
113
121
  # MusicBrainz API settings (optional)
114
122
  musicbrainz:
115
123
  username: "your_username" # For personal genre preferences
@@ -122,18 +130,23 @@ pip install audiolibrarian
122
130
 
123
131
  ### Available Settings ###
124
132
 
125
- | Setting | Default | Description |
126
- |--------------------------|----------------------------------|-------------------------------------------|
127
- | `library_dir` | `library` (in the current dir) | Directory for storing audio files |
128
- | `work_dir` | `$XDG_CACHE_HOME/audiolibrarian` | Directory for temporary files |
129
- | `discid_device` | `null` | CD device path (null for default device) |
130
- | `normalize_gain` | `5` | Normalization gain in dB |
131
- | `normalize_preset` | `"radio"` | Normalization preset ("album" or "radio") |
132
- | `musicbrainz.username` | (not set) | MusicBrainz username |
133
- | `musicbrainz.password` | (not set) | MusicBrainz password |
134
- | `musicbrainz.rate_limit` | `1.5` | Seconds between requests |
135
-
136
- > **Note**: The `musicbrainz` section is optional but recommended for accessing personal genre preferences on [MusicBrainz](https://musicbrainz.org/).
133
+ | Setting | Default | Description |
134
+ |--------------------------|---------------------------|-------------------------------------------|
135
+ | `library_dir` | `./library` | Directory for storing audio files |
136
+ | `work_dir` | `~/.cache/audiolibrarian` | Directory for temporary files |
137
+ | `discid_device` | `null` | CD device path (null for default device) |
138
+ | `normalize_gain` | `5` | Normalization gain in dB |
139
+ | `normalize_preset` | `"radio"` | Normalization preset ("album" or "radio") |
140
+ | `musicbrainz.username` | (not set) | MusicBrainz username |
141
+ | `musicbrainz.password` | (not set) | MusicBrainz password |
142
+ | `musicbrainz.rate_limit` | `1.5` | Seconds between requests |
143
+
144
+ > **Notes**:
145
+ >
146
+ > - The `musicbrainz` username and password are optional but recommended for accessing personal genre
147
+ > preferences on [MusicBrainz](https://musicbrainz.org/).
148
+ > - The `work_dir` default is actually `$XDG_CACHE_HOME/audiolibrarian`, which defaults to
149
+ > `~/.cache/audiolibrarian` on Linux and macOS.
137
150
 
138
151
  ## Usage ##
139
152
 
@@ -162,31 +175,40 @@ audiolibrarian genre /path/to/audio/directories --tag # Update tags with MB gen
162
175
  audiolibrarian --help
163
176
  ```
164
177
 
165
- ### Combining Configuration Sources ###
166
-
167
- Configuration sources are combined with the following precedence (highest to lowest):
168
- 1. Environment variables
169
- 2. YAML configuration file
170
- 3. Default values
171
-
172
- For example, with this `config.yaml`:
178
+ ### Directory Structure ###
173
179
 
174
- ```yaml
175
- # config.yaml
176
- library_dir: /media/music/library
177
- normalize_gain: 5.0
178
- ```
180
+ `audiolibrarian` organizes files in the following structure:
179
181
 
180
- And this environment variable:
181
- ```bash
182
- export AUDIOLIBRARIAN__NORMALIZE_GAIN="8.0"
183
- ```
182
+ **Processed audio files** (organized by format):
184
183
 
185
- The effective value of `normalize_gain` will be `8.0` (from the environment variable), while `library_dir` will be set to `/media/music/library` from the YAML file.
184
+ ```text
185
+ library/
186
+ ├── flac/
187
+ │ └── Artist/
188
+ │ └── YYYY__Album/
189
+ │ ├── 01__Track_Title.flac
190
+ │ └── 02__Another_Track.flac
191
+ ├── m4a/
192
+ │ └── Artist/
193
+ │ └── YYYY__Album/
194
+ │ ├── 01__Track_Title.m4a
195
+ │ └── 02__Another_Track.m4a
196
+ ├── mp3/
197
+ │ └── Artist/
198
+ │ └── YYYY__Album/
199
+ │ ├── 01__Track_Title.mp3
200
+ │ └── 02__Another_Track.mp3
201
+ ├── source/
202
+ │ └── Artist/
203
+ │ └── YYYY__Album/
204
+ │ ├── 01__Track_Title.flac
205
+ │ ├── 02__Another_Track.flac
206
+ │ └── Manifest.yaml
207
+ ```
186
208
 
187
209
  ### Advanced Usage ###
188
210
 
189
- 1. **Ripping CDs**
211
+ #### Ripping CDs ####
190
212
 
191
213
  ```bash
192
214
  # Basic CD rip
@@ -202,7 +224,7 @@ audiolibrarian rip --mb-release-id "12345678-1234-1234-1234-123456789012"
202
224
  audiolibrarian rip --disc "1/2" # First disc of two
203
225
  ```
204
226
 
205
- 2. **Converting Audio Files**
227
+ #### Converting Audio Files ####
206
228
 
207
229
  ```bash
208
230
  # Convert with specific artist and album
@@ -215,7 +237,7 @@ audiolibrarian convert --mb-release-id "12345678-1234-1234-1234-123456789012" /p
215
237
  audiolibrarian convert --disc "1/2" /path/to/disc1/files
216
238
  ```
217
239
 
218
- 2. **Working with Manifests**
240
+ #### Working with Manifests ####
219
241
 
220
242
  ```bash
221
243
  # Create manifest for existing files
@@ -225,11 +247,13 @@ audiolibrarian manifest /path/to/audio/files
225
247
  audiolibrarian manifest --cd /path/to/audio/files
226
248
 
227
249
  # Specify MusicBrainz artist and release IDs
228
- audiolibrarian manifest --mb-artist-id "12345678-1234-1234-1234-123456789012" \
229
- --mb-release-id "12345678-1234-1234-1234-123456789012" /path/to/audio/files
250
+ audiolibrarian manifest \
251
+ --mb-artist-id "12345678-1234-1234-1234-123456789012" \
252
+ --mb-release-id "87654321-4321-4321-4321-210987654321" \
253
+ /path/to/audio/files
230
254
  ```
231
255
 
232
- 3. **Reconverting Files**
256
+ #### Reconverting Files ####
233
257
 
234
258
  ```bash
235
259
  # Reconvert all files in directory
@@ -239,7 +263,7 @@ audiolibrarian reconvert /path/to/source/directories
239
263
  audiolibrarian reconvert --dry-run /path/to/source/directories
240
264
  ```
241
265
 
242
- 4. **Renaming Files**
266
+ #### Renaming Files ####
243
267
 
244
268
  ```bash
245
269
  # Rename files based on tags
@@ -249,7 +273,7 @@ audiolibrarian rename /path/to/audio/directories
249
273
  audiolibrarian rename --dry-run /path/to/audio/directories
250
274
  ```
251
275
 
252
- 5. **Using Different Normalization Presets**
276
+ #### Using Different Normalization Presets ####
253
277
 
254
278
  ```bash
255
279
  # Use radio normalization preset (default)
@@ -259,9 +283,33 @@ export AUDIOLIBRARIAN__NORMALIZE_PRESET="radio"
259
283
  export AUDIOLIBRARIAN__NORMALIZE_PRESET="album"
260
284
  ```
261
285
 
286
+ #### Combining Configuration Sources ####
287
+
288
+ Configuration sources are combined with the following precedence (highest to lowest):
289
+ 1. Environment variables
290
+ 2. YAML configuration file
291
+ 3. Default values
292
+
293
+ For example, with this `config.yaml`:
294
+
295
+ ```yaml
296
+ # config.yaml
297
+ library_dir: /media/music/library
298
+ normalize_gain: 5.0
299
+ ```
300
+
301
+ And this environment variable:
302
+
303
+ ```bash
304
+ export AUDIOLIBRARIAN__NORMALIZE_GAIN="8.0"
305
+ ```
306
+
307
+ The effective value of `normalize_gain` will be `8.0` (from the environment variable), while
308
+ `library_dir` will be set to `/media/music/library` from the YAML file.
309
+
262
310
  ### Troubleshooting ###
263
311
 
264
- 1. **Increasing Verbosity**
312
+ #### Increasing Verbosity ####
265
313
 
266
314
  ```bash
267
315
  # Show more detailed output
@@ -271,58 +319,15 @@ audiolibrarian --log-level INFO cd
271
319
  audiolibrarian --log-level DEBUG cd
272
320
  ```
273
321
 
274
- 2. **Checking Dependencies**
275
-
276
- ```bash
277
- # Verify all required tools are installed
278
- audiolibrarian --log-level DEBUG cd
279
- ```
280
-
281
- 3. **MusicBrainz Issues**
322
+ #### MusicBrainz Issues ####
282
323
 
283
324
  If you encounter MusicBrainz-related errors:
284
325
 
285
326
  1. Verify your credentials are correct
286
- 2. Check your internet connection
327
+ 2. Check your Internet connection
287
328
  3. Use the debug log level to get more information
288
329
  4. Increase the rate limit if you're hitting rate limits
289
330
 
290
331
  ```bash
291
332
  export AUDIOLIBRARIAN__MUSICBRAINZ__RATE_LIMIT="2.0"
292
333
  ```
293
-
294
- ### Directory Structure ###
295
-
296
- `audiolibrarian` organizes files in the following structure:
297
-
298
- 1. **Source files** (original audio files):
299
- ```
300
- library/source/
301
- └── Artist/
302
- └── YYYY__Album/
303
- ├── 01__Track_Title.flac
304
- ├── 02__Another_Track.flac
305
- └── Manifest.yaml
306
- ```
307
-
308
- 2. **Processed audio files** (organized by format):
309
- ```
310
- library/
311
- ├── flac/
312
- │ └── Artist/
313
- │ └── YYYY__Album/
314
- │ ├── 01__Track_Title.flac
315
- │ └── 02__Another_Track.flac
316
- ├── m4a/
317
- │ └── Artist/
318
- │ └── YYYY__Album/
319
- │ ├── 01__Track_Title.m4a
320
- │ └── 02__Another_Track.m4a
321
- └── mp3/
322
- └── Artist/
323
- └── YYYY__Album/
324
- ├── 01__Track_Title.mp3
325
- └── 02__Another_Track.mp3
326
- ```
327
-
328
- Each track filename follows the format: `track_number__track_name.extension` (e.g., `01__Call_to_Arms.flac`).
@@ -2,8 +2,9 @@
2
2
 
3
3
  ## Overview ##
4
4
 
5
- `audiolibrarian` is a powerful command-line tool for managing digital music libraries. It provides a streamlined
6
- workflow for ripping, converting, organizing, and tagging audio files with high-quality metadata from MusicBrainz.
5
+ `audiolibrarian` is a command-line tool for ripping audio from CDs (or taking
6
+ high-quality audio from local files), tagging them with comprehensive metadata from MusicBrainz,
7
+ converting them to multiple formats, and organizing them in a clean directory structure.
7
8
 
8
9
  ### Key Features ###
9
10
 
@@ -20,28 +21,32 @@ workflow for ripping, converting, organizing, and tagging audio files with high-
20
21
  - **Consistent Quality**: Maintains audio quality through the conversion process
21
22
  - **Accurate Metadata**: Leverages MusicBrainz for comprehensive music information
22
23
  - **Automated Workflow**: Reduces manual work in organizing and tagging music
23
- - **Scriptable**: Perfect for automating large music library management tasks
24
24
  - **Open Source**: Free to use and modify under the GPL-3.0 license
25
25
 
26
- Whether you're digitizing a CD collection, organizing existing music files, or managing a large digital library,
27
- `audiolibrarian` provides the tools you need to keep your music collection well-organized and properly tagged.
28
-
26
+ Whether you're digitizing a CD collection, organizing existing music files, or managing a large
27
+ digital library, `audiolibrarian` provides the tools you need to keep your music collection
28
+ well-organized and properly tagged.
29
29
 
30
30
  ## Installation ##
31
31
 
32
+ > **NOTE:** This library has only been tested on Linux. It may not work on other operating
33
+ > systems.
34
+
32
35
  ### External Requirements ###
33
36
 
34
37
  `audiolibrarian` uses a few command-line tools to run:
35
38
 
36
- * `cd-paranoia`: [cd-paranoia](https://www.gnu.org/software/libcdio/)
37
- * `eject`: [util-linux](https://github.com/util-linux/util-linux)
38
- * `faad`: [faad2](https://github.com/knik0/faad2)
39
- * `fdkaac`: [fdkaac](https://github.com/nu774/fdkaac)
40
- * `flac`: [flac](https://github.com/xiph/flac)
41
- * `lame`: [lame](https://lame.sourceforge.io/)
42
- * `mpg123`: [mpg123](https://www.mpg123.de/)
43
- * `sndfile-convert`: [libsndfile](https://github.com/libsndfile/libsndfile)
44
- * `wavegain`: [wavegain](https://rarewares.org/others.php)
39
+ - [cd-paranoia](https://www.gnu.org/software/libcdio/)
40
+ - [util-linux](https://github.com/util-linux/util-linux)
41
+ - [faad2](https://github.com/knik0/faad2)
42
+ - [fdkaac](https://github.com/nu774/fdkaac)
43
+ - [flac](https://github.com/xiph/flac)
44
+ - [lame](https://lame.sourceforge.io/)
45
+ - [mpg123](https://www.mpg123.de/)
46
+ - [libsndfile](https://github.com/libsndfile/libsndfile)
47
+ - [wavegain](https://github.com/MestreLion/wavegain)
48
+
49
+ It also requires the [libdiscid](https://musicbrainz.org/doc/libdiscid) library.
45
50
 
46
51
  ### Install from PyPI ###
47
52
 
@@ -53,38 +58,41 @@ pip install audiolibrarian
53
58
 
54
59
  ## Configuration ##
55
60
 
56
- `audiolibrarian` uses a flexible configuration system that supports multiple configuration sources, listed in order of precedence:
61
+ `audiolibrarian` uses a flexible configuration system that supports multiple configuration sources,
62
+ listed in order of precedence:
57
63
 
58
64
  1. **Environment Variables** (highest precedence)
59
65
  - Prefix: `AUDIOLIBRARIAN__`
60
66
  - Nested fields: Use `__` as delimiter (e.g., `AUDIOLIBRARIAN__MUSICBRAINZ__USERNAME`)
61
67
  - Example:
68
+
62
69
  ```bash
63
- # Override library directory
70
+ # Override library directory (library_dir)
64
71
  export AUDIOLIBRARIAN__LIBRARY_DIR="/mnt/music/library"
65
72
 
66
- # Set MusicBrainz credentials
73
+ # Set MusicBrainz credentials (musicbrainz.username and musicbrainz.password)
67
74
  export AUDIOLIBRARIAN__MUSICBRAINZ__USERNAME="your_username"
68
75
  export AUDIOLIBRARIAN__MUSICBRAINZ__PASSWORD="your_password"
69
76
  ```
70
77
 
71
- 2. **YAML Configuration File**
72
- - Location: `~/.config/audiolibrarian/config.yaml` (or `$XDG_CONFIG_HOME/audiolibrarian/config.yaml` if set)
78
+ 2. **YAML Configuration File** (medium precedence)
79
+ - Default location: `~/.config/audiolibrarian/config.yaml`
73
80
  - Example:
81
+
74
82
  ```yaml
75
83
  # Base directory for your music library
76
84
  library_dir: "~/music/library"
77
-
85
+
78
86
  # Cache and working directory
79
87
  work_dir: "~/.cache/audiolibrarian"
80
-
88
+
81
89
  # CD/DVD device path (use null for default device)
82
90
  discid_device: null
83
-
91
+
84
92
  # Audio normalization settings
85
93
  normalize_gain: 5 # dB gain for normalization
86
94
  normalize_preset: "radio" # "album" or "radio"
87
-
95
+
88
96
  # MusicBrainz API settings (optional)
89
97
  musicbrainz:
90
98
  username: "your_username" # For personal genre preferences
@@ -97,18 +105,23 @@ pip install audiolibrarian
97
105
 
98
106
  ### Available Settings ###
99
107
 
100
- | Setting | Default | Description |
101
- |--------------------------|----------------------------------|-------------------------------------------|
102
- | `library_dir` | `library` (in the current dir) | Directory for storing audio files |
103
- | `work_dir` | `$XDG_CACHE_HOME/audiolibrarian` | Directory for temporary files |
104
- | `discid_device` | `null` | CD device path (null for default device) |
105
- | `normalize_gain` | `5` | Normalization gain in dB |
106
- | `normalize_preset` | `"radio"` | Normalization preset ("album" or "radio") |
107
- | `musicbrainz.username` | (not set) | MusicBrainz username |
108
- | `musicbrainz.password` | (not set) | MusicBrainz password |
109
- | `musicbrainz.rate_limit` | `1.5` | Seconds between requests |
110
-
111
- > **Note**: The `musicbrainz` section is optional but recommended for accessing personal genre preferences on [MusicBrainz](https://musicbrainz.org/).
108
+ | Setting | Default | Description |
109
+ |--------------------------|---------------------------|-------------------------------------------|
110
+ | `library_dir` | `./library` | Directory for storing audio files |
111
+ | `work_dir` | `~/.cache/audiolibrarian` | Directory for temporary files |
112
+ | `discid_device` | `null` | CD device path (null for default device) |
113
+ | `normalize_gain` | `5` | Normalization gain in dB |
114
+ | `normalize_preset` | `"radio"` | Normalization preset ("album" or "radio") |
115
+ | `musicbrainz.username` | (not set) | MusicBrainz username |
116
+ | `musicbrainz.password` | (not set) | MusicBrainz password |
117
+ | `musicbrainz.rate_limit` | `1.5` | Seconds between requests |
118
+
119
+ > **Notes**:
120
+ >
121
+ > - The `musicbrainz` username and password are optional but recommended for accessing personal genre
122
+ > preferences on [MusicBrainz](https://musicbrainz.org/).
123
+ > - The `work_dir` default is actually `$XDG_CACHE_HOME/audiolibrarian`, which defaults to
124
+ > `~/.cache/audiolibrarian` on Linux and macOS.
112
125
 
113
126
  ## Usage ##
114
127
 
@@ -137,31 +150,40 @@ audiolibrarian genre /path/to/audio/directories --tag # Update tags with MB gen
137
150
  audiolibrarian --help
138
151
  ```
139
152
 
140
- ### Combining Configuration Sources ###
141
-
142
- Configuration sources are combined with the following precedence (highest to lowest):
143
- 1. Environment variables
144
- 2. YAML configuration file
145
- 3. Default values
146
-
147
- For example, with this `config.yaml`:
153
+ ### Directory Structure ###
148
154
 
149
- ```yaml
150
- # config.yaml
151
- library_dir: /media/music/library
152
- normalize_gain: 5.0
153
- ```
155
+ `audiolibrarian` organizes files in the following structure:
154
156
 
155
- And this environment variable:
156
- ```bash
157
- export AUDIOLIBRARIAN__NORMALIZE_GAIN="8.0"
158
- ```
157
+ **Processed audio files** (organized by format):
159
158
 
160
- The effective value of `normalize_gain` will be `8.0` (from the environment variable), while `library_dir` will be set to `/media/music/library` from the YAML file.
159
+ ```text
160
+ library/
161
+ ├── flac/
162
+ │ └── Artist/
163
+ │ └── YYYY__Album/
164
+ │ ├── 01__Track_Title.flac
165
+ │ └── 02__Another_Track.flac
166
+ ├── m4a/
167
+ │ └── Artist/
168
+ │ └── YYYY__Album/
169
+ │ ├── 01__Track_Title.m4a
170
+ │ └── 02__Another_Track.m4a
171
+ ├── mp3/
172
+ │ └── Artist/
173
+ │ └── YYYY__Album/
174
+ │ ├── 01__Track_Title.mp3
175
+ │ └── 02__Another_Track.mp3
176
+ ├── source/
177
+ │ └── Artist/
178
+ │ └── YYYY__Album/
179
+ │ ├── 01__Track_Title.flac
180
+ │ ├── 02__Another_Track.flac
181
+ │ └── Manifest.yaml
182
+ ```
161
183
 
162
184
  ### Advanced Usage ###
163
185
 
164
- 1. **Ripping CDs**
186
+ #### Ripping CDs ####
165
187
 
166
188
  ```bash
167
189
  # Basic CD rip
@@ -177,7 +199,7 @@ audiolibrarian rip --mb-release-id "12345678-1234-1234-1234-123456789012"
177
199
  audiolibrarian rip --disc "1/2" # First disc of two
178
200
  ```
179
201
 
180
- 2. **Converting Audio Files**
202
+ #### Converting Audio Files ####
181
203
 
182
204
  ```bash
183
205
  # Convert with specific artist and album
@@ -190,7 +212,7 @@ audiolibrarian convert --mb-release-id "12345678-1234-1234-1234-123456789012" /p
190
212
  audiolibrarian convert --disc "1/2" /path/to/disc1/files
191
213
  ```
192
214
 
193
- 2. **Working with Manifests**
215
+ #### Working with Manifests ####
194
216
 
195
217
  ```bash
196
218
  # Create manifest for existing files
@@ -200,11 +222,13 @@ audiolibrarian manifest /path/to/audio/files
200
222
  audiolibrarian manifest --cd /path/to/audio/files
201
223
 
202
224
  # Specify MusicBrainz artist and release IDs
203
- audiolibrarian manifest --mb-artist-id "12345678-1234-1234-1234-123456789012" \
204
- --mb-release-id "12345678-1234-1234-1234-123456789012" /path/to/audio/files
225
+ audiolibrarian manifest \
226
+ --mb-artist-id "12345678-1234-1234-1234-123456789012" \
227
+ --mb-release-id "87654321-4321-4321-4321-210987654321" \
228
+ /path/to/audio/files
205
229
  ```
206
230
 
207
- 3. **Reconverting Files**
231
+ #### Reconverting Files ####
208
232
 
209
233
  ```bash
210
234
  # Reconvert all files in directory
@@ -214,7 +238,7 @@ audiolibrarian reconvert /path/to/source/directories
214
238
  audiolibrarian reconvert --dry-run /path/to/source/directories
215
239
  ```
216
240
 
217
- 4. **Renaming Files**
241
+ #### Renaming Files ####
218
242
 
219
243
  ```bash
220
244
  # Rename files based on tags
@@ -224,7 +248,7 @@ audiolibrarian rename /path/to/audio/directories
224
248
  audiolibrarian rename --dry-run /path/to/audio/directories
225
249
  ```
226
250
 
227
- 5. **Using Different Normalization Presets**
251
+ #### Using Different Normalization Presets ####
228
252
 
229
253
  ```bash
230
254
  # Use radio normalization preset (default)
@@ -234,9 +258,33 @@ export AUDIOLIBRARIAN__NORMALIZE_PRESET="radio"
234
258
  export AUDIOLIBRARIAN__NORMALIZE_PRESET="album"
235
259
  ```
236
260
 
261
+ #### Combining Configuration Sources ####
262
+
263
+ Configuration sources are combined with the following precedence (highest to lowest):
264
+ 1. Environment variables
265
+ 2. YAML configuration file
266
+ 3. Default values
267
+
268
+ For example, with this `config.yaml`:
269
+
270
+ ```yaml
271
+ # config.yaml
272
+ library_dir: /media/music/library
273
+ normalize_gain: 5.0
274
+ ```
275
+
276
+ And this environment variable:
277
+
278
+ ```bash
279
+ export AUDIOLIBRARIAN__NORMALIZE_GAIN="8.0"
280
+ ```
281
+
282
+ The effective value of `normalize_gain` will be `8.0` (from the environment variable), while
283
+ `library_dir` will be set to `/media/music/library` from the YAML file.
284
+
237
285
  ### Troubleshooting ###
238
286
 
239
- 1. **Increasing Verbosity**
287
+ #### Increasing Verbosity ####
240
288
 
241
289
  ```bash
242
290
  # Show more detailed output
@@ -246,58 +294,15 @@ audiolibrarian --log-level INFO cd
246
294
  audiolibrarian --log-level DEBUG cd
247
295
  ```
248
296
 
249
- 2. **Checking Dependencies**
250
-
251
- ```bash
252
- # Verify all required tools are installed
253
- audiolibrarian --log-level DEBUG cd
254
- ```
255
-
256
- 3. **MusicBrainz Issues**
297
+ #### MusicBrainz Issues ####
257
298
 
258
299
  If you encounter MusicBrainz-related errors:
259
300
 
260
301
  1. Verify your credentials are correct
261
- 2. Check your internet connection
302
+ 2. Check your Internet connection
262
303
  3. Use the debug log level to get more information
263
304
  4. Increase the rate limit if you're hitting rate limits
264
305
 
265
306
  ```bash
266
307
  export AUDIOLIBRARIAN__MUSICBRAINZ__RATE_LIMIT="2.0"
267
308
  ```
268
-
269
- ### Directory Structure ###
270
-
271
- `audiolibrarian` organizes files in the following structure:
272
-
273
- 1. **Source files** (original audio files):
274
- ```
275
- library/source/
276
- └── Artist/
277
- └── YYYY__Album/
278
- ├── 01__Track_Title.flac
279
- ├── 02__Another_Track.flac
280
- └── Manifest.yaml
281
- ```
282
-
283
- 2. **Processed audio files** (organized by format):
284
- ```
285
- library/
286
- ├── flac/
287
- │ └── Artist/
288
- │ └── YYYY__Album/
289
- │ ├── 01__Track_Title.flac
290
- │ └── 02__Another_Track.flac
291
- ├── m4a/
292
- │ └── Artist/
293
- │ └── YYYY__Album/
294
- │ ├── 01__Track_Title.m4a
295
- │ └── 02__Another_Track.m4a
296
- └── mp3/
297
- └── Artist/
298
- └── YYYY__Album/
299
- ├── 01__Track_Title.mp3
300
- └── 02__Another_Track.mp3
301
- ```
302
-
303
- Each track filename follows the format: `track_number__track_name.extension` (e.g., `01__Call_to_Arms.flac`).
@@ -5,4 +5,3 @@ To have git use the hooks in this directory, run
5
5
  ```bash
6
6
  git config core.hooksPath git_hooks
7
7
  ```
8
-
@@ -7,6 +7,7 @@ dev = [
7
7
  "coverage",
8
8
  "hatchling",
9
9
  "mypy",
10
+ "pymarkdownlnt",
10
11
  "pytest",
11
12
  "ruff",
12
13
  "types-pyyaml",
@@ -77,6 +78,12 @@ strict = true
77
78
  module = "picard_src.*"
78
79
  ignore_errors = true # This is not our code.
79
80
 
81
+ [tool.pymarkdown]
82
+ plugins.md013.line_length = 100
83
+ plugins.md013.code_block_line_length = 100
84
+ #plugins.md007.enabled = true
85
+ #plugins.md007.code_block_line_length = 160
86
+
80
87
  [tool.ruff]
81
88
  extend-exclude = [
82
89
  "picard_src", # This is not our code.
@@ -16,4 +16,4 @@
16
16
  # You should have received a copy of the GNU General Public License along with audiolibrarian.
17
17
  # If not, see <https://www.gnu.org/licenses/>.
18
18
  #
19
- __version__ = "0.16.3"
19
+ __version__ = "0.16.4"
@@ -2,10 +2,10 @@
2
2
 
3
3
  Code in this directory comes from (or is derived from) the super-cool Picard project.
4
4
 
5
- https://github.com/metabrainz/picard
5
+ [Picard](https://github.com/metabrainz/picard)
6
6
 
7
7
  I'd like to express my thanks to all of have contributed to that project.
8
8
 
9
- Note: we could have just set the Picard library as a dependency of audiolibrarian, but
10
- it includes other dependencies (such as PyQT) that add a lot of overhead not required
9
+ Note: we could have just set the Picard library as a dependency of audiolibrarian, but
10
+ it includes other dependencies (such as PyQT) that add a lot of overhead not required
11
11
  by this project.
@@ -20,6 +20,20 @@ wheels = [
20
20
  { url = "https://files.pythonhosted.org/packages/53/18/a56e2fe47b259bb52201093a3a9d4a32014f9d85071ad07e9d60600890ca/ansicolors-1.1.8-py2.py3-none-any.whl", hash = "sha256:00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187", size = 13847, upload-time = "2017-06-02T21:22:12.67Z" },
21
21
  ]
22
22
 
23
+ [[package]]
24
+ name = "application-properties"
25
+ version = "0.8.2"
26
+ source = { registry = "https://pypi.jibson.com/simple" }
27
+ dependencies = [
28
+ { name = "pyyaml" },
29
+ { name = "tomli" },
30
+ { name = "typing-extensions" },
31
+ ]
32
+ sdist = { url = "https://files.pythonhosted.org/packages/c1/5e/29ec0fa553ee5befc6a1e47eb0c8ffea75eed941251524678700e2d3e747/application_properties-0.8.2.tar.gz", hash = "sha256:e5e6918c8e29ab57175567d51dfa39c00a1d75b3205625559bb02250f50f0420", size = 29595, upload-time = "2024-01-28T23:43:07.403Z" }
33
+ wheels = [
34
+ { url = "https://files.pythonhosted.org/packages/06/27/ea2b77232385ec1c4b5cb766ee13b5a3085ed2fa789d61374e7af36b79e1/application_properties-0.8.2-py3-none-any.whl", hash = "sha256:a4fe684e4d95fc45054d3316acf763a7b0f29342ccea02eee09de53004f0139c", size = 18399, upload-time = "2024-01-28T23:43:05.631Z" },
35
+ ]
36
+
23
37
  [[package]]
24
38
  name = "audiolibrarian"
25
39
  source = { editable = "." }
@@ -42,6 +56,7 @@ dev = [
42
56
  { name = "coverage" },
43
57
  { name = "hatchling" },
44
58
  { name = "mypy" },
59
+ { name = "pymarkdownlnt" },
45
60
  { name = "pytest" },
46
61
  { name = "ruff" },
47
62
  { name = "types-pyyaml" },
@@ -69,6 +84,7 @@ dev = [
69
84
  { name = "coverage" },
70
85
  { name = "hatchling" },
71
86
  { name = "mypy" },
87
+ { name = "pymarkdownlnt" },
72
88
  { name = "pytest" },
73
89
  { name = "ruff" },
74
90
  { name = "types-pyyaml" },
@@ -116,6 +132,19 @@ wheels = [
116
132
  { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
117
133
  ]
118
134
 
135
+ [[package]]
136
+ name = "columnar"
137
+ version = "1.4.1"
138
+ source = { registry = "https://pypi.jibson.com/simple" }
139
+ dependencies = [
140
+ { name = "toolz" },
141
+ { name = "wcwidth" },
142
+ ]
143
+ sdist = { url = "https://files.pythonhosted.org/packages/5e/0d/a0b2fd781050d29c9df64ac6df30b5f18b775724b79779f56fc5a8298fe9/Columnar-1.4.1.tar.gz", hash = "sha256:c3cb57273333b2ff9cfaafc86f09307419330c97faa88dcfe23df05e6fbb9c72", size = 11386, upload-time = "2021-12-27T21:58:56.123Z" }
144
+ wheels = [
145
+ { url = "https://files.pythonhosted.org/packages/06/00/a17a5657bf090b9dffdb310ac273c553a38f9252f60224da9fe62d9b60e9/Columnar-1.4.1-py3-none-any.whl", hash = "sha256:8efb692a7e6ca07dcc8f4ea889960421331a5dffa8e5af81f0a67ad8ea1fc798", size = 11845, upload-time = "2021-12-27T21:58:54.388Z" },
146
+ ]
147
+
119
148
  [[package]]
120
149
  name = "coverage"
121
150
  version = "7.8.2"
@@ -370,6 +399,20 @@ wheels = [
370
399
  { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
371
400
  ]
372
401
 
402
+ [[package]]
403
+ name = "pymarkdownlnt"
404
+ version = "0.9.30"
405
+ source = { registry = "https://pypi.jibson.com/simple" }
406
+ dependencies = [
407
+ { name = "application-properties" },
408
+ { name = "columnar" },
409
+ { name = "typing-extensions" },
410
+ ]
411
+ sdist = { url = "https://files.pythonhosted.org/packages/86/00/4156086d7f32e3058cebb6b813e93f5a227ae2590ac528b2344d2c669973/pymarkdownlnt-0.9.30.tar.gz", hash = "sha256:cf274935b128abd7f30c44314510d0f4d36965149bb9dae84f6cac9491dc1f58", size = 416281, upload-time = "2025-05-20T02:26:30.652Z" }
412
+ wheels = [
413
+ { url = "https://files.pythonhosted.org/packages/28/92/81059c9eecd973168890e6b730f852abfd310389f67d4fb6b132a3976338/pymarkdownlnt-0.9.30-py3-none-any.whl", hash = "sha256:29b881434def9d3796be4a89cb277ab9f8f4fbb558379ce7836c653c9c351d2c", size = 500322, upload-time = "2025-05-20T02:26:29.098Z" },
414
+ ]
415
+
373
416
  [[package]]
374
417
  name = "pytest"
375
418
  version = "8.4.0"
@@ -487,6 +530,34 @@ wheels = [
487
530
  { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" },
488
531
  ]
489
532
 
533
+ [[package]]
534
+ name = "tomli"
535
+ version = "2.2.1"
536
+ source = { registry = "https://pypi.jibson.com/simple" }
537
+ sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" }
538
+ wheels = [
539
+ { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" },
540
+ { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" },
541
+ { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" },
542
+ { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" },
543
+ { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" },
544
+ { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" },
545
+ { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" },
546
+ { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" },
547
+ { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" },
548
+ { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" },
549
+ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" },
550
+ ]
551
+
552
+ [[package]]
553
+ name = "toolz"
554
+ version = "1.0.0"
555
+ source = { registry = "https://pypi.jibson.com/simple" }
556
+ sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" }
557
+ wheels = [
558
+ { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" },
559
+ ]
560
+
490
561
  [[package]]
491
562
  name = "trove-classifiers"
492
563
  version = "2025.5.9.12"
@@ -556,6 +627,15 @@ wheels = [
556
627
  { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" },
557
628
  ]
558
629
 
630
+ [[package]]
631
+ name = "wcwidth"
632
+ version = "0.2.13"
633
+ source = { registry = "https://pypi.jibson.com/simple" }
634
+ sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" }
635
+ wheels = [
636
+ { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" },
637
+ ]
638
+
559
639
  [[package]]
560
640
  name = "xdg-base-dirs"
561
641
  version = "6.0.2"
File without changes
File without changes