# python-soundrecording-utils
Utility methods related to handling Sound Recording Version files and creating DDEX documents

## testing

### run unit tests

```bash
python3 -m venv env
source env/bin/activate

pip install poetry

# ensure you use the python specified in pyproject.toml 
# or do something like this:
sed -i .bak 's/~3.11/~3.14/g' pyproject.toml  #where 3.14 is your local python version

poetry lock

make test_unit

deactivate

git checkout pyproject.toml
git checkout poetry.lock
rm *.bak
```

## Installation

Install `soundrecording-utils` as a dependency in your application.

### Install using Poetry (`pyproject.toml`)

#### pypi.theorchard.com

1. Update `pyproject.toml` to include:

```toml
[[tool.poetry.source]]
name = "pde"
url = "https://pypi.theorchard.io/pypi/"
priority = "supplemental"
```

2. Add this to the `[tool.poetry.dependencies]` section in `pyproject.toml`:
```toml
[tool.poetry.dependencies]
...
soundrecording-utils = {version = "^0.1.0", source = "pde"}
```

3. Run `poetry lock`


#### git+ssh

1. Add this to the `[tool.poetry.dependencies]` section in `pyproject.toml`:

```toml
[tool.poetry.dependencies]
...
soundrecording-utils = { git = "ssh://git@github.com/theorchard/python-soundrecording-utils#v0.1.0"}
```

2. Run `poetry lock`

## Usage

### DDEX Document Generation

Generate DDEX XML documents for delivery to platforms like TikTok (v3.8) and YouTube (v4.3):

```python
from soundrecording_utils.ddex.generate import generate_ddex
from soundrecording_utils.metadata.types import OrchardSoundRecording

# Create sound recording metadata
osr = OrchardSoundRecording(
    label_name="Example Records",
    album_title="Greatest Hits",
    tracks=[...],  # List of Track objects
    # ... other metadata
)

# Generate DDEX v3.8 (TikTok format)
xml_bytes = generate_ddex(
    osr=osr,
    version="3.8",
    message_id="MSG123",
    delivery_date="2026-02-23",
)

# Generate DDEX v4.3 (YouTube format)
xml_bytes = generate_ddex(
    osr=osr,
    version="4.3",
    message_id="MSG123",
    delivery_date="2026-02-23",
)
```

### Metadata Types

Core data types for sound recording metadata:

```python
from soundrecording_utils.metadata.types import (
    OrchardSoundRecording,
    Track,
    Asset,
    Label,
    Product,
    FingerprintRule,
    FingerprintRuleBuilder,
    PolicyType,
    ExplicitStatus,
)

# Build fingerprint rules using the builder pattern
rule = (
    FingerprintRuleBuilder()
    .with_policy(PolicyType.MONETIZE)
    .with_territory("US")
    .with_service("youtube")
    .with_start_date("2026-01-01")
    .build()
)

# Create track metadata
track = Track(
    isrc="USRC12345678",
    title="Example Song",
    artists=[{"name": "Artist Name", "role": "MainArtist"}],
    fingerprint_rules=[rule],
    # ... other fields
)
```

### Rights Consolidation

Consolidate fingerprint rules across tracks for rights management:

```python
from soundrecording_utils.constants.ddex.constants import RuleService
from soundrecording_utils.metadata.consolidation_logic import consolidate_rights

# Consolidate rights for a specific service
rights = consolidate_rights(
    tracks=osr.tracks,
    service=RuleService.YOUTUBE,
)

# Access consolidated rights data
for isrc, track_rights in rights.items():
    print(f"{isrc}: {len(track_rights.monetize)} monetize territories")
```

### Territory Utilities

Work with ISO territory codes:

```python
from soundrecording_utils.constants.territories import (
    ALL,
    RULE_TERRITORIES,
)

# ALL: Set of all valid ISO 3166-1 alpha-2 codes
# RULE_TERRITORIES: All territories for fingerprint rules
```

### DDEX Version Differences

This library supports two DDEX ERN versions:

| Version | Primary Use | Platform |
|---------|-------------|----------|
| **v3.8** | Audio-only deliveries | TikTok |
| **v4.3** | Audio deliveries with enhanced party/contributor data | YouTube |

**v3.8** is the simpler format, suitable for platforms that only need basic track and release metadata.

**v4.3** includes additional structures like `PartyList` for detailed contributor information and supports more complex rights scenarios.

## API Reference

### Main Exports

| Export | Description |
|--------|-------------|
| `generate_ddex()` | Generate DDEX XML document (v3.8 or v4.3) |
| `consolidate_rights()` | Consolidate fingerprint rules across tracks |
| `OrchardSoundRecording` | Main metadata container for a release |
| `Track` | Individual track metadata |
| `Asset` | Audio/video asset information |
| `FingerprintRule` | Rights/policy rule for a track |
| `FingerprintRuleBuilder` | Builder pattern for creating rules |
| `PolicyType` | Enum: MONETIZE, BLOCK_FILE, BLOCK_ACCESS |
| `ExplicitStatus` | Enum: CLEAN, EXPLICIT, NOT_EXPLICIT, UNKNOWN |
| `RuleService` | Enum for platform services |

## Contributing

### Dependencies

This library uses Poetry for dependency management. Please use `poetry add` when adding new dependencies. Always add/commit changes made to the `pyproject.toml` and `poetry.lock` files.

Avoid being overly-restrictive when adding installation requirements. [This](https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/) has a good overview of considerations when specifying what is required to install soundrecording-utils. A few key quotes:

> It’s best practice to indicate any known lower or upper bounds
> It is not considered best practice to use install_requires to pin dependencies to specific versions, or to specify sub-dependencies (i.e. dependencies of your dependencies). This is overly-restrictive, and prevents the user from gaining the benefit of dependency upgrades.

Do indicate if a dependency belongs to development (and thus, not required when the library is installed) using `poetry add <the new dependency> --group dev`.

On a regular basis, run `poetry update` to update to the latest versions of all dependencies in the `poetry.lock` file. Specific dependencies can be updated with `poetry update <the specific dependencies>`.

### `make` targets

You can always use `make help` to view all the documented targets for working in this library. Some common ones are:

```
make env         # Prepare environment
make lint        # Run code linters (mypy, flake8)
make test_unit   # Run unit tests with coverage
make test_cov    # Run all tests with coverage report
make ci_test     # Run linter and unit tests (for CI)
make clean       # Clean environment
```

### Packaging/Versioning

Use semver and [Jenkins Pipeline](https://pipeline.theorchard.io/job/publish-pypi-package-v2/) to build/publish new versions of this library to the private PyPI repository at [pypi.theorchard.io](https://pypi.theorchard.io) (currently only available if you are on our VPN).

After a release tag has been pushed to Github, use the Github UI to Create a Release from the tag. Start from the autogenerated notes, and add salient details to the change(s) being added. This will be used by clients of the library to determine what to expect when upgrading (easy vs breaking?).
