mudio 1.0.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.
- mudio-1.0.0/.gitignore +130 -0
- mudio-1.0.0/LICENSE +21 -0
- mudio-1.0.0/PKG-INFO +153 -0
- mudio-1.0.0/README.md +137 -0
- mudio-1.0.0/docs/api_reference.md +175 -0
- mudio-1.0.0/docs/cli_reference.md +286 -0
- mudio-1.0.0/pyproject.toml +46 -0
- mudio-1.0.0/src/mudio/__init__.py +43 -0
- mudio-1.0.0/src/mudio/__main__.py +9 -0
- mudio-1.0.0/src/mudio/batch.py +186 -0
- mudio-1.0.0/src/mudio/cli.py +597 -0
- mudio-1.0.0/src/mudio/core.py +1116 -0
- mudio-1.0.0/src/mudio/operations.py +484 -0
- mudio-1.0.0/src/mudio/processor.py +554 -0
- mudio-1.0.0/src/mudio/tests_integration.py +301 -0
- mudio-1.0.0/src/mudio/utils.py +133 -0
mudio-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
*.manifest
|
|
31
|
+
*.spec
|
|
32
|
+
|
|
33
|
+
# Installer logs
|
|
34
|
+
pip-log.txt
|
|
35
|
+
pip-delete-this-directory.txt
|
|
36
|
+
|
|
37
|
+
# Unit test / coverage reports
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
nosetests.xml
|
|
45
|
+
coverage.xml
|
|
46
|
+
*.cover
|
|
47
|
+
*.py,cover
|
|
48
|
+
.hypothesis/
|
|
49
|
+
.pytest_cache/
|
|
50
|
+
|
|
51
|
+
# Translations
|
|
52
|
+
*.mo
|
|
53
|
+
*.pot
|
|
54
|
+
|
|
55
|
+
# Django stuff:
|
|
56
|
+
*.log
|
|
57
|
+
local_settings.py
|
|
58
|
+
db.sqlite3
|
|
59
|
+
db.sqlite3-journal
|
|
60
|
+
|
|
61
|
+
# Flask stuff:
|
|
62
|
+
instance/
|
|
63
|
+
.webassets-cache
|
|
64
|
+
|
|
65
|
+
# Scrapy stuff:
|
|
66
|
+
.scrapy
|
|
67
|
+
|
|
68
|
+
# Sphinx documentation
|
|
69
|
+
docs/_build/
|
|
70
|
+
|
|
71
|
+
# PyBuilder
|
|
72
|
+
target/
|
|
73
|
+
|
|
74
|
+
# Jupyter Notebook
|
|
75
|
+
.ipynb_checkpoints
|
|
76
|
+
|
|
77
|
+
# IPython
|
|
78
|
+
profile_default/
|
|
79
|
+
ipython_config.py
|
|
80
|
+
|
|
81
|
+
# pyenv
|
|
82
|
+
.python-version
|
|
83
|
+
|
|
84
|
+
# pipenv
|
|
85
|
+
Pipfile.lock
|
|
86
|
+
|
|
87
|
+
# PEP 582
|
|
88
|
+
__pypackages__/
|
|
89
|
+
|
|
90
|
+
# Celery stuff
|
|
91
|
+
celerybeat-schedule
|
|
92
|
+
celerybeat.pid
|
|
93
|
+
|
|
94
|
+
# SageMath parsed files
|
|
95
|
+
*.sage.py
|
|
96
|
+
|
|
97
|
+
# Environments
|
|
98
|
+
.env
|
|
99
|
+
.venv
|
|
100
|
+
env/
|
|
101
|
+
venv/
|
|
102
|
+
ENV/
|
|
103
|
+
env.bak/
|
|
104
|
+
venv.bak/
|
|
105
|
+
|
|
106
|
+
# Spyder project settings
|
|
107
|
+
.spyderproject
|
|
108
|
+
.spyproject
|
|
109
|
+
|
|
110
|
+
# Rope project settings
|
|
111
|
+
.ropeproject
|
|
112
|
+
|
|
113
|
+
# mkdocs documentation
|
|
114
|
+
/site
|
|
115
|
+
|
|
116
|
+
# mypy
|
|
117
|
+
.mypy_cache/
|
|
118
|
+
.dmypy.json
|
|
119
|
+
dmypy.json
|
|
120
|
+
|
|
121
|
+
# Pyre type checker
|
|
122
|
+
.pyre/
|
|
123
|
+
|
|
124
|
+
# Project-specific
|
|
125
|
+
logs/
|
|
126
|
+
*.log
|
|
127
|
+
test_artifacts/
|
|
128
|
+
|
|
129
|
+
venv/
|
|
130
|
+
benchmark_results.png
|
mudio-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matthew Deik
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mudio-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mudio
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Friendly command-line music-metadata editor and Python library
|
|
5
|
+
Project-URL: Homepage, https://github.com/mdeik/mudio
|
|
6
|
+
Project-URL: Repository, https://github.com/mdeik/mudio
|
|
7
|
+
Author-email: Matthew Deik <131482791+mdeik@users.noreply.github.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Requires-Dist: mutagen>=1.47.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# mudio
|
|
18
|
+
|
|
19
|
+
**mudio** is a powerful, friendly command-line music metadata editor and Python library. It provides a unified API for handling metadata across MP3, FLAC, M4A, and more, making batch processing and automation simple and safe.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **Unified API**: Write code once, run it on MP3, FLAC, M4A, WAV, OGG, OPUS, WMA, and WavPack.
|
|
24
|
+
- **Batch Processing**: robust CLI for processing thousands of files.
|
|
25
|
+
- **Parallel Execution**: Automatically uses multi-threading for large batches.
|
|
26
|
+
- **Safety First**: Built-in **backup** system, **dry-run** mode, and careful validation.
|
|
27
|
+
- **Powerful Operations**:
|
|
28
|
+
- **Find & Replace**: Regex-supported search and replace in tags.
|
|
29
|
+
- **Mass Edits**: Set, overwrite, append, prefix, or clear tags.
|
|
30
|
+
- **Filtering**: Apply changes only to files matching specific criteria (e.g. `artist="The Beatles"`).
|
|
31
|
+
|
|
32
|
+
## Supported Formats
|
|
33
|
+
|
|
34
|
+
- **MP3** (`.mp3`) - ID3v2.3/v2.4
|
|
35
|
+
- **FLAC** (`.flac`) - Vorbis Comments
|
|
36
|
+
- **M4A / MP4** (`.m4a`, `.mp4`) - MP4 Tags
|
|
37
|
+
- **Ogg Vorbis** (`.ogg`)
|
|
38
|
+
- **Opus** (`.opus`)
|
|
39
|
+
- **WAV** (`.wav`)
|
|
40
|
+
- **Windows Media Audio** (`.wma`)
|
|
41
|
+
- **WavPack** (`.wv`)
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install mudio
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## CLI Usage
|
|
50
|
+
|
|
51
|
+
`mudio` is designed for efficient batch operations.
|
|
52
|
+
|
|
53
|
+
### Basic Commands
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# View metadata
|
|
57
|
+
mudio song.mp3 --mode view
|
|
58
|
+
|
|
59
|
+
# Set Album and Date
|
|
60
|
+
mudio *.mp3 --mode set --album "New Album" --date "2024"
|
|
61
|
+
|
|
62
|
+
# View metadata (truncated if long)
|
|
63
|
+
mudio song.mp3 --mode print
|
|
64
|
+
|
|
65
|
+
# Overwrite Title
|
|
66
|
+
mudio song.flac --mode overwrite --fields title --value "My Song"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Advanced Batch Operations
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Regex Find & Replace (Fix features)
|
|
73
|
+
# Changes "feat." -> "ft." in title and artist
|
|
74
|
+
mudio /music --recursive \
|
|
75
|
+
--mode find-replace --find "feat\." --replace "ft." --regex \
|
|
76
|
+
--fields title,artist
|
|
77
|
+
|
|
78
|
+
For full command details, see the [CLI Reference](docs/cli_reference.md).
|
|
79
|
+
For code API details, see the [API Reference](docs/api_reference.md).
|
|
80
|
+
|
|
81
|
+
# Append to Comment
|
|
82
|
+
mudio *.m4a --mode append --fields comment --value " [Remastered]"
|
|
83
|
+
|
|
84
|
+
# Filtered Processing
|
|
85
|
+
# Only add "Rock" genre to tracks by "Led Zeppelin"
|
|
86
|
+
mudio /library --recursive \
|
|
87
|
+
--filter "artist=Led Zeppelin" \
|
|
88
|
+
--mode overwrite --fields genre --value "Rock"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Safety Features
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Dry Run (See what would happen without modifying files)
|
|
95
|
+
mudio *.mp3 --mode set --album "Test" --dry-run
|
|
96
|
+
|
|
97
|
+
# Create Backups (Saved to ./backups/)
|
|
98
|
+
mudio *.flac --mode clear --fields comment --backup ./backups
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Python Library Usage
|
|
102
|
+
|
|
103
|
+
`mudio` provides a Pythonic wrapper around `mutagen` for scripts and tools.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from mudio import SimpleMusic
|
|
107
|
+
|
|
108
|
+
# Reading
|
|
109
|
+
with SimpleMusic("song.flac") as sm:
|
|
110
|
+
print(sm.read_fields())
|
|
111
|
+
# {'artist': ['The Band'], 'title': ['The Song'], ...}
|
|
112
|
+
|
|
113
|
+
# Writing
|
|
114
|
+
with SimpleMusic("song.mp3") as sm:
|
|
115
|
+
sm.write_fields({
|
|
116
|
+
'title': ['New Title'],
|
|
117
|
+
'genre': ['Pop', 'Rock'] # Multi-value support
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
# Error handling is managed by the context manager
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Comparison with Alternatives
|
|
124
|
+
|
|
125
|
+
### vs. **Mutagen**
|
|
126
|
+
- **Mutagen** is the low-level library that `mudio` uses. It is powerful but requires learning different APIs for ID3, Vorbis, and MP4 tags.
|
|
127
|
+
- **mudio** abstracts these differences. Use `mudio` if you want a simple, unified API (e.g. `sm.write_fields({'title': ...})` works on everything). Use `mutagen` if you need byte-level control or support for obscure frame types.
|
|
128
|
+
|
|
129
|
+
### vs. **Beets**
|
|
130
|
+
- **Beets** is a complete library manager with a centralized database, autotagger, and plugin system. It implies a workflow where it "owns" your library.
|
|
131
|
+
- **mudio** is a stateless tool. It modifies files directly without a database. Use `mudio` for quick fixes, batch scripting, or if you prefer managing your file structure manually.
|
|
132
|
+
|
|
133
|
+
### vs. **Picard**
|
|
134
|
+
- **MusicBrainz Picard** is a GUI application focused on matching files to the MusicBrainz database.
|
|
135
|
+
- **mudio** is a CLI/Library tool. It's better for automation, headless servers, or mass-editing tags based on patterns rather than database matching.
|
|
136
|
+
|
|
137
|
+
### vs. **music_tag**
|
|
138
|
+
- **music_tag** is a library primarily for Python scripts, offering a dictionary-like interface. It is excellent for simple script usage.
|
|
139
|
+
- **mudio** offers similar library features but includes a **robust CLI** for batch processing, filtering, and safety operations (backups, dry-runs) out of the box.
|
|
140
|
+
|
|
141
|
+
### vs. **EyeD3**
|
|
142
|
+
- **EyeD3** is excellent but specific to MP3/ID3.
|
|
143
|
+
- **mudio** supports FLAC, M4A, OGG, and more with the same commands.
|
|
144
|
+
|
|
145
|
+
## Development
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Install dependencies
|
|
149
|
+
pip install -e ".[dev]"
|
|
150
|
+
|
|
151
|
+
# Run tests
|
|
152
|
+
pytest
|
|
153
|
+
```
|
mudio-1.0.0/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# mudio
|
|
2
|
+
|
|
3
|
+
**mudio** is a powerful, friendly command-line music metadata editor and Python library. It provides a unified API for handling metadata across MP3, FLAC, M4A, and more, making batch processing and automation simple and safe.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Unified API**: Write code once, run it on MP3, FLAC, M4A, WAV, OGG, OPUS, WMA, and WavPack.
|
|
8
|
+
- **Batch Processing**: robust CLI for processing thousands of files.
|
|
9
|
+
- **Parallel Execution**: Automatically uses multi-threading for large batches.
|
|
10
|
+
- **Safety First**: Built-in **backup** system, **dry-run** mode, and careful validation.
|
|
11
|
+
- **Powerful Operations**:
|
|
12
|
+
- **Find & Replace**: Regex-supported search and replace in tags.
|
|
13
|
+
- **Mass Edits**: Set, overwrite, append, prefix, or clear tags.
|
|
14
|
+
- **Filtering**: Apply changes only to files matching specific criteria (e.g. `artist="The Beatles"`).
|
|
15
|
+
|
|
16
|
+
## Supported Formats
|
|
17
|
+
|
|
18
|
+
- **MP3** (`.mp3`) - ID3v2.3/v2.4
|
|
19
|
+
- **FLAC** (`.flac`) - Vorbis Comments
|
|
20
|
+
- **M4A / MP4** (`.m4a`, `.mp4`) - MP4 Tags
|
|
21
|
+
- **Ogg Vorbis** (`.ogg`)
|
|
22
|
+
- **Opus** (`.opus`)
|
|
23
|
+
- **WAV** (`.wav`)
|
|
24
|
+
- **Windows Media Audio** (`.wma`)
|
|
25
|
+
- **WavPack** (`.wv`)
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install mudio
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## CLI Usage
|
|
34
|
+
|
|
35
|
+
`mudio` is designed for efficient batch operations.
|
|
36
|
+
|
|
37
|
+
### Basic Commands
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# View metadata
|
|
41
|
+
mudio song.mp3 --mode view
|
|
42
|
+
|
|
43
|
+
# Set Album and Date
|
|
44
|
+
mudio *.mp3 --mode set --album "New Album" --date "2024"
|
|
45
|
+
|
|
46
|
+
# View metadata (truncated if long)
|
|
47
|
+
mudio song.mp3 --mode print
|
|
48
|
+
|
|
49
|
+
# Overwrite Title
|
|
50
|
+
mudio song.flac --mode overwrite --fields title --value "My Song"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Advanced Batch Operations
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Regex Find & Replace (Fix features)
|
|
57
|
+
# Changes "feat." -> "ft." in title and artist
|
|
58
|
+
mudio /music --recursive \
|
|
59
|
+
--mode find-replace --find "feat\." --replace "ft." --regex \
|
|
60
|
+
--fields title,artist
|
|
61
|
+
|
|
62
|
+
For full command details, see the [CLI Reference](docs/cli_reference.md).
|
|
63
|
+
For code API details, see the [API Reference](docs/api_reference.md).
|
|
64
|
+
|
|
65
|
+
# Append to Comment
|
|
66
|
+
mudio *.m4a --mode append --fields comment --value " [Remastered]"
|
|
67
|
+
|
|
68
|
+
# Filtered Processing
|
|
69
|
+
# Only add "Rock" genre to tracks by "Led Zeppelin"
|
|
70
|
+
mudio /library --recursive \
|
|
71
|
+
--filter "artist=Led Zeppelin" \
|
|
72
|
+
--mode overwrite --fields genre --value "Rock"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Safety Features
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Dry Run (See what would happen without modifying files)
|
|
79
|
+
mudio *.mp3 --mode set --album "Test" --dry-run
|
|
80
|
+
|
|
81
|
+
# Create Backups (Saved to ./backups/)
|
|
82
|
+
mudio *.flac --mode clear --fields comment --backup ./backups
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Python Library Usage
|
|
86
|
+
|
|
87
|
+
`mudio` provides a Pythonic wrapper around `mutagen` for scripts and tools.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from mudio import SimpleMusic
|
|
91
|
+
|
|
92
|
+
# Reading
|
|
93
|
+
with SimpleMusic("song.flac") as sm:
|
|
94
|
+
print(sm.read_fields())
|
|
95
|
+
# {'artist': ['The Band'], 'title': ['The Song'], ...}
|
|
96
|
+
|
|
97
|
+
# Writing
|
|
98
|
+
with SimpleMusic("song.mp3") as sm:
|
|
99
|
+
sm.write_fields({
|
|
100
|
+
'title': ['New Title'],
|
|
101
|
+
'genre': ['Pop', 'Rock'] # Multi-value support
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
# Error handling is managed by the context manager
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Comparison with Alternatives
|
|
108
|
+
|
|
109
|
+
### vs. **Mutagen**
|
|
110
|
+
- **Mutagen** is the low-level library that `mudio` uses. It is powerful but requires learning different APIs for ID3, Vorbis, and MP4 tags.
|
|
111
|
+
- **mudio** abstracts these differences. Use `mudio` if you want a simple, unified API (e.g. `sm.write_fields({'title': ...})` works on everything). Use `mutagen` if you need byte-level control or support for obscure frame types.
|
|
112
|
+
|
|
113
|
+
### vs. **Beets**
|
|
114
|
+
- **Beets** is a complete library manager with a centralized database, autotagger, and plugin system. It implies a workflow where it "owns" your library.
|
|
115
|
+
- **mudio** is a stateless tool. It modifies files directly without a database. Use `mudio` for quick fixes, batch scripting, or if you prefer managing your file structure manually.
|
|
116
|
+
|
|
117
|
+
### vs. **Picard**
|
|
118
|
+
- **MusicBrainz Picard** is a GUI application focused on matching files to the MusicBrainz database.
|
|
119
|
+
- **mudio** is a CLI/Library tool. It's better for automation, headless servers, or mass-editing tags based on patterns rather than database matching.
|
|
120
|
+
|
|
121
|
+
### vs. **music_tag**
|
|
122
|
+
- **music_tag** is a library primarily for Python scripts, offering a dictionary-like interface. It is excellent for simple script usage.
|
|
123
|
+
- **mudio** offers similar library features but includes a **robust CLI** for batch processing, filtering, and safety operations (backups, dry-runs) out of the box.
|
|
124
|
+
|
|
125
|
+
### vs. **EyeD3**
|
|
126
|
+
- **EyeD3** is excellent but specific to MP3/ID3.
|
|
127
|
+
- **mudio** supports FLAC, M4A, OGG, and more with the same commands.
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Install dependencies
|
|
133
|
+
pip install -e ".[dev]"
|
|
134
|
+
|
|
135
|
+
# Run tests
|
|
136
|
+
pytest
|
|
137
|
+
```
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# mudio API Reference
|
|
2
|
+
|
|
3
|
+
This document provides a detailed reference for the internal Python API of `mudio`. It is useful for developers who want to use `mudio` as a library in their own scripts or applications.
|
|
4
|
+
|
|
5
|
+
## Core (`mudio.core`)
|
|
6
|
+
|
|
7
|
+
The core module handles the abstraction layer for reading and writing metadata across different audio formats.
|
|
8
|
+
|
|
9
|
+
### `SimpleMusic`
|
|
10
|
+
|
|
11
|
+
The primary interface for interacting with audio files. It automatically handles format detection (MP3, FLAC, M4A, etc.) and provides a unified dictionary-based API for tags.
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from mudio.core import SimpleMusic, managed_simple_music
|
|
15
|
+
|
|
16
|
+
# Recommended: Use context manager to ensure files are closed safely
|
|
17
|
+
with managed_simple_music("path/to/song.mp3") as sm:
|
|
18
|
+
fields = sm.read_fields()
|
|
19
|
+
sm.write_fields({"title": ["New Title"]})
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
#### Class Reference
|
|
23
|
+
|
|
24
|
+
**`SimpleMusic(path: Union[str, Path])`**
|
|
25
|
+
* **path**: The file path to open.
|
|
26
|
+
* **Raises**:
|
|
27
|
+
* `FormatError`: If the file format is unsupported or corrupted.
|
|
28
|
+
* `RuntimeError`: If the file does not exist.
|
|
29
|
+
|
|
30
|
+
**`SimpleMusic.read_fields(mode: str = 'canonical') -> Dict[str, List[str]]`**
|
|
31
|
+
Reads metadata fields from the file.
|
|
32
|
+
* **mode**:
|
|
33
|
+
* `'canonical'` (default): Returns a standardized dictionary using `mudio`'s canonical field names (e.g. `title`, `artist`, `date`).
|
|
34
|
+
* `'raw'`: Returns the raw mapping of tags as they appear in the file (e.g. `TIT2` for MP3 title, `©nam` for MP4).
|
|
35
|
+
* `'extended'`: Returns all canonical fields **plus** any other fields found in the file that didn't map to a canonical one (e.g. `acoustid_id`, custom TXXX frames).
|
|
36
|
+
* **Returns**: A dictionary where keys are field names and values are a **list of strings**.
|
|
37
|
+
* **Note**: `mudio` uses a unified list-based structure for I/O consistency. However, fields have semantic cardinality:
|
|
38
|
+
* **Single-valued** (e.g. `title`, `date`, `track`): Logic operations will typically use only the first value.
|
|
39
|
+
* **Multi-valued** (e.g. `artist`, `genre`): Logic operations maintain the full list.
|
|
40
|
+
* See `mudio.operations` for field definitions.
|
|
41
|
+
|
|
42
|
+
**`SimpleMusic.write_fields(fields: Dict[str, List[str]])`**
|
|
43
|
+
Writes metadata to the file.
|
|
44
|
+
* **Raises**:
|
|
45
|
+
* `PermissionError`: If the file is not writable.
|
|
46
|
+
* `RuntimeError`: If no file is loaded.
|
|
47
|
+
* **fields**: A dictionary of fields to write. Keys can be canonical field names (like `title`, `artist`) or **any custom string**.
|
|
48
|
+
* **Behavior**:
|
|
49
|
+
* **Custom Fields**: Arbitrary keys are written as format-specific custom tags (TXXX for ID3, comments for Vorbis, freeform atoms for MP4).
|
|
50
|
+
* Existing fields not in the input dictionary are **preserved**. (To delete a field, use `delete_fields` or pass an empty list `[]` as the value).
|
|
51
|
+
* This method transparently handles format-specific details.
|
|
52
|
+
|
|
53
|
+
**`SimpleMusic.delete_fields(fields: List[str])`**
|
|
54
|
+
Deletes the specified fields from the file.
|
|
55
|
+
* **fields**: List of canonical or custom field names to remove.
|
|
56
|
+
|
|
57
|
+
**`SimpleMusic.close()`**
|
|
58
|
+
Closes the underlying file handle. Automatically called when using the context manager.
|
|
59
|
+
|
|
60
|
+
**`SimpleMusic.parse_list_string(s: Optional[str], delimiter: str = ';') -> List[str]`**
|
|
61
|
+
Static utility method to split a string into a list based on a delimiter.
|
|
62
|
+
* **s**: The string to parse.
|
|
63
|
+
* **delimiter**: The delimiter character (default `;`).
|
|
64
|
+
* **Returns**: List of strings, stripped of whitespace.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Processor (`mudio.processor`)
|
|
69
|
+
|
|
70
|
+
The processor module handles high-level batch processing, including parallel execution, file validation, backups, and error reporting.
|
|
71
|
+
|
|
72
|
+
### Batch Processing Functions
|
|
73
|
+
|
|
74
|
+
**`process_files(files: Iterable[Path], ops: FieldOperationsType, targeted_fields: List[str], ...)`**
|
|
75
|
+
The main entry point for processing a batch of files. It automatically chooses between sequential and parallel processing based on the number of files and configuration.
|
|
76
|
+
|
|
77
|
+
* **files**: An iterable of `Path` objects to process.
|
|
78
|
+
* **ops**: A dictionary mapping field names to operation functions (see `mudio.operations`).
|
|
79
|
+
* **targeted_fields**: A list of fields being modified (used for verification).
|
|
80
|
+
* **max_workers** (int): Number of threads to use (default: CPU count).
|
|
81
|
+
* **dry_run** (bool): If `True`, calculates changes but does not write to disk.
|
|
82
|
+
* **backup_dir** (str): Path to directory for storing backups.
|
|
83
|
+
* **force** (bool): If `True`, overwrites existing backups/files where necessary.
|
|
84
|
+
* **verbose** (bool): Enables progress printing.
|
|
85
|
+
* **filters** (List): A list of filters to apply before processing.
|
|
86
|
+
|
|
87
|
+
**`process_file(path: str, ops: FieldOperationsType, targeted_fields: List[str], ...)`**
|
|
88
|
+
Processes a single file.
|
|
89
|
+
1. Validates file (permissions, format).
|
|
90
|
+
2. Applies filters.
|
|
91
|
+
3. Computes new tag values using `ops`.
|
|
92
|
+
4. Creates backup (if requested).
|
|
93
|
+
5. Writes changes.
|
|
94
|
+
6. Verifies changes by re-reading the file.
|
|
95
|
+
|
|
96
|
+
### Validation
|
|
97
|
+
|
|
98
|
+
**`validate_file(path: Path) -> Tuple[bool, str]`**
|
|
99
|
+
Performs comprehensive checks:
|
|
100
|
+
* Existence and file type.
|
|
101
|
+
* Read/Write permissions.
|
|
102
|
+
* File size (checks for empty files or files exceeding limits).
|
|
103
|
+
* Format validity (can `mutagen` parse it?).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Operations (`mudio.operations`)
|
|
108
|
+
|
|
109
|
+
This module defines how field values are transformed. It provides the logic for "Set", "Append", "Regex Replace", etc.
|
|
110
|
+
|
|
111
|
+
### `FieldOperations` Class
|
|
112
|
+
|
|
113
|
+
**`FieldOperations.normalize_values(field_name: str, values: List[str]) -> List[str]`**
|
|
114
|
+
Ensures field values are consistent.
|
|
115
|
+
* **Multi-valued fields** (artist, genre, etc.): Deduplicates values while preserving order (case-insensitive).
|
|
116
|
+
* **Single-valued fields** (title, date, track): Takes only the first value.
|
|
117
|
+
|
|
118
|
+
### Operation Factories
|
|
119
|
+
|
|
120
|
+
These functions return a callable `op(values: List[str]) -> List[str]` that transforms existing values into new ones.
|
|
121
|
+
|
|
122
|
+
* **`op_overwrite(field, value, delimiter=';')`**: Replaces existing values. Splits strings on `delimiter` for multi-valued fields.
|
|
123
|
+
* **`op_append(field, value, delimiter=';')`**:
|
|
124
|
+
* Single-valued: Appends string.
|
|
125
|
+
* Multi-valued: Adds new item(s) (split by `delimiter`) if not present.
|
|
126
|
+
* **`op_prefix(field, value)`**: Prepends string to values.
|
|
127
|
+
* **`op_find_replace(field, find, replace, regex=False, delimiter=';')`**: Performs string substitution. If result contains `delimiter`, splits into multiple values (for multi-valued fields).
|
|
128
|
+
* **`op_enlist(field, value, delimiter=';')`**: Enlists value(s) (split by `delimiter`) to a multi-valued field list only if it doesn't already exist.
|
|
129
|
+
* **`op_delist(field, value, delimiter=';')`**: Delists (removes) specific value(s) from a multi-valued field.
|
|
130
|
+
* **`op_clear(field)`**: Returns `[""]` (empty string), setting the tag to empty but keeping the key.
|
|
131
|
+
* **`op_delete(field)`**: Returns `[]` (empty list), removing the tag key entirely.
|
|
132
|
+
|
|
133
|
+
> **Note**: Behavior of empty values varies by format. ID3 tags may store empty frames; Vorbis comments typically omit empty values.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Utilities (`mudio.utils`)
|
|
138
|
+
|
|
139
|
+
**`Config`**
|
|
140
|
+
Global configuration settings, loaded from environment variables.
|
|
141
|
+
* `MUDIO_MAX_WORKERS`: Default thread count.
|
|
142
|
+
* `MUDIO_BACKUP_DIR`: Default backup location.
|
|
143
|
+
* `MUDIO_VERBOSE`: Default verbosity.
|
|
144
|
+
|
|
145
|
+
**`get_file_hash(path: Path)`**
|
|
146
|
+
Calculates SHA-256 hash of a file for verification.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Types and Errors
|
|
151
|
+
|
|
152
|
+
### Error Hierarchy
|
|
153
|
+
|
|
154
|
+
The API defines a hierarchy of exceptions for robust error handling:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
class MudioError(Exception): ...
|
|
158
|
+
class ValidationError(MudioError): ... # Invalid arguments or state
|
|
159
|
+
class FormatError(MudioError): ... # File format issues
|
|
160
|
+
class PermissionError(MudioError): ... # Filesystem permission issues
|
|
161
|
+
class VerificationError(MudioError): ... # Post-write verification failed
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Type Definitions
|
|
165
|
+
|
|
166
|
+
Common type aliases used in function signatures:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
FieldOperationsType = Dict[str, Callable[[List[str]], List[str]]]
|
|
170
|
+
FieldValuesType = Dict[str, List[str]]
|
|
171
|
+
FilterType = Tuple[str, str, bool]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
* **`FieldOperationsType`**: Maps target field names to transformation functions.
|
|
175
|
+
* **`FieldValuesType`**: Standard dictionary for metadata (Field -> List of Strings).
|