1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-09-15 04:08:07 -04:00

Iterate towards optional TagLib support, as well as scripted metadata support.

This is just the first step and equivalent to current functionality.


git-svn-id: https://svn.xiph.org/trunk/ezstream@12680 0101bb08-14d6-0310-b084-bc0e0c8e3800
This commit is contained in:
moritz 2007-03-08 14:39:00 +00:00
parent d302a64c2e
commit 900886ab3f
5 changed files with 631 additions and 202 deletions

View File

@ -64,7 +64,7 @@ AC_TYPE_SIZE_T
dnl USEFUL HEADERS dnl USEFUL HEADERS
AC_CHECK_HEADERS(sys/time.h paths.h signal.h) AC_CHECK_HEADERS(sys/time.h paths.h signal.h libgen.h)
dnl LIBRARY FUNCTIONS dnl LIBRARY FUNCTIONS

View File

@ -2,12 +2,14 @@ AUTOMAKE_OPTIONS = 1.9 foreign
bin_PROGRAMS = ezstream bin_PROGRAMS = ezstream
ezstream_SOURCES = ezstream.c compat.c configfile.c playlist.c util.c ezstream_SOURCES = compat.c configfile.c ezstream.c metadata.c playlist.c \
util.c
ezstream_LDADD = @LIBOBJS@ @XIPH_LIBS@ ezstream_LDADD = @LIBOBJS@ @XIPH_LIBS@
AM_CFLAGS = @XIPH_CFLAGS@ AM_CFLAGS = @XIPH_CFLAGS@
AM_CPPFLAGS = @XIPH_CPPFLAGS@ AM_CPPFLAGS = @XIPH_CPPFLAGS@
EXTRA_DIST = compat.h configfile.h getopt.h playlist.h strfctns.h util.h EXTRA_DIST = compat.h configfile.h getopt.h metadata.h playlist.h \
strfctns.h util.h
CLEANFILES = core *.core *~ .*~ CLEANFILES = core *.core *~ .*~

View File

