moosicbox_library 0.3.0

MoosicBox Library Music API package
Documentation
# MoosicBox Library

Music library management package providing database operations for artists, albums, and tracks with support for filtering, search, and pagination.

## Features

- **Artist Management**: List and retrieve artists from the library
- **Album Management**: Browse albums with filtering, sorting, and pagination
- **Track Management**: Access track information with detailed metadata
- **Search Functionality**: Full-text search across artists, albums, and tracks
- **Pagination Support**: Efficient browsing of large music collections
- **Filtering & Sorting**: Filter albums by artist, name, source, and sort by various criteria
- **Database Integration**: Async database operations with proper error handling
- **Version Support**: Manage multiple album versions from different sources with varying quality levels

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
moosicbox_library = "0.1.4"
```

Enable additional features:

```toml
[dependencies]
moosicbox_library = { version = "0.1.4", features = ["api"] }
```

## Usage

### Working with Artists

```rust
use moosicbox_library::favorite_artists;
use switchy_database::profiles::LibraryDatabase;

// LibraryDatabase is obtained from the PROFILES registry or via actix-web request extraction
async fn example(db: &LibraryDatabase) -> Result<(), Box<dyn std::error::Error>> {
    // Get favorite artists with pagination
    let artists_result = favorite_artists(
        &db,
        Some(0),    // offset
        Some(20),   // limit
        None,       // order
        None,       // order direction
    ).await?;

    println!("Found {} artists", artists_result.page.total().unwrap_or(0));

    for artist in artists_result.page.items() {
        println!("Artist: {} (ID: {})", artist.title, artist.id);
    }

    Ok(())
}
```

### Album Operations

```rust
use moosicbox_library::{favorite_albums, album, album_tracks, album_versions};
use moosicbox_music_api_models::AlbumsRequest;
use moosicbox_music_models::id::Id;
use switchy_database::profiles::LibraryDatabase;

// LibraryDatabase is obtained from the PROFILES registry or via actix-web request extraction
async fn example(db: &LibraryDatabase) -> Result<(), Box<dyn std::error::Error>> {
    // Get favorite albums
    let request = AlbumsRequest::default();
    let albums_result = favorite_albums(&db, &request).await?;

    for album in albums_result.page.items() {
        println!("Album: {} by {}", album.title, album.artist);
        println!("  Date: {:?}", album.date_released);

        // Get album details
        let album_id = Id::Number(album.id);
        if let Some(album_detail) = album(&db, &album_id).await? {
            println!("  Detailed info: {} versions", album_detail.versions.len());
        }

        // Get album tracks
        let tracks_result = album_tracks(&db, &album_id, Some(0), Some(10)).await?;
        println!("  Tracks ({}):", tracks_result.page.items().len());

        for track in tracks_result.page.items() {
            println!("    {}: {} ({}s)", track.number, track.title, track.duration);
        }

        // Get album versions
        let versions = album_versions(&db, &album_id).await?;
        println!("  Available versions: {}", versions.len());
        for version in versions {
            println!("    Source: {:?}, Format: {:?}", version.source, version.format);
        }
    }

    Ok(())
}
```

### Track Management

```rust
use moosicbox_library::{favorite_tracks, track};
use moosicbox_music_models::id::Id;
use switchy_database::profiles::LibraryDatabase;

// LibraryDatabase is obtained from the PROFILES registry or via actix-web request extraction
async fn example(db: &LibraryDatabase) -> Result<(), Box<dyn std::error::Error>> {
    // Get favorite tracks
    let tracks_result = favorite_tracks(
        &db,
        None,       // track_ids filter
        Some(0),    // offset
        Some(50),   // limit
        None,       // order
        None,       // order direction
    ).await?;

    println!("Favorite tracks: {}", tracks_result.page.items().len());

    for track in tracks_result.page.items() {
        println!("Track: {} - {} ({}s)", track.artist, track.title, track.duration);

        // Get detailed track info
        let track_id = Id::Number(track.id);
        if let Some(track_detail) = track(&db, &track_id).await? {
            println!("  Album: {}", track_detail.album);
            println!("  Track #: {}", track_detail.number);
        }
    }

    Ok(())
}
```

### Filtering and Sorting Albums

```rust
use moosicbox_library::{filter_albums, sort_albums};
use moosicbox_music_api_models::{AlbumsRequest, AlbumFilters};
use moosicbox_music_models::{AlbumSort, id::Id};

fn example_filtering() {
    let albums = vec![]; // Your album collection

    // Create filter request
    let request = AlbumsRequest {
        sources: None,
        sort: Some(AlbumSort::ArtistAsc),
        filters: Some(AlbumFilters {
            name: Some("Dark Side".to_string()),
            artist_id: Some(Id::Number(123)),
            artist_api_id: None,
            artist: None,
            album_type: None,
            search: None,
        }),
        page: None,
    };

    // Filter albums
    let filtered: Vec<_> = filter_albums(&albums, &request).collect();
    println!("Filtered to {} albums", filtered.len());

    // Sort albums
    let sorted = sort_albums(filtered, &request);
    for album in sorted {
        println!("  {}: {}", album.artist, album.title);
    }
}
```

### Search Operations

```rust
use moosicbox_library::{search, LibrarySearchType};
use moosicbox_music_api_models::search::api::ApiGlobalSearchResult;

