Metadata-Version: 2.4
Name: aup-parser
Version: 0.10.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Rust
Classifier: Topic :: Multimedia :: Sound/Audio
Summary: Audacity .aup3 parser with Rust core and Python interface
Keywords: audacity,aup3,audio,parser,rust,pyo3
Author: aup-parser contributors
License: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# aup-parser

`aup-parser` is an Audacity `.aup3` parser package with a Rust core and typed Python interface.

## Highlights

- Rust core for binary XML and sampleblocks analysis
- Class-based Python API (`AUPParser`) with `TypedDict` return types
- Optional audio export helper

## Package Layout

- `src/`: Rust core (`PyO3` extension)
- `python/aup_parser/`: Python API, types, exports
- `tests/`: API/parity tests and golden fixtures

## Build (local dev)

```bash
cd /Users/joonholee/deeply/aup3-parser
python3 -m pip install --user --break-system-packages maturin
python3 -m maturin build --release -i python3
python3 -m pip install --user --break-system-packages --force-reinstall target/wheels/aup_parser-*.whl
```

## Python API (Class-only)

```python
from aup_parser import AUPParser

parser = AUPParser("tests/test.aup3")
essential = parser.parse(profile="essential")
full = parser.parse(profile="full")
```

`AUPParser.parse()` signature:

```python
def parse(
    self,
    *,
    profile: Literal["essential", "full"] = "essential",
    audio_output_path: str | pathlib.Path | None = None,
    sample_rate: int = 48000,
    output_naming: Literal["channel_index", "track_name"] = "channel_index",
) -> ParseResultTD: ...
```

- `audio_output_path`: `None`이 아니면 WAV를 export
  - 싱글 채널 프로젝트: 단일 WAV 파일 출력
  - 멀티 채널 프로젝트: `audio_output_path`를 폴더로 사용하여 채널별 WAV 파일 생성
  - 멀티 채널 + 파일처럼 보이는 경로(`out.wav`) 입력 시: 자동으로 `out_channels/` 폴더로 정규화
  - 타임라인 복원: clip metadata(`offset`, `trimLeft`, `trimRight`)를 우선 적용하고, 불가능한 경우 `waveblock.start` 기준으로 배치
  - gap 구간은 zero-fill, 겹침 구간은 later block overwrite 규칙 사용
- `sample_rate`: `audio_output_path` export 시 사용할 샘플레이트
- `output_naming`: 멀티 채널 파일 이름 전략
  - `channel_index`: `channel_00.wav`, `channel_01.wav`, ...
  - `track_name`: 트랙명을 안전한 파일명으로 변환해 사용(중복 시 suffix 추가)

## Compatibility Notes

- Python 3.11~3.14
- `abi3-py311` build strategy
- CI validates install + runtime parse on all combinations:
  - Linux/macOS/Windows
  - Python 3.11, 3.12, 3.13, 3.14
- Release wheels are built for:
  - Linux (`ubuntu-latest`)
  - Windows (`windows-latest`)
  - macOS Apple Silicon (`macos-15`)
  - macOS Intel (`macos-15-intel`)
- If a wheel is unavailable for your environment, `pip` falls back to sdist build and requires a Rust toolchain.

## Release

GitHub Actions workflow (`.github/workflows/release.yml`) runs:

1. Matrix tests on PRs
2. Wheel/sdist build on version tags (`v*`)
3. Publish `dist/*` to GitHub Release assets
4. Publish `dist/*` to GitHub Packages (GHCR OCI artifact)
5. Optional PyPI publish (only when `UV_PUBLISH_TOKEN` secret is set)

### PyPI Token Setup

1. Create a PyPI API token (`__token__`) on PyPI account settings.
2. In GitHub repo settings, add:
   - `Settings > Secrets and variables > Actions > New repository secret`
   - Name: `UV_PUBLISH_TOKEN`
   - Value: `pypi-...` token string
3. Push a release tag (`vX.Y.Z`). The `publish-pypi` job uploads `dist/*` via:
   - `uv publish --trusted-publishing never dist/*`

### GitHub Distribution

- Release assets: `https://github.com/<owner>/<repo>/releases/tag/vX.Y.Z`
- GitHub Packages (GHCR): `ghcr.io/<owner>/aup-parser:vX.Y.Z` and `ghcr.io/<owner>/aup-parser:X.Y.Z`
- GHCR pull example:
  - `oras pull ghcr.io/<owner>/aup-parser:vX.Y.Z`
  - pulled wheel/sdist files can then be installed with `pip install <wheel-file>`

