diff --git a/NEWS b/NEWS
index 6d8bb10c8..586d11eaf 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ ver 0.20 (not yet released)
- "commands" returns playlist commands only if playlist_directory configured
- "search"/"find" have a "window" parameter
- report song duration with milliseconds precision
+ - "sticker find" can match sticker values
* tags
- ape, ogg: drop support for non-standard tag "album artist"
affected filetypes: vorbis, flac, opus & all files with ape2 tags
diff --git a/doc/protocol.xml b/doc/protocol.xml
index 2d5979a5f..e5567c91f 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -2138,6 +2138,25 @@ OK
+
+
+
+
+ sticker
+ find
+ TYPE
+ URI
+ NAME
+ =
+ VALUE
+
+
+
+
+ Searches for stickers with the given value.
+
+
+
diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx
index b8eee55c5..07bed032e 100644
--- a/src/command/StickerCommands.cxx
+++ b/src/command/StickerCommands.cxx
@@ -138,7 +138,8 @@ handle_sticker_song(Client &client, ConstBuffer args)
return CommandResult::OK;
/* find song dir key */
- } else if (args.size == 4 && strcmp(cmd, "find") == 0) {
+ } else if ((args.size == 4 || args.size == 6) &&
+ strcmp(cmd, "find") == 0) {
/* "sticker find song a/directory name" */
const char *const base_uri = args[2];
@@ -146,6 +147,21 @@ handle_sticker_song(Client &client, ConstBuffer args)
StickerOperator op = StickerOperator::EXISTS;
const char *value = nullptr;
+ if (args.size == 6) {
+ /* match the value */
+
+ const char *op_s = args[4];
+ value = args[5];
+
+ if (strcmp(op_s, "=") == 0)
+ op = StickerOperator::EQUALS;
+ else {
+ command_error(client, ACK_ERROR_ARG,
+ "bad operator");
+ return CommandResult::ERROR;
+ }
+ }
+
bool success;
struct sticker_song_find_data data = {
client,
diff --git a/src/sticker/Match.hxx b/src/sticker/Match.hxx
index f91e70b40..6165ffb84 100644
--- a/src/sticker/Match.hxx
+++ b/src/sticker/Match.hxx
@@ -26,6 +26,12 @@ enum class StickerOperator {
* "value" parameter is ignored (must be nullptr).
*/
EXISTS,
+
+ /**
+ * Matches if a sticker with the specified name and value
+ * exists.
+ */
+ EQUALS,
};
#endif
diff --git a/src/sticker/StickerDatabase.cxx b/src/sticker/StickerDatabase.cxx
index 3c1245a6e..bd809c1d3 100644
--- a/src/sticker/StickerDatabase.cxx
+++ b/src/sticker/StickerDatabase.cxx
@@ -43,6 +43,7 @@ enum sticker_sql {
STICKER_SQL_DELETE,
STICKER_SQL_DELETE_VALUE,
STICKER_SQL_FIND,
+ STICKER_SQL_FIND_VALUE,
};
static const char *const sticker_sql[] = {
@@ -60,6 +61,9 @@ static const char *const sticker_sql[] = {
"DELETE FROM sticker WHERE type=? AND uri=? AND name=?",
//[STICKER_SQL_FIND] =
"SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=?",
+
+ //[STICKER_SQL_FIND_VALUE] =
+ "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=? AND value=?",
};
static const char sticker_sql_create[] =
@@ -383,9 +387,12 @@ BindFind(const char *type, const char *base_uri, const char *name,
case StickerOperator::EXISTS:
return BindAllOrNull(error, sticker_stmt[STICKER_SQL_FIND],
type, base_uri, name);
- }
- (void)value;
+ case StickerOperator::EQUALS:
+ return BindAllOrNull(error,
+ sticker_stmt[STICKER_SQL_FIND_VALUE],
+ type, base_uri, name, value);
+ }
assert(false);
gcc_unreachable();