fn search_library() -> Result<(), Box<dyn std::error::Error>> {
    let query = "Pink Floyd";
    let search_types = vec![
        LibrarySearchType::Artists,
        LibrarySearchType::Albums,
        LibrarySearchType::Tracks,
    ];

    let results = search(
        query,
        Some(0),    // offset
        Some(20),   // limit
        Some(&search_types),
    )?;

    println!("Search results for '{}':", query);
    println!("Found {} results", results.results.len());

    for result in &results.results {
        match result {
            ApiGlobalSearchResult::Artist(artist) => {
                println!("  Artist: {}", artist.title);
            }
            ApiGlobalSearchResult::Album(album) => {
                println!("  Album: {} - {}", album.artist, album.title);
            }
            ApiGlobalSearchResult::Track(track) => {
                println!("  Track: {} - {}", track.artist, track.title);
            }
        }
    }

    Ok(())
}
```

### Artist Albums

```rust
use moosicbox_library::artist_albums;
use moosicbox_library_models::LibraryAlbumType;
use moosicbox_music_models::id::Id;
use switchy_database::profiles::LibraryDatabase;

// LibraryDatabase is obtained from the PROFILES registry or via actix-web request extraction
async fn example(db: &LibraryDatabase) -> Result<(), Box<dyn std::error::Error>> {
    let artist_id = Id::Number(123);

    // Get all albums by artist
    let albums_result = artist_albums(
        &db,
        &artist_id,
        Some(0),    // offset
        Some(10),   // limit
        None,       // album type filter
    ).await?;

    println!("Albums by artist: {}", albums_result.page.items().len());

    for album in albums_result.page.items() {
        println!("  {} ({})", album.title, album.date_released.unwrap_or_default());
    }

    // Get only LP albums
    let lp_albums = artist_albums(
        &db,
        &artist_id,
        Some(0),
        Some(10),
        Some(LibraryAlbumType::Lp),
    ).await?;

    println!("LP albums: {}", lp_albums.page.items().len());

    Ok(())
}
```

### Track File URLs

```rust
use moosicbox_library::{track_file_url, LibraryAudioQuality};
use moosicbox_music_models::id::Id;
use switchy_database::profiles::LibraryDatabase;

// LibraryDatabase is obtained from the PROFILES registry or via actix-web request extraction
async fn example(db: &LibraryDatabase) -> Result<(), Box<dyn std::error::Error>> {
    let track_id = Id::Number(456);

    // Get high quality track URL
    let url = track_file_url(
        &db,
        LibraryAudioQuality::High,
        &track_id,
    ).await?;

    println!("Track URL: {}", url);

    Ok(())
}
```

## API Reference

### Core Functions

- `favorite_artists()` - Get paginated artists from the library
- `favorite_albums()` - Get paginated albums with filtering and sorting
- `favorite_tracks()` - Get paginated tracks with optional ID filtering
- `artist()` - Get artist by ID
- `album()` - Get album by ID
- `album_from_source()` - Get album by ID and API source
- `track()` - Get track by ID
- `artist_albums()` - Get albums by specific artist with optional type filtering
- `album_tracks()` - Get tracks in specific album
- `album_versions()` - Get available versions of an album grouped by quality

### Utility Functions

- `filter_albums()` - Filter albums by criteria
- `sort_albums()` - Sort albums by specified order
- `search()` - Search across library content
- `track_file_url()` - Get file URL for track playback
- `reindex_global_search_index()` - Rebuild the search index from library data

### API Integration (`api` feature)

- `api::bind_services()` - Register all library HTTP endpoints on an Actix-web scope

### Management Functions

**Note:** The following functions are currently non-functional placeholders that return `Ok(())`:

- `add_favorite_artist()` - Placeholder: Add artist to favorites
- `remove_favorite_artist()` - Placeholder: Remove artist from favorites
- `add_favorite_album()` - Placeholder: Add album to favorites
- `remove_favorite_album()` - Placeholder: Remove album from favorites
- `add_favorite_track()` - Placeholder: Add track to favorites
- `remove_favorite_track()` - Placeholder: Remove track from favorites

## Error Handling

The library provides specific error types for different operations:

- `LibraryFavoriteArtistsError` - Errors when fetching favorite artists
- `LibraryFavoriteAlbumsError` - Errors when fetching favorite albums
- `LibraryFavoriteTracksError` - Errors when fetching favorite tracks
- `LibraryArtistError` - Errors when fetching artist information
- `LibraryAlbumError` - Errors when fetching album information
- `LibraryTrackError` - Errors when fetching track information
- `SearchError` - Errors during search operations

## Enums and Types

### Order and Direction

- `LibraryArtistOrder`, `LibraryAlbumOrder`, `LibraryTrackOrder`
- `LibraryArtistOrderDirection`, `LibraryAlbumOrderDirection`, `LibraryTrackOrderDirection`

### Search Types

- `LibrarySearchType` - Artists, Albums, Tracks, Videos, Playlists, UserProfiles
- `SearchType` - Enum variants for search filtering

### Audio Quality

- `LibraryAudioQuality` - High, Lossless, HiResLossless

## Features

The following cargo features are available:

- `api` - Enable API integration features (actix-web support)
- `openapi` - Enable OpenAPI/utoipa schema generation
- `fail-on-warnings` - Treat warnings as errors during compilation
- `all-encoders` - Enable all audio encoders
- `all-formats` - Enable all audio format support
- Format-specific features: `format-aac`, `format-flac`, `format-mp3`, `format-opus`
- Encoder-specific features: `encoder-aac`, `encoder-flac`, `encoder-mp3`, `encoder-opus`

## Dependencies

- `switchy_database` - Database connection and operations
- `moosicbox_music_models` - Core music data models
- `moosicbox_library_models` - Library-specific data models
- `moosicbox_paging` - Pagination utilities
- `moosicbox_search` - Search functionality