Metadata-Version: 2.4
Name: music-metadata-fixer
Version: 0.4.0
Summary: Fix metadata for audio files using AcoustID and MusicBrainz
Author-email: Music Metadata Fixer Contributors <support@example.com>
License: MIT
Project-URL: Homepage, https://github.com/yourusername/music-metadata-fixer
Project-URL: Documentation, https://github.com/yourusername/music-metadata-fixer#readme
Project-URL: Repository, https://github.com/yourusername/music-metadata-fixer.git
Project-URL: Bug Tracker, https://github.com/yourusername/music-metadata-fixer/issues
Keywords: audio,metadata,acoustid,musicbrainz,id3,flac,mp4
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyacoustid>=1.2.2
Requires-Dist: musicbrainzngs>=0.7
Requires-Dist: mutagen>=1.46.0
Requires-Dist: pydub>=0.25.1
Provides-Extra: audio
Requires-Dist: pygame>=2.1.0; extra == "audio"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: flake8>=4.0; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Requires-Dist: pylint>=2.15; extra == "dev"
Dynamic: license-file

# Music Metadata Fixer

[![Python 3.8+](https://img.shields.io/badge/Python-3.8%2B-blue)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/Tests-Passing-green)](#testing)

Automatically fix audio file metadata using **AcoustID fingerprinting** and **MusicBrainz** database. Supports MP3, FLAC, and M4A formats with both CLI and optional GUI interfaces.

## Features

- 🎵 **Automatic Identification** – Fingerprints audio files using AcoustID
- 🗄️ **Metadata Lookup** – Fetches comprehensive metadata from MusicBrainz
- 📝 **Multi-Format Support** – MP3 (ID3), FLAC (Vorbis), M4A (MP4 tags)
- 🎛️ **Dual Interface** – Command-line or Tkinter GUI (optional)
- 🔄 **Batch Processing** – Process entire folders at once
- ⏸️ **Cancellation** – Stop processing cleanly at any time
- 🔧 **Configurable** – Customize API keys, timeouts, preview duration
- 📋 **Full Logging** – Detailed error tracking and debugging
- 🧪 **Well-Tested** – Comprehensive test coverage including edge cases

## Quick Start

### Installation

**From PyPI (Recommended)**
```bash
pip install music-metadata-fixer
```

**From Source**
```bash
git clone https://github.com/yourusername/music-metadata-fixer.git
cd music-metadata-fixer
pip install -e .[dev]
```

### Setup

1. **Get AcoustID API Key** (free): https://acoustid.org/api

2. **Create config file**:
   ```bash
   cp config.json.example config.json
   ```

3. **Edit `config.json`** and add your API key:
   ```json
   {
     "acoustid_api_key": "YOUR_KEY_HERE",
     "preview_duration_ms": 30000,
     ...
   }
   ```

### Usage

#### Command Line

```bash
# Interactive mode (prompts for confirmation on each file)
music-metadata-fixer --directory /path/to/music

# Batch mode (no prompts, requires --batch flag)
music-metadata-fixer --directory /path/to/music --batch

# Disable audio preview
music-metadata-fixer --directory /path/to/music --no-audio

# GUI mode (if available)
music-metadata-fixer --gui
```

#### Python API

```python
from config import Config
from providers import AcoustIDProvider
from engine import MetadataFixerEngine

# Initialize
config = Config('config.json')
provider = AcoustIDProvider(config.get('acoustid_api_key'))
engine = MetadataFixerEngine(provider)

# Process folder
results = engine.batch_process(
    directory='/path/to/music',
    interactive=False,
    auto_confirm=True
)

print(f"Success: {results['success']}, Failed: {results['failed']}")
```

## Requirements

### System Dependencies

- **ffmpeg** – For audio conversion (optional but recommended)
  - macOS: `brew install ffmpeg`
  - Ubuntu: `sudo apt install ffmpeg`
  - Windows: Download from https://ffmpeg.org/download.html

- **fpcalc** – AcoustID fingerprint calculator
  - macOS: `brew install chromaprint`
  - Ubuntu: `sudo apt install libchromaprint-tools`
  - Windows: Download from https://acoustid.org/chromaprint

### Python Dependencies

All installed automatically via `pip install`:
- pyacoustid ≥ 1.2.2
- musicbrainzngs ≥ 0.7
- mutagen ≥ 1.46.0
- pydub ≥ 0.25.1
- pygame ≥ 2.1.0 (audio playback, optional)

## Configuration

### config.json

```json
{
  "acoustid_api_key": "YOUR_API_KEY",           # Required: AcoustID API key
  "preview_duration_ms": 30000,                 # Audio preview duration (ms)
  "log_file": "music_fixer_errors.log",         # Log file path
  "supported_formats": [".mp3", ".flac", ".m4a"], # File formats to process
  "feature_preview": true,                      # Enable audio playback
  "feature_auto_identify": true,                # Auto-identify files
  "feature_manual_edit": true,                  # Allow manual editing
  "console_log": false,                         # Log to console
  "log_level": "INFO"                           # Logging level (DEBUG, INFO, WARNING, ERROR)
}
```

## Architecture

```
┌─────────────────────────────────────────┐
│             CLI / GUI                    │
│    (music_fixer.py / gui_interface.py)   │
└─────────────────┬───────────────────────┘
                  │
┌─────────────────▼───────────────────────┐
│      MetadataFixerEngine                 │
│  (orchestrates identify → fetch → apply) │
└─────────────────┬───────────────────────┘
    ┌─────────────┼─────────────┐
    │             │             │
┌───▼──┐   ┌─────▼─────┐  ┌────▼────┐
│Provider  │FileHandler │  │AudioPlayer
│(AcoustID │  (MP3,     │  │(Preview)
│+Brainz)  │FLAC,M4A)   │  │
└──────┘   └───────────┘  └─────────┘
```

### Module Overview

| Module | Purpose |
|--------|---------|
| `music_fixer.py` | CLI entry point & argument handling |
| `engine.py` | Core processing workflow orchestration |
| `providers.py` | AcoustID + MusicBrainz integration |
| `file_handler.py` | Format-specific tag readers/writers |
| `config.py` | Configuration file management |
| `audio_player.py` | Audio preview with pygame |
| `gui_interface.py` | Optional Tkinter GUI |
| `logger.py` | Centralized logging |
| `cancellable.py` | Cancellation token for clean shutdown |

## Testing

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=. --cov-report=html

# Run specific test file
pytest tests/test_engine.py -v

# Run specific test class
pytest tests/test_providers.py::ProviderCancellationTests -v
```

### Test Coverage

- ✓ Engine workflow (identify → fetch → apply)
- ✓ Provider retries, timeouts, and error handling
- ✓ Cancellation token propagation
- ✓ Batch processing with partial failures
- ✓ File format handlers (MP3, FLAC, M4A)
- ✓ GUI components and threading
- ✓ Configuration loading and validation

## Development

### Setup Development Environment

```bash
pip install -e .[dev]
pre-commit install
```

### Code Quality

```bash
# Type checking
mypy .

# Linting
flake8 .
pylint music_fixer.py

# Auto-formatting
black .
```

### Adding New Provider

See [DEVELOPMENT.md](DEVELOPMENT.md#adding-a-new-provider)

### Adding File Format Support

See [DEVELOPMENT.md](DEVELOPMENT.md#adding-file-format-support)

## Troubleshooting

### "Missing external tools" warning

Install ffmpeg and fpcalc:
```bash
# macOS
brew install ffmpeg chromaprint

# Ubuntu/Debian
sudo apt install ffmpeg libchromaprint-tools

# Or download Windows binaries from respective websites
```

### "API key not found"

Ensure `config.json` has `acoustid_api_key` field populated:
```bash
cp config.json.example config.json
# Edit config.json with your key
```

### Files not being identified

1. Check file format is supported (MP3, FLAC, M4A)
2. Ensure file is a valid audio file (try playing in media player)
3. Verify AcoustID API is responding (check log file)
4. Try with `--no-audio` flag (some systems have audio issues)

### GUI doesn't start

Tkinter may not be installed:
```bash
# Ubuntu/Debian
sudo apt install python3-tk

# macOS
# Should be included; if not: brew install python-tk

# Windows
# Should be included with Python; reinstall Python and select Tcl/Tk
```

### Metadata lookup returns "Unknown"

- File may not be in MusicBrainz database
- Fingerprint calculation may have failed
- Network connectivity issue (check logs)
- Use `--batch --no-audio` for faster processing

## Examples

### Process single folder

```bash
music-metadata-fixer --directory ~/Music/unsorted
```

### Batch process multiple folders

```bash
for folder in ~/Music/Artist1 ~/Music/Artist2; do
    music-metadata-fixer --directory "$folder" --batch
done
```

### Process with logging

```bash
music-metadata-fixer --directory ~/Music --no-audio > processing.log 2>&1
```

### GUI with custom timeout

Edit `config.json`:
```json
{
  "acoustid_api_key": "YOUR_KEY",
  "timeout": 20  // Longer timeout for slow connections
}
```

Then run: `music-metadata-fixer --gui`

## Performance

- Typical file processing: 3-5 seconds (fingerprint + lookup + write)
- Batch processing: ~100 files in 5-10 minutes (depending on network)
- Memory usage: ~50MB idle, ~200MB during batch processing
- Can be reduced by using `--no-audio` flag

## Known Limitations

- GUI is Tkinter-only (not PyQt/PySide)
- Cannot process multiple folders simultaneously
- Requires specific audio file formats (no WAV, OGG, etc. yet)
- Interactive mode requires user input for each file
- No proxy support for MusicBrainz API

## Contributing

Contributions welcome! Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Add tests for new functionality
4. Ensure tests pass (`pytest`)
5. Submit a pull request

See [DEVELOPMENT.md](DEVELOPMENT.md) for detailed guidelines.

## Version History

### v0.4.0 (Current)
- Full type hints across all modules
- Comprehensive test suite (cancellation, failures, GUI)
- Package entry point (`music-metadata-fixer` command)
- Optional dev dependencies for testing/linting
- GUI validation and documentation

### v0.2.0
- Added FLAC and M4A support
- Improved error handling and retries
- Configuration management system

### v0.1.0
- Initial release
- MP3 support with ID3 tags
- AcoustID + MusicBrainz integration
- CLI interface

## License

MIT License – see [LICENSE](LICENSE) for details

## Credits

Built with:
- [pyacoustid](https://github.com/beetbox/pyacoustid) – AcoustID fingerprinting
- [musicbrainzngs](https://github.com/alastair/python-musicbrainzngs) – MusicBrainz API
- [mutagen](https://github.com/quodlibet/mutagen) – Audio metadata handling
- [pydub](https://github.com/jiaaro/pydub) – Audio processing

## Support

- 📖 [Documentation](DEVELOPMENT.md)
- 🐛 [Report Issues](https://github.com/yourusername/music-metadata-fixer/issues)
- 💬 [Discussions](https://github.com/yourusername/music-metadata-fixer/discussions)

---

**Questions?** Check out the [FAQ](FAQ.md) or [troubleshooting guide](#troubleshooting).
