Skip to content
Extraits de code Groupes Projets
Vérifiée Valider c380b1be rédigé par Kubat's avatar Kubat
Parcourir les fichiers

Add the search in playlists

parent 1c24e888
Branches
Étiquettes
1 requête de fusion!98Queue and playlist interactions with lkt
......@@ -100,13 +100,16 @@ struct lkt_search {
long continuation; /* The continuation state of the client */
int msg_count; /* How much messages we can send */
const char *st_name; /* Stickers and playlists */
union {
const char *st_name; /* Sticker name */
const char *plt_name; /* Playlist name */
};
int st_value; /* The value of a sticker */
int st_uri; /* URI of a sticker */
char st_op; /* Comparaison operator for stickers */
char *st_type; /* Type of sticker */
struct lkt_uri ka_uri; /* Search by uri, depract the use of ka_rgx */
struct lkt_uri ka_uri; /* Search by uri */
};
typedef bool (*lkt_search_init_add_func)(volatile sqlite3 *, struct lkt_uri *, int);
......@@ -117,6 +120,7 @@ typedef bool (*lkt_search_sticker_func) (struct lkt_state *srv, size_t c, const
bool database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret);
bool database_search_queue_init (volatile sqlite3 *db, struct lkt_search *ret);
bool database_search_sticker_init (volatile sqlite3 *db, struct lkt_search *ret);
bool database_search_playlist_init(volatile sqlite3 *db, struct lkt_search *ret);
bool database_search_iter(struct lkt_search *item);
/* Next and prev operation on the queue. */
......
......@@ -282,9 +282,8 @@ command_addid(volatile sqlite3 *db, struct lkt_win *win,
errno = 0;
int i;
struct lkt_uri uri = { .type = uri_id };
for (i = 0; (uri.id = strtol(args[i], NULL, 0)) && ! errno; ++i) {
for (i = 0; (uri.id = strtol(args[i], NULL, 0)) && ! errno; ++i)
errno |= database_queue_add_id(db, uri.id, 1);
}
*watch_mask_ptr |= MPD_IDLE_PLAYLIST;
return ! errno;
}
......@@ -443,15 +442,22 @@ command_find(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX],
.srv = srv,
.c = c,
.continuation = continuation,
.msg_count = lkt_remaining_msg(srv, c) - 3, /* Reserve slots for OK/ACK and continue: */
/* Reserve slots for OK/ACK and continue: */
.msg_count = lkt_remaining_msg(srv, c) - 3,
.call = (void(*)(void)) lkt_callback_send_row_v2,
.ka_uri = {0},
.plt_name = args[0], /* In case of playlist searchs */
};
/* Check args */
RETURN_UNLESS(args[0], "Invalid argument", false);
RETURN_UNLESS(lkt_uri_from_list(&search.ka_uri, args),
"Failed to create the uri from the cmd", false);
if (!lkt_uri_from_list(&search.ka_uri, args)) {
/* Try from idx 1, in case of playlust searches */
LOG_DEBUG("COMMAND", "URI may not starts at idx 0, may be because "
"of playlist search. At idx 0, value was '%s'", args[0]);
RETURN_UNLESS(lkt_uri_from_list(&search.ka_uri, &args[1]),
"Failed to create the uri", false);
}
/* Make the search langand do the right action */
RETURN_UNLESS(init(srv->db, &search), "Failed to init search", false);
......
......@@ -8,6 +8,12 @@
#include <stdio.h>
#include <string.h>
static inline int
__check_sticker_type(const char *type)
{
return ! ( STR_MATCH(type, "kara") || STR_MATCH(type, "plt") );
}
bool
database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret)
{
......@@ -33,11 +39,43 @@ error:
return false;
}
bool
database_search_playlist_init(volatile sqlite3 *db, struct lkt_search *ret)
{
RETURN_UNLESS(ret, "Exit because return pointer is NULL", false);
static const char *SQL_TEMPLATE =
"WITH content AS ("
" SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len"
" FROM kara_playlist"
" JOIN playlist ON playlist.id = playlist_id"
" AND playlist.name COLLATE nocase = ?"
" JOIN kara ON kara.id = kara_id"
" AND %s LIKE ?)"
"SELECT id, string, (SELECT MAX(len) FROM content)"
"FROM content LIMIT %d OFFSET %d;";
char SQL_STMT[LKT_MAX_SQLITE_STATEMENT];
ret->type = lkt_search_playlist;
safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE,
ret->ka_uri.column_name, ret->msg_count, ret->continuation);
SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error);
SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->plt_name, error);
SQLITE_BIND_TEXT(db, ret->stmt, 2, ret->ka_uri.value, error);
ret->db = db;
return true;
error:
sqlite3_finalize(ret->stmt);
return false;
}
bool
database_search_sticker_init(volatile sqlite3 *db, struct lkt_search *ret)
{
/* No bound checks in strcats, should be fine. Possible SQL injection,
depend on the `type`. */
if (__check_sticker_type(ret->st_type)) {
LOG_ERROR("DB", "Type '%s' is invalid", ret->st_type);
return false;
}
static const char *SQL_all_types =
"SELECT name, sts.id, value FROM 'stickers' JOIN "
"( SELECT id, sticker, value, 'kara' FROM 'stickers.kara'"
......@@ -125,19 +163,19 @@ database_search_iter(struct lkt_search *item)
switch (item->type) {
case lkt_search_database:
case lkt_search_queue:
case lkt_search_playlist:
id = sqlite3_column_int (item->stmt, 0);
sql_row = (const char *) sqlite3_column_text(item->stmt, 1);
sql_row = sqlite3_column_chars(item->stmt, 1);
id_len = sqlite3_column_int (item->stmt, 2);
return ((lkt_search_database_func) item->call)
(item->srv, item->c, id, id_len, sql_row);
case lkt_search_sticker:
sql_row = (const char *) sqlite3_column_text(item->stmt, 0); /* Name */
sql_row = sqlite3_column_chars(item->stmt, 0); /* Name */
id = sqlite3_column_int (item->stmt, 1); /* Id */
code = sqlite3_column_int (item->stmt, 2); /* Val */
type = (const char *) sqlite3_column_text(item->stmt, 3); /* Type */
type = sqlite3_column_chars(item->stmt, 3); /* Type */
return ((lkt_search_sticker_func) item->call)
(item->srv, item->c, sql_row, type, id, code);
case lkt_search_playlist:
default:
LOG_WARN("DB", "Search type %d is not implemented", item->type);
goto end;
......
......@@ -669,7 +669,7 @@ database_queue_dump(volatile sqlite3 *db, const char *plt_name)
static const char *SQL =
"WITH plt_id AS (SELECT playlist.id AS id FROM playlist"
" WHERE name COLLATE nocase = ?) "
"INSERT INTO kara_playlist (kara_id, playlist_id)"
"INSERT OR IGNORE INTO kara_playlist (kara_id, playlist_id)"
" SELECT DISTINCT kara_id, plt_id.id"
" FROM queue, plt_id"
" ORDER BY RANDOM();";
......
......@@ -855,7 +855,7 @@ redo:
write_socket(sock, "%d listplaylist %s %s://", continuation,
args->argv[0], args->argv[1]);
for (i = 1; i < args->argc - 1; ++i)
for (i = 2; i < args->argc - 1; ++i)
write_socket(sock, "%s ", args->argv[i]);
write_socket(sock, "%s\n", args->argv[i]);
......
......@@ -254,6 +254,8 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
err = ! command_plt_import(srv->db, cmd.args, &srv->mpd_idle_events);
else if (STR_MATCH(cmd.name, "__dump"))
err = ! command_dump(srv->db, cmd.args, &srv->mpd_idle_events);
else if (STR_MATCH(cmd.name, "listplaylist"))
err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_playlist_init);
else if (STR_MATCH(cmd.name, "random"))
err = !command_set_playback_option(srv, c, lkt_playback_option_random, cmd.args);
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter