serenity-rs / songbird

An async Rust library for the Discord voice API
ISC License
384 stars 110 forks source link

Retrieving Metadata for HttpRequest on Songbird `next` #183

Closed maxall41 closed 1 year ago

maxall41 commented 1 year ago

Songbird version: next branch

Rust version (rustc -V): 1.69

Serenity/Twilight version: serenity: next

Description: I'm trying to pull the metadata off of an HttpRequest or TrackHandle it seems like aux_metadata is unsupported for HttpRequest and that using a track handle action to get a view to pull the metadata from just results in a None value for the metadata. Even though the ready state is "Playing" so it should be fine. I'm not sure if this is a bug or something intentional but i can't seem to find another way to get the metadata.

Steps to reproduce:

  1. Create HttpRequest
  2. Start playback using HttpRequest
  3. Attempt to get metadata from TrackHandle in TrackHandle::Action with View like below:

fn get_metadata_action(view: View) -> Option { let meta = view.meta.unwrap().probe.get().unwrap(); let metadata = meta.current().unwrap().tags(); println!("{:?}",metadata); None }

FelixMcFelix commented 1 year ago

The first part is intentional; an HttpRequest points to 'the thing you want to play', aux_metadata is filled in by tools which have access to other context (e.g., a youtube player page, or bandcamp url).

You're doing the right thing to access in-stream metadata, but in general you must also check format; what format is the file you're pointing to? However, the metadata field should always be accessible when you hit ReadyState::Playable. the only time adding it to View fails is if the underlying track is not Parsed. I will try to have another check some time tonight.

EDIT: ProbedMetadata is not guaranteed to be safe to unwrap -- not all formats prepend metadata in ID3 tags!

maxall41 commented 1 year ago

So i wrote this somewhat sketchy code to check both format and probed metadata but both fail:

fn get_probed_metadata(meta: &mut Metadata) -> Result<Vec<Tag>,Whatever> {
    let probed = meta.probe.get().with_whatever_context(|| "Failed to get probed metadata")?;
    let tags = probed.current().with_whatever_context(|| "Failed to get current metadata")?.tags();
    Ok(tags.to_vec())
}

fn get_format_metadata(meta: &Metadata) -> Result<Vec<Tag>,Whatever> {
    let format = meta.format.current().with_whatever_context(|| "Failed to get format metadata")?;
    let tags = format.tags();
    Ok(tags.to_vec())
}

fn get_metadata_action(view: View) -> Option<Action> {
    let mut meta = view.meta.unwrap();
    let tags = get_probed_metadata(&mut meta);
    match tags {
        Ok(t) => {
            println!("{:?}",t)
        },
        Err(e) => {
            println!("Probed failed with: {}",e);
            // This is fine for testing
            let tags = get_format_metadata(&meta).unwrap();
            println!("{:?}",tags);
        }
    }
    None
}

pub async fn get_metadata(track: &Option<TrackHandle>) -> Result<(),Whatever> {
    let t = track.as_ref().with_whatever_context(|| format!("Track not found"))?;
    t.action(get_metadata_action).unwrap();
    Ok(())
}

I'm using this file for testing https://www.ee.columbia.edu/~dpwe/sounds/music/africa-toto.wav. And I can extract metadata from it with exiftool so it is definitely there.

FelixMcFelix commented 1 year ago

I don't think symphonia can find any metadata encoded in this file, nor can VLC for that matter. Symphonia-play reports as much: image vs. image Exiftool doesn't show me anything that's not shown here; none of this information (codecs etc.) goes into symphonia's metadata. If you want that sort of info, then it shouldn't be that hard to change the lib to expose it on View/Parsed/whatever.

maxall41 commented 1 year ago

Ah I didn't know Tracks was not part of Metadata in symphonia. I updated my fork of songbird to add CodecParameters to the View and now it works fine.