Skip to content

Commit 8963a55

Browse files
committed
display tags with multiple values in song formatting
Replaced existing functionality that only took the first found tag with a function that concatenates all the found tags with a comma delimiter. Allows displaying multiple artists, albums, etc. Function implemetation mostly based on the one in ncmpc.
1 parent 9b1c704 commit 8963a55

2 files changed

Lines changed: 74 additions & 2 deletions

File tree

src/song_format.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,52 @@
1212
#include <string.h>
1313
#include <stdlib.h>
1414

15+
/**
16+
* Append all tag entries of a given type into dest buffer.
17+
*
18+
* @param dest Pointer to current write position in buffer
19+
* @param end Pointer to the end of buffer (one past last byte)
20+
* @param song MPD song object
21+
* @param tag MPD tag type
22+
* @return Updated dest pointer after writing; If text added, null-terminated.
23+
* If no tag of this type fund, returns NULL.
24+
*/
25+
static char *
26+
copy_tags(char *dest, char *end, const struct mpd_song *song, enum mpd_tag_type tag)
27+
{
28+
const char *value = mpd_song_get_tag(song, tag, 0);
29+
if (value == NULL)
30+
return NULL;
31+
32+
// Get first tag separately, as it should not have a comma if it is the only entry.
33+
int written = snprintf(dest, (size_t)(end - dest), "%s", value);
34+
if (written < 0 || written >= (int)(end - dest))
35+
return dest + (end - dest - 1);
36+
dest += written;
37+
38+
/* mpd_song_get_tag can be called repeatedly with different index
39+
if tag has multiple entries (e.g. multiple artists)
40+
It returns nullptr when it runs out. */
41+
for (unsigned i = 1; ; ++i) {
42+
value = mpd_song_get_tag(song, tag, i);
43+
if (value == NULL)
44+
break;
45+
46+
// need at least room for ", " + \0
47+
if ((size_t)(end - dest) <= 2)
48+
break;
49+
*dest++ = ',';
50+
*dest++ = ' ';
51+
52+
written = snprintf(dest, (size_t)(end - dest), "%s", value);
53+
if (written < 0 || written >= (int)(end - dest))
54+
break;
55+
dest += written;
56+
}
57+
58+
return dest;
59+
}
60+
1561
static const char *
1662
format_mtime(char *buffer, size_t buffer_size,
1763
const struct mpd_song *song, const char *format)
@@ -44,7 +90,9 @@ gcc_pure
4490
static const char *
4591
song_value(const struct mpd_song *song, const char *name)
4692
{
47-
static char buffer[40];
93+
/* Arbitrary size.
94+
Should be large enough to fit multiple artists with long names */
95+
static char buffer[256];
4896
const char *value;
4997

5098
if (strcmp(name, "file") == 0)
@@ -85,7 +133,12 @@ song_value(const struct mpd_song *song, const char *name)
85133
if (tag_type == MPD_TAG_UNKNOWN)
86134
return NULL;
87135

88-
value = mpd_song_get_tag(song, tag_type, 0);
136+
const char *added_text = copy_tags(buffer, buffer + sizeof(buffer), song, tag_type);
137+
if (added_text != NULL) {
138+
value = buffer;
139+
}
140+
else
141+
value = NULL;
89142
}
90143

91144
if (value != NULL)

test/test_format.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,24 @@ START_TEST(test_escape)
125125
}
126126
END_TEST
127127

128+
START_TEST(test_multi_artist)
129+
{
130+
struct mpd_song *song = construct_song(default_file,
131+
"Artist", "Foo",
132+
"Artist", "Bar",
133+
"Artist", "Baz",
134+
"Title", "Collab Track",
135+
NULL);
136+
137+
// Expect multiple artists separated by ", "
138+
assert_format(song, "%artist%", "Foo, Bar, Baz");
139+
assert_format(song, "%title%", "Collab Track");
140+
assert_format(song, "%artist% - %title%", "Foo, Bar, Baz - Collab Track");
141+
142+
mpd_song_free(song);
143+
}
144+
END_TEST
145+
128146
static Suite *
129147
create_suite(void)
130148
{
@@ -136,6 +154,7 @@ create_suite(void)
136154
tcase_add_test(tc_core, test_fallback);
137155
tcase_add_test(tc_core, test_default);
138156
tcase_add_test(tc_core, test_escape);
157+
tcase_add_test(tc_core, test_multi_artist);
139158
suite_add_tcase(s, tc_core);
140159
return s;
141160
}

0 commit comments

Comments
 (0)