mirror of
https://gitlab.xiph.org/xiph/ezstream.git
synced 2024-11-03 04:17:18 -05:00
Add new <metadata_progname> configuration option, which specifies an external
program/script to get metadata from. Also include SIGUSR2 handling that triggers metadata updates from the external program mid-stream. git-svn-id: https://svn.xiph.org/trunk/ezstream@12693 0101bb08-14d6-0310-b084-bc0e0c8e3800
This commit is contained in:
parent
163b7ca187
commit
304908bff4
6
NEWS
6
NEWS
@ -19,6 +19,12 @@ Changes in 0.4.0, (SVN trunk):
|
||||
* various:
|
||||
- [ADD] Allow ezstream to use TagLib for reading metadata from media
|
||||
files. TagLib (libtag_c) is now an optional dependency.
|
||||
- [ADD] New <metadata_progname> configuration option, which causes
|
||||
metadata to be read from the output of an external program or
|
||||
script.
|
||||
- [ADD] New runtime control via the SIGUSR2 signal, which triggers reading
|
||||
of fresh metadata information from <metadata_progname> (metadata
|
||||
is always read at song changes.)
|
||||
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ezstream
|
||||
.Nd source client for Icecast with external en-/decoder support
|
||||
.Nd source client for Icecast with external de-/encoder support
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Bk -words
|
||||
@ -59,8 +59,7 @@ and bitrate \(em is displayed.
|
||||
.Ss Runtime control
|
||||
On POSIX systems,
|
||||
.Nm
|
||||
offers limited runtime control via signals when it is not streaming data from
|
||||
standard input.
|
||||
offers limited runtime control via signals.
|
||||
By sending a signal to the ezstream process, e.g. with the
|
||||
.Xr kill 1
|
||||
utility, a certain action will be triggered.
|
||||
@ -74,6 +73,11 @@ following it, or restarts from the beginning of the list otherwise.
|
||||
.It Cd SIGUSR1
|
||||
Skips the currently playing track and moves on to the next in playlist mode, or
|
||||
restarts the current track when streaming a single file.
|
||||
.It Cd SIGUSR2
|
||||
Triggers rereading of metadata for the stream by running the program or script
|
||||
specified in \&<metadata_progname/\&>
|
||||
.Pq see below.
|
||||
This is the only meaningful signal when streaming from standard input.
|
||||
.El
|
||||
.Pp
|
||||
.Sh CONFIGURATION FILE SYNTAX
|
||||
@ -103,7 +107,7 @@ In the configuration file, they need to be used as
|
||||
.Em start tag + content + end tag ,
|
||||
like in the introductory example shown above.
|
||||
.Ss Root element
|
||||
.Bl -ohang
|
||||
.Bl -tag -width -Ds
|
||||
.It Sy \&<ezstream\ /\&>
|
||||
.Pq Mandatory.
|
||||
The configuration file's root element.
|
||||
@ -112,7 +116,7 @@ It contains all other configuration elements.
|
||||
.Ss Global configuration elements
|
||||
Each of the global configuration elements have the \&<ezstream/\&> element as
|
||||
their parent.
|
||||
.Bl -ohang
|
||||
.Bl -tag -width -Ds
|
||||
.It Sy \&<url\ /\&>
|
||||
.Pq Mandatory.
|
||||
Specifies the location and mountpoint of the Icecast server, to which the
|
||||
@ -170,10 +174,6 @@ Set to
|
||||
.Pq one
|
||||
to indicate that the file in \&<filename/\&> is actually an executable program
|
||||
or script.
|
||||
This program is supposed to print
|
||||
.Pq to standard output
|
||||
one line with the name of a file that should be streamed next and then exit.
|
||||
.Pp
|
||||
If set to
|
||||
.Sy 0
|
||||
.Pq zero ,
|
||||
@ -181,6 +181,10 @@ If set to
|
||||
keyword
|
||||
.Pa stdin
|
||||
.Pq the default .
|
||||
.Pp
|
||||
See the
|
||||
.Sy SCRIPTING
|
||||
section for details on how the playlist program must behave.
|
||||
.It Sy \&<shuffle\ /\&>
|
||||
.Pq Optional.
|
||||
Set to
|
||||
@ -193,6 +197,24 @@ Files are played sequentially if set to
|
||||
or when the \&<shuffle/\&> element is absent.
|
||||
This option will be ignored if \&<playlist_program/\&> is set to 1
|
||||
.Pq one.
|
||||
.It Sy \&<metadata_progname\ /\&>
|
||||
.Pq Optional.
|
||||
Set the path and name of an executable program or script that should be used by
|
||||
.Nm
|
||||
to set the metadata of the stream.
|
||||
The program is automatically queried when a new track is streamed, or whenever
|
||||
the
|
||||
.Sy SIGUSR2
|
||||
signal is received.
|
||||
.Pp
|
||||
If the \&<metadata_progname/\&> element is present in the configuration, no
|
||||
attempts will be made to read metadata from files that are being streamed.
|
||||
If this behavior is not desired, it should be removed or commented out in the
|
||||
configuration file.
|
||||
.Pp
|
||||
See the
|
||||
.Sy SCRIPTING
|
||||
section for details on how the metadata program must behave.
|
||||
.It Sy \&<stream_once\ /\&>
|
||||
Set to
|
||||
.Sy 1
|
||||
@ -268,7 +290,7 @@ should be done.
|
||||
.Ss Reencoding settings
|
||||
Each of the reencoding configuration elements have the \&<reencode/\&>
|
||||
element as their parent.
|
||||
.Bl -ohang
|
||||
.Bl -tag -width -Ds
|
||||
.It Sy \&<enable\ /\&>
|
||||
Set to
|
||||
.Sy 1
|
||||
@ -287,7 +309,7 @@ Each format is described by a separate \&<encdec/\&> element.
|
||||
.Ss Decoder/Encoder settings
|
||||
Each of the decoder/encoder configuration elements have the \&<encdec/\&>
|
||||
element as their parent.
|
||||
.Bl -ohang
|
||||
.Bl -tag -width -Ds
|
||||
.It Sy \&<format\ /\&>
|
||||
This element is used by
|
||||
.Nm
|
||||
@ -353,6 +375,54 @@ utility:
|
||||
.Pp
|
||||
.Dl \&<encode\&>oggenc -r -q 1.5 -t \&"@M@\&" -\&</encode\&>
|
||||
.El
|
||||
.Sh SCRIPTING
|
||||
The
|
||||
.Nm
|
||||
utility provides hooks for externally controlled playlist and metadata
|
||||
management.
|
||||
This is done by running external programs or scripts that need to behave in
|
||||
ways explained here.
|
||||
.Ss Common Rules
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
The program must be an executable file.
|
||||
.It
|
||||
The program must write one line to standard output and exit.
|
||||
.It
|
||||
The program must not require arbitary command line options to function.
|
||||
A wrapper script must be used if there is no other way.
|
||||
.El
|
||||
.Ss Playlist Programs
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
The program must return only filenames, with one filename per execution.
|
||||
.It
|
||||
The program should not return an empty line unless
|
||||
.Nm
|
||||
is supposed to know that the end of the playlist has been reached.
|
||||
This is significant when the \&<stream_once/\&> option is enabled.
|
||||
.El
|
||||
.Ss Metadata Programs
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
The program must not return anything (just a newline character is okay) if it
|
||||
is called by
|
||||
.Nm
|
||||
with a command line parameter that the program does not support.
|
||||
.It
|
||||
When called without command line parameters, the program should return a
|
||||
complete string that should be used for metadata.
|
||||
.It
|
||||
When called with the command line parameter
|
||||
.Qq artist ,
|
||||
the program should return only the artist information of the metadata.
|
||||
.Pq Optional.
|
||||
.It
|
||||
When called with the command line parameter
|
||||
.Qq title ,
|
||||
the program should return only the title information of the metadata.
|
||||
.Pq Optional.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "!!EXAMPLES_DIR!!" -compact
|
||||
.It Pa !!EXAMPLES_DIR!!
|
||||
|
@ -98,6 +98,8 @@ freeConfig(EZCONFIG *cfg)
|
||||
xfree(cfg->format);
|
||||
if (cfg->fileName != NULL)
|
||||
xfree(cfg->fileName);
|
||||
if (cfg->metadataProgram != NULL)
|
||||
xfree(cfg->metadataProgram);
|
||||
if (cfg->serverName != NULL)
|
||||
xfree(cfg->serverName);
|
||||
if (cfg->serverURL != NULL)
|
||||
@ -228,6 +230,25 @@ parseConfig(const char *fileName)
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, BAD_CAST "metadata_progname")) {
|
||||
if (ezConfig.metadataProgram != NULL) {
|
||||
printf("%s[%ld]: Error: Cannot have multiple <metadata_progname> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (strlen(ls_xmlContentPtr) > PATH_MAX - 1) {
|
||||
printf("%s[%ld]: Error: Path or filename in <metadata_progname> is too long\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
ezConfig.metadataProgram = xstrdup(ls_xmlContentPtr);
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, BAD_CAST "playlist_program")) {
|
||||
if (program_set) {
|
||||
printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",
|
||||
|
@ -44,6 +44,7 @@ typedef struct tag_EZCONFIG {
|
||||
char *password;
|
||||
char *format;
|
||||
char *fileName;
|
||||
char *metadataProgram;
|
||||
char *serverName;
|
||||
char *serverURL;
|
||||
char *serverGenre;
|
||||
|
111
src/ezstream.c
111
src/ezstream.c
@ -69,6 +69,7 @@
|
||||
#define STREAM_CONT 1
|
||||
#define STREAM_SKIP 2
|
||||
#define STREAM_SERVERR 3
|
||||
#define STREAM_UPDMDATA 4
|
||||
|
||||
#ifdef HAVE___PROGNAME
|
||||
extern char *__progname;
|
||||
@ -78,6 +79,7 @@ char *__progname;
|
||||
|
||||
int qFlag;
|
||||
int vFlag;
|
||||
int metadataFromProgram;
|
||||
|
||||
EZCONFIG *pezConfig = NULL;
|
||||
static const char *blankString = "";
|
||||
@ -85,15 +87,17 @@ playlist_t *playlist = NULL;
|
||||
int playlistMode = 0;
|
||||
|
||||
#ifdef HAVE_SIGNALS
|
||||
const int ezstream_signals[] = { SIGHUP, SIGUSR1 };
|
||||
const int ezstream_signals[] = { SIGHUP, SIGUSR1, SIGUSR2 };
|
||||
|
||||
volatile sig_atomic_t rereadPlaylist = 0;
|
||||
volatile sig_atomic_t rereadPlaylist_notify = 0;
|
||||
volatile sig_atomic_t skipTrack = 0;
|
||||
volatile sig_atomic_t queryMetadata = 0;
|
||||
#else
|
||||
int rereadPlaylist = 0;
|
||||
int rereadPlaylist_notify = 0;
|
||||
int skipTrack = 0;
|
||||
int queryMetadata = 0;
|
||||
#endif /* HAVE_SIGNALS */
|
||||
|
||||
typedef struct tag_ID3Tag {
|
||||
@ -133,6 +137,9 @@ sig_handler(int sig)
|
||||
case SIGUSR1:
|
||||
skipTrack = 1;
|
||||
break;
|
||||
case SIGUSR2:
|
||||
queryMetadata = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -291,16 +298,26 @@ processMetadata(shout_t *shout, const char *fileName)
|
||||
shout_metadata_t *shout_mdata = NULL;
|
||||
metadata_t *mdata = NULL;
|
||||
|
||||
if ((mdata = metadata_file(fileName)) == NULL) {
|
||||
songInfo = xstrdup(blankString);
|
||||
return (songInfo);
|
||||
if (metadataFromProgram) {
|
||||
if ((mdata = metadata_program(fileName)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (!metadata_program_update(mdata, METADATA_STRING)) {
|
||||
metadata_free(&mdata);
|
||||
songInfo = xstrdup(blankString);
|
||||
return (songInfo);
|
||||
}
|
||||
} else {
|
||||
if ((mdata = metadata_file(fileName)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (!metadata_file_update(mdata)) {
|
||||
metadata_free(&mdata);
|
||||
songInfo = xstrdup(blankString);
|
||||
return (songInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata_file_update(mdata)) {
|
||||
metadata_free(&mdata);
|
||||
songInfo = xstrdup(blankString);
|
||||
return (songInfo);
|
||||
}
|
||||
songInfo = xstrdup(metadata_get_string(mdata));
|
||||
metadata_free(&mdata);
|
||||
|
||||
@ -327,6 +344,10 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
|
||||
char *pCommandString = NULL;
|
||||
|
||||
if (strcmp(fileName, "stdin") == 0) {
|
||||
if (metadataFromProgram &&
|
||||
processMetadata(shout, pezConfig->metadataProgram) == NULL)
|
||||
return (filep);
|
||||
|
||||
if (vFlag)
|
||||
printf("%s: Reading from standard input\n",
|
||||
__progname);
|
||||
@ -354,7 +375,12 @@ openResource(shout_t *shout, const char *fileName, int *popenFlag,
|
||||
return (filep);
|
||||
}
|
||||
|
||||
pMetadata = processMetadata(shout, fileName);
|
||||
if (metadataFromProgram)
|
||||
pMetadata = processMetadata(shout, pezConfig->metadataProgram);
|
||||
else
|
||||
pMetadata = processMetadata(shout, fileName);
|
||||
if (pMetadata == NULL)
|
||||
return (filep);
|
||||
if (metaCopy != NULL)
|
||||
*metaCopy = xstrdup(pMetadata);
|
||||
|
||||
@ -487,6 +513,19 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
|
||||
break;
|
||||
}
|
||||
|
||||
shout_sync(shout);
|
||||
|
||||
if (shout_send(shout, buff, read) != SHOUTERR_SUCCESS) {
|
||||
printf("%s: shout_send(): %s\n", __progname,
|
||||
shout_get_error(shout));
|
||||
if (reconnectServer(shout, 1))
|
||||
break;
|
||||
else {
|
||||
ret = STREAM_SERVERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rereadPlaylist_notify) {
|
||||
rereadPlaylist_notify = 0;
|
||||
if (!pezConfig->fileNameIsProgram)
|
||||
@ -498,16 +537,10 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
|
||||
ret = STREAM_SKIP;
|
||||
break;
|
||||
}
|
||||
|
||||
shout_sync(shout);
|
||||
|
||||
if (shout_send(shout, buff, read) != SHOUTERR_SUCCESS) {
|
||||
printf("%s: shout_send(): %s\n", __progname,
|
||||
shout_get_error(shout));
|
||||
if (reconnectServer(shout, 1))
|
||||
break;
|
||||
else {
|
||||
ret = STREAM_SERVERR;
|
||||
if (queryMetadata) {
|
||||
queryMetadata = 0;
|
||||
if (metadataFromProgram) {
|
||||
ret = STREAM_UPDMDATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -609,9 +642,14 @@ streamFile(shout_t *shout, const char *fileName)
|
||||
ret = sendStream(shout, filepstream, fileName, isStdin, NULL);
|
||||
#endif
|
||||
if (ret != STREAM_DONE) {
|
||||
if (skipTrack && rereadPlaylist) {
|
||||
if ((skipTrack && rereadPlaylist) ||
|
||||
(skipTrack && queryMetadata)) {
|
||||
skipTrack = 0;
|
||||
ret = 1;
|
||||
ret = STREAM_CONT;
|
||||
}
|
||||
if (queryMetadata && rereadPlaylist) {
|
||||
queryMetadata = 0;
|
||||
ret = STREAM_CONT;
|
||||
}
|
||||
if (ret == STREAM_SKIP || skipTrack) {
|
||||
skipTrack = 0;
|
||||
@ -621,13 +659,30 @@ streamFile(shout_t *shout, const char *fileName)
|
||||
retval = 1;
|
||||
ret = STREAM_DONE;
|
||||
}
|
||||
if (ret == STREAM_UPDMDATA || queryMetadata) {
|
||||
queryMetadata = 0;
|
||||
if (metadataFromProgram) {
|
||||
char *mdataStr;
|
||||
|
||||
if (vFlag > 1)
|
||||
printf("%s: Querying '%s' for fresh metadata\n",
|
||||
__progname, pezConfig->metadataProgram);
|
||||
if ((mdataStr = processMetadata(shout, pezConfig->metadataProgram)) == NULL) {
|
||||
retval = 0;
|
||||
ret = STREAM_DONE;
|
||||
}
|
||||
printf("%s: New metadata: ``%s''\n",
|
||||
__progname, mdataStr);
|
||||
xfree(mdataStr);
|
||||
}
|
||||
}
|
||||
if (ret == STREAM_SERVERR) {
|
||||
retval = 0;
|
||||
ret = STREAM_DONE;
|
||||
}
|
||||
} else
|
||||
retval = 1;
|
||||
} while (ret);
|
||||
} while (ret != STREAM_DONE);
|
||||
|
||||
if (popenFlag)
|
||||
pclose(filepstream);
|
||||
@ -683,10 +738,7 @@ streamPlaylist(shout_t *shout, const char *fileName)
|
||||
}
|
||||
}
|
||||
|
||||
if (pezConfig->streamOnce)
|
||||
return (0);
|
||||
else
|
||||
return (1);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Borrowed from OpenNTPd-portable's compat-openbsd/bsd-misc.c */
|
||||
@ -976,6 +1028,11 @@ main(int argc, char *argv[])
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (pezConfig->metadataProgram != NULL)
|
||||
metadataFromProgram = 1;
|
||||
else
|
||||
metadataFromProgram = 0;
|
||||
|
||||
#ifdef HAVE_SIGNALS
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = sig_handler;
|
||||
|
132
src/metadata.c
132
src/metadata.c
@ -352,6 +352,11 @@ metadata_t *
|
||||
metadata_program(const char *program)
|
||||
{
|
||||
metadata_t *md;
|
||||
#ifdef HAVE_STAT
|
||||
struct stat st;
|
||||
#else
|
||||
FILE *filep;
|
||||
#endif
|
||||
|
||||
if (program == NULL || strlen(program) == 0) {
|
||||
printf("%s: metadata_program(): Internal error: Bad arguments\n",
|
||||
@ -361,6 +366,27 @@ metadata_program(const char *program)
|
||||
|
||||
md = metadata_create(program);
|
||||
md->program = 1;
|
||||
md->string = xstrdup("");
|
||||
|
||||
#ifdef HAVE_STAT
|
||||
if (stat(program, &st) == -1) {
|
||||
printf("%s: %s: %s\n", __progname, program, strerror(errno));
|
||||
metadata_free(&md);
|
||||
return (NULL);
|
||||
}
|
||||
if (!(st.st_mode & (S_IEXEC | S_IXGRP | S_IXOTH))) {
|
||||
printf("%s: %s: Not an executable program\n", __progname, program);
|
||||
metadata_free(&md);
|
||||
return (NULL);
|
||||
}
|
||||
#else
|
||||
if ((filep = fopen(program, "r")) == NULL) {
|
||||
printf("%s: %s: %s\n", __progname, program, strerror(errno));
|
||||
metadata_free(&md);
|
||||
return (NULL);
|
||||
}
|
||||
fclose(filep);
|
||||
#endif /* HAVE_STAT */
|
||||
|
||||
return (md);
|
||||
}
|
||||
@ -418,8 +444,110 @@ metadata_file_update(metadata_t *md)
|
||||
int
|
||||
metadata_program_update(metadata_t *md, enum metadata_request md_req)
|
||||
{
|
||||
/* XXX not implemented */
|
||||
return (0);
|
||||
FILE *filep;
|
||||
char buf[METADATA_MAX + 1];
|
||||
char command[PATH_MAX + strlen(" artist") + 1];
|
||||
|
||||
if (md == NULL) {
|
||||
printf("%s: metadata_program_update(): Internal error: NULL argument\n",
|
||||
__progname);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!md->program) {
|
||||
printf("%s: metadata_program_update(): Internal error: Received file handle\n",
|
||||
__progname);
|
||||
abort();
|
||||
}
|
||||
|
||||
switch (md_req) {
|
||||
case METADATA_ALL:
|
||||
metadata_clean_md(md);
|
||||
if (!metadata_program_update(md, METADATA_STRING) ||
|
||||
!metadata_program_update(md, METADATA_ARTIST) ||
|
||||
!metadata_program_update(md, METADATA_TITLE))
|
||||
return (0);
|
||||
break;
|
||||
case METADATA_STRING:
|
||||
strlcpy(command, md->filename, sizeof(command));
|
||||
if (md->string != NULL)
|
||||
xfree(md->string);
|
||||
break;
|
||||
case METADATA_ARTIST:
|
||||
snprintf(command, sizeof(command), "%s artist", md->filename);
|
||||
if (md->artist != NULL)
|
||||
xfree(md->artist);
|
||||
break;
|
||||
case METADATA_TITLE:
|
||||
snprintf(command, sizeof(command), "%s title", md->filename);
|
||||
if (md->title != NULL)
|
||||
xfree(md->title);
|
||||
break;
|
||||
default:
|
||||
printf("%s: metadata_program_update(): Internal error: Unknown md_req\n",
|
||||
__progname);
|
||||
abort();
|
||||
}
|
||||
|
||||
fflush(NULL);
|
||||
errno = 0;
|
||||
if ((filep = popen(command, "r")) == NULL) {
|
||||
printf("%s: playlist_run_program(): Error while executing '%s'",
|
||||
__progname, command);
|
||||
/* popen() does not set errno reliably ... */
|
||||
if (errno)
|
||||
printf(": %s\n", strerror(errno));
|
||||
else
|
||||
printf("\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (fgets(buf, sizeof(buf), filep) == NULL) {
|
||||
if (ferror(filep))
|
||||
printf("%s: Error while reading output from program '%s': %s\n",
|
||||
__progname, md->filename, strerror(errno));
|
||||
pclose(filep);
|
||||
printf("%s: FATAL: External program '%s' not (or no longer) usable.\n",
|
||||
__progname, md->filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pclose(filep);
|
||||
|
||||
if (strlen(buf) == sizeof(buf) - 1)
|
||||
printf("%s: Warning: Metadata string received via '%s' is too long and has been truncated\n",
|
||||
__progname, command);
|
||||
|
||||
if (buf[0] != '\0' && buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
if (buf[0] != '\0' && buf[strlen(buf) - 1] == '\r')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
switch (md_req) {
|
||||
case METADATA_STRING:
|
||||
if (strlen(buf) == 0) {
|
||||
printf("%s: Warning: Empty metadata string received from '%s'\n",
|
||||
__progname, md->filename);
|
||||
md->string = xstrdup("");
|
||||
} else
|
||||
md->string = xstrdup(buf);
|
||||
break;
|
||||
case METADATA_ARTIST:
|
||||
if (strlen(buf) > 0)
|
||||
md->artist = xstrdup(buf);
|
||||
break;
|
||||
case METADATA_TITLE:
|
||||
if (strlen(buf) > 0)
|
||||
md->title = xstrdup(buf);
|
||||
break;
|
||||
case METADATA_ALL:
|
||||
default:
|
||||
printf("%s: metadata_program_update(): Internal error: METADATA_ALL in code unreachable by METADATA_ALL\n",
|
||||
__progname);
|
||||
abort();
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -45,8 +45,7 @@ metadata_t * metadata_file(const char * /* filename */);
|
||||
* - 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.
|
||||
* metadata is available.)
|
||||
* - 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
|
||||
|
Loading…
Reference in New Issue
Block a user