static int
parse_date(struct media_file_info *mfi, char *date_string)
{
  char year_string[21];
  uint32_t *year = (uint32_t *) ((char *) mfi + mfi_offsetof(year));
  uint32_t *date_released = (uint32_t *) ((char *) mfi + mfi_offsetof(date_released));
  struct tm tm = { 0 };
  int ret = 0;

  if ((*year == 0) && (safe_atou32(date_string, year) == 0))
    ret++;

  if ( strptime(date_string, "%FT%T%z", &tm) // ISO 8601, %F=%Y-%m-%d, %T=%H:%M:%S
       || strptime(date_string, "%F %T", &tm)
       || strptime(date_string, "%F %H:%M", &tm)
       || strptime(date_string, "%F", &tm)
     )
    {
      *date_released = (uint32_t)mktime(&tm);
      ret++;
    }

  if ((*date_released == 0) && (*year != 0))
    {
      snprintf(year_string, sizeof(year_string), "%" PRIu32 "-01-01T12:00:00", *year);
      if (strptime(year_string, "%FT%T", &tm))
	{
	  *date_released = (uint32_t)mktime(&tm);
	  ret++;
	}
    }

  return ret;
}
static int
parse_disc(struct media_file_info *mfi, char *disc_string)
{
  uint32_t *disc = (uint32_t *) ((char *) mfi + mfi_offsetof(disc));
  uint32_t *total_discs = (uint32_t *) ((char *) mfi + mfi_offsetof(total_discs));

  return parse_slash_separated_ints(disc_string, disc, total_discs);
}
static int
parse_track(struct media_file_info *mfi, char *track_string)
{
  uint32_t *track = (uint32_t *) ((char *) mfi + mfi_offsetof(track));
  uint32_t *total_tracks = (uint32_t *) ((char *) mfi + mfi_offsetof(total_tracks));

  return parse_slash_separated_ints(track_string, track, total_tracks);
}
  return parse_slash_separated_ints(track_string, track, total_tracks);
}

static int
parse_disc(struct media_file_info *mfi, char *disc_string)
{
  uint32_t *disc = (uint32_t *) ((char *) mfi + mfi_offsetof(disc));
  uint32_t *total_discs = (uint32_t *) ((char *) mfi + mfi_offsetof(total_discs));

  return parse_slash_separated_ints(disc_string, disc, total_discs);
}

/* Lookup is case-insensitive, first occurrence takes precedence */
static const struct metadata_map md_map_generic[] =
  {
    { "title",        0, mfi_offsetof(title),              NULL },
    { "artist",       0, mfi_offsetof(artist),             NULL },
    { "author",       0, mfi_offsetof(artist),             NULL },
    { "album_artist", 0, mfi_offsetof(album_artist),       NULL },
    { "album",        0, mfi_offsetof(album),              NULL },
    { "genre",        0, mfi_offsetof(genre),              NULL },
    { "composer",     0, mfi_offsetof(composer),           NULL },
    { "grouping",     0, mfi_offsetof(grouping),           NULL },
    { "orchestra",    0, mfi_offsetof(orchestra),          NULL },
    { "conductor",    0, mfi_offsetof(conductor),          NULL },
    { "comment",      0, mfi_offsetof(comment),            NULL },
    { "description",  0, mfi_offsetof(comment),            NULL },
    { "track",        1, mfi_offsetof(track),              parse_track },
    { "disc",         1, mfi_offsetof(disc),               parse_disc },
    { "year",         1, mfi_offsetof(year),               NULL },
    { "date",         1, mfi_offsetof(year),               NULL },
static int
parse_albumid(struct media_file_info *mfi, char *id_string)
{
  // Already set by a previous tag that we give higher priority
  if (mfi->songalbumid)
    return 0;

  // Limit hash length to 63 bits, due to signed type in sqlite
  mfi->songalbumid = murmur_hash64(id_string, strlen(id_string), 0) >> 1;
  return 1;
}

/* Lookup is case-insensitive, first occurrence takes precedence */
static const struct metadata_map md_map_generic[] =
  {
    { "title",        0, mfi_offsetof(title),              NULL },
    { "artist",       0, mfi_offsetof(artist),             NULL },
    { "author",       0, mfi_offsetof(artist),             NULL },
    { "album_artist", 0, mfi_offsetof(album_artist),       NULL },
    { "album",        0, mfi_offsetof(album),              NULL },
    { "genre",        0, mfi_offsetof(genre),              NULL },
    { "composer",     0, mfi_offsetof(composer),           NULL },
    { "grouping",     0, mfi_offsetof(grouping),           NULL },
    { "orchestra",    0, mfi_offsetof(orchestra),          NULL },
    { "conductor",    0, mfi_offsetof(conductor),          NULL },
    { "comment",      0, mfi_offsetof(comment),            NULL },
    { "description",  0, mfi_offsetof(comment),            NULL },
    { "track",        1, mfi_offsetof(track),              parse_track },
    { "disc",         1, mfi_offsetof(disc),               parse_disc },
    { "year",         1, mfi_offsetof(year),               NULL },
    { "date",         1, mfi_offsetof(date_released),      parse_date },
		<key>Name</key><string>Wish You Were Here</string>
		<key>Artist</key><string>Pink Floyd</string>
		<key>Album Artist</key><string>Pink Floyd</string>
		<key>Composer</key><string>David Gilmour/Roger Waters</string>
		<key>Album</key><string>Wish You Were Here</string>
		<key>Genre</key><string>Classic Rock</string>
		<key>Kind</key><string>MPEG audio file</string>
		<key>Equalizer</key><string>#!#116#!#</string>
		<key>Equalizer</key><string>Rock</string>
		<key>Sort Album</key><string>Wish You Were Here</string>
		<key>Location</key><string>file://localhost/E:/Music/Pink%20Floyd/Wish%20You%20Were%20Here/04%20Wish%20You%20Were%20Here.mp3</string>
	</dict>
 */
static struct metadata_map md_map[] =
  {
    { "Name",         PLIST_STRING,  mfi_offsetof(title) },
    { "Artist",       PLIST_STRING,  mfi_offsetof(artist) },
    { "Album Artist", PLIST_STRING,  mfi_offsetof(album_artist) },
    { "Composer",     PLIST_STRING,  mfi_offsetof(composer) },
    { "Album",        PLIST_STRING,  mfi_offsetof(album) },
    { "Genre",        PLIST_STRING,  mfi_offsetof(genre) },
    { "Comments",     PLIST_STRING,  mfi_offsetof(comment) },
    { "Track Count",  PLIST_UINT,    mfi_offsetof(total_tracks) },
    { "Track Number", PLIST_UINT,    mfi_offsetof(track) },
    { "Disc Count",   PLIST_UINT,    mfi_offsetof(total_discs) },
    { "Disc Number",  PLIST_UINT,    mfi_offsetof(disc) },
    { "Year",         PLIST_UINT,    mfi_offsetof(year) },
    { "Total Time",   PLIST_UINT,    mfi_offsetof(song_length) },
    { "Bit Rate",     PLIST_UINT,    mfi_offsetof(bitrate) },
    { "Sample Rate",  PLIST_UINT,    mfi_offsetof(samplerate) },
    { "BPM",          PLIST_UINT,    mfi_offsetof(bpm) },