Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New sticker find api that supports the new arguments sort and window and support integer sticker values #120

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading