From aa57b2df074349d66cc68f1ff1a21f3051a8244c Mon Sep 17 00:00:00 2001 From: Eric Yape Date: Sun, 30 Nov 2025 20:28:32 +0100 Subject: [PATCH 1/5] add commands playlistlength and searchplaylist --- NEWS | 5 +++-- src/command.c | 27 +++++++++++++++++++++++++++ src/command.h | 25 +++++++------------------ src/main.c | 4 +++- src/search.c | 29 ++++++++++++++++++++++++++++- src/search.h | 3 +++ subprojects/libmpdclient.wrap | 2 +- 7 files changed, 72 insertions(+), 23 deletions(-) diff --git a/NEWS b/NEWS index b989a65..e2f3da7 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ 0.36 (not yet released) -* add command "tags" +* add commands "tags", "playlistlength", "searchplaylist" * concatenate multiple tag values +* require libmpdclient 2.23 or newer 0.35 (2023/12/21) * fix null pointer dereference on bad status format @@ -9,7 +10,7 @@ * add commands "lsdirs", "addplaylist", "delplaylist", "moveplaylist", "renplaylist", "clearplaylist" * add "playlist" option "--with-prio" * bash completion: pass "--" to mpc to allow parameters with dash -* bash completion: fix filenames with paranetheses +* bash completion: fix filenames with parentheses * bash completion: override $MPC_FORMAT 0.34 (2021/11/30) diff --git a/src/command.c b/src/command.c index 7fdfe95..72c4db0 100644 --- a/src/command.c +++ b/src/command.c @@ -843,6 +843,33 @@ cmd_clearplaylist(int argc, char **argv, struct mpd_connection *conn) return 0; } +int +cmd_playlistlength(int argc, char **argv, struct mpd_connection *conn) +{ + (void)argc; // silence warning about unused argument + const char* playlist = argv[0]; + + if (!mpd_send_playlistlength(conn, playlist)) + return -1; + + struct mpd_pair* pair = mpd_recv_pair_named(conn, "songs"); + if (pair != NULL) { + printf("songs: %s\n", pair->value); + mpd_return_pair(conn, pair); + } + + pair = mpd_recv_pair_named(conn, "playtime"); + if (pair != NULL) { + printf("playtime: %s\n", pair->value); + mpd_return_pair(conn, pair); + } + + if (!mpd_response_finish(conn)) + return -1; + + return 0; +} + int cmd_load(int argc, char **argv, struct mpd_connection *conn) { diff --git a/src/command.h b/src/command.h index 6592d39..a209ac6 100644 --- a/src/command.h +++ b/src/command.h @@ -50,23 +50,12 @@ int cmd_toggle(int argc, char **argv, struct mpd_connection *conn); int cmd_partitionlist(int argc, char **argv, struct mpd_connection *conn); int cmd_partitionmake(int argc, char **argv, struct mpd_connection *conn); int cmd_partitiondelete(int argc, char **argv, struct mpd_connection *conn); - -int -cmd_replaygain(int argc, char **argv, struct mpd_connection *conn); - -int -cmd_channels(int argc, char **argv, struct mpd_connection *conn); - -int -cmd_sendmessage(int argc, char **argv, struct mpd_connection *conn); - -int -cmd_waitmessage(int argc, char **argv, struct mpd_connection *conn); - -int -cmd_subscribe(int argc, char **argv, struct mpd_connection *conn); - -int -cmd_tags(int argc, char **argv, struct mpd_connection *conn); +int cmd_replaygain(int argc, char **argv, struct mpd_connection *conn); +int cmd_channels(int argc, char **argv, struct mpd_connection *conn); +int cmd_sendmessage(int argc, char **argv, struct mpd_connection *conn); +int cmd_waitmessage(int argc, char **argv, struct mpd_connection *conn); +int cmd_subscribe(int argc, char **argv, struct mpd_connection *conn); +int cmd_tags(int argc, char **argv, struct mpd_connection *conn); +int cmd_playlistlength(int argc, char **argv, struct mpd_connection *conn); #endif /* COMMAND_H */ diff --git a/src/main.c b/src/main.c index be0543b..765e554 100644 --- a/src/main.c +++ b/src/main.c @@ -47,7 +47,7 @@ static const struct command { /** NULL means they won't be shown in help */ const char *help; } mpc_table [] = { - /* command, min, max, pipe, handler, usage, help */ + /* command, min, max, pipe, handler, usage, help */ {"add", 0, -1, 1, cmd_add, "", "Add a song to the queue"}, {"addplaylist", 2, -1, 3, cmd_addplaylist, " ...", "Add a song to the playlist"}, {"albumart", 1, 1, 0, cmd_albumart, "", "Download album art for the given song and write to stdout." }, @@ -95,6 +95,7 @@ static const struct command { {"pause-if-playing", 0, 0, 0, cmd_pause_if_playing, "", "Pauses the currently playing song; exits with failure if not playing"}, {"play", 0, 1, 2, cmd_play, "[]", "Start playing at "}, {"playlist", 0, 1, 0, cmd_playlist, "[]", "Print "}, + {"playlistlength", 1, 1, 0, cmd_playlistlength, "", "Display the length of the given playlist"}, {"prev", 0, 0, 0, cmd_prev, "", "Play the previous song in the queue"}, {"prio", 2, -1, 2, cmd_prio, " ...", "Change song priorities in the queue"}, {"queued", 0, 0, 0, cmd_queued, "", "Show the next queued song"}, @@ -109,6 +110,7 @@ static const struct command { {"search", 1, -1, 0, cmd_search, " ", "Search for a song"}, {"searchadd", 1, -1, 0, cmd_searchadd, " ", "Search songs and add them to the queue"}, {"searchplay", 1, -1, 0, cmd_searchplay, "", "Find and play a song in the queue"}, + {"searchplaylist", 2, 2, 0, cmd_searchplaylist, " ", "Search for songs in the given playlist"}, {"seek", 1, 1, 0, cmd_seek, "[+-][HH:MM:SS]|<0-100>%", "Seeks to the specified position"}, {"seekthrough", 1, 1, 0, cmd_seek_through, "[+-][HH:MM:SS]", "Seeks by an amount of time within the song and playlist"}, {"sendmessage", 2, 2, 0, cmd_sendmessage, " ", "Send a message to the specified channel." }, diff --git a/src/search.c b/src/search.c index 9821f94..1738e48 100644 --- a/src/search.c +++ b/src/search.c @@ -170,7 +170,6 @@ cmd_search(int argc, char **argv, struct mpd_connection *conn) return do_search(argc, argv, conn, false); } - int cmd_searchadd(int argc, char **argv, struct mpd_connection *conn) { @@ -188,3 +187,31 @@ cmd_findadd(int argc, char **argv, struct mpd_connection *conn) { return do_searchadd(argc, argv, conn, true); } + +int +cmd_searchplaylist(int argc, char **argv, struct mpd_connection *conn) +{ + (void)argc; // silence warning about unused argument + const char* playlist = argv[0]; + const char* expression = argv[1]; + + /* ask MPD to omit the tags which are not used by the + `--format` to reduce network transfer for tag values we're + not going to use anyway */ + if (!mpd_command_list_begin(conn, false) || + !send_tag_types_for_format(conn, options.custom_format ? options.format : NULL)) + printErrorAndExit(conn); + + mpd_playlist_search_begin(conn, playlist, expression); + + if (!mpd_playlist_search_commit(conn)) + printErrorAndExit(conn); + + if (!mpd_command_list_end(conn)) + printErrorAndExit(conn); + + print_entity_list(conn, MPD_ENTITY_TYPE_SONG, options.custom_format); + + my_finishCommand(conn); + return 0; +} diff --git a/src/search.h b/src/search.h index 2bf6ef4..96551f5 100644 --- a/src/search.h +++ b/src/search.h @@ -23,4 +23,7 @@ cmd_find(int argc, char **argv, struct mpd_connection *conn); int cmd_findadd(int argc, char **argv, struct mpd_connection *conn); +int +cmd_searchplaylist(int argc, char **argv, struct mpd_connection *conn); + #endif diff --git a/subprojects/libmpdclient.wrap b/subprojects/libmpdclient.wrap index 002c003..f13aff5 100644 --- a/subprojects/libmpdclient.wrap +++ b/subprojects/libmpdclient.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/MusicPlayerDaemon/libmpdclient -revision = v2.21 +revision = v2.23 [provide] libmpdclient = libmpdclient_dep From d5b570a680b7b9ca8f71e1487bd787b4da9c925f Mon Sep 17 00:00:00 2001 From: Eric Yape Date: Sat, 6 Dec 2025 17:34:19 +0100 Subject: [PATCH 2/5] update doc & commands help --- doc/index.rst | 8 +++++++- src/main.c | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 729a367..0d836e0 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -264,7 +264,13 @@ Playlist Commands :command:`renplaylist ` - Rename a playlist. -:command:`clearplaylist ` - Clear the playlist name (i.e. truncate playlist.m3u). +:command:`clearplaylist ` - Clear the playlist name. + +:command:`searchplaylist ` - Search the playlist for songs + matching the expression + +:command:`playlistlength ` - Show the number of songs and + their total playtime (seconds) in the playlist Database Commands ^^^^^^^^^^^^^^^^^ diff --git a/src/main.c b/src/main.c index 765e554..0b6cfa4 100644 --- a/src/main.c +++ b/src/main.c @@ -95,7 +95,7 @@ static const struct command { {"pause-if-playing", 0, 0, 0, cmd_pause_if_playing, "", "Pauses the currently playing song; exits with failure if not playing"}, {"play", 0, 1, 2, cmd_play, "[]", "Start playing at "}, {"playlist", 0, 1, 0, cmd_playlist, "[]", "Print "}, - {"playlistlength", 1, 1, 0, cmd_playlistlength, "", "Display the length of the given playlist"}, + {"playlistlength", 1, 1, 0, cmd_playlistlength, "", "Show the number of songs and their total playtime (seconds) in the playlist"}, {"prev", 0, 0, 0, cmd_prev, "", "Play the previous song in the queue"}, {"prio", 2, -1, 2, cmd_prio, " ...", "Change song priorities in the queue"}, {"queued", 0, 0, 0, cmd_queued, "", "Show the next queued song"}, @@ -110,7 +110,7 @@ static const struct command { {"search", 1, -1, 0, cmd_search, " ", "Search for a song"}, {"searchadd", 1, -1, 0, cmd_searchadd, " ", "Search songs and add them to the queue"}, {"searchplay", 1, -1, 0, cmd_searchplay, "", "Find and play a song in the queue"}, - {"searchplaylist", 2, 2, 0, cmd_searchplaylist, " ", "Search for songs in the given playlist"}, + {"searchplaylist", 2, 2, 0, cmd_searchplaylist, " ", "Search the playlist for songs matching the expression"}, {"seek", 1, 1, 0, cmd_seek, "[+-][HH:MM:SS]|<0-100>%", "Seeks to the specified position"}, {"seekthrough", 1, 1, 0, cmd_seek_through, "[+-][HH:MM:SS]", "Seeks by an amount of time within the song and playlist"}, {"sendmessage", 2, 2, 0, cmd_sendmessage, " ", "Send a message to the specified channel." }, From c0b969950448c7358941267566198750b9244c59 Mon Sep 17 00:00:00 2001 From: Eric Yape Date: Sun, 21 Dec 2025 14:44:16 +0100 Subject: [PATCH 3/5] New commands stickernames, stickertypes & stickernamestypes --- NEWS | 2 +- doc/index.rst | 16 +++++++++--- src/main.c | 5 +++- src/sticker.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/sticker.h | 10 ++++++++ 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index e2f3da7..9343512 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ 0.36 (not yet released) -* add commands "tags", "playlistlength", "searchplaylist" +* add commands "tags", "playlistlength", "searchplaylist", "stickernames", "stickertypes", "stickernamestypes" * concatenate multiple tag values * require libmpdclient 2.23 or newer diff --git a/doc/index.rst b/doc/index.rst index 0d836e0..6de6e17 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -372,20 +372,28 @@ Sticker Commands The :command:`sticker` command allows you to get and set song stickers. -:command:`sticker set ` - Set the value of a song +:command:`sticker set ` - Set the value of a song sticker. -:command:`sticker get ` - Print the value of a song +:command:`sticker get ` - Print the value of a song sticker. :command:`sticker list` - List all stickers of a song. -:command:`sticker delete ` - Delete a song sticker. +:command:`sticker delete ` - Delete a song sticker. -:command:`sticker find ` - Search for stickers with the +:command:`sticker find ` - Search for stickers with the specified name, below the specified directory. +:command:`stickernames` - Display the list of unique sticker names +:command:`stickertypes` - Display the list of available sticker types + +:command:`stickernamestypes ` - Display the list of unique sticker names + for this sticker type + +:command:`searchsticker ` - Search for MPD + entities having sticker set at Output Commands ^^^^^^^^^^^^^^^ diff --git a/src/main.c b/src/main.c index 0b6cfa4..61b6df5 100644 --- a/src/main.c +++ b/src/main.c @@ -118,7 +118,10 @@ static const struct command { {"single", 0, 1, 0, cmd_single, "", "Toggle single mode, or specify state"}, {"stats", 0, -1, 0, cmd_stats, "", "Display statistics about MPD"}, {"status", 0, -1, 0, cmd_status, "", NULL}, /* status was added for pedantic reasons */ - {"sticker", 2, -1, 0, cmd_sticker, " [args..]", "Sticker management"}, + {"sticker", 2, -1, 0, cmd_sticker, " [args..]", "Sticker management"}, + {"stickernames", 0, 0, 0, cmd_stickernames, "", "Display the list of unique sticker names"}, + {"stickertypes", 0, 0, 0, cmd_stickertypes, "", "Display the list of available sticker types"}, + {"stickernamestypes",1, 1, 0, cmd_stickernamestypes,"", "Display the list of unique sticker names for this sticker type"}, {"stop", 0, 0, 0, cmd_stop, "", "Stop playback"}, {"subscribe", 1, 1, 0, cmd_subscribe, "", "Subscribe to the specified channel and continuously receive messages." }, {"tab", 1, 1, 0, cmd_tab, "", NULL}, diff --git a/src/sticker.c b/src/sticker.c index 94fb931..16a95c1 100644 --- a/src/sticker.c +++ b/src/sticker.c @@ -50,7 +50,7 @@ cmd_sticker(int argc, char **argv, struct mpd_connection *conn) { if(argc < 4) { - fputs("syntax: sticker set \n", stderr); + fputs("syntax: sticker set \n", stderr); return 0; } @@ -62,7 +62,7 @@ cmd_sticker(int argc, char **argv, struct mpd_connection *conn) { if(argc < 3) { - fputs("syntax: sticker get \n", stderr); + fputs("syntax: sticker get \n", stderr); return 0; } @@ -74,7 +74,7 @@ cmd_sticker(int argc, char **argv, struct mpd_connection *conn) { if(argc < 3) { - fputs("syntax: sticker find \n", stderr); + fputs("syntax: sticker find \n", stderr); return 0; } @@ -84,7 +84,7 @@ cmd_sticker(int argc, char **argv, struct mpd_connection *conn) } else if (strcmp(argv[1], "delete") == 0) { if(argc < 2) { - fputs("syntax: sticker delete [key]\n", stderr); + fputs("syntax: sticker delete [name]\n", stderr); return 0; } @@ -108,3 +108,66 @@ cmd_sticker(int argc, char **argv, struct mpd_connection *conn) return 0; } + +int +cmd_stickernames(int argc, char **argv, struct mpd_connection *conn) +{ + (void)argc; // silence warning about unused argument + (void)argv; // silence warning about unused argument + struct mpd_pair *pair; + + mpd_send_stickernames(conn); + + while ((pair = mpd_recv_pair(conn)) != NULL) { + + if (!strcmp(pair->name, "name")) { + printf("%s\n", pair->value); + } + mpd_return_pair(conn, pair); + } + + my_finishCommand(conn); + return 0; +} + +int +cmd_stickertypes(int argc, char **argv, struct mpd_connection *conn) +{ + (void)argc; // silence warning about unused argument + (void)argv; // silence warning about unused argument + struct mpd_pair *pair; + + mpd_send_stickertypes(conn); + + while ((pair = mpd_recv_pair(conn)) != NULL) { + + if (!strcmp(pair->name, "stickertype")) { + printf("%s\n", pair->value); + } + mpd_return_pair(conn, pair); + } + + my_finishCommand(conn); + return 0; +} + +int +cmd_stickernamestypes(int argc, char **argv, struct mpd_connection *conn) +{ + (void)argc; // silence warning about unused argument + const char* type = argv[0]; + struct mpd_pair *pair; + + mpd_send_stickernamestypes(conn, type); + + while ((pair = mpd_recv_pair(conn)) != NULL) { + + if (!strcmp(pair->name, "name")) { + printf("%s\n", pair->value); + } + mpd_return_pair(conn, pair); + } + + my_finishCommand(conn); + return 0; +} diff --git a/src/sticker.h b/src/sticker.h index bec9161..00c9993 100644 --- a/src/sticker.h +++ b/src/sticker.h @@ -9,4 +9,14 @@ struct mpd_connection; int cmd_sticker(int argc, char **argv, struct mpd_connection *conn); +int +cmd_stickernames(int argc, char **argv, struct mpd_connection *conn); + +int +cmd_stickertypes(int argc, char **argv, struct mpd_connection *conn); + +int +cmd_stickernamestypes(int argc, char **argv, struct mpd_connection *conn); + + #endif From 5948bb183e0a2975027c4f4e64cc5316cc0e94cc Mon Sep 17 00:00:00 2001 From: Eric Yape Date: Sun, 21 Dec 2025 17:11:41 +0100 Subject: [PATCH 4/5] Add command searchsticker --- NEWS | 2 +- doc/index.rst | 9 ++--- src/main.c | 1 + src/sticker.c | 92 ++++++++++++++++++++++++++++++++++++--------------- src/sticker.h | 2 ++ 5 files changed, 75 insertions(+), 31 deletions(-) diff --git a/NEWS b/NEWS index 9343512..37f40bc 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ 0.36 (not yet released) -* add commands "tags", "playlistlength", "searchplaylist", "stickernames", "stickertypes", "stickernamestypes" +* add commands "tags", "playlistlength", "searchplaylist", "stickernames", "stickertypes", "stickernamestypes", "searchsticker" * concatenate multiple tag values * require libmpdclient 2.23 or newer diff --git a/doc/index.rst b/doc/index.rst index 6de6e17..299104e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -262,9 +262,9 @@ Playlist Commands :command:`moveplaylist ` - Moves the song at given position to the position in the playlist. -:command:`renplaylist ` - Rename a playlist. +:command:`renplaylist ` - Rename the playlist. -:command:`clearplaylist ` - Clear the playlist name. +:command:`clearplaylist ` - Clear the playlist. :command:`searchplaylist ` - Search the playlist for songs matching the expression @@ -392,8 +392,9 @@ stickers. :command:`stickernamestypes ` - Display the list of unique sticker names for this sticker type -:command:`searchsticker ` - Search for MPD - entities having sticker set at +:command:`searchsticker ` - Search + for MPD entities having sticker @ . + Valid are:: ``=``, ``>``, ``<``, ``eq``, ``gt``, ``lt``, ``contains``, ``starts_with`` Output Commands ^^^^^^^^^^^^^^^ diff --git a/src/main.c b/src/main.c index 61b6df5..d006b5b 100644 --- a/src/main.c +++ b/src/main.c @@ -122,6 +122,7 @@ static const struct command { {"stickernames", 0, 0, 0, cmd_stickernames, "", "Display the list of unique sticker names"}, {"stickertypes", 0, 0, 0, cmd_stickertypes, "", "Display the list of available sticker types"}, {"stickernamestypes",1, 1, 0, cmd_stickernamestypes,"", "Display the list of unique sticker names for this sticker type"}, + {"searchsticker", 5, 5, 0, cmd_searchsticker, " ", "Search for MPD entities having sticker to set at "}, {"stop", 0, 0, 0, cmd_stop, "", "Stop playback"}, {"subscribe", 1, 1, 0, cmd_subscribe, "", "Subscribe to the specified channel and continuously receive messages." }, {"tab", 1, 1, 0, cmd_tab, "", NULL}, diff --git a/src/sticker.c b/src/sticker.c index 16a95c1..c36d34c 100644 --- a/src/sticker.c +++ b/src/sticker.c @@ -46,66 +46,60 @@ recv_print_stickers2(struct mpd_connection *connection) int cmd_sticker(int argc, char **argv, struct mpd_connection *conn) { - if(!strcmp(argv[1], "set")) - { - if(argc < 4) - { + if (!strcmp(argv[1], "set")) { + + if (argc < 4) { fputs("syntax: sticker set \n", stderr); return 0; } mpd_send_sticker_set(conn, "song", argv[0], argv[2], argv[3]); - my_finishCommand(conn); - return 0; } - else if(!strcmp(argv[1], "get")) - { - if(argc < 3) - { + else if (!strcmp(argv[1], "get")) { + + if (argc < 3) { fputs("syntax: sticker get \n", stderr); return 0; } mpd_send_sticker_get(conn, "song", argv[0], argv[2]); recv_print_stickers(conn); - my_finishCommand(conn); } - else if(!strcmp(argv[1], "find")) - { - if(argc < 3) - { + else if (!strcmp(argv[1], "find")) { + + if (argc < 3) { fputs("syntax: sticker find \n", stderr); return 0; } mpd_send_sticker_find(conn, "song", argv[0], argv[2]); recv_print_stickers2(conn); - my_finishCommand(conn); - } else if (strcmp(argv[1], "delete") == 0) { - if(argc < 2) - { + } + else if (!strcmp(argv[1], "delete")) { + + if (argc < 2) { fputs("syntax: sticker delete [name]\n", stderr); return 0; } mpd_send_sticker_delete(conn, "song", argv[0], argc > 2 ? argv[2] : NULL); - my_finishCommand(conn); } - else if(!strcmp(argv[1], "list")) - { - if(argc < 2) - { + else if (!strcmp(argv[1], "list")) { + + if (argc < 2) { fputs("syntax: sticker list\n", stderr); return 0; } mpd_send_sticker_list(conn, "song", argv[0]); recv_print_stickers(conn); - my_finishCommand(conn); } - else + else { fputs("error: unknown command.\n", stderr); + return 0; + } + my_finishCommand(conn); return 0; } @@ -171,3 +165,49 @@ cmd_stickernamestypes(int argc, char **argv, struct mpd_connection *conn) my_finishCommand(conn); return 0; } + +int +cmd_searchsticker(int argc, char **argv, struct mpd_connection *conn) +{ + (void)argc; // silence warning about unused argument + const char* type = argv[0]; + const char* base_uri = argv[1]; + const char* name = argv[2]; + const char* oper = argv[3]; + const char* value = argv[4]; + + enum mpd_sticker_operator sticker_op; + + // reverse get_sticker_oper_str() ! + if (!strcmp(oper, "=")) + sticker_op = MPD_STICKER_OP_EQ; + else if (!strcmp(oper, ">")) + sticker_op = MPD_STICKER_OP_GT; + else if (!strcmp(oper, "<")) + sticker_op = MPD_STICKER_OP_LT; + else if (!strcmp(oper, "eq")) + sticker_op = MPD_STICKER_OP_EQ_INT; + else if (!strcmp(oper, "gt")) + sticker_op = MPD_STICKER_OP_GT_INT; + else if (!strcmp(oper, "lt")) + sticker_op = MPD_STICKER_OP_LT_INT; + else if (!strcmp(oper, "contains")) + sticker_op = MPD_STICKER_OP_CONTAINS; + else if (!strcmp(oper, "starts_with")) + sticker_op = MPD_STICKER_OP_STARTS_WITH; + else { + fprintf(stderr, "error: unknown operator %s.\n", oper); + return 0; + } + + mpd_sticker_search_begin(conn, type, base_uri, name); + + mpd_sticker_search_add_value_constraint(conn, sticker_op, value); + + if (!mpd_sticker_search_commit(conn)) + printErrorAndExit(conn); + + recv_print_stickers2(conn); + my_finishCommand(conn); + return 0; +} diff --git a/src/sticker.h b/src/sticker.h index 00c9993..996ee04 100644 --- a/src/sticker.h +++ b/src/sticker.h @@ -18,5 +18,7 @@ cmd_stickertypes(int argc, char **argv, struct mpd_connection *conn); int cmd_stickernamestypes(int argc, char **argv, struct mpd_connection *conn); +int +cmd_searchsticker(int argc, char **argv, struct mpd_connection *conn); #endif From c2a47396400bad7c00049500a8e7f7411f99515a Mon Sep 17 00:00:00 2001 From: Eric Yape Date: Mon, 22 Dec 2025 12:44:41 +0100 Subject: [PATCH 5/5] complete "sticker" API with "playlist" & "tags" entities subcommands and documentation --- NEWS | 3 + doc/index.rst | 104 +++++++++++++++++++------- src/main.c | 2 +- src/sticker.c | 202 +++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 266 insertions(+), 45 deletions(-) diff --git a/NEWS b/NEWS index 37f40bc..6e5fdc3 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ 0.36 (not yet released) * add commands "tags", "playlistlength", "searchplaylist", "stickernames", "stickertypes", "stickernamestypes", "searchsticker" +* complete command "sticker" API with "playlist" & "tags" entities subcommands (get/set/delete/list/find/inc/dec) +* fix a bug in "sticker" API "delete" subcommand where "name" parameter is mandatory +* update documentation * concatenate multiple tag values * require libmpdclient 2.23 or newer diff --git a/doc/index.rst b/doc/index.rst index 299104e..a0495e4 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -252,25 +252,19 @@ Playlist Commands :command:`save ` - Saves playlist as . -:command:`addplaylist ` - Adds a song from the music database to the - playlist. The playlist will be created if it does not exist. - Can also read input from pipes. +:command:`addplaylist ` - Adds a song from the music database to the playlist. The playlist will be created if it does not exist. Can also read input from pipes. -:command:`delplaylist ` - Removes the song at given position from the playlist. Can - also read input from pipes. +:command:`delplaylist ` - Removes the song at given position from the playlist. Can also read input from pipes. -:command:`moveplaylist ` - Moves the song at given position - to the position in the playlist. +:command:`moveplaylist ` - Moves the song at given position to the position in the playlist. :command:`renplaylist ` - Rename the playlist. :command:`clearplaylist ` - Clear the playlist. -:command:`searchplaylist ` - Search the playlist for songs - matching the expression +:command:`searchplaylist ` - Search the playlist for songs matching the expression. -:command:`playlistlength ` - Show the number of songs and - their total playtime (seconds) in the playlist +:command:`playlistlength ` - Show the number of songs and their total playtime (in seconds) in the playlist. Database Commands ^^^^^^^^^^^^^^^^^ @@ -369,32 +363,90 @@ Mount Commands Sticker Commands ^^^^^^^^^^^^^^^^^ -The :command:`sticker` command allows you to get and set song -stickers. +The :command:`sticker` command allows you to get and set stickers on "songs", "playlists" and several MPD "tags". -:command:`sticker set ` - Set the value of a song - sticker. +1. "song" API -:command:`sticker get ` - Print the value of a song - sticker. +:command:`sticker set ` - Set the value of a song sticker. + +:command:`sticker get ` - Print the value of a song sticker. :command:`sticker list` - List all stickers of a song. :command:`sticker delete ` - Delete a song sticker. -:command:`sticker find ` - Search for stickers with the - specified name, below the specified directory. +:command:`sticker inc ` - Increment the sticker of the song by the given value. + +:command:`sticker dec ` - Decrement the sticker of the song by the given value. + +:command:`sticker find ` - Search for stickers with the specified name, below the given directory. + Search for any values of the ``rated`` stickers under the ``Wolfgang Amadeus Mozart`` MPD folder:: + + mpc sticker "Wolfgang Amadeus Mozart" find rated + + Search for any values of the ``rated`` stickers under any MPD folders:: + + mpc sticker "" find rated + + +2. "playlist" API + +:command:`sticker playlist-set ` - Set the value of a playlist sticker. + +:command:`sticker playlist-get ` - Print the value of a playlist sticker. + +:command:`sticker playlist-list` - List all stickers of a playlist. + +:command:`sticker playlist-delete ` - Delete a playlist sticker. + +:command:`sticker playlist-inc ` - Increment the sticker of the playlist by the given value. + + Increments the ``played`` sticker of the ``Christmas Playlist`` playlist by ``1``:: + + mpc sticker "Christmas Playlist" playlist-inc played 1 + +:command:`sticker playlist-dec ` - Decrement the sticker of the playlist by the given value. + +:command:`sticker playlist-find ` - Search for stickers with the specified name, below the given directory. + +3. "tags" API + +:command:`sticker tag-set ` - Set the value of a playlist sticker. + +:command:`sticker tag-get ` - Print the value of a tag sticker. + +:command:`sticker tag-list ` - List all stickers of a tag. + +:command:`sticker tag-delete ` - Delete a tag sticker. + +:command:`sticker tag-inc ` - Increment the sticker of the tag by the given value. + + Increments the ``played`` sticker of the ``Kraftwerk`` artist by 1:: + + mpc sticker "Kraftwerk" tag-inc Artist played 1 + +:command:`sticker tag-dec ` - Decrement the sticker of the tag by the given value. + +:command:`sticker tag-find ` - Search for stickers of the tag with the specified name, below the specified directory. + +4. Misc commands + +:command:`stickernames` - Display the list of unique sticker names. + +:command:`stickertypes` - Display the list of available sticker types. + +:command:`stickernamestypes ` - Display the list of unique sticker names for this sticker type. + +:command:`searchsticker ` - Search for MPD entities @ having stickers matching the expression " ". + Valid are ``=``, ``>``, ``<``, ``eq``, ``gt``, ``lt``, ``contains``, ``starts_with`` -:command:`stickernames` - Display the list of unique sticker names + Search for any songs in the ``Wolfgang Amadeus Mozart`` MPD folder having sticker ``rated`` equals to ``Good``:: -:command:`stickertypes` - Display the list of available sticker types + mpc searchsticker song "Wolfgang Amadeus Mozart" rated = Good -:command:`stickernamestypes ` - Display the list of unique sticker names - for this sticker type + Search for any playlist having sticker ``played`` greater than 100:: -:command:`searchsticker ` - Search - for MPD entities having sticker @ . - Valid are:: ``=``, ``>``, ``<``, ``eq``, ``gt``, ``lt``, ``contains``, ``starts_with`` + mpc searchsticker playlist "" played gt 100 Output Commands ^^^^^^^^^^^^^^^ diff --git a/src/main.c b/src/main.c index d006b5b..382e7c2 100644 --- a/src/main.c +++ b/src/main.c @@ -118,7 +118,7 @@ static const struct command { {"single", 0, 1, 0, cmd_single, "", "Toggle single mode, or specify state"}, {"stats", 0, -1, 0, cmd_stats, "", "Display statistics about MPD"}, {"status", 0, -1, 0, cmd_status, "", NULL}, /* status was added for pedantic reasons */ - {"sticker", 2, -1, 0, cmd_sticker, " [args..]", "Sticker management"}, + {"sticker", 2, -1, 0, cmd_sticker, " [args..]", "Sticker management"}, {"stickernames", 0, 0, 0, cmd_stickernames, "", "Display the list of unique sticker names"}, {"stickertypes", 0, 0, 0, cmd_stickertypes, "", "Display the list of available sticker types"}, {"stickernamestypes",1, 1, 0, cmd_stickernamestypes,"", "Display the list of unique sticker names for this sticker type"}, diff --git a/src/sticker.c b/src/sticker.c index c36d34c..d1a957f 100644 --- a/src/sticker.c +++ b/src/sticker.c @@ -20,6 +20,7 @@ recv_print_stickers(struct mpd_connection *connection) } } +/* static void recv_print_stickers2(struct mpd_connection *connection) { @@ -42,60 +43,225 @@ recv_print_stickers2(struct mpd_connection *connection) if (!first) putchar('\n'); } +*/ + +static void +recv_print_stickers3(struct mpd_connection *connection) { + + struct mpd_pair *pair; + while ((pair = mpd_recv_pair(connection)) != NULL) { + + if (strcmp(pair->name, "sticker")) { + printf("%s: ", pair->value); + } + else { + printf("%s\n", pair->value); + } + mpd_return_pair(connection, pair); + } +} int cmd_sticker(int argc, char **argv, struct mpd_connection *conn) { - if (!strcmp(argv[1], "set")) { + const char* uri = argv[0]; + const char* command = argv[1]; + //printf("argc = %d, command = %s, uri = %s\n", argc, command, uri); + + // "song" entity + if (!strcmp(command, "set")) { if (argc < 4) { fputs("syntax: sticker set \n", stderr); return 0; } - - mpd_send_sticker_set(conn, "song", argv[0], argv[2], argv[3]); + mpd_send_sticker_set(conn, "song", uri, argv[2], argv[3]); } - else if (!strcmp(argv[1], "get")) { + else if (!strcmp(command, "get")) { if (argc < 3) { fputs("syntax: sticker get \n", stderr); return 0; } - - mpd_send_sticker_get(conn, "song", argv[0], argv[2]); + mpd_send_sticker_get(conn, "song", uri, argv[2]); recv_print_stickers(conn); } - else if (!strcmp(argv[1], "find")) { + else if (!strcmp(command, "find")) { if (argc < 3) { - fputs("syntax: sticker find \n", stderr); + fputs("syntax: sticker find \n", stderr); return 0; } + mpd_send_sticker_find(conn, "song", uri, argv[2]); + recv_print_stickers3(conn); + } + else if (!strcmp(command, "delete")) { - mpd_send_sticker_find(conn, "song", argv[0], argv[2]); - recv_print_stickers2(conn); + if (argc < 3) { + fputs("syntax: sticker delete \n", stderr); + return 0; + } + mpd_send_sticker_delete(conn, "song", uri, argv[2]); } - else if (!strcmp(argv[1], "delete")) { + else if (!strcmp(command, "list")) { if (argc < 2) { - fputs("syntax: sticker delete [name]\n", stderr); + fputs("syntax: sticker list\n", stderr); + return 0; + } + mpd_send_sticker_list(conn, "song", uri); + recv_print_stickers(conn); + } + else if (!strcmp(command, "inc")) { + + if (argc < 4) { + fputs("syntax: sticker inc \n", stderr); + return 0; + } + unsigned value; + sscanf(argv[3], "%u", &value); + mpd_send_sticker_inc(conn, "song", uri, argv[2], value); + } + else if (!strcmp(command, "dec")) { + + if (argc < 4) { + fputs("syntax: sticker dec \n", stderr); + return 0; + } + unsigned value; + sscanf(argv[3], "%u", &value); + mpd_send_sticker_dec(conn, "song", uri, argv[2], value); + } + // "playlist" entity + else if (!strcmp(command, "playlist-set")) { + + if (argc < 4) { + fputs("syntax: sticker playlist-set \n", stderr); return 0; } + mpd_send_sticker_set(conn, "playlist", uri, argv[2], argv[3]); + } + else if (!strcmp(command, "playlist-get")) { + + if (argc < 3) { + fputs("syntax: sticker playlist-get \n", stderr); + return 0; + } + mpd_send_sticker_get(conn, "playlist", uri, argv[2]); + recv_print_stickers(conn); + } + else if (!strcmp(command, "playlist-find")) { - mpd_send_sticker_delete(conn, "song", argv[0], argc > 2 ? argv[2] : NULL); + if (argc < 3) { + fputs("syntax: sticker playlist-find \n", stderr); + return 0; + } + mpd_send_sticker_find(conn, "playlist", uri, argv[2]); + recv_print_stickers3(conn); } - else if (!strcmp(argv[1], "list")) { + else if (!strcmp(command, "playlist-delete")) { + + if (argc < 3) { + fputs("syntax: sticker playlist-delete \n", stderr); + return 0; + } + mpd_send_sticker_delete(conn, "playlist", uri, argv[2]); + } + else if (!strcmp(command, "playlist-list")) { if (argc < 2) { - fputs("syntax: sticker list\n", stderr); + fputs("syntax: sticker playlist-list\n", stderr); + return 0; + } + mpd_send_sticker_list(conn, "playlist", uri); + recv_print_stickers(conn); + } + else if (!strcmp(command, "playlist-inc")) { + + if (argc < 4) { + fputs("syntax: sticker playlist-inc \n", stderr); + return 0; + } + unsigned value; + sscanf(argv[3], "%u", &value); + mpd_send_sticker_inc(conn, "playlist", uri, argv[2], value); + } + else if (!strcmp(command, "playlist-dec")) { + + if (argc < 4) { + fputs("syntax: sticker playlist-dec \n", stderr); + return 0; + } + unsigned value; + sscanf(argv[3], "%u", &value); + mpd_send_sticker_dec(conn, "playlist", uri, argv[2], value); + } + // MPD "tag" entity + else if (!strcmp(command, "tag-set")) { + + if (argc < 5) { + fputs("syntax: sticker tag-set \n", stderr); return 0; } + mpd_send_sticker_set(conn, argv[2], uri, argv[3], argv[4]); + } + else if (!strcmp(command, "tag-get")) { - mpd_send_sticker_list(conn, "song", argv[0]); + if (argc < 4) { + fputs("syntax: sticker tag-get \n", stderr); + return 0; + } + mpd_send_sticker_get(conn, argv[2], uri, argv[3]); recv_print_stickers(conn); } + else if (!strcmp(command, "tag-find")) { + + if (argc < 4) { + fputs("syntax: sticker tag-find \n", stderr); + return 0; + } + mpd_send_sticker_find(conn, argv[2], uri, argv[3]); + recv_print_stickers3(conn); + } + else if (!strcmp(command, "tag-delete")) { + + if (argc < 4) { + fputs("syntax: sticker tag-delete \n", stderr); + return 0; + } + mpd_send_sticker_delete(conn, argv[2], uri, argv[3]); + } + else if (!strcmp(command, "tag-list")) { + + if (argc < 3) { + fputs("syntax: sticker tag-list \n", stderr); + return 0; + } + mpd_send_sticker_list(conn, argv[2], uri); + recv_print_stickers(conn); + } + else if (!strcmp(command, "tag-inc")) { + + if (argc < 5) { + fputs("syntax: sticker tag-inc \n", stderr); + return 0; + } + unsigned value; + sscanf(argv[4], "%u", &value); + mpd_send_sticker_inc(conn, argv[2], uri, argv[3], value); + } + else if (!strcmp(command, "tag-dec")) { + + if (argc < 5) { + fputs("syntax: sticker tag-dec \n", stderr); + return 0; + } + unsigned value; + sscanf(argv[4], "%u", &value); + mpd_send_sticker_dec(conn, argv[2], uri, argv[3], value); + } else { - fputs("error: unknown command.\n", stderr); + fprintf(stderr, "error: unknown command '%s'.\n", command); return 0; } @@ -207,7 +373,7 @@ cmd_searchsticker(int argc, char **argv, struct mpd_connection *conn) if (!mpd_sticker_search_commit(conn)) printErrorAndExit(conn); - recv_print_stickers2(conn); + recv_print_stickers3(conn); my_finishCommand(conn); return 0; }