mirror of
https://gitlab.xiph.org/xiph/ezstream.git
synced 2024-12-04 14:46:31 -05:00
More metadata featuritis, add <metadata_format/> and implement support for
'@a@', '@t@' and '@s@'. git-svn-id: https://svn.xiph.org/trunk/ezstream@12707 0101bb08-14d6-0310-b084-bc0e0c8e3800
This commit is contained in:
parent
6f779c21f3
commit
c5aaa28594
4
NEWS
4
NEWS
@ -25,6 +25,10 @@ Changes in 0.4.0, (SVN trunk):
|
|||||||
- [ADD] New runtime control via the SIGUSR2 signal, which triggers reading
|
- [ADD] New runtime control via the SIGUSR2 signal, which triggers reading
|
||||||
of fresh metadata information from <metadata_progname> (metadata
|
of fresh metadata information from <metadata_progname> (metadata
|
||||||
is always read at song changes.)
|
is always read at song changes.)
|
||||||
|
- [ADD] New <metadata_format> configuration option, to customize metadata
|
||||||
|
strings when used with the new <metadata_progname> feature.
|
||||||
|
- [ADD] New '@a@' and '@t@' placeholders for separate artist and title
|
||||||
|
metadata in de-/encoder commands.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,6 +215,17 @@ configuration file.
|
|||||||
See the
|
See the
|
||||||
.Sy SCRIPTING
|
.Sy SCRIPTING
|
||||||
section for details on how the metadata program must behave.
|
section for details on how the metadata program must behave.
|
||||||
|
.It Sy \&<metadata_format\ /\&>
|
||||||
|
.Pq Optional.
|
||||||
|
Set the format of the string that should be used for the
|
||||||
|
.Sq @M@
|
||||||
|
placeholder when setting metadata with an external program or script via
|
||||||
|
\&<metadata_progname/\&>.
|
||||||
|
.Pp
|
||||||
|
See the
|
||||||
|
.Sy METADATA
|
||||||
|
section for details on how metadata is handled by
|
||||||
|
.Nm .
|
||||||
.It Sy \&<stream_once\ /\&>
|
.It Sy \&<stream_once\ /\&>
|
||||||
Set to
|
Set to
|
||||||
.Sy 1
|
.Sy 1
|
||||||
@ -339,16 +350,17 @@ Set the command to decode the specified media file format to raw data and send
|
|||||||
it to standard output.
|
it to standard output.
|
||||||
During runtime, the placeholder
|
During runtime, the placeholder
|
||||||
.Sq Li @T@
|
.Sq Li @T@
|
||||||
is replaced with the fully qualified name of the media file, as specified in
|
is replaced with the name of the media file, as it is specified in the
|
||||||
the \&<filename/\&> element or a playlist file.
|
\&<filename/\&> element or contained in a playlist file.
|
||||||
It should always be enclosed in quotes, to prevent problems with filenames that
|
It should always be enclosed in quotes, to prevent problems with filenames that
|
||||||
contain whitespaces.
|
contain whitespaces.
|
||||||
.Pp
|
.Pp
|
||||||
The metadata placeholder,
|
Metadata placeholders can be used in the \&<decode/\&> element as well, for
|
||||||
.Sq @M@ ,
|
combined de-/encoder programs that produce streamable data.
|
||||||
is also available in the \&<decode/\&> element.
|
See the
|
||||||
That way it can be used for combined de-/encoder programs that produce readily
|
.Sy METADATA
|
||||||
streamable data.
|
section for details on how metadata is handled by
|
||||||
|
.Nm .
|
||||||
.Pp
|
.Pp
|
||||||
For example, to decode Ogg Vorbis files using the
|
For example, to decode Ogg Vorbis files using the
|
||||||
.Cm oggdec
|
.Cm oggdec
|
||||||
@ -358,15 +370,13 @@ utility:
|
|||||||
.It Sy \&<encode\ /\&>
|
.It Sy \&<encode\ /\&>
|
||||||
Set the command to encode raw data, received from standard input, to the
|
Set the command to encode raw data, received from standard input, to the
|
||||||
specified stream format.
|
specified stream format.
|
||||||
During runtime, the placeholder
|
.Pp
|
||||||
.Sq Li @M@
|
Metadata placeholders can be used in the \&<encode/\&> element.
|
||||||
is replaced with the metadata
|
For details about using metadata in
|
||||||
.Po
|
.Nm ,
|
||||||
e.g.
|
see below in the
|
||||||
.Dq Artist - Title
|
.Sy METADATA
|
||||||
.Pc
|
section.
|
||||||
for the current track.
|
|
||||||
It also should be enclosed in quotes at all times.
|
|
||||||
.Pp
|
.Pp
|
||||||
For example, to encode an Ogg Vorbis stream using the quality setting 1.5 with
|
For example, to encode an Ogg Vorbis stream using the quality setting 1.5 with
|
||||||
the
|
the
|
||||||
@ -423,11 +433,89 @@ When called with the command line parameter
|
|||||||
the program should return only the title information of the metadata.
|
the program should return only the title information of the metadata.
|
||||||
.Pq Optional.
|
.Pq Optional.
|
||||||
.El
|
.El
|
||||||
|
.Sh METADATA
|
||||||
|
The main tool for handling metadata with
|
||||||
|
.Nm
|
||||||
|
is placeholders in decoder and encoder commands that are replaced with real
|
||||||
|
content during runtime.
|
||||||
|
The tricky part about is that one placeholders has to be handled differently
|
||||||
|
depending on where the metadata comes from.
|
||||||
|
This section will explain each possible scenario.
|
||||||
|
.Ss Metadata Placeholders
|
||||||
|
.Bl -tag -width -Ds
|
||||||
|
.It Sy @T@
|
||||||
|
Replaced with the media file name.
|
||||||
|
Required in \&<decode/\&> and is available in \&<metadata_format/\&>.
|
||||||
|
.It Sy @M@
|
||||||
|
Replaced with a metadata string.
|
||||||
|
See below for a detailed explanation.
|
||||||
|
Available in \&<decode/\&> and \&<encode/\&>.
|
||||||
|
.It Sy @a@
|
||||||
|
Replaced with the artist information.
|
||||||
|
Available in \&<decode/\&>, \&<encode/\&> and \&<metadata_format/\&>.
|
||||||
|
.It Sy @t@
|
||||||
|
Replaced with the title information.
|
||||||
|
Available in \&<decode/\&>, \&<encode/\&> and \&<metadata_format/\&>.
|
||||||
|
.It Sy @s@
|
||||||
|
Replaced with the string returned by \&<metadata_progname/\&> when called
|
||||||
|
without any command line parameters.
|
||||||
|
Available only in \&<metadata_format/\&>.
|
||||||
|
.El
|
||||||
|
.Ss The @M@ Placeholder
|
||||||
|
While all other placeholders are simply replaced with whatever data they are
|
||||||
|
associated with,
|
||||||
|
.Sq @M@
|
||||||
|
is context-sensitive.
|
||||||
|
The logic used by
|
||||||
|
.Nm
|
||||||
|
is the following:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
If ('@M@ is present')
|
||||||
|
If ('\&<metadata_progname/\&>' AND '\&<metadata_format/\&>')
|
||||||
|
Replace with format string result.
|
||||||
|
Else
|
||||||
|
If (NOT '\&<metadata_progname/\&>' AND '@t@ is present')
|
||||||
|
Replace with empty string.
|
||||||
|
else
|
||||||
|
Replace with generated metadata string.
|
||||||
|
Endif
|
||||||
|
Endif
|
||||||
|
Endif
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The generated metadata string for
|
||||||
|
.Sq @M@
|
||||||
|
is of the format
|
||||||
|
.Dq Artist - Title ,
|
||||||
|
if both artist and title information is available.
|
||||||
|
If one of the two is missing, the available one is displayed without a leading
|
||||||
|
or trailing dash, e.g. just
|
||||||
|
.Dq Artist .
|
||||||
|
If neither artist nor title are available, the name of the media file, without
|
||||||
|
its file extension, is used.
|
||||||
|
.Ss Metadata Caveats
|
||||||
|
It is possible to generate strange results with odd combinations of
|
||||||
|
placeholders, external metadata programs and updates during runtime via
|
||||||
|
.Sy SIGUSR2 .
|
||||||
|
If things start to become just confusing, simplify.
|
||||||
|
.Pp
|
||||||
|
Metadata updates during runtime are done with a relatively broken feature of
|
||||||
|
libshout.
|
||||||
|
Additional metadata information that is already present in the stream sent via
|
||||||
|
.Nm
|
||||||
|
is usually destroyed and replaced with the new data.
|
||||||
|
It is not possible to properly discern between artist and title information,
|
||||||
|
which means that anything set with the
|
||||||
|
.Sy SIGUSR2
|
||||||
|
feature will continue to end up entirely in the
|
||||||
|
.Qq Title
|
||||||
|
field of a stream.
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width "!!EXAMPLES_DIR!!" -compact
|
.Bl -tag -width "!!EXAMPLES_DIR!!" -compact
|
||||||
.It Pa !!EXAMPLES_DIR!!
|
.It Pa !!EXAMPLES_DIR!!
|
||||||
Directory containing example configuration files for various uses of
|
Directory containing example configuration files for various uses of
|
||||||
.Nm .
|
.Nm ,
|
||||||
|
as well as example playlist and metadata scripts.
|
||||||
.El
|
.El
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -39,6 +39,7 @@ static const char *blankString = "";
|
|||||||
void freeConfig(EZCONFIG *);
|
void freeConfig(EZCONFIG *);
|
||||||
unsigned int checkDecoderLine(const char *, const char *, long);
|
unsigned int checkDecoderLine(const char *, const char *, long);
|
||||||
unsigned int checkEncoderLine(const char *, const char *, long);
|
unsigned int checkEncoderLine(const char *, const char *, long);
|
||||||
|
unsigned int checkFormatLine(const char *, const char *, long);
|
||||||
|
|
||||||
EZCONFIG *
|
EZCONFIG *
|
||||||
getEZConfig(void)
|
getEZConfig(void)
|
||||||
@ -198,6 +199,27 @@ parseConfig(const char *fileName)
|
|||||||
xmlFree(ls_xmlContentPtr);
|
xmlFree(ls_xmlContentPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!xmlStrcmp(cur->name, BAD_CAST "metadata_format")) {
|
||||||
|
if (ezConfig.metadataFormat != NULL) {
|
||||||
|
printf("%s[%ld]: Error: Cannot have multiple <metadata_format> elements\n",
|
||||||
|
fileName, xmlGetLineNo(cur));
|
||||||
|
config_error++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cur->xmlChildrenNode != NULL) {
|
||||||
|
unsigned int ret;
|
||||||
|
|
||||||
|
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||||
|
ezConfig.metadataFormat = xstrdup(ls_xmlContentPtr);
|
||||||
|
xmlFree(ls_xmlContentPtr);
|
||||||
|
if ((ret = checkFormatLine(ezConfig.metadataFormat,
|
||||||
|
fileName, xmlGetLineNo(cur)))
|
||||||
|
> 0) {
|
||||||
|
config_error += ret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!xmlStrcmp(cur->name, BAD_CAST "playlist_program")) {
|
if (!xmlStrcmp(cur->name, BAD_CAST "playlist_program")) {
|
||||||
if (program_set) {
|
if (program_set) {
|
||||||
printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",
|
printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",
|
||||||
@ -564,6 +586,8 @@ freeConfig(EZCONFIG *cfg)
|
|||||||
xfree(cfg->fileName);
|
xfree(cfg->fileName);
|
||||||
if (cfg->metadataProgram != NULL)
|
if (cfg->metadataProgram != NULL)
|
||||||
xfree(cfg->metadataProgram);
|
xfree(cfg->metadataProgram);
|
||||||
|
if (cfg->metadataFormat != NULL)
|
||||||
|
xfree(cfg->metadataFormat);
|
||||||
if (cfg->serverName != NULL)
|
if (cfg->serverName != NULL)
|
||||||
xfree(cfg->serverName);
|
xfree(cfg->serverName);
|
||||||
if (cfg->serverURL != NULL)
|
if (cfg->serverURL != NULL)
|
||||||
@ -604,15 +628,22 @@ checkDecoderLine(const char *str, const char *file, long line)
|
|||||||
{
|
{
|
||||||
unsigned int errors;
|
unsigned int errors;
|
||||||
char *p;
|
char *p;
|
||||||
|
int have_track = 0;
|
||||||
|
|
||||||
errors = 0;
|
errors = 0;
|
||||||
|
if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: `%s' placeholder not allowed in decoder command\n",
|
||||||
|
file, line, STRING_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
|
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
|
||||||
p += strlen(TRACK_PLACEHOLDER);
|
p += strlen(TRACK_PLACEHOLDER);
|
||||||
if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
|
if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
|
||||||
printf("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
|
printf("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
|
||||||
file, line, TRACK_PLACEHOLDER);
|
file, line, TRACK_PLACEHOLDER);
|
||||||
errors++;
|
errors++;
|
||||||
}
|
} else
|
||||||
|
have_track = 1;
|
||||||
}
|
}
|
||||||
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
||||||
p += strlen(METADATA_PLACEHOLDER);
|
p += strlen(METADATA_PLACEHOLDER);
|
||||||
@ -639,6 +670,12 @@ checkDecoderLine(const char *str, const char *file, long line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!have_track) {
|
||||||
|
printf("%s[%ld]: Error: The decoder command requires the '%s' track placeholder\n",
|
||||||
|
file, line, TRACK_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
|
||||||
return (errors);
|
return (errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,6 +691,11 @@ checkEncoderLine(const char *str, const char *file, long line)
|
|||||||
file, line, TRACK_PLACEHOLDER);
|
file, line, TRACK_PLACEHOLDER);
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
|
if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: `%s' placeholder not allowed in encoder command\n",
|
||||||
|
file, line, STRING_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
||||||
p += strlen(METADATA_PLACEHOLDER);
|
p += strlen(METADATA_PLACEHOLDER);
|
||||||
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
|
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
|
||||||
@ -681,3 +723,51 @@ checkEncoderLine(const char *str, const char *file, long line)
|
|||||||
|
|
||||||
return (errors);
|
return (errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
checkFormatLine(const char *str, const char *file, long line)
|
||||||
|
{
|
||||||
|
unsigned int errors;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
errors = 0;
|
||||||
|
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: `%s' placeholder not allowed in <metadata_format>\n",
|
||||||
|
file, line, METADATA_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
|
||||||
|
p += strlen(TRACK_PLACEHOLDER);
|
||||||
|
if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||||
|
file, line, TRACK_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
|
||||||
|
p += strlen(STRING_PLACEHOLDER);
|
||||||
|
if ((p = strstr(p, STRING_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||||
|
file, line, STRING_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p = strstr(str, ARTIST_PLACEHOLDER)) != NULL) {
|
||||||
|
p += strlen(ARTIST_PLACEHOLDER);
|
||||||
|
if ((p = strstr(p, ARTIST_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||||
|
file, line, ARTIST_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p = strstr(str, TITLE_PLACEHOLDER)) != NULL) {
|
||||||
|
p += strlen(TITLE_PLACEHOLDER);
|
||||||
|
if ((p = strstr(p, TITLE_PLACEHOLDER)) != NULL) {
|
||||||
|
printf("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||||
|
file, line, TITLE_PLACEHOLDER);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (errors);
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#define METADATA_PLACEHOLDER "@M@"
|
#define METADATA_PLACEHOLDER "@M@"
|
||||||
#define ARTIST_PLACEHOLDER "@a@"
|
#define ARTIST_PLACEHOLDER "@a@"
|
||||||
#define TITLE_PLACEHOLDER "@t@"
|
#define TITLE_PLACEHOLDER "@t@"
|
||||||
|
#define STRING_PLACEHOLDER "@s@"
|
||||||
|
|
||||||
typedef struct tag_FORMAT_ENCDEC {
|
typedef struct tag_FORMAT_ENCDEC {
|
||||||
char *format;
|
char *format;
|
||||||
@ -47,6 +48,7 @@ typedef struct tag_EZCONFIG {
|
|||||||
char *format;
|
char *format;
|
||||||
char *fileName;
|
char *fileName;
|
||||||
char *metadataProgram;
|
char *metadataProgram;
|
||||||
|
char *metadataFormat;
|
||||||
char *serverName;
|
char *serverName;
|
||||||
char *serverURL;
|
char *serverURL;
|
||||||
char *serverGenre;
|
char *serverGenre;
|
||||||
|
163
src/ezstream.c
163
src/ezstream.c
@ -112,6 +112,7 @@ 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 *);
|
||||||
char * buildCommandString(const char *, const char *, metadata_t *);
|
char * buildCommandString(const char *, const char *, metadata_t *);
|
||||||
|
char * getMetadataString(const char *, metadata_t *);
|
||||||
metadata_t * getMetadata(const char *);
|
metadata_t * getMetadata(const char *);
|
||||||
int setMetadata(shout_t *, metadata_t *, char **);
|
int setMetadata(shout_t *, metadata_t *, char **);
|
||||||
FILE * openResource(shout_t *, const char *, int *, char **, int *);
|
FILE * openResource(shout_t *, const char *, int *, char **, int *);
|
||||||
@ -247,14 +248,61 @@ buildCommandString(const char *extension, const char *fileName,
|
|||||||
newDecoder = xcalloc(1, newDecoderLen);
|
newDecoder = xcalloc(1, newDecoderLen);
|
||||||
replaceString(decoder, newDecoder, newDecoderLen, TRACK_PLACEHOLDER,
|
replaceString(decoder, newDecoder, newDecoderLen, TRACK_PLACEHOLDER,
|
||||||
fileName);
|
fileName);
|
||||||
if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
|
if (strstr(decoder, ARTIST_PLACEHOLDER) != NULL) {
|
||||||
size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_string(mdata)) + 1;
|
size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_artist(mdata)) + 1;
|
||||||
char *tmpStr = xcalloc(1, tmpLen);
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
replaceString(newDecoder, tmpStr, tmpLen, METADATA_PLACEHOLDER,
|
replaceString(newDecoder, tmpStr, tmpLen, ARTIST_PLACEHOLDER,
|
||||||
metadata_get_string(mdata));
|
metadata_get_artist(mdata));
|
||||||
xfree(newDecoder);
|
xfree(newDecoder);
|
||||||
newDecoder = tmpStr;
|
newDecoder = tmpStr;
|
||||||
}
|
}
|
||||||
|
if (strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
|
||||||
|
size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_title(mdata)) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newDecoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
|
||||||
|
metadata_get_title(mdata));
|
||||||
|
xfree(newDecoder);
|
||||||
|
newDecoder = tmpStr;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if meta
|
||||||
|
* if (prog && format)
|
||||||
|
* metatoformat
|
||||||
|
* else
|
||||||
|
* if (!prog && title)
|
||||||
|
* emptymeta
|
||||||
|
* else
|
||||||
|
* replacemeta
|
||||||
|
*/
|
||||||
|
if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
|
||||||
|
if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
|
||||||
|
char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
|
||||||
|
size_t tmpLen = strlen(newDecoder) + strlen(mdataString) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newDecoder, tmpStr, tmpLen,
|
||||||
|
METADATA_PLACEHOLDER, mdataString);
|
||||||
|
xfree(newDecoder);
|
||||||
|
xfree(mdataString);
|
||||||
|
newDecoder = tmpStr;
|
||||||
|
} else {
|
||||||
|
if (!metadataFromProgram && strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
|
||||||
|
size_t tmpLen = strlen(newDecoder) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newDecoder, tmpStr, tmpLen,
|
||||||
|
METADATA_PLACEHOLDER, "");
|
||||||
|
xfree(newDecoder);
|
||||||
|
newDecoder = tmpStr;
|
||||||
|
} else {
|
||||||
|
size_t tmpLen = strlen(newDecoder) + strlen(metadata_get_string(mdata)) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newDecoder, tmpStr, tmpLen,
|
||||||
|
METADATA_PLACEHOLDER,
|
||||||
|
metadata_get_string(mdata));
|
||||||
|
xfree(newDecoder);
|
||||||
|
newDecoder = tmpStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder = xstrdup(getFormatEncoder(pezConfig->format));
|
encoder = xstrdup(getFormatEncoder(pezConfig->format));
|
||||||
if (strlen(encoder) == 0) {
|
if (strlen(encoder) == 0) {
|
||||||
@ -272,10 +320,47 @@ buildCommandString(const char *extension, const char *fileName,
|
|||||||
return (commandString);
|
return (commandString);
|
||||||
}
|
}
|
||||||
|
|
||||||
newEncoderLen = strlen(encoder) + strlen(metadata_get_string(mdata)) + 1;
|
newEncoderLen = strlen(encoder) + strlen(metadata_get_artist(mdata)) + 1;
|
||||||
newEncoder = xcalloc(1, newEncoderLen);
|
newEncoder = xcalloc(1, newEncoderLen);
|
||||||
replaceString(encoder, newEncoder, newEncoderLen, METADATA_PLACEHOLDER,
|
replaceString(encoder, newEncoder, newEncoderLen, ARTIST_PLACEHOLDER,
|
||||||
metadata_get_string(mdata));
|
metadata_get_artist(mdata));
|
||||||
|
if (strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
|
||||||
|
size_t tmpLen = strlen(newEncoder) + strlen(metadata_get_title(mdata)) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newEncoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
|
||||||
|
metadata_get_title(mdata));
|
||||||
|
xfree(newEncoder);
|
||||||
|
newEncoder = tmpStr;
|
||||||
|
}
|
||||||
|
if (strstr(encoder, METADATA_PLACEHOLDER) != NULL) {
|
||||||
|
if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
|
||||||
|
char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
|
||||||
|
size_t tmpLen = strlen(newEncoder) + strlen(mdataString) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newEncoder, tmpStr, tmpLen,
|
||||||
|
METADATA_PLACEHOLDER, mdataString);
|
||||||
|
xfree(newEncoder);
|
||||||
|
xfree(mdataString);
|
||||||
|
newEncoder = tmpStr;
|
||||||
|
} else {
|
||||||
|
if (!metadataFromProgram && strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
|
||||||
|
size_t tmpLen = strlen(newEncoder) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newEncoder, tmpStr, tmpLen,
|
||||||
|
METADATA_PLACEHOLDER, "");
|
||||||
|
xfree(newEncoder);
|
||||||
|
newEncoder = tmpStr;
|
||||||
|
} else {
|
||||||
|
size_t tmpLen = strlen(newEncoder) + strlen(metadata_get_string(mdata)) + 1;
|
||||||
|
char *tmpStr = xcalloc(1, tmpLen);
|
||||||
|
replaceString(newEncoder, tmpStr, tmpLen,
|
||||||
|
METADATA_PLACEHOLDER,
|
||||||
|
metadata_get_string(mdata));
|
||||||
|
xfree(newEncoder);
|
||||||
|
newEncoder = tmpStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
commandStringLen = strlen(newDecoder) + strlen(" | ") +
|
commandStringLen = strlen(newDecoder) + strlen(" | ") +
|
||||||
strlen(newEncoder) + 1;
|
strlen(newEncoder) + 1;
|
||||||
@ -291,6 +376,59 @@ buildCommandString(const char *extension, const char *fileName,
|
|||||||
return (commandString);
|
return (commandString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
getMetadataString(const char *format, metadata_t *mdata)
|
||||||
|
{
|
||||||
|
char *tmp, *str;
|
||||||
|
size_t siz;
|
||||||
|
|
||||||
|
if (mdata == NULL) {
|
||||||
|
printf("%s: getMetadataString(): Internal error: NULL metadata_t\n",
|
||||||
|
__progname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
str = xstrdup(format);
|
||||||
|
|
||||||
|
if (strstr(format, ARTIST_PLACEHOLDER) != NULL) {
|
||||||
|
siz = strlen(str) + strlen(metadata_get_artist(mdata)) + 1;
|
||||||
|
tmp = xcalloc(1, siz);
|
||||||
|
replaceString(str, tmp, siz, ARTIST_PLACEHOLDER,
|
||||||
|
metadata_get_artist(mdata));
|
||||||
|
xfree(str);
|
||||||
|
str = tmp;
|
||||||
|
}
|
||||||
|
if (strstr(format, TITLE_PLACEHOLDER) != NULL) {
|
||||||
|
siz = strlen(str) + strlen(metadata_get_title(mdata)) + 1;
|
||||||
|
tmp = xcalloc(1, siz);
|
||||||
|
replaceString(str, tmp, siz, TITLE_PLACEHOLDER,
|
||||||
|
metadata_get_title(mdata));
|
||||||
|
xfree(str);
|
||||||
|
str = tmp;
|
||||||
|
}
|
||||||
|
if (strstr(format, STRING_PLACEHOLDER) != NULL) {
|
||||||
|
siz = strlen(str) + strlen(metadata_get_string(mdata)) + 1;
|
||||||
|
tmp = xcalloc(1, siz);
|
||||||
|
replaceString(str, tmp, siz, STRING_PLACEHOLDER,
|
||||||
|
metadata_get_string(mdata));
|
||||||
|
xfree(str);
|
||||||
|
str = tmp;
|
||||||
|
}
|
||||||
|
if (strstr(format, TRACK_PLACEHOLDER) != NULL) {
|
||||||
|
siz = strlen(str) + strlen(metadata_get_filename(mdata)) + 1;
|
||||||
|
tmp = xcalloc(1, siz);
|
||||||
|
replaceString(str, tmp, siz, TRACK_PLACEHOLDER,
|
||||||
|
metadata_get_filename(mdata));
|
||||||
|
xfree(str);
|
||||||
|
str = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (str);
|
||||||
|
}
|
||||||
|
|
||||||
metadata_t *
|
metadata_t *
|
||||||
getMetadata(const char *fileName)
|
getMetadata(const char *fileName)
|
||||||
{
|
{
|
||||||
@ -339,10 +477,13 @@ setMetadata(shout_t *shout, metadata_t *mdata, char **mdata_copy)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata_get_artist(mdata) == NULL && metadata_get_title(mdata) == NULL)
|
if ((songInfo = getMetadataString(pezConfig->metadataFormat, mdata)) == NULL) {
|
||||||
songInfo = xstrdup(metadata_get_string(mdata));
|
if (strlen(metadata_get_artist(mdata)) == 0 &&
|
||||||
else
|
strlen(metadata_get_title(mdata)) == 0)
|
||||||
songInfo = metadata_assemble_string(mdata);
|
songInfo = xstrdup(metadata_get_string(mdata));
|
||||||
|
else
|
||||||
|
songInfo = metadata_assemble_string(mdata);
|
||||||
|
}
|
||||||
|
|
||||||
if (shout_metadata_add(shout_mdata, "song", songInfo) != SHOUTERR_SUCCESS) {
|
if (shout_metadata_add(shout_mdata, "song", songInfo) != SHOUTERR_SUCCESS) {
|
||||||
/* Assume SHOUTERR_MALLOC */
|
/* Assume SHOUTERR_MALLOC */
|
||||||
|
@ -43,8 +43,10 @@
|
|||||||
#include "strfctns.h"
|
#include "strfctns.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
extern int vFlag;
|
extern int vFlag;
|
||||||
|
|
||||||
|
static const char *blankString = "";
|
||||||
|
|
||||||
struct metadata {
|
struct metadata {
|
||||||
char *filename;
|
char *filename;
|
||||||
@ -563,7 +565,10 @@ metadata_get_artist(metadata_t *md)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (md->artist);
|
if (md->artist == NULL)
|
||||||
|
return (blankString);
|
||||||
|
else
|
||||||
|
return (md->artist);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
@ -575,7 +580,26 @@ metadata_get_title(metadata_t *md)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (md->title);
|
if (md->title == NULL)
|
||||||
|
return (blankString);
|
||||||
|
else
|
||||||
|
return (md->title);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
metadata_get_filename(metadata_t *md)
|
||||||
|
{
|
||||||
|
if (md == NULL) {
|
||||||
|
printf("%s: metadata_get_filename(): Internal error: Bad arguments\n",
|
||||||
|
__progname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md->filename == NULL)
|
||||||
|
/* Should never happen: */
|
||||||
|
return (blankString);
|
||||||
|
else
|
||||||
|
return (md->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
@ -75,23 +75,27 @@ int metadata_program_update(metadata_t *, enum metadata_request);
|
|||||||
/*
|
/*
|
||||||
* Returns a pointer to a metadata string ``artist - title'', or just
|
* Returns a pointer to a metadata string ``artist - title'', or just
|
||||||
* ``artist'' or ``title'' if one of the two is not available. If neither
|
* ``artist'' or ``title'' if one of the two is not available. If neither
|
||||||
* are present, it usually returns the filename without the extension.
|
* are present, it returns the filename without the extension. An empty string
|
||||||
* This function never returns NULL.
|
* is returned for metadata_program() handles that didn't supply any generic
|
||||||
|
* information.
|
||||||
*/
|
*/
|
||||||
const char * metadata_get_string(metadata_t *);
|
const char * metadata_get_string(metadata_t *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a pointer to the artist string, or NULL if the file did not
|
* Returns a pointer to the artist string, which may be empty.
|
||||||
* contain any artist information.
|
|
||||||
*/
|
*/
|
||||||
const char * metadata_get_artist(metadata_t *);
|
const char * metadata_get_artist(metadata_t *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a pointer to the title string, or NULL if the file did not
|
* Returns a pointer to the title string, which may be empty.
|
||||||
* contain any title information.
|
|
||||||
*/
|
*/
|
||||||
const char * metadata_get_title(metadata_t *);
|
const char * metadata_get_title(metadata_t *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a pointer to the filename used in the metadata handle.
|
||||||
|
*/
|
||||||
|
const char * metadata_get_filename(metadata_t *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocates and returns a meaningful string based on a metadata handle's
|
* Allocates and returns a meaningful string based on a metadata handle's
|
||||||
* content. The result is what metadata_get_string() defaults to if an external
|
* content. The result is what metadata_get_string() defaults to if an external
|
||||||
|
Loading…
Reference in New Issue
Block a user