Metadata-Version: 2.4
Name: lrc-maker
Version: 0.2.0
Summary: Convert M4A and TTML lyric files to Enhanced LRC (word-by-word karaoke format)
License: MIT
Project-URL: Homepage, https://github.com/YOUR_USERNAME/lrc-maker
Project-URL: Issues, https://github.com/YOUR_USERNAME/lrc-maker/issues
Keywords: lyrics,lrc,karaoke,musixmatch,apple-music,ttml
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Sound/Audio
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mutagen>=1.47
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Dynamic: license-file

# lrc-maker

Convert **M4A** and **TTML** lyric files into **Enhanced LRC** — the word-by-word karaoke format supported by players like Poweramp, Plexamp, foobar2000, and others.

Lyrics are sourced from **LyricsPlus** (Apple Music, Spotify, Musixmatch) with **Musixmatch** as a fallback. No Apple Music or Spotify credentials required.

---

## Features

- 🎵 **Word-by-word Enhanced LRC** from Apple Music TTML data
- 🔄 **Automatic fallback chain**: Apple Music → Spotify → Musixmatch (word) → Musixmatch (line)
- 🏷️ **Full metadata in LRC headers**: artist, album, year, genre, ISRC, composer, etc.
- 📁 **Batch processing** — point at a folder and convert everything recursively
- 🔍 **Smart matching** — handles accented characters, smart quotes, featured artists
- 📄 **TTML support** — convert raw Apple Music `.ttml` files directly

---

## Installation

### From PyPI (once published)
```bash
pip install lrc-maker
```

### From source
```bash
git clone https://github.com/YOUR_USERNAME/lrc-maker.git
cd lrc-maker
pip install -e .
```

**Requirements:** Python 3.10+, [`mutagen`](https://mutagen.readthedocs.io/) (installed automatically)

---

## Usage

### M4A → Enhanced LRC

Convert a single file or an entire music folder:

```bash
# Single file
m4a-to-lrc "path/to/song.m4a" --musixmatch-token-file data.json

# Entire folder (recursive)
m4a-to-lrc "G:\Music\Apple Music" --musixmatch-token-file data.json

# Overwrite existing .lrc files
m4a-to-lrc "G:\Music" --musixmatch-token-file data.json --overwrite

# Preview without writing files
m4a-to-lrc "G:\Music" --musixmatch-token-file data.json --dry-run
```

**Example output:**
```
Converted [Apple (word)]:      Cigarettes After Sex - Apocalypse -> ...lrc
Converted [Apple (line)]:      Cigarettes After Sex - Affection -> ...lrc
Converted [Spotify (word)]:    The Marías - Blur -> ...lrc
Converted [Musixmatch (word)]: Some Track -> ...lrc
Converted [Musixmatch (line)]: Some Track -> ...lrc
Done. 27 file(s) processed, 0 failed.
```

The label in brackets tells you the source and timing type:
| Label | Meaning |
|---|---|
| `Apple (word)` | Apple Music TTML, word-by-word ✨ best quality |
| `Apple (line)` | Apple Music, line-by-line |
| `Spotify (word)` | Spotify synced, word-by-word |
| `Spotify (line)` | Spotify synced, line-by-line |
| `Musixmatch (word)` | Musixmatch RichSync, word-by-word |
| `Musixmatch (line)` | Musixmatch Subtitle, line-by-line |

### TTML → Enhanced LRC

Convert raw Apple Music `.ttml` files:

```bash
# Single file
ttml-to-lrc "song.ttml"

# Folder
ttml-to-lrc "path/to/ttml/folder" --overwrite

# With Musixmatch RichSync as primary source
ttml-to-lrc "path/to/ttml/folder" --musixmatch-token-file data.json --overwrite
```

---

## Getting a Musixmatch Token

The Musixmatch token is used as a fallback when LyricsPlus can't find a track. To get one:

1. Open [musixmatch.com](https://www.musixmatch.com) in your browser
2. Open DevTools → Network tab
3. Search for any song and filter requests by `apic-desktop`
4. Copy the `usertoken` value from any request URL
5. Save it to `data.json`:

```json
{
  "tokens": {
    "web-desktop-app-v1.0": "YOUR_TOKEN_HERE"
  }
}
```

---

## How It Works

```
m4a-to-lrc
    │
    ▼
Read M4A tags (artist, title, album, year, genre, ISRC, ...)
    │
    ▼
LyricsPlus API  ──► Apple Music TTML  (word-by-word) ✨
(no auth)       ──► Spotify           (word or line)
                ──► Musixmatch        (word or line)
                ──► own cache
    │
    │  if nothing found
    ▼
Musixmatch API  ──► RichSync  (word-by-word)
(token needed)  ──► Subtitle  (line-by-line)
    │
    ▼
Write .lrc file next to the .m4a
```

Artist and title are read from the M4A tags. If tags are missing, the filename is parsed as `Artist - Title.m4a`. Multiple candidate spellings are tried (smart quotes → straight, accented → ASCII, strip featured artist credits) to maximise match rate.

---

## LRC Format

Enhanced LRC files look like this:

```lrc
[ar:Cigarettes After Sex]
[ti:Apocalypse]
[al:Cigarettes After Sex]
[yr:2017]
[re:lyricsplus-apple]

[00:13.15]<00:13.15>Oh <00:13.55>it <00:13.80>was <00:14.20>the <00:14.50>night
[00:16.80]<00:16.80>Things <00:17.10>were <00:17.40>different
```

Each `[timestamp]` is the line start; each `<timestamp>word` is when that individual word is sung.

---

## Project Structure

```
lrc-maker/
├── src/lrc_maker/
│   ├── __init__.py
│   ├── m4a_to_elrc.py   # M4A → LRC (LyricsPlus + Musixmatch)
│   └── ttml_to_elrc.py  # TTML → LRC (direct parse + optional Musixmatch)
├── pyproject.toml
├── README.md
└── LICENSE
```

---

## Contributing

Pull requests welcome. Please open an issue first for significant changes.

---

## License

MIT — see [LICENSE](LICENSE).

---

## Credits

- [LyricsPlus / KPOE](https://github.com/MetrolistGroup/Metrolist/issues/2969) — the serverless lyrics aggregation API
- [mutagen](https://mutagen.readthedocs.io/) — M4A/MP4 tag reading
- [Musixmatch](https://www.musixmatch.com) — lyrics fallback source
