Crate icy_metadata

Source
Expand description

§icy-metadata

crates.io docs.rs Dependency Status license CI codecov GitHub repo size Lines of Code

icy-metadata is a library for reading metadata returned from Icecast-compatible web servers.

§Installation

cargo add icy-metadata

§Features

  • reqwest - adds convenience methods to set icy metadata headers on reqwest’s client builder and request builder.
  • serde - enables serialization/deserialization for metadata structs.

§Headers

Parse common Icecast headers from an HTTP response. icy-metadata will look for several common aliases to find the header values.

use icy_metadata::IcyHeaders;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let stream = reqwest::get("https://some-cool-url.com/some-file.mp3").await?;

    let icy_headers = IcyHeaders::parse_from_headers(stream.headers());
    println!("{icy_headers:?}");

    Ok(())
}

§Reading information contained within the stream

Some streams have information about the current track contained within the stream itself. Wrapping the stream in an IcyMetadataReader provides an interface to read those values.

use std::error::Error;
use std::num::NonZeroUsize;

use icy_metadata::{IcyHeaders, IcyMetadataReader, RequestIcyMetadata};
use stream_download::http::HttpStream;
use stream_download::http::reqwest::{self, Client};
use stream_download::storage::bounded::BoundedStorageProvider;
use stream_download::storage::memory::MemoryStorageProvider;
use stream_download::{Settings, StreamDownload};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // We need to add a header to tell the Icecast server that we can parse the metadata
    // embedded within the stream itself.
    let client = Client::builder().request_icy_metadata().build()?;
    let stream =
        HttpStream::new(client, "https://some-cool-url.com/some-file.mp3".parse()?).await?;

    let icy_headers = IcyHeaders::parse_from_headers(stream.headers());

    // buffer 5 seconds of audio
    // bitrate (in kilobits) / bits per byte * bytes per kilobyte * 5 seconds
    let prefetch_bytes = icy_headers.bitrate().unwrap() / 8 * 1024 * 5;

    let reader = StreamDownload::from_stream(
        stream,
        // use bounded storage to keep the underlying size from growing indefinitely
        BoundedStorageProvider::new(
            MemoryStorageProvider,
            // be liberal with the buffer size, you need to make sure it holds
            // enough space to prevent any out-of-bounds reads
            NonZeroUsize::new(512 * 1024).unwrap(),
        ),
        Settings::default().prefetch_bytes(prefetch_bytes as u64),
    )
    .await?;

    let metadata_reader = IcyMetadataReader::new(
        reader,
        // Since we requested icy metadata, the metadata interval header should be
        // present in the response. This will allow us to parse the metadata
        // within the stream.
        icy_headers.metadata_interval(),
        // Print the stream metadata whenever we receive new values
        |metadata| println!("{metadata:?}\n"),
    );

    Ok(())
}

§Seeking within the stream

Seeking is supported with a few limitations. See the docs for IcyMetadataReader for details.

§Supported Rust Versions

The MSRV is currently 1.81.0.

Modules§

error
Errors returned from parsing icy metadata.

Structs§

IcyAudioInfo
Optional additional information about the stream audio
IcyHeaders
Icy metadata found within HTTP response headers.
IcyMetadata
Metadata contained within a stream
IcyMetadataReader
Reads icy metadata contained within a stream.

Constants§

ICY_METADATA_HEADER
Header name to request icy metadata.

Traits§

RequestIcyMetadata
Trait for requesting icy metadata from an HTTP request builder

Functions§

add_icy_metadata_header
Appends the Icy-MetaData header to the header_map.