Skip to content

Commit

Permalink
New sticker find api with support for new MPD 0.24 protocol
Browse files Browse the repository at this point in the history
- Arguments sort and window
- Filter operators contains, starts_with
- Support for integer sticker values

This commit moves also some common search functions from src/search.c to src/isearch.c.
  • Loading branch information
jcorporation committed Apr 23, 2024
1 parent 606cf6e commit 35b4d6f
Show file tree
Hide file tree
Showing 8 changed files with 478 additions and 154 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ libmpdclient 2.23 (not yet released)
- allow window for listplaylist and listplaylistinfo
- command "playlistlength"
* Support open end for mpd_search_add_window
* new sticker find api

libmpdclient 2.22 (2023/12/22)
* drop the unmaintained Vala bindings
Expand Down
111 changes: 111 additions & 0 deletions include/mpd/sticker.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@

struct mpd_connection;

/**
* Comparison operators for sticker search api
*/
enum mpd_sticker_operator {
MPD_STICKER_OP_UNKOWN = -1,
MPD_STICKER_OP_EQ,
MPD_STICKER_OP_GT,
MPD_STICKER_OP_LT,
MPD_STICKER_OP_EQ_INT,
MPD_STICKER_OP_GT_INT,
MPD_STICKER_OP_LT_INT,
MPD_STICKER_OP_CONTAINS,
MPD_STICKER_OP_STARTS_WITH,
};

/**
* Sort by settings for sticker search api
*/
enum mpd_sticker_sort {
MPD_STICKER_SORT_UNKOWN = -1,
MPD_STICKER_SORT_URI,
MPD_STICKER_SORT_VALUE,
MPD_STICKER_SORT_VALUE_INT,
};

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -198,6 +223,92 @@ mpd_return_sticker(struct mpd_connection *connection, struct mpd_pair *pair);
bool
mpd_send_stickernames(struct mpd_connection *connection);

/**
* Search for stickers in the database.
* Constraints may be specified with mpd_search_add_tag_constraint().
* Send the search command with mpd_search_commit(), and read the
* response items with mpd_recv_song().
*
* @param connection the connection to MPD
* @param type the object type, e.g. "song"
* @param base_uri the base URI to start the search, e.g. a directory;
* NULL to search for all objects of the specified type
* @param name the name of the sticker
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_sticker_search_begin(struct mpd_connection *connection, const char *type,
const char *base_uri, const char *name);

/**
* Adds the value constraint to the search
* @param connection a #mpd_connection
* @param oper compare operator
* @param value value to compare against
* @return true on success, else false
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_sticker_search_add_value_constraint(struct mpd_connection *connection,
enum mpd_sticker_operator oper,
const char *value);

/**
* Sort the results by the specified named attribute.
*
* @param connection a #mpd_connection
* @param sort sort by field
* @param descending sort in reverse order?
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_sticker_search_add_sort(struct mpd_connection *connection,
enum mpd_sticker_sort sort, bool descending);

/**
* Request only a portion of the result set.
*
* @param connection a #mpd_connection
* @param start the start offset (including)
* @param end the end offset (not including)
* value "UINT_MAX" makes the end of the range open
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_sticker_search_add_window(struct mpd_connection *connection,
unsigned start, unsigned end);

/**
* Starts the real search with constraints added with
* mpd_sticker_search_add_constraint().
*
* @param connection the connection to MPD
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_sticker_search_commit(struct mpd_connection *connection);

/**
* Cancels the search request before you have called
* mpd_sticker_search_commit(). Call this to clear the current search
* request.
*
* @param connection the connection to MPD
*
* @since libmpdclient 2.23, MPD 0.24
*/
void
mpd_sticker_search_cancel(struct mpd_connection *connection);

#ifdef __cplusplus
}
#endif
Expand Down
6 changes: 6 additions & 0 deletions libmpdclient.ld
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,12 @@ global:
mpd_recv_sticker;
mpd_return_sticker;
mpd_send_stickernames;
mpd_sticker_search_begin;
mpd_sticker_search_add_value_constraint;
mpd_sticker_search_add_sort;
mpd_sticker_search_add_window;
mpd_sticker_search_commit;
mpd_sticker_search_cancel;