@ -33,6 +33,10 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif
#include <limits.h>
#ifdef HAVE_PATHS_H #ifdef HAVE_PATHS_H
# include <paths.h> # include <paths.h>
#endif #endif
@ -42,22 +46,21 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#ifdef WIN32 #ifdef WIN32
# include <io.h> # include <io.h>
# include <windows.h> # include <windows.h>
#else
# include <libgen.h>
# include <unistd.h>
#endif /* WIN32 */ #endif /* WIN32 */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <shout/shout.h> #include <shout/shout.h>
#include <vorbis/vorbisfile.h>
#include "compat.h" #include "compat.h"
#include "configfile.h" #include "configfile.h"
#ifndef HAVE_GETOPT #ifndef HAVE_GETOPT
# include "getopt.h" # include "getopt.h"
#endif #endif
#include "metadata.h"
#include "playlist.h" #include "playlist.h"
#include "strfctns.h" #include "strfctns.h"
#include "util.h" #include "util.h"
@ -105,9 +108,8 @@ typedef struct tag_ID3Tag {
int urlParse(const char *, char **, int *, char **); int urlParse(const char *, char **, int *, char **);
void replaceString(const char *, char *, size_t, const char *, const char *); void replaceString(const char *, char *, size_t, const char *, const char *);
void setMetadata(shout_t *, const char *);
char * buildCommandString(const char *, const char *, const char *); char * buildCommandString(const char *, const char *, const char *);
char * processMetadata(shout_t *, const char *, const char *); char * processMetadata(shout_t *, const char *);
FILE * openResource(shout_t *, const char *, int *, char **, int *); FILE * openResource(shout_t *, const char *, int *, char **, int *);
int reconnectServer(shout_t *, int); int reconnectServer(shout_t *, int);
int sendStream(shout_t *, FILE *, const char *, int, void *); int sendStream(shout_t *, FILE *, const char *, int, void *);
@ -214,17 +216,7 @@ replaceString(const char *source, char *dest, size_t size,
strlcat(dest, p1, size); strlcat(dest, p1, size);
} }
void char *
setMetadata(shout_t *shout, const char *metadata)
{
shout_metadata_t *shoutMetadata = shout_metadata_new();
shout_metadata_add(shoutMetadata, "song", metadata);
shout_set_metadata(shout, shoutMetadata);
shout_metadata_free(shoutMetadata);
}
char*
buildCommandString(const char *extension, const char *fileName, buildCommandString(const char *extension, const char *fileName,
const char *metadata) const char *metadata)
{ {
@ -293,154 +285,33 @@ buildCommandString(const char *extension, const char *fileName,
} }
char * char *
processMetadata(shout_t *shout, const char *extension, const char *fileName) processMetadata(shout_t *shout, const char *fileName)
{ {
FILE *filepstream = NULL;
char *songInfo = NULL; char *songInfo = NULL;
size_t songLen = 0; shout_metadata_t *shout_mdata = NULL;
ID3Tag id3tag; metadata_t *mdata = NULL;
shout_metadata_t *pmetadata = NULL;
if ((filepstream = fopen(fileName, "rb")) == NULL) { if ((mdata = metadata_file(fileName)) == NULL) {
printf("%s: processMetadata(): %s: %s\n", songInfo = xstrdup(blankString);
__progname, fileName, strerror(errno)); return (songInfo);
return (xstrdup(blankString));
} }
if (strcmp(extension, ".mp3") == 0) { if (!metadata_file_update(mdata)) {
/* Look for the ID3 tag */ metadata_free(mdata);
memset(&id3tag, '\000', sizeof(id3tag)); songInfo = xstrdup(blankString);
fseek(filepstream, -128L, SEEK_END); return (songInfo);
fread(&id3tag, 1, 127, filepstream);
if (strncmp(id3tag.tag, "TAG", strlen("TAG")) == 0) {
char tempTrackName[31];
char tempArtistName[31];
snprintf(tempTrackName, sizeof(tempTrackName), "%s",
id3tag.trackName);
snprintf(tempArtistName, sizeof(tempArtistName), "%s",
id3tag.artistName);
if (strlen(tempTrackName) > 0 ||
strlen(tempArtistName) > 0) {
songLen = strlen(tempArtistName) +
strlen(" - ") + strlen(tempTrackName)
+ 1;
songInfo = xmalloc(songLen);
strlcpy(songInfo, tempArtistName, songLen);
if (strlen(songInfo) > 0 &&
strlen(tempTrackName) > 0)
strlcat(songInfo, " - ", songLen);
strlcat(songInfo, tempTrackName, songLen);
} }
} songInfo = xstrdup(metadata_get_string(mdata));
} else if (strcmp(extension, ".ogg") == 0) { metadata_free(mdata);
OggVorbis_File vf;
int ret;
if ((ret = ov_open(filepstream, &vf, NULL, 0)) != 0) { if ((shout_mdata = shout_metadata_new()) == NULL) {
switch (ret) {
case OV_EREAD:
printf("%s: No metadata support: %s: Media read error\n",
__progname, fileName);
break;
case OV_ENOTVORBIS:
printf("%s: No metadata support: %s: Invalid Vorbis bitstream\n",
__progname, fileName);
break;
case OV_EVERSION:
printf("%s: No metadata support: %s: Vorbis version mismatch\n",
__progname, fileName);
break;
case OV_EBADHEADER:
printf("%s: No metadata support: %s: Invalid Vorbis bitstream header\n",
__progname, fileName);
break;
case OV_EFAULT:
printf("%s: Fatal: Internal libvorbisfile fault\n",
__progname);
abort();
default:
printf("%s: No metadata support: %s: ov_read() returned unknown error\n",
__progname, fileName);
break;
}
} else {
char **ptr = ov_comment(&vf, -1)->user_comments;
char *artist = NULL;
char *title = NULL;
while(*ptr){
if (artist == NULL &&
strncasecmp(*ptr, "ARTIST", strlen("ARTIST")) == 0)
artist = xstrdup(*ptr + strlen("ARTIST="));
if (title == NULL &&
strncasecmp(*ptr, "TITLE", strlen("TITLE")) == 0)
title = xstrdup(*ptr + strlen("TITLE="));
++ptr;
}
if (artist != NULL || title != NULL) {
songLen = 0;
if (artist != NULL)
songLen += strlen(artist);
if (title != NULL)
songLen += strlen(title);
songLen += strlen(" - ") + 1;
songInfo = xcalloc(1, songLen);
if (artist != NULL)
strlcpy(songInfo, artist, songLen);
if (title != NULL) {
if (artist != NULL)
strlcat(songInfo, " - ", songLen);
strlcat(songInfo, title, songLen);
xfree(title);
}
if (artist != NULL)
xfree(artist);
}
ov_clear(&vf);
filepstream = NULL;
}
}
if (filepstream != NULL)
fclose(filepstream);
if (songInfo == NULL) {
/*
* If we didn't get any song info via tags or comments, then
* let's just use the filename.
*/
char *p1 = NULL;
char *p2 = NULL;
char *filename_copy = NULL;
filename_copy = xstrdup(fileName);
p2 = basename(filename_copy);
if (p2 == NULL) {
/* Assert that basename() cannot fail. */
printf("%s: Internal error: basename() failed with '%s'\n",
__progname, filename_copy);
exit(1);
}
songInfo = xstrdup(p2);
xfree(filename_copy);
p1 = strrchr(songInfo, '.');
if (p1 != NULL)
*p1 = '\000';
}
if ((pmetadata = shout_metadata_new()) == NULL) {
printf("%s: shout_metadata_new(): %s\n", __progname, printf("%s: shout_metadata_new(): %s\n", __progname,
strerror(ENOMEM)); strerror(ENOMEM));
exit(1); exit(1);
} }
shout_metadata_add(pmetadata, "song", songInfo); shout_metadata_add(shout_mdata, "song", songInfo);
shout_set_metadata(shout, pmetadata); shout_set_metadata(shout, shout_mdata);
shout_metadata_free(pmetadata); shout_metadata_free(shout_mdata);
return (songInfo); return (songInfo);
} }
@ -451,7 +322,7 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
{ {
FILE *filep = NULL; FILE *filep = NULL;
char extension[25]; char extension[25];
char *p1 = NULL; char *p = NULL;
char *pMetadata = NULL; char *pMetadata = NULL;
char *pCommandString = NULL; char *pCommandString = NULL;
@ -471,18 +342,24 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
*isStdin = 0; *isStdin = 0;
extension[0] = '\0'; extension[0] = '\0';
p1 = strrchr(fileName, '.'); p = strrchr(fileName, '.');
if (p1 != NULL) if (p != NULL)
strlcpy(extension, p1, sizeof(extension)); strlcpy(extension, p, sizeof(extension));
for (p1 = extension; *p1 != '\0'; p1++) for (p = extension; *p != '\0'; p++)
*p1 = tolower((int)*p1); *p = tolower((int)*p);
pMetadata = processMetadata(shout, extension, fileName);
if (strlen(extension) == 0) {
printf("%s: Error: Cannot determine file type of '%s'\n",
__progname, fileName);
return (filep);
}
pMetadata = processMetadata(shout, fileName);
if (metaCopy != NULL) if (metaCopy != NULL)
*metaCopy = xstrdup(pMetadata); *metaCopy = xstrdup(pMetadata);
*popenFlag = 0; *popenFlag = 0;
if (pezConfig->reencode) { if (pezConfig->reencode) {
if (strlen(extension) > 0) {
int stderr_fd = dup(fileno(stderr)); int stderr_fd = dup(fileno(stderr));
pCommandString = buildCommandString(extension, fileName, pMetadata); pCommandString = buildCommandString(extension, fileName, pMetadata);
@ -524,9 +401,6 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
if (qFlag) if (qFlag)
dup2(stderr_fd, fileno(stderr)); dup2(stderr_fd, fileno(stderr));
} else
printf("%s: Error: Cannot determine file type of '%s'\n",
__progname, fileName);
xfree(pMetadata); xfree(pMetadata);
return (filep); return (filep);

457
src/metadata.c Normal file
View File

@ -0,0 +1,457 @@
/*
* Copyright (c) 2007 Moritz Grimm <gtgbr@gmx.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/vorbisfile.h>
#include "compat.h"
#include "metadata.h"
#include "strfctns.h"
#include "util.h"
extern char *__progname;
struct metadata {
char *filename;
char *string;
char *artist;
char *title;
int program;
};
struct ID3Tag {
char tag[3];
char trackName[30];
char artistName[30];
char albumName[30];
char year[3];
char comment[30];
char genre;
};
metadata_t * metadata_create(const char *);
void metadata_use_taglib(metadata_t *, FILE **);
void metadata_use_self(metadata_t *, FILE **);
void metadata_clean_md(metadata_t *);
void metadata_get_extension(char *, size_t, const char *);
char * metadata_get_name(const char *);
void metadata_process_md(metadata_t *);
metadata_t *
metadata_create(const char *filename)
{
metadata_t *md;
md = xcalloc(1, sizeof(metadata_t));
md->filename = xstrdup(filename);
return (md);
}
void
metadata_use_taglib(metadata_t *md, FILE **filep)
#ifdef HAVE_TAG_C
{
TagLib_File *tf;
TagLib_Tag *tt;
char *str;
if (md == NULL || md->filename == NULL) {
printf("%s: metadata_use_taglib(): Internal error: Bad arguments\n",
__progname);
abort();
}
if (filep != NULL)
fclose(*filep);
metadata_clean_md(md);
taglib_set_string_management_enabled(0);
if (md->string != NULL)
xfree(md->string);
if ((tf = taglib_file_new(md->filename)) == NULL) {
md->string = metadata_get_name(md->filename);
return;
}
tt = taglib_file_tag(tf);
str = taglib_tag_artist(tt);
if (str != NULL) {
if (strlen(str) > 0)
md->artist = xstrdup(str);
xfree(str);
}
str = taglib_tag_title(tt);
if (str != NULL) {
if (strlen(str) > 0)
md->title = xstrdup(str);
xfree(str);
}
taglib_file_free(tf);
}
#else
{
printf("%s: Internal error: metadata_use_taglib() called without TagLib support\n",
__progname);
abort();
}
#endif /* HAVE_TAG_C */
void
metadata_use_self(metadata_t *md, FILE **filep)
#ifdef HAVE_TAG_C
{
printf("%s: Internal error: metadata_use_self() called with TagLib support\n",
__progname);
abort();
}
#else
{
char extension[25];
struct ID3Tag id3tag;
if (md == NULL || filep == NULL || *filep == NULL ||
md->filename == NULL) {
printf("%s: metadata_use_self(): Internal error: Bad arguments\n",
__progname);
abort();
}
metadata_clean_md(md);
metadata_get_extension(extension, sizeof(extension), md->filename);
if (strcmp(extension, ".mp3") == 0) {
memset(&id3tag, 0, sizeof(id3tag));
fseek(*filep, -128L, SEEK_END);
fread(&id3tag, 1, 127, *filep);
if (strncmp(id3tag.tag, "TAG", strlen("TAG")) == 0) {
if (strlen(id3tag.artistName) > 0)
md->artist = xstrdup(id3tag.artistName);
if (strlen(id3tag.trackName) > 0)
md->title = xstrdup(id3tag.trackName);
}
} else if (strcmp(extension, ".ogg") == 0) {
OggVorbis_File vf;
int ret;
if ((ret = ov_open(*filep, &vf, NULL, 0)) != 0) {
switch (ret) {
case OV_EREAD:
printf("%s: ov_open(): %s: Media read error\n",
__progname, md->filename);
break;
case OV_ENOTVORBIS:
printf("%s: ov_open(): %s: Invalid Vorbis bitstream\n",
__progname, md->filename);
break;
case OV_EVERSION:
printf("%s: ov_open(): %s: Vorbis version mismatch\n",
__progname, md->filename);
break;
case OV_EBADHEADER:
printf("%s: ov_open(): %s: Invalid Vorbis bitstream header\n",
__progname, md->filename);
break;
case OV_EFAULT:
printf("%s: Fatal: Internal libvorbisfile fault\n",
__progname);
abort();
default:
printf("%s: ov_open(): %s: ov_read() returned unknown error\n",
__progname, md->filename);
break;
}
} else {
char **ptr;
for (ptr = ov_comment(&vf, -1)->user_comments; *ptr != NULL; ptr++) {
if (md->artist == NULL &&
strncasecmp(*ptr, "ARTIST", strlen("ARTIST")) == 0) {
if (strlen(*ptr + strlen("ARTIST=")) > 0)
md->artist = xstrdup(*ptr + strlen("ARTIST="));
}
if (md->title == NULL &&
strncasecmp(*ptr, "TITLE", strlen("TITLE")) == 0) {
if (strlen(*ptr + strlen("TITLE=")) > 0)
md->title = xstrdup(*ptr + strlen("TITLE="));
}
}
ov_clear(&vf);
*filep = NULL;
}
}
if (*filep != NULL)
fclose(*filep);
if (md->artist == NULL && md->title == NULL)
md->string = metadata_get_name(md->filename);
}
#endif /* HAVE_TAG_C */
void
metadata_clean_md(metadata_t *md)
{
if (md == NULL) {
printf("%s: Internal error: metadata_clean_md(): NULL argument\n",
__progname);
abort();
}
if (md->string != NULL)
xfree(md->string);
if (md->artist != NULL)
xfree(md->artist);
if (md->title != NULL)
xfree(md->title);
}
void
metadata_get_extension(char *buf, size_t siz, const char *filename)
{
char *p;
if (buf == NULL || siz == 0 || filename == NULL) {
printf("%s: metadata_get_extension(): Internal error: Bad arguments\n",
__progname);
abort();
}
if ((p = strrchr(filename, '.')) != NULL)
strlcpy(buf, p, siz);
else
buf[0] = '\0';
for (p = buf; *p != '\0'; p++)
*p = tolower((int)*p);
}
char *
metadata_get_name(const char *file)
{
char *filename = xstrdup(file);
char *p1, *p2, *name;
if (file == NULL) {
printf("%s: metadata_get_name(): Internal error: Bad arguments\n",
__progname);
abort();
}
if ((p1 = basename(filename)) == NULL) {
printf("%s: Internal error: basename() failed with '%s'\n",
__progname, filename);
exit(1);
}
if ((p2 = strrchr(p1, '.')) != NULL)
*p2 = '\0';
if (strlen(p1) == 0)
name = xstrdup("[unknown]");
else
name = xstrdup(p1);
xfree(filename);
return (name);
}
void
metadata_process_md(metadata_t *md)
{
size_t siz = 0;
if (md == NULL) {
printf("%s: metadata_process_md(): Internal error: Bad arguments\n",
__progname);
abort();
}
if (md->string != NULL)
return;
if (md->artist != NULL)
siz += strlen(md->artist);
if (md->title != NULL) {
if (siz > 0)
siz += strlen(" - ");
siz += strlen(md->title);
}
siz++;
md->string = xcalloc(1, siz);
if (md->artist != NULL)
strlcpy(md->string, md->artist, siz);
if (md->title != NULL) {
if (md->artist != NULL)
strlcat(md->string, " - ", siz);
strlcat(md->string, md->title, siz);
}
}
metadata_t *
metadata_file(const char *filename)
{
metadata_t *md;
if (filename == NULL || strlen(filename) == 0) {
printf("%s: metadata_file(): Internal error: Bad arguments\n",
__progname);
abort();
}
md = metadata_create(filename);
if (!metadata_file_update(md)) {
metadata_free(md);
return (NULL);
}
return (md);
}
metadata_t *
metadata_program(const char *program)
{
metadata_t *md;
if (program == NULL || strlen(program) == 0) {
printf("%s: metadata_program(): Internal error: Bad arguments\n",
__progname);
abort();
}
md = metadata_create(program);
md->program = 1;
return (md);
}
void
metadata_free(metadata_t *md)
{
if (md == NULL)
return;
if (md->filename != NULL)
xfree(md->filename);
metadata_clean_md(md);
xfree(md);
}
int
metadata_file_update(metadata_t *md)
{
FILE *filep;
if (md == NULL) {
printf("%s: metadata_file_update(): Internal error: NULL argument\n",
__progname);
abort();
}
if (md->program) {
printf("%s: metadata_file_update(): Internal error: Called with program handle\n",
__progname);
abort();
}
if ((filep = fopen(md->filename, "rb")) == NULL) {
printf("%s: %s: %s\n", __progname, md->filename, strerror(errno));
return (0);
}
#ifdef HAVE_TAG_C
metadata_use_taglib(md, &filep);
#else
metadata_use_self(md, &filep);
#endif /* HAVE_TAG_C */
metadata_process_md(md);
return (1);
}
int
metadata_program_update(metadata_t *md, enum metadata_request md_req)
{
/* XXX not implemented */
return (0);
}
const char *
metadata_get_string(metadata_t *md)
{
if (md == NULL) {
printf("%s: metadata_get_string(): Internal error: Bad arguments\n",
__progname);
abort();
}
if (md->string == NULL) {
printf("%s: metadata_get_string(): Internal error: md->string cannot be NULL\n",
__progname);
abort();
}
return (md->string);
}
const char *
metadata_get_artist(metadata_t *md)
{
if (md == NULL) {
printf("%s: metadata_get_artist(): Internal error: Bad arguments\n",
__progname);
abort();
}
return (md->artist);
}
const char *
metadata_get_title(metadata_t *md)
{
if (md == NULL) {
printf("%s: metadata_get_title(): Internal error: Bad arguments\n",
__progname);
abort();
}
return (md->title);
}

96
src/metadata.h Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2007 Moritz Grimm <gtgbr@gmx.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __METADATA_H__
#define __METADATA_H__
#define METADATA_MAX 1023
enum metadata_request {
METADATA_ALL = 0,
METADATA_STRING,
METADATA_ARTIST,
METADATA_TITLE
};
typedef struct metadata metadata_t;
/*
* Read the metadata of a media file and return a new metadata handle on
* success, or NULL on failure. The returned handle is "branded" for reading
* metadata from media files.
*/
metadata_t * metadata_file(const char * /* filename */);
/*
* Create a metadata handle that is "branded" for acquiring metadata from an
* external program. The handle is returned on success, or NULL on failure.
* The program is NOT YET being queried, use metadata_program_update() for
* that. Also, the program (or script) needs to follow these rules:
*
* - Print one line to standard output and exit.
* - Accept no command line parameter and return a complete metadata string
* (for metadata_get_string()). The program *should* always return
* something in this case (e.g. something based on the filename in case no
* metadata is available.) This string will default to "[unknown]"
* otherwise.
* - Accept the command line parameter "artist" and return only the artist
* metadata, or an empty string if no artist information is available.
* - Accept the command line parameter "title" and return only the song title
* metadata, or an empty string if no artist information is available.
* - Return at most METADATA_MAX characters, or the result will be truncated.
*/
metadata_t * metadata_program(const char * /* program name */);
/*
* Free all memory used by a metadata handle that has been created with
* metadata_file() or metadata_program().
*/
void metadata_free(metadata_t *);
/*
* Update/read the metadata for the given handle. Returns 1 on success, and 0
* on failure.
*/
int metadata_file_update(metadata_t *);
/*
* Update/read the specified metadata for the given program-handle. Returns 1
* on success, and 0 on failure.
*/
int metadata_program_update(metadata_t *, enum metadata_request);
/*
* Returns a pointer to a metadata string ``artist - title'', or just
* ``artist'' or ``title'' if one of the two is not available. If neither
* are present, it usually returns the filename without the extension.
* This function never returns NULL.
*/
const char * metadata_get_string(metadata_t *);
/*
* Returns a pointer to the artist string, or NULL if the file did not
* contain any artist information.
*/
const char * metadata_get_artist(metadata_t *);
/*
* Returns a pointer to the title string, or NULL if the file did not
* contain any title information.
*/
const char * metadata_get_title(metadata_t *);
#endif /* __METADATA_H__ */