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.
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/.gitignore +2 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/CONTRIBUTING.md +2 -2
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/Makefile +4 -1
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/PKG-INFO +114 -109
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/README.md +113 -108
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/git_hooks/README.md +0 -1
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/pyproject.toml +7 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/__init__.py +1 -1
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/picard_src/README.md +3 -3
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/uv.lock +80 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/.github/workflows/main.yml +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/.python-version +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/COPYING +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/LICENSE +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/git_hooks/pre-push +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/scripts/update_links.sh +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/__init__.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/audiofile.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/__init__.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/flac.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/m4a.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/mp3.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/tags.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiosource.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/base.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/cli.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/commands.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/genremanager.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/musicbrainz.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/output.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/records.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/settings.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/sh.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/text.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/picard_src/__init__.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/picard_src/textencoding.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/tools/__init__.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/tools/diff.py +0 -0
- {audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/tools/show_tags.py +0 -0
@@ -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
|
+
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
|
31
|
-
|
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
|
52
|
-
`audiolibrarian` provides the tools you need to keep your music collection
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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,
|
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
|
-
-
|
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
|
126
|
-
|
127
|
-
| `library_dir` |
|
128
|
-
| `work_dir` |
|
129
|
-
| `discid_device` | `null`
|
130
|
-
| `normalize_gain` | `5`
|
131
|
-
| `normalize_preset` | `"radio"`
|
132
|
-
| `musicbrainz.username` | (not set)
|
133
|
-
| `musicbrainz.password` | (not set)
|
134
|
-
| `musicbrainz.rate_limit` | `1.5`
|
135
|
-
|
136
|
-
> **
|
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
|
-
###
|
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
|
-
|
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
|
-
|
181
|
-
```bash
|
182
|
-
export AUDIOLIBRARIAN__NORMALIZE_GAIN="8.0"
|
183
|
-
```
|
182
|
+
**Processed audio files** (organized by format):
|
184
183
|
|
185
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
229
|
-
--mb-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
6
|
-
|
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
|
27
|
-
`audiolibrarian` provides the tools you need to keep your music collection
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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,
|
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
|
-
-
|
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
|
101
|
-
|
102
|
-
| `library_dir` |
|
103
|
-
| `work_dir` |
|
104
|
-
| `discid_device` | `null`
|
105
|
-
| `normalize_gain` | `5`
|
106
|
-
| `normalize_preset` | `"radio"`
|
107
|
-
| `musicbrainz.username` | (not set)
|
108
|
-
| `musicbrainz.password` | (not set)
|
109
|
-
| `musicbrainz.rate_limit` | `1.5`
|
110
|
-
|
111
|
-
> **
|
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
|
-
###
|
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
|
-
|
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
|
-
|
156
|
-
```bash
|
157
|
-
export AUDIOLIBRARIAN__NORMALIZE_GAIN="8.0"
|
158
|
-
```
|
157
|
+
**Processed audio files** (organized by format):
|
159
158
|
|
160
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
204
|
-
--mb-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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`).
|
@@ -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.
|
@@ -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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/__init__.py
RENAMED
File without changes
|
{audiolibrarian-0.16.3 → audiolibrarian-0.16.4}/src/audiolibrarian/audiofile/formats/flac.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|