/* mpd/fingerprint.h */
mpd_parse_fingerprint_type;
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ libmpdclient = library('mpdclient',
'src/replay_gain.c',
'src/response.c',
'src/run.c',
'src/isearch.c',
'src/search.c',
'src/send.c',
'src/socket.c',
Expand Down
166 changes: 166 additions & 0 deletions src/isearch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright The Music Player Daemon Project

#include "isearch.h"

#include <mpd/send.h>

#include "internal.h"

#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *
mpd_sanitize_arg(const char *src)
{
assert(src != NULL);

/* instead of counting in that loop above, just
* use a bit more memory and half running time
*/
char *result = malloc(strlen(src) * 2 + 1);
if (result == NULL)
return NULL;

char *dest = result;
char ch;
do {
ch = *src++;
if (ch == '"' || ch == '\\')
*dest++ = '\\';
*dest++ = ch;
} while (ch != 0);

return result;
}

bool
mpd_request_begin(struct mpd_connection *connection)
{
assert(connection != NULL);

if (mpd_error_is_defined(&connection->error))
return false;

if (connection->request) {
mpd_error_code(&connection->error, MPD_ERROR_STATE);
mpd_error_message(&connection->error,
"search already in progress");
return false;
}

return true;
}

bool
mpd_request_command(struct mpd_connection *connection, const char *cmd)
{
connection->request = strdup(cmd);
if (connection->request == NULL) {
mpd_error_code(&connection->error, MPD_ERROR_OOM);
return false;
}

return true;
}

char *
mpd_request_prepare_append(struct mpd_connection *connection,
size_t add_length)
{
assert(connection != NULL);

if (mpd_error_is_defined(&connection->error))
return NULL;

if (connection->request == NULL) {
mpd_error_code(&connection->error, MPD_ERROR_STATE);
mpd_error_message(&connection->error,
"no search in progress");
return NULL;
}

const size_t old_length = strlen(connection->request);
char *new_request = realloc(connection->request,
old_length + add_length + 1);
if (new_request == NULL) {
mpd_error_code(&connection->error, MPD_ERROR_OOM);
return NULL;
}

connection->request = new_request;
return new_request + old_length;
}

bool
mpd_request_add_sort(struct mpd_connection *connection,
const char *name, bool descending)
{
assert(connection != NULL);

const size_t size = 64;
char *dest = mpd_request_prepare_append(connection, size);
if (dest == NULL)
return false;

snprintf(dest, size, " sort %s%s",
descending ? "-" : "",
name);
return true;
}

bool
mpd_request_add_window(struct mpd_connection *connection,
unsigned start, unsigned end)
{
assert(connection != NULL);
assert(start <= end);

const size_t size = 64;
char *dest = mpd_request_prepare_append(connection, size);
if (dest == NULL)
return false;

if (end == UINT_MAX)
/* the special value -1 means "open end" */
snprintf(dest, size, " window %u:", start);
else
snprintf(dest, size, " window %u:%u", start, end);
return true;
}

bool
mpd_request_commit(struct mpd_connection *connection)
{
assert(connection != NULL);

if (mpd_error_is_defined(&connection->error)) {
mpd_request_cancel(connection);
return false;
}

if (connection->request == NULL) {
mpd_error_code(&connection->error, MPD_ERROR_STATE);
mpd_error_message(&connection->error,
"no search in progress");
return false;
}

bool success = mpd_send_command(connection, connection->request, NULL);
free(connection->request);
connection->request = NULL;

return success;
}

void
mpd_request_cancel(struct mpd_connection *connection)
{
assert(connection != NULL);

free(connection->request);
connection->request = NULL;
}
39 changes: 39 additions & 0 deletions src/isearch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright The Music Player Daemon Project

#ifndef MPD_ISEARCH_H
#define MPD_ISEARCH_H

#include <stdbool.h>
#include <stdlib.h>

struct mpd_connection;

char *
mpd_sanitize_arg(const char *src);

bool
mpd_request_begin(struct mpd_connection *connection);

bool
mpd_request_command(struct mpd_connection *connection, const char *cmd);

char *
mpd_request_prepare_append(struct mpd_connection *connection,
size_t add_length);

bool
mpd_request_add_sort(struct mpd_connection *connection,
const char *name, bool descending);

bool
mpd_request_add_window(struct mpd_connection *connection,
unsigned start, unsigned end);

bool
mpd_request_commit(struct mpd_connection *connection);

void
mpd_request_cancel(struct mpd_connection *connection);

#endif
Loading

0 comments on commit 35b4d6f

Please sign in to comment.