track-id 0.1.3__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.
- track_id-0.1.3/.cursor/rules/uv-track-id-setup.mdc +25 -0
- track_id-0.1.3/.github/workflows/package-validation.yml +34 -0
- track_id-0.1.3/.github/workflows/publish-pypi.yml +47 -0
- track_id-0.1.3/.gitignore +27 -0
- track_id-0.1.3/.python-version +1 -0
- track_id-0.1.3/CLAUDE.md +72 -0
- track_id-0.1.3/LICENSE +21 -0
- track_id-0.1.3/PKG-INFO +184 -0
- track_id-0.1.3/README.md +132 -0
- track_id-0.1.3/docs/pypi-release-guide.md +53 -0
- track_id-0.1.3/pyproject.toml +60 -0
- track_id-0.1.3/tests/__init__.py +1 -0
- track_id-0.1.3/tests/conftest.py +39 -0
- track_id-0.1.3/tests/test_artwork.py +141 -0
- track_id-0.1.3/tests/test_bandcamp_api.py +221 -0
- track_id-0.1.3/tests/test_data_sources.py +317 -0
- track_id-0.1.3/tests/test_discogs_api.py +256 -0
- track_id-0.1.3/tests/test_filename_parsing.py +109 -0
- track_id-0.1.3/tests/test_id3_tags.py +44 -0
- track_id-0.1.3/tests/test_integration.py +117 -0
- track_id-0.1.3/tests/test_musicbrainz_api.py +290 -0
- track_id-0.1.3/tests/test_track_id.py +321 -0
- track_id-0.1.3/track_id/__init__.py +6 -0
- track_id-0.1.3/track_id/bandcamp_api.py +88 -0
- track_id-0.1.3/track_id/data_sources.py +202 -0
- track_id-0.1.3/track_id/discogs_api.py +169 -0
- track_id-0.1.3/track_id/display.py +387 -0
- track_id-0.1.3/track_id/enrichment_handlers.py +75 -0
- track_id-0.1.3/track_id/id3_tags.py +49 -0
- track_id-0.1.3/track_id/mp3_utils.py +288 -0
- track_id-0.1.3/track_id/musicbrainz_api.py +156 -0
- track_id-0.1.3/track_id/track_id.py +88 -0
- track_id-0.1.3/track_id/unified_api.py +52 -0
- track_id-0.1.3/uv.lock +541 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
description:
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Cursor Rules for track-id project
|
|
8
|
+
|
|
9
|
+
## Project Setup
|
|
10
|
+
- This is a Python project using uv for dependency management
|
|
11
|
+
- Main package: `track_id`
|
|
12
|
+
- Entry point: `track_id.track_id:app`
|
|
13
|
+
- Python version: >=3.9
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
- Install dependencies: `uv sync`
|
|
17
|
+
- Run the app: `uv run track-id`
|
|
18
|
+
- Run tests: `uv run pytest`
|
|
19
|
+
- Add dependency: `uv add <package>`
|
|
20
|
+
- Add dev dependency: `uv add --dev <package>`
|
|
21
|
+
|
|
22
|
+
## Code Style
|
|
23
|
+
- Follow Python conventions
|
|
24
|
+
- Use type hints where appropriate
|
|
25
|
+
- Keep functions focused and testable
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Package Validation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
validate-package:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- name: Install uv
|
|
22
|
+
uses: astral-sh/setup-uv@v5
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: uv sync --dev
|
|
26
|
+
|
|
27
|
+
- name: Run tests
|
|
28
|
+
run: uv run pytest
|
|
29
|
+
|
|
30
|
+
- name: Build distributions
|
|
31
|
+
run: uv build
|
|
32
|
+
|
|
33
|
+
- name: Validate distribution metadata
|
|
34
|
+
run: uvx twine check dist/*
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: publish-pypi
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
repository:
|
|
7
|
+
description: "Target repository (testpypi or pypi)"
|
|
8
|
+
required: true
|
|
9
|
+
default: testpypi
|
|
10
|
+
type: choice
|
|
11
|
+
options:
|
|
12
|
+
- testpypi
|
|
13
|
+
- pypi
|
|
14
|
+
push:
|
|
15
|
+
tags:
|
|
16
|
+
- "v*"
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
publish:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
environment:
|
|
22
|
+
name: pypi
|
|
23
|
+
url: https://pypi.org/p/track-id
|
|
24
|
+
permissions:
|
|
25
|
+
id-token: write
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Set up Python
|
|
31
|
+
uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
|
|
35
|
+
- name: Install build dependencies
|
|
36
|
+
run: python -m pip install --upgrade pip build twine
|
|
37
|
+
|
|
38
|
+
- name: Build package
|
|
39
|
+
run: python -m build
|
|
40
|
+
|
|
41
|
+
- name: Check package metadata
|
|
42
|
+
run: twine check dist/*
|
|
43
|
+
|
|
44
|
+
- name: Publish to PyPI
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
46
|
+
with:
|
|
47
|
+
repository-url: ${{ inputs.repository == 'testpypi' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Test files
|
|
13
|
+
.coverage
|
|
14
|
+
|
|
15
|
+
# MacOS files
|
|
16
|
+
.DS_Store
|
|
17
|
+
|
|
18
|
+
# Audio files
|
|
19
|
+
*.mp3
|
|
20
|
+
*.m4a
|
|
21
|
+
*.flac
|
|
22
|
+
*.wav
|
|
23
|
+
*.ogg
|
|
24
|
+
*.aac
|
|
25
|
+
*.m4b
|
|
26
|
+
*.m4p
|
|
27
|
+
*.m4a
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.9
|
track_id-0.1.3/CLAUDE.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**Track-ID** is a Python CLI tool for music metadata enrichment and search. It searches tracks across multiple music data sources (Bandcamp, MusicBrainz), displays MP3 file info, and enriches MP3 files with metadata from external music databases.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
uv sync
|
|
14
|
+
|
|
15
|
+
# Run the CLI
|
|
16
|
+
uv run track-id search "Artist - Title"
|
|
17
|
+
uv run track-id info path/to/file.mp3
|
|
18
|
+
uv run track-id enrich path/to/file.mp3
|
|
19
|
+
|
|
20
|
+
# Run tests
|
|
21
|
+
uv run pytest
|
|
22
|
+
uv run pytest tests/test_bandcamp_api.py -v # single file
|
|
23
|
+
uv run pytest -m unit # unit tests only
|
|
24
|
+
uv run pytest -m integration # integration tests only
|
|
25
|
+
uv run pytest -m "not slow" # exclude slow tests
|
|
26
|
+
uv run pytest --cov=track_id --cov-report=term-missing
|
|
27
|
+
|
|
28
|
+
# Type checking
|
|
29
|
+
mypy track_id/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
### Data Source Plugin System
|
|
35
|
+
|
|
36
|
+
New music sources are added by subclassing `DataSource` in `data_sources.py` and registering with `DataSourceRegistry`. Each source must implement:
|
|
37
|
+
- `search(search_text)` — call external API, return raw response
|
|
38
|
+
- `find_matching_track(search_results, artist, title)` — select best match
|
|
39
|
+
- `extract_metadata(track_data)` — normalize to ID3 tag dict
|
|
40
|
+
- `enrich_mp3_file(file_path)` — orchestrates enrichment end-to-end
|
|
41
|
+
|
|
42
|
+
`unified_api.py` initializes all sources and aggregates results across them.
|
|
43
|
+
|
|
44
|
+
### Data Flow
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
CLI (track_id.py)
|
|
48
|
+
→ unified_api.py # aggregates across sources
|
|
49
|
+
→ DataSourceRegistry # dispatches to each source
|
|
50
|
+
→ BandcampDataSource / MusicBrainzDataSource
|
|
51
|
+
→ MP3File (mp3_utils.py) # reads/writes ID3 tags via mutagen
|
|
52
|
+
→ display.py # Rich console output
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Key Files
|
|
56
|
+
|
|
57
|
+
| File | Role |
|
|
58
|
+
|------|------|
|
|
59
|
+
| `track_id/track_id.py` | CLI commands (Typer app) |
|
|
60
|
+
| `track_id/unified_api.py` | Orchestrates search/enrich across all sources |
|
|
61
|
+
| `track_id/data_sources.py` | Abstract base class + registry |
|
|
62
|
+
| `track_id/mp3_utils.py` | `MP3File` class — ID3 read/write, filename parsing |
|
|
63
|
+
| `track_id/display.py` | All Rich console output |
|
|
64
|
+
| `track_id/enrichment_handlers.py` | Shared logic reused by concrete data sources |
|
|
65
|
+
|
|
66
|
+
### MP3File
|
|
67
|
+
|
|
68
|
+
`MP3File` in `mp3_utils.py` is the core data object. It wraps mutagen for ID3 tag access, parses `Artist - Title` filenames, caches metadata, and handles artwork download. Pass it between layers rather than raw file paths wherever possible.
|
|
69
|
+
|
|
70
|
+
### ID3 Tags
|
|
71
|
+
|
|
72
|
+
`id3_tags.py` holds the canonical mapping of tag names used across the project. When adding new metadata fields, update this file first.
|
track_id-0.1.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 track-id contributors
|
|
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.
|
track_id-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: track-id
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: CLI for searching and enriching MP3 metadata from Bandcamp, MusicBrainz, and Discogs
|
|
5
|
+
Project-URL: Homepage, https://github.com/vtasca/track-id
|
|
6
|
+
Project-URL: Repository, https://github.com/vtasca/track-id
|
|
7
|
+
Project-URL: Issues, https://github.com/vtasca/track-id/issues
|
|
8
|
+
Author: track-id contributors
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 track-id contributors
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: bandcamp,cli,discogs,id3,metadata,mp3,music,musicbrainz
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Environment :: Console
|
|
34
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
43
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
44
|
+
Classifier: Topic :: Utilities
|
|
45
|
+
Requires-Python: >=3.9
|
|
46
|
+
Requires-Dist: mutagen>=1.47.0
|
|
47
|
+
Requires-Dist: requests>=2.32.4
|
|
48
|
+
Requires-Dist: rich>=13.0.0
|
|
49
|
+
Requires-Dist: typer>=0.16.0
|
|
50
|
+
Requires-Dist: urllib3<2.0.0
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
# track-id
|
|
54
|
+
|
|
55
|
+
A Python CLI tool for music metadata enrichment and search. Searches tracks across Bandcamp, MusicBrainz, and Discogs, displays MP3 file info, and enriches MP3 files with metadata from external music databases.
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- **Search**: Search for tracks across Bandcamp, MusicBrainz, and Discogs
|
|
60
|
+
- **Info**: Display detailed information about an MP3 file including all ID3 tags
|
|
61
|
+
- **Enrich**: Automatically populate an MP3 file's metadata (artist, album, genre, label, styles, track number, artwork, etc.) from Bandcamp, MusicBrainz, and Discogs
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
### Using uv
|
|
66
|
+
|
|
67
|
+
Install from PyPI as a tool:
|
|
68
|
+
```bash
|
|
69
|
+
uv tool install track-id
|
|
70
|
+
track-id --version
|
|
71
|
+
track-id search "Chaos In The CBD"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Using pip
|
|
75
|
+
|
|
76
|
+
Install from PyPI with pip:
|
|
77
|
+
```bash
|
|
78
|
+
pip install track-id
|
|
79
|
+
track-id --version
|
|
80
|
+
track-id search "Chaos In The CBD"
|
|
81
|
+
track-id info "path/to/your/file.mp3"
|
|
82
|
+
track-id enrich "path/to/your/file.mp3"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Clone and install locally
|
|
86
|
+
|
|
87
|
+
Mainly for development purposes:
|
|
88
|
+
```bash
|
|
89
|
+
# Clone the repository
|
|
90
|
+
git clone https://github.com/vtasca/track-id
|
|
91
|
+
cd track-id
|
|
92
|
+
|
|
93
|
+
# Install dependencies
|
|
94
|
+
uv sync
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Usage
|
|
98
|
+
|
|
99
|
+
### Search for tracks
|
|
100
|
+
|
|
101
|
+
Search across Bandcamp, MusicBrainz, and Discogs simultaneously:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
track-id search "Chaos In The CBD"
|
|
105
|
+
track-id search "Burial - Archangel" --top 5
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The `--top` / `-t` flag controls how many results are shown per source (default: 3).
|
|
109
|
+
|
|
110
|
+
### Display MP3 file information
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
track-id info "path/to/your/file.mp3"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Enrich an MP3 file with metadata
|
|
117
|
+
|
|
118
|
+
Queries Bandcamp, MusicBrainz, and Discogs for a matching track and writes the retrieved metadata directly into the file's ID3 tags:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
track-id enrich "path/to/your/file.mp3"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The file must have either existing `Artist` and `Title` ID3 tags, or an `Artist - Title` filename so the tool knows what to search for. All three sources are tried and their results merged — existing tags are never overwritten.
|
|
125
|
+
|
|
126
|
+
Tags populated across sources include: `Title`, `Artist`, `Album Artist`, `Album`, `Year`, `Track Number`, `Genre`, `Publisher/Label`, `Style` (Discogs community tags), `Artwork`, and a `Discogs URL` reference.
|
|
127
|
+
|
|
128
|
+
## Development
|
|
129
|
+
|
|
130
|
+
### Setting up the development environment
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv sync --dev
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Running tests
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Run all tests
|
|
140
|
+
uv run pytest
|
|
141
|
+
|
|
142
|
+
# Run with coverage
|
|
143
|
+
uv run pytest --cov=track_id --cov-report=term-missing
|
|
144
|
+
|
|
145
|
+
# Run a specific file
|
|
146
|
+
uv run pytest tests/test_data_sources.py -v
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Project Structure
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
track-id/
|
|
153
|
+
├── track_id/
|
|
154
|
+
│ ├── track_id.py # CLI commands (Typer app)
|
|
155
|
+
│ ├── unified_api.py # Orchestrates search/enrich across all sources
|
|
156
|
+
│ ├── data_sources.py # Abstract base class + registry
|
|
157
|
+
│ ├── bandcamp_api.py # Bandcamp data source
|
|
158
|
+
│ ├── musicbrainz_api.py # MusicBrainz data source
|
|
159
|
+
│ ├── discogs_api.py # Discogs data source
|
|
160
|
+
│ ├── enrichment_handlers.py# Shared enrichment logic
|
|
161
|
+
│ ├── mp3_utils.py # MP3File class — ID3 read/write, filename parsing
|
|
162
|
+
│ ├── display.py # Rich console output
|
|
163
|
+
│ ├── id3_tags.py # Canonical ID3 tag name mapping
|
|
164
|
+
│ └── __init__.py
|
|
165
|
+
├── tests/
|
|
166
|
+
│ ├── conftest.py
|
|
167
|
+
│ ├── test_data_sources.py
|
|
168
|
+
│ ├── test_bandcamp_api.py
|
|
169
|
+
│ ├── test_musicbrainz_api.py
|
|
170
|
+
│ ├── test_discogs_api.py
|
|
171
|
+
│ ├── test_artwork.py
|
|
172
|
+
│ ├── test_id3_tags.py
|
|
173
|
+
│ ├── test_track_id.py
|
|
174
|
+
│ └── test_integration.py
|
|
175
|
+
├── pyproject.toml
|
|
176
|
+
└── README.md
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Contributing
|
|
180
|
+
|
|
181
|
+
1. Write tests for new features
|
|
182
|
+
2. Ensure all tests pass
|
|
183
|
+
3. Follow the existing code style
|
|
184
|
+
4. Update documentation as needed
|
track_id-0.1.3/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# track-id
|
|
2
|
+
|
|
3
|
+
A Python CLI tool for music metadata enrichment and search. Searches tracks across Bandcamp, MusicBrainz, and Discogs, displays MP3 file info, and enriches MP3 files with metadata from external music databases.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Search**: Search for tracks across Bandcamp, MusicBrainz, and Discogs
|
|
8
|
+
- **Info**: Display detailed information about an MP3 file including all ID3 tags
|
|
9
|
+
- **Enrich**: Automatically populate an MP3 file's metadata (artist, album, genre, label, styles, track number, artwork, etc.) from Bandcamp, MusicBrainz, and Discogs
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
### Using uv
|
|
14
|
+
|
|
15
|
+
Install from PyPI as a tool:
|
|
16
|
+
```bash
|
|
17
|
+
uv tool install track-id
|
|
18
|
+
track-id --version
|
|
19
|
+
track-id search "Chaos In The CBD"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Using pip
|
|
23
|
+
|
|
24
|
+
Install from PyPI with pip:
|
|
25
|
+
```bash
|
|
26
|
+
pip install track-id
|
|
27
|
+
track-id --version
|
|
28
|
+
track-id search "Chaos In The CBD"
|
|
29
|
+
track-id info "path/to/your/file.mp3"
|
|
30
|
+
track-id enrich "path/to/your/file.mp3"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Clone and install locally
|
|
34
|
+
|
|
35
|
+
Mainly for development purposes:
|
|
36
|
+
```bash
|
|
37
|
+
# Clone the repository
|
|
38
|
+
git clone https://github.com/vtasca/track-id
|
|
39
|
+
cd track-id
|
|
40
|
+
|
|
41
|
+
# Install dependencies
|
|
42
|
+
uv sync
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Search for tracks
|
|
48
|
+
|
|
49
|
+
Search across Bandcamp, MusicBrainz, and Discogs simultaneously:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
track-id search "Chaos In The CBD"
|
|
53
|
+
track-id search "Burial - Archangel" --top 5
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The `--top` / `-t` flag controls how many results are shown per source (default: 3).
|
|
57
|
+
|
|
58
|
+
### Display MP3 file information
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
track-id info "path/to/your/file.mp3"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Enrich an MP3 file with metadata
|
|
65
|
+
|
|
66
|
+
Queries Bandcamp, MusicBrainz, and Discogs for a matching track and writes the retrieved metadata directly into the file's ID3 tags:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
track-id enrich "path/to/your/file.mp3"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The file must have either existing `Artist` and `Title` ID3 tags, or an `Artist - Title` filename so the tool knows what to search for. All three sources are tried and their results merged — existing tags are never overwritten.
|
|
73
|
+
|
|
74
|
+
Tags populated across sources include: `Title`, `Artist`, `Album Artist`, `Album`, `Year`, `Track Number`, `Genre`, `Publisher/Label`, `Style` (Discogs community tags), `Artwork`, and a `Discogs URL` reference.
|
|
75
|
+
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
### Setting up the development environment
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
uv sync --dev
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Running tests
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Run all tests
|
|
88
|
+
uv run pytest
|
|
89
|
+
|
|
90
|
+
# Run with coverage
|
|
91
|
+
uv run pytest --cov=track_id --cov-report=term-missing
|
|
92
|
+
|
|
93
|
+
# Run a specific file
|
|
94
|
+
uv run pytest tests/test_data_sources.py -v
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Project Structure
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
track-id/
|
|
101
|
+
├── track_id/
|
|
102
|
+
│ ├── track_id.py # CLI commands (Typer app)
|
|
103
|
+
│ ├── unified_api.py # Orchestrates search/enrich across all sources
|
|
104
|
+
│ ├── data_sources.py # Abstract base class + registry
|
|
105
|
+
│ ├── bandcamp_api.py # Bandcamp data source
|
|
106
|
+
│ ├── musicbrainz_api.py # MusicBrainz data source
|
|
107
|
+
│ ├── discogs_api.py # Discogs data source
|
|
108
|
+
│ ├── enrichment_handlers.py# Shared enrichment logic
|
|
109
|
+
│ ├── mp3_utils.py # MP3File class — ID3 read/write, filename parsing
|
|
110
|
+
│ ├── display.py # Rich console output
|
|
111
|
+
│ ├── id3_tags.py # Canonical ID3 tag name mapping
|
|
112
|
+
│ └── __init__.py
|
|
113
|
+
├── tests/
|
|
114
|
+
│ ├── conftest.py
|
|
115
|
+
│ ├── test_data_sources.py
|
|
116
|
+
│ ├── test_bandcamp_api.py
|
|
117
|
+
│ ├── test_musicbrainz_api.py
|
|
118
|
+
│ ├── test_discogs_api.py
|
|
119
|
+
│ ├── test_artwork.py
|
|
120
|
+
│ ├── test_id3_tags.py
|
|
121
|
+
│ ├── test_track_id.py
|
|
122
|
+
│ └── test_integration.py
|
|
123
|
+
├── pyproject.toml
|
|
124
|
+
└── README.md
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Contributing
|
|
128
|
+
|
|
129
|
+
1. Write tests for new features
|
|
130
|
+
2. Ensure all tests pass
|
|
131
|
+
3. Follow the existing code style
|
|
132
|
+
4. Update documentation as needed
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# PyPI release guide for `track-id`
|
|
2
|
+
|
|
3
|
+
This guide documents the release path that is now wired into this repository.
|
|
4
|
+
|
|
5
|
+
## One-time setup
|
|
6
|
+
|
|
7
|
+
1. Create and verify accounts:
|
|
8
|
+
- https://pypi.org
|
|
9
|
+
- https://test.pypi.org
|
|
10
|
+
2. In both PyPI and TestPyPI, configure a **Trusted Publisher** for this repo:
|
|
11
|
+
- Owner: `vtasca`
|
|
12
|
+
- Repository: `track-id`
|
|
13
|
+
- Workflow file: `publish-pypi.yml`
|
|
14
|
+
- Environment: leave empty unless you add environment protection rules
|
|
15
|
+
3. Ensure you have permission to create GitHub releases in this repository.
|
|
16
|
+
|
|
17
|
+
## What this repository now includes
|
|
18
|
+
|
|
19
|
+
- Package metadata in `pyproject.toml` ready for PyPI.
|
|
20
|
+
- CI package check workflow: `.github/workflows/package-validation.yml`.
|
|
21
|
+
- Publish workflow: `.github/workflows/publish-pypi.yml`.
|
|
22
|
+
|
|
23
|
+
## Release checklist (every release)
|
|
24
|
+
|
|
25
|
+
1. Update the version in `pyproject.toml` under `[project].version`.
|
|
26
|
+
2. Commit and push the version change.
|
|
27
|
+
3. Wait for package checks to pass in GitHub Actions.
|
|
28
|
+
4. Publish to **TestPyPI** (recommended dry run):
|
|
29
|
+
- Run the `publish-pypi` workflow manually.
|
|
30
|
+
- Choose input `repository = testpypi`.
|
|
31
|
+
5. Verify install from TestPyPI:
|
|
32
|
+
- `python -m venv /tmp/track-id-test && source /tmp/track-id-test/bin/activate`
|
|
33
|
+
- `pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ track-id==<version>`
|
|
34
|
+
- `track-id --version`
|
|
35
|
+
6. Publish to **PyPI**:
|
|
36
|
+
- Preferred: create a GitHub Release (for example `v0.1.4`), which triggers publish to PyPI.
|
|
37
|
+
- Alternative: run workflow dispatch with `repository = pypi`.
|
|
38
|
+
7. Verify public install:
|
|
39
|
+
- `python -m venv /tmp/track-id-prod && source /tmp/track-id-prod/bin/activate`
|
|
40
|
+
- `pip install track-id==<version>`
|
|
41
|
+
- `track-id --version`
|
|
42
|
+
|
|
43
|
+
## Local preflight commands
|
|
44
|
+
|
|
45
|
+
Run these before making a release:
|
|
46
|
+
|
|
47
|
+
1. `uv sync --dev`
|
|
48
|
+
2. `uv run pytest`
|
|
49
|
+
3. `rm -rf dist`
|
|
50
|
+
4. `uv build`
|
|
51
|
+
5. `uvx twine check dist/*`
|
|
52
|
+
|
|
53
|
+
If `twine check` passes and tests are green, the artifact is usually safe to publish.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "track-id"
|
|
3
|
+
version = "0.1.3"
|
|
4
|
+
description = "CLI for searching and enriching MP3 metadata from Bandcamp, MusicBrainz, and Discogs"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.9"
|
|
7
|
+
license = { file = "LICENSE" }
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "track-id contributors" },
|
|
10
|
+
]
|
|
11
|
+
keywords = ["mp3", "id3", "metadata", "music", "cli", "bandcamp", "musicbrainz", "discogs"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Environment :: Console",
|
|
15
|
+
"Intended Audience :: End Users/Desktop",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Multimedia :: Sound/Audio",
|
|
25
|
+
"Topic :: Utilities",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"requests>=2.32.4",
|
|
29
|
+
"typer>=0.16.0",
|
|
30
|
+
"urllib3<2.0.0",
|
|
31
|
+
"mutagen>=1.47.0",
|
|
32
|
+
"rich>=13.0.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/vtasca/track-id"
|
|
37
|
+
Repository = "https://github.com/vtasca/track-id"
|
|
38
|
+
Issues = "https://github.com/vtasca/track-id/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
track-id = "track_id.track_id:app"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["hatchling"]
|
|
45
|
+
build-backend = "hatchling.build"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["track_id"]
|
|
49
|
+
|
|
50
|
+
[dependency-groups]
|
|
51
|
+
dev = [
|
|
52
|
+
"pytest>=7.0.0",
|
|
53
|
+
"pytest-cov>=4.0.0",
|
|
54
|
+
"mypy>=1.17.1",
|
|
55
|
+
"types-requests>=2.31.0.6",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
addopts = ["-v"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests package for track-id
|