Login
1 branch 0 tags
Ben (T14/NixOS) GNU unifont experiments 27b6a39 1 month ago 53 Commits
moon / src / audio_metadata.c
#include "audio_metadata.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Implemented in metadata/
bool parse_m4a(const char *path, audio_metadata_t *meta);
bool parse_mp3(const char *path, audio_metadata_t *meta);
bool parse_wav(const char *path, audio_metadata_t *meta);
bool parse_flac(const char *path, audio_metadata_t *meta);
bool parse_ogg(const char *path, audio_metadata_t *meta);

// Helper to get file extension (lowercase)
static const char *get_extension(const char *path) {
  const char *dot = strrchr(path, '.');
  return dot ? dot + 1 : "";
}

// Helper to extract filename without extension for fallback title
static void extract_filename(const char *path, char *buf, size_t buf_size) {
  const char *name = strrchr(path, '/');
  name = name ? name + 1 : path;

  const char *dot = strrchr(name, '.');
  size_t len = dot ? (size_t)(dot - name) : strlen(name);
  if (len >= buf_size)
    len = buf_size - 1;

  memcpy(buf, name, len);
  buf[len] = '\0';
}

bool audio_metadata_get(const char *path, audio_metadata_t *meta) {
  if (!path || !meta)
    return false;

  // Initialize metadata
  memset(meta, 0, sizeof(*meta));

  // Set filename as fallback title
  extract_filename(path, meta->title, sizeof(meta->title));

  // Get extension
  const char *ext = get_extension(path);

  // Dispatch to format-specific parser
  bool success = false;

  if (strcasecmp(ext, "mp3") == 0) {
    success = parse_mp3(path, meta);
  } else if (strcasecmp(ext, "m4a") == 0 || strcasecmp(ext, "m4b") == 0 ||
             strcasecmp(ext, "mp4") == 0 || strcasecmp(ext, "aac") == 0) {
    success = parse_m4a(path, meta);
  } else if (strcasecmp(ext, "wav") == 0) {
    success = parse_wav(path, meta);
  } else if (strcasecmp(ext, "flac") == 0) {
    success = parse_flac(path, meta);
  } else if (strcasecmp(ext, "ogg") == 0 || strcasecmp(ext, "opus") == 0 || strcasecmp(ext, "opu") == 0) {
    success = parse_ogg(path, meta);
  }

  // If parsing failed but we have a filename, still return partial success
  if (!success && meta->title[0] != '\0') {
    meta->valid = false; // Indicate metadata is incomplete
  }

  return success;
}