### Install System Dependencies (Ubuntu/macOS) Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Installs necessary system libraries for development on Ubuntu/Debian and macOS. Requires root privileges on Ubuntu/Debian. ```bash sudo apt-get install libasound2-dev pkg-config ``` ```bash brew install pkg-config ``` -------------------------------- ### Install Rust Development Tools Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Installs essential and additional Rust development tools for enhanced code quality, security, and productivity. Includes tools for formatting, linting, auditing, and more. ```bash # Core tools (included in CI) rustup component add rustfmt clippy # Additional tools cargo install cargo-audit # Security auditing cargo install cargo-deny # License/security checking cargo install cargo-machete # Find unused dependencies cargo install cargo-llvm-cov # Code coverage cargo install cargo-vet # Supply chain security cargo install cargo-watch # Watch for changes ``` -------------------------------- ### Setup Pre-commit Git Hook Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Configures a pre-commit Git hook to automatically run code formatting, clippy linting, and tests before each commit. Ensures code quality and consistency. ```bash #!/bin/bash set -e echo "Running pre-commit checks..." # Check formatting echo "→ Checking formatting..." cargo fmt --all -- --check # Run clippy echo "→ Running clippy..." cargo clippy --workspace --all-targets --all-features -- -D warnings # Run tests echo "→ Running tests..." cargo test --workspace --all-features echo "✓ All checks passed!" ``` -------------------------------- ### Install System Dependencies for rmpd Source: https://github.com/m0rf30/rmpd/blob/main/README.md Installs necessary system libraries for building rmpd on Ubuntu/Debian and macOS. These include ALSA development files and pkg-config for handling audio output and build configurations. ```bash # Ubuntu/Debian sudo apt-get install libasound2-dev pkg-config # macOS brew install pkg-config ``` -------------------------------- ### Configure Cross-compilation for ARM64 on Ubuntu Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Sets up the environment for cross-compiling Rust projects for ARM64 architecture on an Ubuntu system. Involves installing a cross-compiler and setting Cargo's target linker. ```bash # Install cross-compiler sudo apt-get install gcc-aarch64-linux-gnu # Set linker export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc # Build cargo build --target aarch64-unknown-linux-gnu ``` -------------------------------- ### Configure rmpd Server Settings Source: https://github.com/m0rf30/rmpd/blob/main/README.md Example TOML configuration file for rmpd. It defines general settings like music and playlist directories, network bind address and port, and audio output preferences including ALSA and Snapcast. ```toml [general] music_directory = "~/Music" playlist_directory = "~/.config/rmpd/playlists" db_file = "~/.config/rmpd/database.db" log_level = "info" [network] bind_address = "127.0.0.1" port = 6600 [audio] default_output = "alsa" gapless = true replay_gain = "auto" buffer_time = 500 [[output]] name = "ALSA Output" type = "alsa" enabled = true device = "default" [[output]] name = "Snapcast Output" type = "snapcast" enabled = false fifo_path = "/tmp/snapfifo" ``` -------------------------------- ### MPD Output Control Commands Source: https://context7.com/m0rf30/rmpd/llms.txt Commands to manage audio outputs, essential for multi-room audio setups. This includes listing, enabling, disabling, and toggling outputs. ```bash # List all outputs outputs # outputid: 0 # outputname: ALSA Output # plugin: alsa # outputenabled: 1 # outputid: 1 # outputname: Snapcast Output # plugin: snapcast # outputenabled: 0 # OK # Enable output enableoutput 1 # OK # Disable output disableoutput 0 # OK # Toggle output toggleoutput 0 # OK ``` -------------------------------- ### Run rmpd Music Server Source: https://github.com/m0rf30/rmpd/blob/main/README.md Starts the rmpd music server with specified network binding, port, and music directory. This command is used to launch the server after building it. ```bash ./target/release/rmpd --bind 127.0.0.1 --port 6600 --music-dir ~/Music ``` -------------------------------- ### MPD Sticker (Custom Metadata) Management Source: https://context7.com/m0rf30/rmpd/llms.txt Commands for managing custom metadata (stickers) associated with songs. This includes setting, getting, listing, finding, and deleting stickers. ```bash # Set a sticker sticker set song "path/to/song.mp3" rating 5 # OK # Get a sticker sticker get song "path/to/song.mp3" rating # sticker: rating=5 # OK # List all stickers for a song sticker list song "path/to/song.mp3" # sticker: rating=5 # sticker: playcount=42 # OK # Find songs with sticker sticker find song "" rating # file: path/to/song1.mp3 # sticker: rating=5 # file: path/to/song2.mp3 # sticker: rating=4 # OK # Delete sticker sticker delete song "path/to/song.mp3" rating # OK ``` -------------------------------- ### Scan Directories and Populate Database with Scanner API Source: https://context7.com/m0rf30/rmpd/llms.txt The `rmpd_library::Scanner` scans directories for audio files and populates the database. It utilizes an `EventBus` for progress notifications. Dependencies include `rmpd_library`, `rmpd_core`, and `tokio`. ```rust use rmpd_library::{Scanner, Database}; use rmpd_core::event::EventBus; use std::path::Path; // Create scanner with event bus for progress notifications let event_bus = EventBus::new(); let scanner = Scanner::new(event_bus.clone()); // Open database let db = Database::open("/path/to/database.db")?; // Scan music directory let stats = scanner.scan_directory(&db, Path::new("/home/user/Music"))?; println!("Scan complete:"); println!(" Files scanned: {}", stats.scanned); println!(" Songs added: {}", stats.added); println!(" Songs updated: {}", stats.updated); println!(" Errors: {}", stats.errors); // Subscribe to scan progress events let mut rx = event_bus.subscribe(); tokio::spawn(async move { while let Ok(event) = rx.recv().await { match event { rmpd_core::event::Event::DatabaseUpdateStarted => { println!("Scan started"); } rmpd_core::event::Event::DatabaseUpdateProgress { scanned, total } => { println!("Progress: {} files", scanned); } rmpd_core::event::Event::DatabaseUpdateFinished => { println!("Scan finished"); } _ => {} } } }); ``` -------------------------------- ### MPD Playback Options Configuration Source: https://context7.com/m0rf30/rmpd/llms.txt Commands to configure various playback behaviors such as repeat, random, single mode, consume, crossfade, and ReplayGain. These options allow fine-tuning of the listening experience. ```bash # Enable/disable repeat repeat 1 # OK repeat 0 # OK # Enable/disable random random 1 # OK # Single mode (0=off, 1=on, oneshot) single 1 # OK single oneshot # OK # Consume mode (remove songs after playing) consume 1 # OK # Crossfade (seconds) crossfade 5 # OK # ReplayGain mode (off, track, album, auto) replay_gain_mode auto # OK ``` -------------------------------- ### Using with MPD Clients Source: https://context7.com/m0rf30/rmpd/llms.txt Information on how to connect standard MPD clients to the rmpd server. ```APIDOC ## Using with MPD Clients ### Description rmpd is compatible with standard MPD clients. Configure them to connect to the rmpd server address. ### Command-line Client (mpc) Set environment variables before running mpc: ```bash export MPD_HOST=localhost export MPD_PORT=6600 mpc status mpc update mpc add / mpc play mpc pause mpc next mpc volume 75 mpc search artist "Beatles" mpc playlist ``` ### ncmpcpp (TUI Client) Edit `~/.config/ncmpcpp/config`: ```ini mpd_host = "localhost" mpd_port = "6600" ``` Then run `ncmpcpp`. ### Cantata (Qt GUI) Configure the connection in Cantata's settings: - Host: `localhost` - Port: `6600` ``` -------------------------------- ### Interact with rmpd using mpc Client Source: https://github.com/m0rf30/rmpd/blob/main/README.md Demonstrates basic commands to interact with a running rmpd server using the 'mpc' command-line client. This includes checking status, updating the music library, and controlling playback. ```bash # Check status mpc status # Update library mpc update # Add and play music mpc add / mpc play ``` -------------------------------- ### Run MPD Server with rmpd_protocol::MpdServer (Rust) Source: https://context7.com/m0rf30/rmpd/llms.txt The `MpdServer` struct implements the MPD protocol server, allowing clients to connect and control music playback. It can be initialized with default or custom application state and uses a broadcast channel for graceful shutdown. Dependencies include `rmpd_protocol::{MpdServer, AppState}` and `tokio::sync::broadcast`. ```rust use rmpd_protocol::{MpdServer, AppState}; use tokio::sync::broadcast; // Create shutdown channel let (shutdown_tx, shutdown_rx) = broadcast::channel(1); // Create server with default state let server = MpdServer::new("127.0.0.1:6600".to_string(), shutdown_rx); // Or with custom state let state = AppState::new(); // Configure state with database path, music directory, etc. let server = MpdServer::with_state("0.0.0.0:6600".to_string(), state, shutdown_rx); // Run server (blocks until shutdown) tokio::spawn(async move { if let Err(e) = server.run().await { eprintln!("Server error: {}", e); } }); // Trigger graceful shutdown shutdown_tx.send(()).ok(); ``` -------------------------------- ### Local CI Simulation and Security Checks Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Commands to simulate the full CI pipeline locally, perform security audits, check for unused dependencies, and generate code coverage reports. ```bash # Full local CI simulation cargo fmt && \ cargo clippy --workspace --all-targets --all-features -- -D warnings && \ cargo test --workspace --all-features && \ cargo doc --workspace --no-deps --all-features # Security audit cargo audit && cargo deny check # Find unused dependencies cargo machete # Generate coverage cargo llvm-cov --workspace --all-features --html ``` -------------------------------- ### Manage Music Library with Database API Source: https://context7.com/m0rf30/rmpd/llms.txt The `rmpd_library::Database` struct provides SQLite-backed music library storage with full-text search capabilities. It allows for adding, querying, searching, and listing songs and their metadata. Dependencies include `rmpd_library` and `rmpd_core`. ```rust use rmpd_library::Database; use rmpd_core::song::Song; // Open or create database let db = Database::open("/path/to/database.db")?; // Add a song let song = Song { id: 0, path: "Artist/Album/track.flac".into(), title: Some("Track Name".to_string()), artist: Some("Artist Name".to_string()), album: Some("Album Name".to_string()), duration: Some(std::time::Duration::from_secs(234)), // ... other fields added_at: 0, last_modified: 1699876543, }; let song_id = db.add_song(&song)?; // Query songs let song = db.get_song(song_id)?; let song = db.get_song_by_path("Artist/Album/track.flac")?; // Full-text search let results = db.search_songs("beatles abbey")?; // Find by tag (exact match) let songs = db.find_songs("artist", "Pink Floyd")?; let songs = db.find_songs("album", "Dark Side of the Moon")?; // List unique values let artists = db.list_artists()?; let albums = db.list_albums()?; let genres = db.list_genres()?; // Filtered listing let albums = db.list_filtered("album", "artist", "Beatles")?; // Directory browsing let listing = db.list_directory("Artist/Album")?; for dir in listing.directories { println!("Directory: {}", dir); } for song in listing.songs { println!("Song: {}", song.path); } // Statistics let song_count = db.count_songs()?; let artist_count = db.count_artists()?; let total_playtime = db.get_db_playtime()?; ``` -------------------------------- ### Connect to rmpd Server with MPD Clients (Bash/Configuration) Source: https://context7.com/m0rf30/rmpd/llms.txt rmpd is compatible with standard MPD clients. This section shows how to configure popular clients like `mpc`, `ncmpcpp`, and `Cantata` to connect to the rmpd server by setting the `MPD_HOST` and `MPD_PORT` environment variables or by editing client configuration files. ```bash # Command-line client (mpc) export MPD_HOST=localhost export MPD_PORT=6600 mpc status mpc update mpc add / mpc play mpc pause mpc next mpc volume 75 mpc search artist "Beatles" mpc playlist # ncmpcpp (TUI client) # Edit ~/.config/ncmpcpp/config: # mpd_host = "localhost" # mpd_port = "6600" nc # Cantata (Qt GUI) # Configure connection: localhost:6600 ``` -------------------------------- ### Git Branching and Committing Workflow Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Standard Git workflow for creating feature branches, making changes, testing, and committing code. Includes steps for formatting, linting, testing, and pushing. ```bash # 1. Create a branch: git checkout -b feature/my-feature # 2. Make changes and test: # Run tests continuously cargo watch -x test # Check formatting cargo fmt # Run lints cargo lint # 3. Before committing: # Format code cargo fmt # Check all lints cargo clippy --workspace --all-targets --all-features # Run all tests cargo test-all # Check docs cargo doc-check # 4. Commit and push: git add . git commit -m "feat: add my feature" git push origin feature/my-feature # 5. Create PR - CI will run automatically ``` -------------------------------- ### Control Audio Playback with PlaybackEngine API Source: https://context7.com/m0rf30/rmpd/llms.txt The `rmpd_player::PlaybackEngine` handles audio decoding and output with support for PCM and DSD formats. It allows for playing, pausing, stopping, seeking, and volume control. Dependencies include `rmpd_player`, `rmpd_core`, and `tokio`. ```rust use rmpd_player::PlaybackEngine; use rmpd_core::event::EventBus; use rmpd_core::state::PlayerStatus; use std::sync::Arc; use std::sync::atomic::AtomicU8; use tokio::sync::RwLock; // Create engine with shared state let event_bus = EventBus::new(); let status = Arc::new(RwLock::new(PlayerStatus::default())); let atomic_state = Arc::new(AtomicU8::new(0)); // 0=Stop, 1=Play, 2=Pause let mut engine = PlaybackEngine::new(event_bus, status, atomic_state.clone()); // Play a song let song = /* load song from database */; engine.play(song).await?; // Control playback engine.pause().await?; // Toggle pause engine.set_pause(true).await?; // Explicit pause engine.set_pause(false).await?; // Resume engine.stop().await?; // Stop playback // Seek to position (seconds) engine.seek(30.5).await?; // Volume control (0-100) engine.set_volume(75).await?; let volume = engine.get_volume().await; // Check state (lock-free) let state = engine.get_state_atomic(); match state { PlayerState::Stop => println!("Stopped"), PlayerState::Play => println!("Playing"), PlayerState::Pause => println!("Paused"), } // Get current song if let Some(song) = engine.get_current_song().await { println!("Now playing: {}", song.display_title()); } ``` -------------------------------- ### MPD Search and List Commands Source: https://context7.com/m0rf30/rmpd/llms.txt Commands to find music based on exact matches or filter expressions, and to list artists or albums. These commands are fundamental for browsing and selecting music within MPD. ```bash # Find exact match find album "Dark Side of the Moon" # OK # Find with filter expression find "(artist == 'Beatles') AND (album == 'Abbey Road')" # OK # List all values for a tag list artist # Artist: AC/DC # Artist: Beatles # Artist: Pink Floyd # ... # OK # List albums by artist list album artist "Beatles" # Album: Abbey Road # Album: Let It Be # OK # Count songs matching criteria count artist "Beatles" # songs: 42 # playtime: 8765 # OK # Browse directory lsinfo "Artist/Album" # directory: Artist/Album/Disc 1 # file: Artist/Album/01 - Track.flac # Title: Track # ... # OK ``` -------------------------------- ### MPD Stored Playlist Management Source: https://context7.com/m0rf30/rmpd/llms.txt Commands for creating, loading, listing, and modifying stored playlists. These operations allow users to save and recall sets of songs. ```bash # Save current queue as playlist save "My Favorites" # OK # Save with mode (create, replace, append) save "My Favorites" replace # OK # Load playlist into queue load "My Favorites" # OK # Load playlist at position load "My Favorites" 0 # OK # Load range from playlist load "My Favorites" 0:10 # OK # List all playlists listplaylists # playlist: My Favorites # Last-Modified: 2024-01-15T10:30:00Z # playlist: Rock Mix # Last-Modified: 2024-01-14T08:00:00Z # OK # List playlist contents listplaylistinfo "My Favorites" # file: path/to/song.mp3 # Title: Song Name # ... # OK # Add song to stored playlist playlistadd "My Favorites" "path/to/song.mp3" # OK # Delete from playlist playlistdelete "My Favorites" 5 # OK # Rename playlist rename "My Favorites" "Top Hits" # OK # Delete playlist rm "Old Playlist" # OK ``` -------------------------------- ### Manage Playback Queue with rmpd_core::queue::Queue (Rust) Source: https://context7.com/m0rf30/rmpd/llms.txt The `Queue` struct manages the playback queue, supporting operations like adding, accessing, removing, reordering, and shuffling songs. It allows manipulation by position or unique ID and tracks changes via a version number. Dependencies include `rmpd_core::queue::Queue` and `rmpd_core::song::Song`. ```rust use rmpd_core::queue::Queue; use rmpd_core::song::Song; let mut queue = Queue::new(); // Add songs (returns unique ID) let id1 = queue.add(song1); let id2 = queue.add(song2); let id3 = queue.add_at(song3, Some(0)); // Insert at position // Access items let item = queue.get(0); // By position let item = queue.get_by_id(id1); // By ID let all_items = queue.items(); // All items // Remove songs queue.delete(0); // By position queue.delete_id(id1); // By ID queue.clear(); // All songs // Reorder queue.move_item(5, 0); // Move position 5 to position 0 queue.move_by_id(id2, 3); // Move by ID queue.swap(0, 5); // Swap positions queue.swap_by_id(id1, id2); // Swap by ID // Shuffle queue.shuffle(); // Entire queue queue.shuffle_range(2, 10); // Range [start, end) // Queue info let length = queue.len(); let is_empty = queue.is_empty(); let version = queue.version(); // Increments on changes ``` -------------------------------- ### Queue API Source: https://context7.com/m0rf30/rmpd/llms.txt The Queue API allows for managing the playback queue with position and ID-based operations. You can add, retrieve, remove, reorder, and shuffle songs within the queue. ```APIDOC ## Queue API ### Description Manages the playback queue with position and ID-based operations. ### Methods - `new()`: Creates a new empty queue. - `add(song)`: Adds a song to the end of the queue and returns its unique ID. - `add_at(song, position)`: Inserts a song at a specific position. - `get(position)`: Retrieves an item from the queue by its position. - `get_by_id(id)`: Retrieves an item from the queue by its unique ID. - `items()`: Returns all items currently in the queue. - `delete(position)`: Removes a song from the queue by its position. - `delete_id(id)`: Removes a song from the queue by its unique ID. - `clear()`: Removes all songs from the queue. - `move_item(from_position, to_position)`: Moves an item from one position to another. - `move_by_id(id, to_position)`: Moves an item identified by ID to a specific position. - `swap(position1, position2)`: Swaps two items in the queue based on their positions. - `swap_by_id(id1, id2)`: Swaps two items in the queue based on their unique IDs. - `shuffle()`: Shuffles the entire queue. - `shuffle_range(start_position, end_position)`: Shuffles a specific range of the queue. - `len()`: Returns the number of items in the queue. - `is_empty()`: Checks if the queue is empty. - `version()`: Returns the current version of the queue (increments on changes). ### Example Usage ```rust use rmpd_core::queue::Queue; use rmpd_core::song::Song; let mut queue = Queue::new(); let song1 = Song { /* ... */ }; let song2 = Song { /* ... */ }; let id1 = queue.add(song1); let id2 = queue.add(song2); queue.add_at(song3, Some(0)); let item = queue.get(0); let item_by_id = queue.get_by_id(id1); queue.delete(0); queue.delete_id(id1); queue.move_item(5, 0); queue.swap(0, 5); queue.shuffle(); let length = queue.len(); let is_empty = queue.is_empty(); ``` ``` -------------------------------- ### Build rmpd Release Binary Source: https://github.com/m0rf30/rmpd/blob/main/README.md Compiles the rmpd project in release mode, optimizing for performance. This command generates an executable binary in the target/release directory. ```bash cargo build --release ``` -------------------------------- ### MpdServer API Source: https://context7.com/m0rf30/rmpd/llms.txt The MpdServer API implements the complete MPD protocol server, allowing clients to connect and control music playback. ```APIDOC ## MpdServer API ### Description Implements the complete MPD protocol server. ### Initialization - `MpdServer::new(address, shutdown_rx)`: Creates a new MPD server with default application state. - `MpdServer::with_state(address, state, shutdown_rx)`: Creates a new MPD server with a custom application state. ### Running the Server - `server.run().await`: Starts the MPD server and blocks until a shutdown signal is received. ### Shutdown - A `broadcast::channel` is used to signal graceful shutdown to the server. - `shutdown_tx.send(()).ok()`: Sends the shutdown signal. ### Example Usage ```rust use rmpd_protocol::{MpdServer, AppState}; use tokio::sync::broadcast; let (shutdown_tx, shutdown_rx) = broadcast::channel(1); // With default state let server = MpdServer::new("127.0.0.1:6600".to_string(), shutdown_rx); // With custom state // let state = AppState::new(); // let server = MpdServer::with_state("0.0.0.0:6600".to_string(), state, shutdown_rx); tokio::spawn(async move { if let Err(e) = server.run().await { eprintln!("Server error: {}", e); } }); // Trigger shutdown shutdown_tx.send(()).ok(); ``` ``` -------------------------------- ### Run rmpd Workspace Tests Source: https://github.com/m0rf30/rmpd/blob/main/README.md Executes all tests within the rmpd workspace, including tests for all features and enabled features. This command is used for verifying the correctness of the codebase during development. ```bash cargo test --workspace --all-features ``` -------------------------------- ### MPD Idle Notifications Source: https://context7.com/m0rf30/rmpd/llms.txt Commands for subscribing to server events, enabling real-time updates on changes within MPD. This is crucial for synchronizing clients with the server state. ```bash # Wait for any change idle # (blocks until change) # changed: player # OK # Wait for specific subsystems idle player playlist database # changed: playlist # OK # Cancel idle noidle # OK # Subsystems: database, update, stored_playlist, playlist, player, mixer, output, options ``` -------------------------------- ### Represent Audio File Metadata with rmpd_core::song::Song (Rust) Source: https://context7.com/m0rf30/rmpd/llms.txt The `Song` struct holds metadata for audio files, including basic information like path and duration, core MPD tags (title, artist, album), MusicBrainz IDs, and extended metadata. It also stores audio properties and ReplayGain information. Dependencies include `rmpd_core::song::{Song, AudioFormat}`, `camino::Utf8PathBuf`, and `std::time::Duration`. ```rust use rmpd_core::song::{Song, AudioFormat}; use camino::Utf8PathBuf; use std::time::Duration; let song = Song { id: 1, path: Utf8PathBuf::from("Artist/Album/01 - Track.flac"), duration: Some(Duration::from_secs(234)), // Core metadata title: Some("Track Name".to_string()), artist: Some("Artist Name".to_string()), album: Some("Album Name".to_string()), album_artist: Some("Album Artist".to_string()), track: Some(1), disc: Some(1), date: Some("2023".to_string()), genre: Some("Rock".to_string()), composer: Some("Composer".to_string()), performer: Some("Performer".to_string()), comment: Some("Comment".to_string()), // MusicBrainz IDs musicbrainz_trackid: Some("uuid".to_string()), musicbrainz_albumid: Some("uuid".to_string()), musicbrainz_artistid: Some("uuid".to_string()), musicbrainz_albumartistid: Some("uuid".to_string()), musicbrainz_releasegroupid: Some("uuid".to_string()), musicbrainz_releasetrackid: Some("uuid".to_string()), // Extended metadata artist_sort: Some("Artist, The".to_string()), album_artist_sort: Some("Artist, The".to_string()), original_date: Some("2020".to_string()), label: Some("Record Label".to_string()), // Audio properties sample_rate: Some(44100), channels: Some(2), bits_per_sample: Some(16), bitrate: Some(320), // ReplayGain replay_gain_track_gain: Some(-6.5), replay_gain_track_peak: Some(0.95), replay_gain_album_gain: Some(-5.2), replay_gain_album_peak: Some(0.98), // Timestamps (Unix epoch) added_at: 1699876543, last_modified: 1699876543, }; // Display helpers println!("Title: {}", song.display_title()); // Falls back to filename println!("Artist: {}", song.display_artist()); // Falls back to album_artist println!("Album: {}", song.display_album()); // Falls back to "Unknown Album" // Audio format struct let format = AudioFormat::new(44100, 2, 16); println!("Format: {}Hz {}ch {}bit", format.sample_rate, format.channels, format.bits_per_sample); ``` -------------------------------- ### MPD Album Art Retrieval Source: https://context7.com/m0rf30/rmpd/llms.txt Commands to retrieve embedded album artwork from audio files. This includes fetching the initial art and subsequent data chunks using offset. ```bash # Get album art (binary response) albumart "Artist/Album/01 - Track.flac" 0 # size: 245678 # type: image/jpeg # binary: 8192 # [binary data] # OK # Get subsequent chunks (offset > 0) albumart "Artist/Album/01 - Track.flac" 8192 # size: 245678 # type: image/jpeg # binary: 8192 # [binary data] # OK # Alternative: readpicture (same interface) readpicture "path/to/song.flac" 0 # OK ``` -------------------------------- ### Song Struct Source: https://context7.com/m0rf30/rmpd/llms.txt The Song struct represents audio file metadata, including core information, MusicBrainz IDs, and audio properties. ```APIDOC ## Song Struct ### Description Represents audio file metadata. ### Fields - `id` (u32): Unique identifier for the song. - `path` (Utf8PathBuf): Path to the audio file. - `duration` (Option): Duration of the audio file. - `title` (Option): Song title. - `artist` (Option): Artist name. - `album` (Option): Album name. - `album_artist` (Option): Album artist name. - `track` (Option): Track number. - `disc` (Option): Disc number. - `date` (Option): Release date. - `genre` (Option): Genre. - `composer` (Option): Composer. - `performer` (Option): Performer. - `comment` (Option): Comment. - `musicbrainz_trackid` (Option): MusicBrainz Track ID. - `musicbrainz_albumid` (Option): MusicBrainz Album ID. - `musicbrainz_artistid` (Option): MusicBrainz Artist ID. - `musicbrainz_albumartistid` (Option): MusicBrainz Album Artist ID. - `musicbrainz_releasegroupid` (Option): MusicBrainz Release Group ID. - `musicbrainz_releasetrackid` (Option): MusicBrainz Release Track ID. - `artist_sort` (Option): Sortable artist name. - `album_artist_sort` (Option): Sortable album artist name. - `original_date` (Option): Original release date. - `label` (Option): Record label. - `sample_rate` (Option): Audio sample rate. - `channels` (Option): Number of audio channels. - `bits_per_sample` (Option): Bits per sample. - `bitrate` (Option): Audio bitrate. - `replay_gain_track_gain` (Option): ReplayGain track gain. - `replay_gain_track_peak` (Option): ReplayGain track peak. - `replay_gain_album_gain` (Option): ReplayGain album gain. - `replay_gain_album_peak` (Option): ReplayGain album peak. - `added_at` (u64): Timestamp when the song was added. - `last_modified` (u64): Timestamp when the song was last modified. ### Display Helpers - `display_title()`: Returns the song title, falling back to filename. - `display_artist()`: Returns the artist, falling back to album artist. - `display_album()`: Returns the album name, falling back to "Unknown Album". ### AudioFormat Struct - `AudioFormat::new(sample_rate, channels, bits_per_sample)`: Creates a new AudioFormat. ### Example Usage ```rust use rmpd_core::song::{Song, AudioFormat}; use camino::Utf8PathBuf; use std::time::Duration; let song = Song { id: 1, path: Utf8PathBuf::from("Artist/Album/01 - Track.flac"), duration: Some(Duration::from_secs(234)), title: Some("Track Name".to_string()), artist: Some("Artist Name".to_string()), album: Some("Album Name".to_string()), // ... other fields added_at: 1699876543, last_modified: 1699876543, }; println!("Title: {}", song.display_title()); let format = AudioFormat::new(44100, 2, 16); println!("Format: {}Hz {}ch {}bit", format.sample_rate, format.channels, format.bits_per_sample); ``` ``` -------------------------------- ### Allowing Specific Clippy Lints in Rust Source: https://github.com/m0rf30/rmpd/blob/main/CI.md Demonstrates how to selectively disable specific Clippy lints at function, module, or inline levels. Use this sparingly to maintain code quality. ```rust // At function level #[allow(clippy::unwrap_used)] fn my_function() { // Can use unwrap here } // At module level #![allow(clippy::missing_errors_doc)] // Inline let x = some_option.unwrap(); // #[allow(clippy::unwrap_used)] ``` -------------------------------- ### Format and Lint rmpd Code Source: https://github.com/m0rf30/rmpd/blob/main/README.md Applies code formatting using 'cargo fmt' and runs the clippy linter to check for common mistakes and improve code quality in the rmpd project. These commands are essential for maintaining code consistency and correctness. ```bash # Format code cargo fmt # Run clippy cargo clippy --workspace --all-targets --all-features ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.