mirror of
https://gitlab.xiph.org/xiph/ezstream.git
synced 2025-02-02 15:07:45 -05: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:
parent
d302a64c2e
commit
900886ab3f
@ -64,7 +64,7 @@ AC_TYPE_SIZE_T
|
||||
|
||||
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
|
||||
|
@ -2,12 +2,14 @@ AUTOMAKE_OPTIONS = 1.9 foreign
|
||||
|
||||
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@
|
||||
|
||||
AM_CFLAGS = @XIPH_CFLAGS@
|
||||
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 *~ .*~
|
||||
|
272
src/ezstream.c
272
src/ezstream.c
@ -33,6 +33,10 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
@ -42,22 +46,21 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#ifdef WIN32
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <libgen.h>
|
||||
# include <unistd.h>
|
||||
#endif /* WIN32 */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <shout/shout.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "configfile.h"
|
||||
#ifndef HAVE_GETOPT
|
||||
# include "getopt.h"
|
||||
#endif
|
||||
#include "metadata.h"
|
||||
#include "playlist.h"
|
||||
#include "strfctns.h"
|
||||
#include "util.h"
|
||||
@ -105,9 +108,8 @@ typedef struct tag_ID3Tag {
|
||||
|
||||
int urlParse(const char *, char **, int *, 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 * processMetadata(shout_t *, const char *, const char *);
|
||||
char * processMetadata(shout_t *, const char *);
|
||||
FILE * openResource(shout_t *, const char *, int *, char **, int *);
|
||||
int reconnectServer(shout_t *, int);
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
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*
|
||||
char *
|
||||
buildCommandString(const char *extension, const char *fileName,
|
||||
const char *metadata)
|
||||
{
|
||||
@ -293,154 +285,33 @@ buildCommandString(const char *extension, const char *fileName,
|
||||
}
|
||||
|
||||
char *
|
||||
processMetadata(shout_t *shout, const char *extension, const char *fileName)
|
||||
processMetadata(shout_t *shout, const char *fileName)
|
||||
{
|
||||
FILE *filepstream = NULL;
|
||||
char *songInfo = NULL;
|
||||
size_t songLen = 0;
|
||||
ID3Tag id3tag;
|
||||
shout_metadata_t *pmetadata = NULL;
|
||||
shout_metadata_t *shout_mdata = NULL;
|
||||
metadata_t *mdata = NULL;
|
||||
|
||||
if ((filepstream = fopen(fileName, "rb")) == NULL) {
|
||||
printf("%s: processMetadata(): %s: %s\n",
|
||||
__progname, fileName, strerror(errno));
|
||||
return (xstrdup(blankString));
|
||||
if ((mdata = metadata_file(fileName)) == NULL) {
|
||||
songInfo = xstrdup(blankString);
|
||||
return (songInfo);
|
||||
}
|
||||
|
||||
if (strcmp(extension, ".mp3") == 0) {
|
||||
/* Look for the ID3 tag */
|
||||
memset(&id3tag, '\000', sizeof(id3tag));
|
||||
fseek(filepstream, -128L, SEEK_END);
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(extension, ".ogg") == 0) {
|
||||
OggVorbis_File vf;
|
||||
int ret;
|
||||
|
||||
if ((ret = ov_open(filepstream, &vf, NULL, 0)) != 0) {
|
||||
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 (!metadata_file_update(mdata)) {
|
||||
metadata_free(mdata);
|
||||
songInfo = xstrdup(blankString);
|
||||
return (songInfo);
|
||||
}
|
||||
songInfo = xstrdup(metadata_get_string(mdata));
|
||||
metadata_free(mdata);
|
||||
|
||||
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) {
|
||||
if ((shout_mdata = shout_metadata_new()) == NULL) {
|
||||
printf("%s: shout_metadata_new(): %s\n", __progname,
|
||||
strerror(ENOMEM));
|
||||
exit(1);
|
||||
}
|
||||
shout_metadata_add(pmetadata, "song", songInfo);
|
||||
shout_set_metadata(shout, pmetadata);
|
||||
shout_metadata_free(pmetadata);
|
||||
shout_metadata_add(shout_mdata, "song", songInfo);
|
||||
shout_set_metadata(shout, shout_mdata);
|
||||
shout_metadata_free(shout_mdata);
|
||||
|
||||
return (songInfo);
|
||||
}
|
||||
@ -451,7 +322,7 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
|
||||
{
|
||||
FILE *filep = NULL;
|
||||
char extension[25];
|
||||
char *p1 = NULL;
|
||||
char *p = NULL;
|
||||
char *pMetadata = NULL;
|
||||
char *pCommandString = NULL;
|
||||
|
||||
@ -471,62 +342,65 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
|
||||
*isStdin = 0;
|
||||
|
||||
extension[0] = '\0';
|
||||
p1 = strrchr(fileName, '.');
|
||||
if (p1 != NULL)
|
||||
strlcpy(extension, p1, sizeof(extension));
|
||||
for (p1 = extension; *p1 != '\0'; p1++)
|
||||
*p1 = tolower((int)*p1);
|
||||
pMetadata = processMetadata(shout, extension, fileName);
|
||||
p = strrchr(fileName, '.');
|
||||
if (p != NULL)
|
||||
strlcpy(extension, p, sizeof(extension));
|
||||
for (p = extension; *p != '\0'; p++)
|
||||
*p = tolower((int)*p);
|
||||
|
||||
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)
|
||||
*metaCopy = xstrdup(pMetadata);
|
||||
|
||||
*popenFlag = 0;
|
||||
if (pezConfig->reencode) {
|
||||
if (strlen(extension) > 0) {
|
||||
int stderr_fd = dup(fileno(stderr));
|
||||
int stderr_fd = dup(fileno(stderr));
|
||||
|
||||
pCommandString = buildCommandString(extension, fileName, pMetadata);
|
||||
if (vFlag > 1)
|
||||
printf("%s: Running command `%s`\n", __progname,
|
||||
pCommandString);
|
||||
pCommandString = buildCommandString(extension, fileName, pMetadata);
|
||||
if (vFlag > 1)
|
||||
printf("%s: Running command `%s`\n", __progname,
|
||||
pCommandString);
|
||||
|
||||
if (qFlag) {
|
||||
int fd;
|
||||
if (qFlag) {
|
||||
int fd;
|
||||
|
||||
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) {
|
||||
printf("%s: Cannot open %s for redirecting STDERR output: %s\n",
|
||||
__progname, _PATH_DEVNULL, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dup2(fd, fileno(stderr));
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) {
|
||||
printf("%s: Cannot open %s for redirecting STDERR output: %s\n",
|
||||
__progname, _PATH_DEVNULL, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fflush(NULL);
|
||||
errno = 0;
|
||||
if ((filep = popen(pCommandString, "r")) == NULL) {
|
||||
printf("%s: popen(): Error while executing '%s'",
|
||||
__progname, pCommandString);
|
||||
/* popen() does not set errno reliably ... */
|
||||
if (errno)
|
||||
printf(": %s\n", strerror(errno));
|
||||
else
|
||||
printf("\n");
|
||||
} else {
|
||||
*popenFlag = 1;
|
||||
dup2(fd, fileno(stderr));
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
fflush(NULL);
|
||||
errno = 0;
|
||||
if ((filep = popen(pCommandString, "r")) == NULL) {
|
||||
printf("%s: popen(): Error while executing '%s'",
|
||||
__progname, pCommandString);
|
||||
/* popen() does not set errno reliably ... */
|
||||
if (errno)
|
||||
printf(": %s\n", strerror(errno));
|
||||
else
|
||||
printf("\n");
|
||||
} else {
|
||||
*popenFlag = 1;
|
||||
#ifdef WIN32
|
||||
_setmode(_fileno(filep), _O_BINARY );
|
||||
_setmode(_fileno(filep), _O_BINARY );
|
||||
#endif
|
||||
}
|
||||
xfree(pCommandString);
|
||||
}
|
||||
xfree(pCommandString);
|
||||
|
||||
if (qFlag)
|
||||
dup2(stderr_fd, fileno(stderr));
|
||||
} else
|
||||
printf("%s: Error: Cannot determine file type of '%s'\n",
|
||||
__progname, fileName);
|
||||
if (qFlag)
|
||||
dup2(stderr_fd, fileno(stderr));
|
||||
|
||||
xfree(pMetadata);
|
||||
return (filep);
|
||||
|
457
src/metadata.c
Normal file
457
src/metadata.c
Normal 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
96
src/metadata.h
Normal 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__ */
|
Loading…
x
Reference in New Issue
Block a user