Streaming FLAC manipulation
Find a file
Mark 3f0969778f
All checks were successful
CI / clippy (push) Successful in 37s
CI / typos (push) Successful in 37s
CI / test-all-features (push) Successful in 38s
CI / test (push) Successful in 40s
CI / test-dev (push) Successful in 57s
CI / test-all-features-dev (push) Successful in 1m5s
CI fix
2026-10-08 20:14:38 -07:00
.forgejo/workflows CI fix 2026-10-08 20:14:38 -07:00
crates/flactag README 2026-10-08 18:48:14 -07:00
.editorconfig Initial commit 2026-10-08 18:35:54 -07:00
.gitignore Initial commit 2026-10-08 18:35:54 -07:00
Cargo.lock v0.0.1 2026-10-08 18:36:19 -07:00
Cargo.toml README 2026-10-08 18:48:14 -07:00
README.md README 2026-10-08 18:48:14 -07:00
rust-toolchain.toml Initial commit 2026-10-08 18:35:54 -07:00
rustfmt.toml Initial commit 2026-10-08 18:35:54 -07:00
typos.toml Initial commit 2026-10-08 18:35:54 -07:00

FLACtag: streaming FLAC manipulation

Usage (read)

Read a file and print its tags and pictures:

use std::fs::File;
use flactag::{FlacBlock, FlacReader};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::open("song.flac")?;

    for block in FlacReader::new(file) {
        match block? {
            FlacBlock::Streaminfo(s) => {
                println!("{} Hz, {} channels, {} bps", s.sample_rate, s.channels, s.bits_per_sample);
            }

            FlacBlock::VorbisComment(c) => {
                for (tag, value) in &c.comment.comments {
                    println!("{tag:?} = {value}");
                }

                // Pictures stored as METADATA_BLOCK_PICTURE comments show up here
                for picture in &c.comment.pictures {
                    println!("inline picture: {} ({} bytes)", picture.mime, picture.img_data.len());
                }
            }

            FlacBlock::Picture(p) => {
                println!("{:?} picture: {} ({}x{})", p.picture_type, p.mime, p.width, p.height);
            }

            // Padding, Application, SeekTable, CueSheet, AudioFrame
            _ => {}
        }
    }

    Ok(())
}

Usage (write)

FLAC writing features of this crate are not finished.

Blocks are re-encoded with FlacBlock::encode(is_last, with_header, target). is_last sets the last-metadata-block flag in the header, and with_header controls whether the 4-byte metablock header is written (audio frames ignore both). A full round-trip looks like this:

use std::{fs::File, io::Write};
use flactag::{FlacBlock, FlacReader};

fn copy(from: &str, to: &str) -> Result<(), Box<dyn std::error::Error>> {
    let blocks: Vec<FlacBlock> = FlacReader::new(File::open(from)?).collect::<Result<_, _>>()?;

    let mut out = File::create(to)?;
    out.write_all(b"fLaC")?;

    for (i, block) in blocks.iter().enumerate() {
        // The last metablock is the one right before the first audio frame
        let is_last = !matches!(block, FlacBlock::AudioFrame(_))
            && matches!(blocks.get(i + 1), Some(FlacBlock::AudioFrame(_)));

        block.encode(is_last, true, &mut out)?;
    }

    Ok(())
}