diff --git a/inc/lektor/cmd.h b/inc/lektor/cmd.h index 194881edac4efdc019d519a7ebbf1dc309e3c5cc..5e0a17b6be084c4f42423c76cff622486e4600d9 100644 --- a/inc/lektor/cmd.h +++ b/inc/lektor/cmd.h @@ -4,7 +4,8 @@ #include <stdnoreturn.h> #include <stddef.h> -#define LKT_OPT_NULL { .name = NULL, .call = NULL, .name_len = 0 } +#define LKT_OPT_NULL { .name = NULL, .call = NULL } +#define LKT_OPT_DEFAULT(func) { .name = NULL, .call = func } struct lkt_cmd_args { int argc; /* The number of arguments passed. */ @@ -15,7 +16,6 @@ typedef void (*lkt_cmd_callback)(struct lkt_cmd_args *); struct lkt_cmd_opt { const char *name; - size_t name_len; lkt_cmd_callback call; }; diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h index 1cc95b662f09d14105422e3284922576e58fdca0..e7199bed2efb1eb953f17b3735e9e16ac41d3ccf 100644 --- a/inc/lektor/commands.h +++ b/inc/lektor/commands.h @@ -39,6 +39,10 @@ bool command_crop(sqlite3 *db, enum mpd_idle_flag *watch_mask_ptr); bool command_move(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_flag *watch_mask_ptr); bool command_shuffle(sqlite3 *db, enum mpd_idle_flag *watch_mask_ptr); bool command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX]); +bool command_playid(sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], + enum mpd_idle_flag *watch_mask_ptr); +bool command_queue_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], + long continuation); /* The playlists */ bool command_plt_create(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_flag *watch_mask_ptr); @@ -83,9 +87,7 @@ enum lkt_playback_option { lkt_playback_option_volume, }; -bool command_set_playback_option(struct lkt_state *srv, - size_t c, - enum lkt_playback_option opt, +bool command_set_playback_option(struct lkt_state *srv, size_t c, enum lkt_playback_option opt, char *args[LKT_MESSAGE_ARGS_MAX]); /* Authentificate users */ diff --git a/inc/lektor/database.h b/inc/lektor/database.h index 748916227b2fe9597a9e86c5fd5be187302ca837..d1bce791f8824e3a9547e96888df225670deb8b8 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -67,6 +67,7 @@ bool database_queue_clear(sqlite3 *db); bool database_queue_crop(sqlite3 *db); bool database_queue_move(sqlite3 *db, int from, int to); bool database_queue_shuffle(sqlite3 *db); +bool database_queue_seekid(sqlite3 *db, int id, int *out_pos); /* Control the playing state of the queue. */ bool database_queue_toggle_pause(sqlite3 *db); @@ -103,6 +104,7 @@ struct lkt_search { typedef bool (*lkt_search_database_func)(struct lkt_state *srv, size_t c, int id, int id_len, const char *row); +bool database_search_database_init(sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret); bool database_search_queue_init(sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret); bool database_search_iter(struct lkt_search *item); diff --git a/inc/lektor/defines.h b/inc/lektor/defines.h index c6eac5cdabfa5a5119f7f8be73bd1c53f2e2603c..84f263d6d7b056e62e29ae47aab22e002c22ddb3 100644 --- a/inc/lektor/defines.h +++ b/inc/lektor/defines.h @@ -13,6 +13,7 @@ #define LKT_DATABASE_NAME_KAUTHOR_YEAR "author_year" #define LKT_DATABASE_NAME_KLANG "language" #define LKT_DATABASE_KARA_COLUMNT_ANY "any_col" +#define LKT_DATABASE_KARA_ALL "string" #define LEKTOR_TAG_MAX 256 diff --git a/inc/lektor/macro.h b/inc/lektor/macro.h index 5403ef8ce96f0ebf4efc9bc18e87c0aa8b056eec..4b93b9e4b726b41adb61babe3ec9d45f7c817085 100644 --- a/inc/lektor/macro.h +++ b/inc/lektor/macro.h @@ -28,6 +28,17 @@ goto error; \ } +#define SQLITE_STEP(db, stmt, code, error) \ + if (sqlite3_step(stmt) != code) { \ + fprintf(stderr, " ! %s: Failed to step and get a row: %s\n", \ + __func__, sqlite3_errmsg(db)); \ + goto error; \ + } + +#define SQLITE_STEP_ROW(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_ROW, error) +#define SQLITE_STEP_DONE(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_DONE, error) +#define SQLITE_STEP_OK(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_OK, error) + #define SQLITE_DO_ROLLBACK(db) \ sqlite3_exec(db, "ROLLBACK TRANSACTION;\n", NULL, NULL, NULL); diff --git a/src/cmd.c b/src/cmd.c index f1983fb2882eb159a92dd57803090fa1c741bb7a..5e70e6d1dec9fefc9e7a381d377c51310f2dee5b 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -24,10 +24,11 @@ lkt_cmd_parse(struct lkt_cmd_opt *opts, int argc, const char **argv, void (*help it = opts + (++offset); } + /* Now search for a unique match */ if (count > 1) goto not_exclusive; - if (!call[1]) + if (!call[1] || count == 0) goto not_found; struct lkt_cmd_args arguments = { @@ -40,6 +41,15 @@ lkt_cmd_parse(struct lkt_cmd_opt *opts, int argc, const char **argv, void (*help exit(EXIT_FAILURE); not_found: + /* The default function */ + if (!it->name && it->call) { + struct lkt_cmd_args arguments = { + .argc = argc, + .argv = (const char **) argv, + }; + it->call(&arguments); + } + fprintf(stderr, "Command '%s' could not be found\n", argv[0]); exit(EXIT_FAILURE); diff --git a/src/commands.c b/src/commands.c index 9f29e29adf6a6a26fcdccaad8d24905dfa3c25e2..d03489ed66eb3824dbe1c970feffd1cc5b7f1a9c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -112,7 +112,7 @@ command_status(struct lkt_state *srv, size_t c) struct lkt_message *out; struct lkt_queue_state queue_state; struct lkt_win *win; - int elapsed, duration; + int elapsed, duration, songid = 0; const char *play_state; if (srv == NULL) @@ -125,6 +125,7 @@ command_status(struct lkt_state *srv, size_t c) return false; } + database_queue_current_kara(srv->db, NULL, &songid); win->get_elapsed(win, &elapsed); win->get_duration(win, &duration); @@ -142,13 +143,13 @@ command_status(struct lkt_state *srv, size_t c) "song: %d\n" "playlistlength: %d\n" "elapsed: %d\n" - "duration: %d\n", + "duration: %d\n" + "songid: %d\n", queue_state.volume, queue_state.repeat, queue_state.random, queue_state.single, queue_state.consume, play_state, queue_state.current < 0 ? -1 : queue_state.current - 1, - queue_state.length, elapsed, duration); + queue_state.length, elapsed, duration, songid); lkt_state_send(srv, c, out); - return true; } @@ -157,9 +158,7 @@ command_next(sqlite3 *db, struct lkt_win *win, enum mpd_idle_flag *watch_mask_pt { *watch_mask_ptr |= MPD_IDLE_PLAYER; char filepath[PATH_MAX]; - bool res = database_queue_next(db, filepath) && - win->load_file(win, filepath); - return res; + return database_queue_next(db, filepath) && win->load_file(win, filepath); } bool @@ -174,9 +173,33 @@ command_previous(sqlite3 *db, struct lkt_win *win, enum mpd_idle_flag *watch_mas { *watch_mask_ptr |= MPD_IDLE_PLAYER; char filepath[PATH_MAX]; - bool res = database_queue_prev(db, filepath) && - win->load_file(win, filepath); - return res; + return database_queue_prev(db, filepath) && win->load_file(win, filepath); +} + +static inline bool +__play_that_file(sqlite3 *db, struct lkt_win *win, int pos) +{ + char filepath[PATH_MAX]; + + if (pos == 0) + return false; + + if (!database_queue_play(db, (int) pos)) { + fprintf(stderr, " ! __play_that_file: command failed because of db interactions\n"); + return false; + } + + if (!database_queue_get_current_file(db, filepath)) { + fprintf(stderr, " ! __play_that_file: command failed because of get current\n"); + return false; + } + + if (!win->load_file(win, filepath)) { + fprintf(stderr, " ! __play_that_file: command failed because of get current\n"); + return false; + } + + return true; } bool @@ -184,66 +207,84 @@ command_play(sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_flag *watch_mask_ptr) { *watch_mask_ptr |= MPD_IDLE_PLAYER; - char filepath[PATH_MAX], *endptr; - long pos; + char *endptr; + long pos = 0; /* Argument handle. */ - if (args[0] == NULL) - pos = 1; - else { - pos = strtol(args[0], &endptr, 10); + pos = args[0] == NULL ? 1 : strtol(args[0], &endptr, 10); - if ((errno == ERANGE && (pos == LONG_MAX || pos == LONG_MIN)) - || (errno != 0 && pos == 0)) { - fprintf(stderr, " ! command_play: strtol failed: %s\n", strerror(errno)); - goto error; - } + if ((errno == ERANGE && (pos == LONG_MAX || pos == LONG_MIN)) + || (errno != 0 && pos == 0)) { + fprintf(stderr, " ! command_play: strtol failed: %s\n", strerror(errno)); + return false; + } - if (endptr == args[0]) { - fprintf(stderr, " . command_play: to digit found in string '%s'\n", args[1]); - goto error; - } + if (endptr == args[0]) { + fprintf(stderr, " . command_play: to digit found in string '%s'\n", args[1]); + return false; } /* Do the actual job here. */ - if (win->window) - win->close(win); + database_queue_stop(db); if (!win->new (win)) { fprintf(stderr, " ! command_play: command failed because of null mpv ctx\n"); - goto error; + return false; } - if (!database_queue_play(db, (int) pos)) { - fprintf(stderr, " ! command_play: command failed because of db interactions\n"); - goto error; - } + return __play_that_file(db, win, pos); +} - if (!database_queue_get_current_file(db, filepath)) { - fprintf(stderr, " ! command_play: command failed because of get current\n"); - goto error; +bool +command_playid(sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], + enum mpd_idle_flag *watch_mask_ptr) +{ + *watch_mask_ptr |= MPD_IDLE_PLAYER; + char *endptr; + int pos = 0; + long id; + + /* Argument handle. */ + + if (args[0] == NULL) + return false; + + id = strtol(args[0], &endptr, 10); + + if ((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) + || (errno != 0 && id == 0)) { + fprintf(stderr, " ! command_playid: strtol failed: %s\n", strerror(errno)); + return false; } - if (!win->load_file(win, filepath)) { - fprintf(stderr, " ! command_play: command failed because of get current\n"); - goto error; + if (endptr == args[0]) { + fprintf(stderr, " . command_playid: to digit found in string '%s'\n", args[1]); + return false; } - return true; -error: - return false; + /* Do the work. */ + + database_queue_stop(db); + + if (!win->new (win)) + return false; + + database_queue_seekid(db, (int) id, &pos); + return __play_that_file(db, win, pos); } + bool command_stop(sqlite3 *db, struct lkt_win *win, enum mpd_idle_flag *watch_mask_ptr) { - *watch_mask_ptr |= MPD_IDLE_PLAYER; - bool res = database_queue_stop(db); - if (res) + if (database_queue_stop(db)) { win->close(win); - return res; + *watch_mask_ptr |= MPD_IDLE_PLAYER; + return true; + } + return false; } bool @@ -258,10 +299,8 @@ command_add(sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], *watch_mask_ptr |= MPD_IDLE_PLAYLIST; struct lkt_uri_t uri; char *query = args[0]; - bool ret, is_insert = false; - int priority = 1; /* To be modified according to the command (insert or add) later */ + int ret, priority = 1; /* To be modified according to the command (insert or add) later (TODO) */ - (void) is_insert; // Don't know what insert looks like (void) win; // No callbacks to the window for the moment if (!lkt_uri_from(&uri, query)) { @@ -373,11 +412,8 @@ command_delid(sqlite3 *db, struct lkt_win *win, char *id_str, enum mpd_idle_flag pointer to reload the kara in the same position (but the kara won't be the same). */ database_queue_current_kara(db, NULL, &uri); - if (id == (long) uri) { - fprintf(stderr, " . command_delid: Can't delete the currently playing kara\n"); + if (id == (long) uri) return false; - } - return database_queue_del_id(db, id); } @@ -431,12 +467,10 @@ command_help(struct lkt_state *srv, size_t c) { struct lkt_message *out; int idx; - out = lkt_message_new(); idx = snprintf(out->data, LKT_MESSAGE_MAX, "HELP\n"); out->data_len = idx; lkt_state_send(srv, c, out); - return true; } @@ -515,7 +549,6 @@ lkt_callback_send_row_v1(void *_args, int id, int id_len, const char *sql_row) { struct lkt_callback *args = (struct lkt_callback *) _args; struct lkt_message *out; - out = lkt_message_new(); out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%*d %s\n", id_len, id, sql_row); lkt_state_send(args->srv, args->c, out); @@ -540,9 +573,9 @@ lkt_callback_insert_v1(struct lkt_state *srv, size_t c, int id, int id_len, cons return database_queue_add_id(srv->db, id, 5); } -bool -command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation, - enum lkt_find_action action) +static bool +__find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation, + enum lkt_find_action action, bool(*init)(sqlite3 *, char *, char *, struct lkt_search *)) { char rgx[PATH_MAX], *col_name, *mpd_tag; int count; @@ -553,13 +586,15 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA .msg_count = lkt_remaining_msg(srv, c) - 3, /* Reserve slots for OK/ACK and continue: */ }; - // Check args // + /* Check args */ + if (cmd_args == NULL || cmd_args[0] == NULL) { - fprintf(stderr, " ! command_find: Argument invalid, empty cmd_args\n"); + fprintf(stderr, " ! __find: Argument invalid, empty cmd_args\n"); return false; } - // Select callback // + /* Select callback */ + switch (action) { case LKT_FND_ACT_RESPOND: search.call = (void(*)(void)) lkt_callback_send_row_v2; @@ -575,7 +610,8 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA return false; } - // Select the right column // + /* Select the right column */ + mpd_tag = cmd_args[0]; if (!strcasecmp("any", mpd_tag) || @@ -596,10 +632,13 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA col_name = LKT_DATABASE_NAME_KLANG; else if (!strcasecmp("date", mpd_tag)) col_name = LKT_DATABASE_NAME_KAUTHOR_YEAR; + else if (!strcasecmp("id", mpd_tag)) + col_name = LKT_DATABASE_NAME_KID; else - col_name = LKT_DATABASE_KARA_COLUMNT_ANY; + return false; + + /* Get the regex */ - // Get the regex // if (!cmd_args[1]) goto no_rgx; memset(rgx, 0, PATH_MAX * sizeof(char)); @@ -610,9 +649,10 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA strncat(rgx, " ", PATH_MAX - 1); } - // Make the search langand do the right action // - if (!database_search_queue_init(srv->db, col_name, rgx, &search)) { - fprintf(stderr, " ! command_find: Failed to init the search\n"); + /* Make the search langand do the right action */ + + if (!init(srv->db, col_name, rgx, &search)) { + fprintf(stderr, " ! __find: Failed to init the search\n"); return false; } @@ -627,8 +667,21 @@ no_rgx: } bool -command_set_playback_option(struct lkt_state *srv, size_t c, - enum lkt_playback_option opt, char *args[LKT_MESSAGE_MAX]) +command_queue_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation) +{ + return __find(srv, c, cmd_args, continuation, LKT_FND_ACT_RESPOND, database_search_queue_init); +} + +bool +command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation, + enum lkt_find_action action) +{ + return __find(srv, c, cmd_args, continuation, action, database_search_database_init); +} + +bool +command_set_playback_option(struct lkt_state *srv, size_t c, enum lkt_playback_option opt, + char *args[LKT_MESSAGE_MAX]) { if (srv == NULL) return false; @@ -758,23 +811,21 @@ command_plt_remove(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_ return database_plt_remove(db, args[0]); } - else { - pos = strtol(args[1], &endptr, 10); - - if ((errno == ERANGE && (pos == LONG_MAX || pos == LONG_MIN)) - || (errno != 0 && pos == 0)) { - fprintf(stderr, " ! command_plt_remove: strtol failed: %s\n", strerror(errno)); - return false; - } + pos = strtol(args[1], &endptr, 10); - if (endptr == args[1]) { - fprintf(stderr, " . command_plt_remove: to digit found in string '%s'\n", args[1]); - return false; - } + if ((errno == ERANGE && (pos == LONG_MAX || pos == LONG_MIN)) + || (errno != 0 && pos == 0)) { + fprintf(stderr, " ! command_plt_remove: strtol failed: %s\n", strerror(errno)); + return false; + } - *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - return database_plt_remove_pos(db, args[0], pos); + if (endptr == args[1]) { + fprintf(stderr, " . command_plt_remove: to digit found in string '%s'\n", args[1]); + return false; } + + *watch_mask_ptr |= MPD_IDLE_PLAYLIST; + return database_plt_remove_pos(db, args[0], pos); } bool @@ -783,12 +834,12 @@ command_plt_clear(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_f if (args == NULL || args[0] == NULL) return false; - if (database_plt_clear(db, args[0])) { - *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - return true; - } else + if (!database_plt_clear(db, args[0])) return false; + *watch_mask_ptr |= MPD_IDLE_PLAYLIST; + return true; + } bool @@ -797,59 +848,51 @@ command_plt_rename(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_ if (args == NULL || args[0] == NULL || args[1] == NULL) return false; - if (database_plt_rename(db, args[0], args[1])) { - *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - return true; - } else + if (!database_plt_rename(db, args[0], args[1])) return false; + + *watch_mask_ptr |= MPD_IDLE_PLAYLIST; + return true; } bool command_plt_export(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_flag *watch_mask_ptr) { - int ret = false; - if (args == NULL || args[0] == NULL || args[1] == NULL) return false; if (!database_attach(db, args[0], args[1])) - goto error; + return false; if (!database_plt_export(db, args[0])) - goto error; + return false; if (!database_detach(db, args[0])) - goto error; + return false; fprintf(stderr, " * Exported playlist %s with path '%s'\n", args[0], args[1]); *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - ret = true; -error: - return ret; + return true; } bool command_plt_import(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_flag *watch_mask_ptr) { - int ret = false; - if (args == NULL || args[0] == NULL || args[1] == NULL) return false; if (!database_attach(db, args[0], args[1])) - goto error; + return false; if (!database_plt_import(db, args[0])) - goto error; + return false; if (!database_detach(db, args[0])) - goto error; + return false; fprintf(stderr, " * Imported playlist %s with path '%s'\n", args[0], args[1]); *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - ret = true; -error: - return ret; + return true; } bool @@ -877,9 +920,7 @@ command_plt_add_uri(sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle bool command_shuffle(sqlite3 *db, enum mpd_idle_flag *watch_mask_ptr) { - bool ret = database_queue_shuffle(db); - - if (ret) { + if (database_queue_shuffle(db)) { *watch_mask_ptr |= MPD_IDLE_PLAYER; return true; } @@ -1005,8 +1046,8 @@ command_user_add(sqlite3 *db, char *argv[LKT_MESSAGE_ARGS_MAX]) return true; } - return false; fprintf(stderr, " . command_user_add: Failed to add user %s\n", argv[0]); + return false; } /* Stickers */ diff --git a/src/database/config.c b/src/database/config.c index 0b33b1517b43da01d74db8d6481fc8b5f62ccbe0..f1311d3c2cfeafd0e46f1a486939f50bbb3e0715 100644 --- a/src/database/config.c +++ b/src/database/config.c @@ -180,10 +180,7 @@ database_get_config(sqlite3 *db, const char *option, int *value) snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TMP, option); SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0; SQLITE_PREPARE(db, stmt, SQL_STMT, error); - - if (sqlite3_step(stmt) != SQLITE_ROW) - goto error; - + SQLITE_STEP_ROW(db, stmt, error); *value = sqlite3_column_int(stmt, 0); ret = true; error: diff --git a/src/database/find.c b/src/database/find.c index a0366d65482adc127bb0aa9af4d627205cb6be22..f76f556986fc660150160c44e76e350a72b82f9b 100644 --- a/src/database/find.c +++ b/src/database/find.c @@ -8,7 +8,7 @@ #include <string.h> bool -database_search_queue_init(sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret) +database_search_database_init(sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret) { if (ret == NULL) { fprintf(stderr, " ! database_search_init: Exit because return pointer is NULL\n"); @@ -36,6 +36,38 @@ error: return false; } + +bool +database_search_queue_init(sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret) +{ + if (ret == NULL) { + fprintf(stderr, " ! database_search_init: Exit because return pointer is NULL\n"); + return false; + } + + static const char *SQL_STMT_TEMPLATE = + "WITH content AS (" + " SELECT kara_id AS id, string AS any_col, LENGTH(CAST(kara_id AS TEXT)) AS len" + " FROM queue_ " + " JOIN kara " + " ON kara_id = kara.id AND %s LIKE ?)" + "SELECT id, any_col, (SELECT MAX(len) FROM content)" + "FROM content LIMIT %d OFFSET %d;"; + char SQL_STMT[LKT_MAX_SQLITE_STATEMENT]; + + snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TEMPLATE, col_name, + ret->msg_count, ret->continuation); + SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0; + SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error); + SQLITE_BIND_TEXT(db, ret->stmt, 1, rgx, error); + ret->db = db; + /* Assign the callback. */ + return true; +error: + sqlite3_finalize(ret->stmt); + return false; +} + bool database_search_iter(struct lkt_search *item) { diff --git a/src/database/open.c b/src/database/open.c index 662e6aa704229dde7fbaf2f814cb03856baa6c3b..424fe81006eeca8549e8523e0462982ee5ec3db5 100644 --- a/src/database/open.c +++ b/src/database/open.c @@ -126,10 +126,8 @@ __is_attached(sqlite3 *db, const char *name) SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - - if (sqlite3_step(stmt) == SQLITE_ROW) - ret = true; - + SQLITE_STEP_ROW(db, stmt, error); + ret = true; error: sqlite3_finalize(stmt); return ret; diff --git a/src/database/playlist.c b/src/database/playlist.c index 7750a1b9796afe75563bb9e0ed8f9cd268a41078..07e3170aed33a82c0c5763a323afae37d0f2f48e 100644 --- a/src/database/playlist.c +++ b/src/database/playlist.c @@ -16,16 +16,9 @@ database_plt_create(sqlite3 *db, const char *name) "INSERT INTO playlist (name, last_update) VALUES (?, strftime('%s', 'now'));"; sqlite3_stmt *stmt = NULL; bool sta = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! database_plt_create: expected SQLITE_DONE in step: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); sta = true; fprintf(stderr, " . database_plt_create: Created playlist %s\n", name); error: @@ -36,20 +29,12 @@ error: bool database_plt_remove(sqlite3 *db, const char *name) { - static const char *SQL_STMT = - "DELETE FROM playlist WHERE name = ?;"; + static const char *SQL_STMT = "DELETE FROM playlist WHERE name = ?;"; sqlite3_stmt *stmt = NULL; bool sta = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! database_plt_remove: expected SQLITE_DONE in step: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); @@ -60,20 +45,14 @@ bool database_plt_remove_pos(sqlite3 *db, const char *name, int pos) { static const char *SQL_STMT = - "DELETE FROM kara_playlist WHERE playlist_id = (SELECT id FROM playlist WHERE name = ? LIMIT 1) and kara_id = ?;"; + "DELETE FROM kara_playlist " + "WHERE playlist_id = (SELECT id FROM playlist WHERE name = ? LIMIT 1) and kara_id = ?;"; sqlite3_stmt *stmt = NULL; bool sta = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); SQLITE_BIND_INT(db, stmt, 2, pos, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_plt_remove_pos: expected SQLITE_DONE in step: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); @@ -87,16 +66,9 @@ database_plt_clear(sqlite3 *db, const char *name) "DELETE FROM kara_playlist WHERE playlist_id = (SELECT id FROM playlist WHERE name = ?);"; sqlite3_stmt *stmt = NULL; bool sta = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_plt_clear: expected SQLITE_DONE in step: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); @@ -106,21 +78,13 @@ error: bool database_plt_rename(sqlite3 *db, const char *old_name, const char *new_name) { - static const char *SQL_STMT = - "UPDATE playlist SET name = ? WHERE name = ?;"; + static const char *SQL_STMT = "UPDATE playlist SET name = ? WHERE name = ?;"; sqlite3_stmt *stmt = NULL; bool sta = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, new_name, error); SQLITE_BIND_TEXT(db, stmt, 2, old_name, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_plt_rename: expected SQLITE_DONE in step: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); @@ -235,13 +199,7 @@ database_plt_add_uri(sqlite3 *db, const char *name, struct lkt_uri_t *uri) SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); SQLITE_BIND_TEXT(db, stmt, 2, (char *) uri->value, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! database_plt_add_uri: expected SQLITE_DONE in step: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); diff --git a/src/database/queue.c b/src/database/queue.c index 2b54a4d4e238300db2422b1b5fd42de49b87a11e..cfb55e007b66132320e051d74dbfbb11a0367359 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -22,11 +22,7 @@ database_queue_state(sqlite3 *db, struct lkt_queue_state *res) bool ret = false; SQLITE_PREPARE(db, stmt, SQL_STMT, error); - - if (sqlite3_step(stmt) != SQLITE_ROW) { - fprintf(stderr, " ! database_queue_state: queue_state has no row.\n"); - goto error; - } + SQLITE_STEP_ROW(db, stmt, error); res->volume = sqlite3_column_int(stmt, 0); res->paused = sqlite3_column_int(stmt, 1); @@ -64,28 +60,23 @@ database_queue_current_kara(sqlite3 *db, struct kara_metadata *res, int *id) int ret = false; SQLITE_PREPARE(db, stmt, SQL_STMT, error); - - if (sqlite3_step(stmt) == SQLITE_ROW) { - /* Here use gotos because of optimisations done by compilators. - Most of the time it won't be NULL. */ - if (!res) - goto no_metadata; - strncpy(res->song_name, (const char *) sqlite3_column_text(stmt, 0), LEKTOR_TAG_MAX - 1); - strncpy(res->source_name, (const char *) sqlite3_column_text(stmt, 1), LEKTOR_TAG_MAX - 1); - strncpy(res->category, (const char *) sqlite3_column_text(stmt, 2), LEKTOR_TAG_MAX - 1); - strncpy(res->language, (const char *) sqlite3_column_text(stmt, 3), LEKTOR_TAG_MAX - 1); - strncpy(res->author_name, (const char *) sqlite3_column_text(stmt, 4), LEKTOR_TAG_MAX - 1); - strncpy(res->song_type, (const char *) sqlite3_column_text(stmt, 5), LEKTOR_TAG_MAX - 1); - res->song_number = sqlite3_column_int(stmt, 6); + SQLITE_STEP_ROW(db, stmt, error); + + /* Here use gotos because of optimisations done by compilators. + Most of the time it won't be NULL. */ + if (!res) + goto no_metadata; + strncpy(res->song_name, (const char *) sqlite3_column_text(stmt, 0), LEKTOR_TAG_MAX - 1); + strncpy(res->source_name, (const char *) sqlite3_column_text(stmt, 1), LEKTOR_TAG_MAX - 1); + strncpy(res->category, (const char *) sqlite3_column_text(stmt, 2), LEKTOR_TAG_MAX - 1); + strncpy(res->language, (const char *) sqlite3_column_text(stmt, 3), LEKTOR_TAG_MAX - 1); + strncpy(res->author_name, (const char *) sqlite3_column_text(stmt, 4), LEKTOR_TAG_MAX - 1); + strncpy(res->song_type, (const char *) sqlite3_column_text(stmt, 5), LEKTOR_TAG_MAX - 1); + res->song_number = sqlite3_column_int(stmt, 6); no_metadata: - /* Most of the time this will be NULL. */ - if (id && sqlite3_column_type(stmt, 7) != SQLITE_NULL) - *id = sqlite3_column_int(stmt, 7); - } else { - fprintf(stderr, " ! database_queue_current_kara: failed: %s\n", - sqlite3_errmsg(db)); - goto error; - } + /* Most of the time this will be NULL. */ + if (id && sqlite3_column_type(stmt, 7) != SQLITE_NULL) + *id = sqlite3_column_int(stmt, 7); ret = true; error: @@ -116,13 +107,7 @@ queue_add_with_col_like_str(sqlite3 *db, const char *col, const char *val, int p SQLITE_PREPARE(db, stmt, SQL, error); SQLITE_BIND_INT(db, stmt, 1, priority, error); SQLITE_BIND_TEXT(db, stmt, 2, val, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! queue_add_with_col_like_str: Failed to insert: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); status = true; error: sqlite3_finalize(stmt); @@ -169,13 +154,7 @@ queue_insert_with_col_like_str(sqlite3 *db, const char *col, const char *val, in SQLITE_PREPARE(db, stmt, SQL, error); SQLITE_BIND_INT(db, stmt, 1, pos, error); SQLITE_BIND_TEXT(db, stmt, 2, val, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! queue_insert_with_col_like_str: Failed to insert: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); status = true; error: sqlite3_finalize(stmt); @@ -185,13 +164,9 @@ error: bool database_queue_insert_query(sqlite3 *db, const char *query, int pos) { - bool status = queue_insert_with_col_like_str(db, "string", query, pos); - - if (status) - fprintf(stderr, " * database_queue_insert_query: Successfull add for query '%s'\n", query); - else - fprintf(stderr, " ! database_queue_insert_query: Failed to add for query '%s'\n", query); - + bool status = queue_insert_with_col_like_str(db, LKT_DATABASE_KARA_ALL, query, pos); + fprintf(stderr, " . %s: %s '%s'\n", __func__, + status ? "Successfull add query" : "Failed add query", query); return status; } @@ -211,13 +186,7 @@ database_queue_add_plt(sqlite3 *db, const char *plt_name, int priority) SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_INT(db, stmt, 1, priority, error); SQLITE_BIND_TEXT(db, stmt, 2, plt_name, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! database_queue_add_plt: Failed to insert: %s\n", - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); status = true; error: sqlite3_finalize(stmt); @@ -227,66 +196,45 @@ error: bool database_queue_add_query(sqlite3 *db, const char *query, int priority) { - bool status = queue_add_with_col_like_str(db, "string", query, priority); - - if (status) - fprintf(stderr, " * database_queue_add_query: Successfull add for query '%s'\n", query); - else - fprintf(stderr, " ! database_queue_add_query: Failed to add for query '%s'\n", query); - + bool status = queue_add_with_col_like_str(db, LKT_DATABASE_KARA_ALL, query, priority); + fprintf(stderr, " . %s: %s '%s'\n", __func__, + status ? "Successfull add query" : "Failed add query", query); return status; } bool database_queue_add_author(sqlite3 *db, const char *author, int priority) { - bool status = queue_add_with_col_like_str(db, "author_name", author, priority); - - if (status) - fprintf(stderr, " * database_queue_add_author: Successfull add for author '%s'\n", author); - else - fprintf(stderr, " ! database_queue_add_author: Failed to add for author '%s'\n", author); - + bool status = queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KAUTHOR, author, priority); + fprintf(stderr, " . %s: %s '%s'\n", __func__, + status ? "Successfull add author" : "Failed add author", author); return status; } bool database_queue_add_language(sqlite3 *db, const char *language, int priority) { - bool status = queue_add_with_col_like_str(db, "language", language, priority); - - if (status) - fprintf(stderr, " * database_queue_add_language: Successfull add for language '%s'\n", language); - else - fprintf(stderr, " ! database_queue_add_language: Failed to add for language '%s'\n", language); - + bool status = queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KLANG, language, priority); + fprintf(stderr, " . %s: %s '%s'\n", __func__, + status ? "Successfull add language" : "Failed add language", language); return status; } bool database_queue_add_category(sqlite3 *db, const char *cat, int priority) { - bool status = queue_add_with_col_like_str(db, "song_type", cat, priority); - - if (status) - fprintf(stderr, " * database_queue_add_category: Successfull add for category (lektor song_type) '%s'\n", - cat); - else - fprintf(stderr, " ! database_queue_add_category: Failed to add for category (lektor song_type) '%s'\n", cat); - + bool status = queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KCAT, cat, priority); + fprintf(stderr, " . %s: %s '%s'\n", __func__, + status ? "Successfull add category" : "Failed add category", cat); return status; } bool database_queue_add_type(sqlite3 *db, const char *type, int priority) { - bool status = queue_add_with_col_like_str(db, "category", type, priority); - - if (status) - fprintf(stderr, " * database_queue_add_type: Successfull add for type (lektor category) '%s'\n", type); - else - fprintf(stderr, " ! database_queue_add_type: Failed to add for type (lektor category) '%s'\n", type); - + bool status = queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KTYPE, type, priority); + fprintf(stderr, " . %s: %s '%s'\n", __func__, + status ? "Successfull add type" : "Failed add type", type); return status; } @@ -296,14 +244,10 @@ database_queue_add_id(sqlite3 *db, int id, int priority) static const char *SQL_STMT = "INSERT INTO queue (kara_id, priority) VALUES (?,?);"; bool status = false; sqlite3_stmt *stmt = NULL; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_INT(db, stmt, 1, id, error); SQLITE_BIND_INT(db, stmt, 2, priority, error); - - if (sqlite3_step(stmt) != SQLITE_DONE) - goto error; - + SQLITE_STEP_DONE(db, stmt, error); status = true; error: sqlite3_finalize(stmt); @@ -600,13 +544,7 @@ error: bool database_queue_set_paused(sqlite3 *db, bool paused) { - const char *SQL; - - if (paused) - SQL = "UPDATE queue_state SET paused = 1;"; - else - SQL = "UPDATE queue_state SET paused = 0;"; - + const char *SQL = paused ? "UPDATE queue_state SET paused = 1;" : "UPDATE queue_state SET paused = 0;"; SQLITE_EXEC(db, SQL, error); return true; error: @@ -665,7 +603,6 @@ database_queue_shuffle(sqlite3 *db) " ELSE NULL" " END;" "COMMIT;"; - SQLITE_EXEC(db, SQL, error); return true; error: @@ -721,3 +658,20 @@ error: sqlite3_finalize(stmt); return ret; } + +bool +database_queue_seekid(sqlite3 *db, int id, int *out_pos) +{ + static const char *SQL_STMT = "SELECT position FROM queue_ WHERE kara_id = ? LIMIT 1"; + int ret; + sqlite3_stmt *stmt; + + SQLITE_PREPARE(db, stmt, SQL_STMT, error); + SQLITE_BIND_INT(db, stmt, 1, id, error); + SQLITE_STEP_ROW(db, stmt, error); + *out_pos = sqlite3_column_int(stmt, 0); + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} diff --git a/src/database/stickers.c b/src/database/stickers.c index 1fd2b2375190587c35883a955087f3453a855313..b36b4c70fb9aa0456de8edb198db8a953fd74f31 100644 --- a/src/database/stickers.c +++ b/src/database/stickers.c @@ -29,13 +29,7 @@ database_sticker_create(sqlite3 *db, const char *name) SQLITE_PREPARE(db, stmt, INSERT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); SQLITE_BIND_TEXT(db, stmt, 2, name, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_sticker_create: Failed to create sticker '%s': %s\n", - name, sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); @@ -57,13 +51,7 @@ database_sticker_delete(sqlite3 *db, const char *name) SQLITE_PREPARE(db, stmt, INSERT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_sticker_delete: Failed to delete sticker '%s': %s\n", - name, sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); @@ -164,13 +152,7 @@ database_sticker_set(sqlite3 *db, const char *type, const char *name, int uri, i SQLITE_BIND_INT(db, stmt, 1, uri, error); SQLITE_BIND_INT(db, stmt, 2, value, error); SQLITE_BIND_TEXT(db, stmt, 3, name, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_sticker_set: Failed to update or set sticker '%s' for " - "'%s' %d: %s\n", name, type, uri, sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); @@ -262,10 +244,7 @@ database_sticker_delete_specify(sqlite3 *db, const char *type, int uri, const ch if (name) SQLITE_BIND_TEXT(db, stmt, 2, name, error); - if (! (ret = (sqlite3_step(stmt) == SQLITE_OK))) { - fprintf(stderr, " . database_sticker_delete_specify: Failed to delete sticker\n"); - goto error; - } + SQLITE_STEP_OK(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); diff --git a/src/database/update.c b/src/database/update.c index da52f2041a39e911427823b68ce88825351ca304..ae1c9c6dcd9c7cdf0c8fa2bba70a02c2c92030b7 100644 --- a/src/database/update.c +++ b/src/database/update.c @@ -61,14 +61,7 @@ database_add_kara(sqlite3 *db, const char *filename) goto error; } - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, - " ! database_add_kara: expected SQLITE_DONE after execution of stmt statement for kara %s: %s\n", - filename, - sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); status = true; error: sqlite3_finalize(stmt); @@ -123,12 +116,7 @@ database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *md goto error; } - if (sqlite3_step(stmt) != SQLITE_DONE) { - fprintf(stderr, " ! database_add_kara: expected sqlite_done after execution of stmt " - "statement for kara %s: %s\n", kara_path, sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_DONE(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); diff --git a/src/database/user.c b/src/database/user.c index c7bf11ecfb67a3feca5fac056757a9c57670c2f0..38704430d4c7f979ddbff6989446caa320d3612d 100644 --- a/src/database/user.c +++ b/src/database/user.c @@ -10,18 +10,11 @@ database_user_authentificate(sqlite3 *db, const char *password) static const char *SQL_STMT = "SELECT username FROM users WHERE password = ?"; sqlite3_stmt *stmt = 0; bool ret = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, password, error); - - if (sqlite3_step(stmt) != SQLITE_ROW) { - fprintf(stderr, " ! database_user_authentificate: No user found\n"); - goto error; - } - + SQLITE_STEP_ROW(db, stmt, error); fprintf(stderr, " * User authentification was successfull for user %s\n", sqlite3_column_text(stmt, 0)); - ret = true; error: sqlite3_finalize(stmt); @@ -34,19 +27,11 @@ database_user_add(sqlite3 *db, const char *username, const char *password) static const char *SQL_STMT = "INSERT INTO users (username, password) VALUES (?, ?)"; sqlite3_stmt *stmt = 0; bool ret = false; - SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, username, error); SQLITE_BIND_TEXT(db, stmt, 2, password, error); - - if (sqlite3_step(stmt) != SQLITE_OK) { - fprintf(stderr, " ! database_user_add: Failed to add user %s: %s\n", - username, sqlite3_errmsg(db)); - goto error; - } - + SQLITE_STEP_OK(db, stmt, error); fprintf(stderr, " * User %s added successfully\n", username); - ret = true; error: sqlite3_finalize(stmt); diff --git a/src/main/lkt.c b/src/main/lkt.c index ca1875c915f442f750855d5ac1e85c22cb613598..8781e704f0aa1193d3fcf0147b1a4f0983a31600 100644 --- a/src/main/lkt.c +++ b/src/main/lkt.c @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L +#include <lektor/macro.h> #include <lektor/defines.h> #include <lektor/net.h> #include <lektor/cmd.h> @@ -45,29 +46,34 @@ help(void) "\n" " COMMANDS:\n" " help display this help message.\n" - " play <?idx> toggle play/pause state of lektor, may start at a certain index.\n" + " play [?idx] toggle play/pause state of lektor, may start at a certain index.\n" " stop stop the playback but not the window if it exists.\n" " status get the status of lektor.\n" " current get the currently playing song.\n" - " add <query> add a kara to the playlist with a query.\n" - " delete <id> delete the id from the queue.\n" - " clear clear the queue of lektor.\n" " prev play previous kara in the queue.\n" " next play the next kara in the queue.\n" " shuffle shuffle lektor's playlist and play it from the begening.\n" - " queue <?arg> prints the queue. The argument is either a range or a count from the current kara.\n" + " queue tge queue sub command.\n" " plt the playlist sub command.\n" " search the search sub command.\n" "\n" + " QUEUE COMMANDS:\n" + " pos <arg> the qrgument can be a position or a range.\n" + " <count> prints the next songs in the queue.\n" + " pop [pos] pop a song in the queue.\n" + " add <query> add a kara to the queue with a query.\n" + " seek <query> seek the next song that matchs the query.\n" + " delete <id> delete the song by its id in the queue.\n" + " clear clear the queue.\n" + " crop crop the queue.\n" + "\n" " PLAYLIST COMMANDS:\n" - " help display this help message.\n" " create <plt> creates a playlist after the argument.\n" " destroy <plt> delete a playlist after the argument.\n" " add <plt> <type> <query> add something to a playlist from the database.\n" " delete <plt> <id> delete domething from a playlist.\n" "\n" " SEARCH COMMANDS:\n" - " help display this help message.\n" " get <query> prints the results of the query.\n" " add <query> add to the queue and prints the results of the query.\n" " insert <query> insert on top of the aueue and prints the results of the query.\n" @@ -82,10 +88,7 @@ help(void) " Supported types are: title, [a]ny, source, [auth]or, [lang]uage, type, title\n" "\n" " RANGE:\n" - " A range is specified like in python:\n" - " - BEGIN:END which implies from BEGIN to END included\n" - " - :END which implies from the very begining to END included\n" - " - BEGIN: which implies from BEGIN to the very end included\n" + " A range is specified like BEGIN:END which implies from BEGIN to END included\n" "\n"; write(1, help_str, strlen(help_str)); exit(EXIT_SUCCESS); @@ -254,7 +257,7 @@ lkt_skip_key(char *buffer) /* Functions implementing options. */ noreturn void -clear__(struct lkt_cmd_args *args) +queue_clear__(struct lkt_cmd_args *args) { if (args->argc != 0) fail("Invalid argument, the clear command takes no arguments"); @@ -262,6 +265,15 @@ clear__(struct lkt_cmd_args *args) lkt_send_and_exit(cmd__, sizeof(cmd__)); } +noreturn void +queue_crop__(struct lkt_cmd_args *args) +{ + if (args->argc != 0) + fail("Invalid argument, the crop command takes no arguments"); + static const char cmd__[] = "crop\nclose\n"; + lkt_send_and_exit(cmd__, sizeof(cmd__)); +} + noreturn void next__(struct lkt_cmd_args *args) @@ -412,6 +424,48 @@ error: exit(EXIT_FAILURE); } +noreturn void +queue_pop__(struct lkt_cmd_args *args) +{ + if (args->argc != 0) + fail("Invalid argument, the status command takes no arguments"); + + int ret = EXIT_FAILURE, songid = 0; + char buff[LKT_MESSAGE_MAX]; + FILE *sock = lkt_connect(); + + /* Get lektor's status. */ + + if (write_socket(sock, "status\n", sizeof("status\n"))) + goto error; + +#define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } + + for (;;) { + memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); + if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) + goto error; + + size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); + assign_int("songid", songid) + + /* At this point every key has been parsed. */ + if (! strncmp(buff, "OK", 2)) + break; + else if (! strncmp(buff, "ACK", 3)) + goto error; + } + + fclose(sock); + sock = lkt_connect(); + if (!songid) + goto error; + write_socket_format(sock, "next\ndeleteid %d\n", songid); + ret = EXIT_SUCCESS; +error: + exit(ret); +} + noreturn void status__(struct lkt_cmd_args *args) { @@ -499,7 +553,7 @@ shuffle__(struct lkt_cmd_args *args) } noreturn void -delete__(struct lkt_cmd_args *args) +queue_delete__(struct lkt_cmd_args *args) { if (args->argc != 1) fail("Invalid argument, need onlt one argument"); @@ -526,7 +580,7 @@ check: } noreturn void -add__(struct lkt_cmd_args *args) +queue_add__(struct lkt_cmd_args *args) { char buff[LKT_MESSAGE_MAX]; int i; @@ -565,15 +619,35 @@ add__(struct lkt_cmd_args *args) } noreturn void -list__(struct lkt_cmd_args *args) +queue_seek__(struct lkt_cmd_args *args) { - char buff[LKT_MESSAGE_MAX], *endptr; + if (args->argc != 1) + fail("The seek command needs one argument"); - if (args->argc == 0) - args->argv = LKT_QUEUE_DEFAULT; + char *endptr, buf[3]; + long id = strtol(args->argv[0], &endptr, 0); + + if ((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) || + (errno != 0 && id == 0) || + (endptr == args->argv[0])) + fail("Invalid argument, not an integer"); - else if (args->argc > 1) - fail("Invalid argument for the queue command"); + if (*endptr != '\0') + fail("Invalid argument, must be only one integer"); + + FILE *sock = lkt_connect(); + write_socket_format(sock, "playid %ld\n", id); + read_socket(sock, buf, 2); + exit(!strncmp(buf, "OK", 2)); +} + +noreturn void +queue_pos__(struct lkt_cmd_args *args) +{ + char buff[LKT_MESSAGE_MAX], *endptr; + + if (args->argc != 1) + fail("Invalid argument for the pos command"); long continuation = 0, up = 0; @@ -619,6 +693,63 @@ redo: } } +noreturn void +queue_list__(struct lkt_cmd_args *args) +{ + char buff[LKT_MESSAGE_MAX], *endptr; + FILE *sock = NULL; + long continuation = 0, song_index = 1; + + /* Arguments stuff. */ + + if (args->argc == 0) + args->argv = LKT_QUEUE_DEFAULT; + else if (args->argc != 1) + fail("Invalid argument"); + + continuation = strtol(args->argv[0], &endptr, 0); + if ((errno == ERANGE && (continuation == LONG_MAX || continuation == LONG_MIN)) || (errno != 0 + && continuation == 0) || (endptr == args->argv[0])) + fail("Invalid argument, not an integer"); + + if (*endptr != '\0') + fail("Invalid argument"); + + /* Get the current pos to get limits for the playlist command. */ + + sock = lkt_connect(); + if (write_socket(sock, "status\n", sizeof("status\n"))) + fail("Communication error"); + +#define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } + + for (;;) { + memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); + if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) + fail("Connextion error"); + + size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); + assign_int("song", song_index); + + /* At this point every key has been parsed. */ + if (! strncmp(buff, "OK", 2)) + break; + else if (! strncmp(buff, "ACK", 3)) + exit(EXIT_FAILURE); + } + fclose(sock); + + /* Get the content of the queue. */ + + continuation = labs(continuation); + song_index = MAX(song_index + 1, 1); + snprintf(buff, LKT_MESSAGE_MAX - 1, "%ld:%ld", song_index, song_index + continuation - 1); + buff[LKT_MESSAGE_MAX - 1] = '\0'; + args->argc = 1; + args->argv[0] = buff; + queue_pos__(args); +} + /* Functions implementing options, but for for playlists. */ noreturn void @@ -803,11 +934,22 @@ search_count__(struct lkt_cmd_args *args) noreturn void search_queue__(struct lkt_cmd_args *args) { - search_with_cmd__(args, "playlistinfo"); + search_with_cmd__(args, "playlistfind"); } /* Parsing stuff. */ +static struct lkt_cmd_opt options_queue[] = { + { .name = "pos", .call = queue_pos__ }, + { .name = "pop", .call = queue_pop__ }, + { .name = "add", .call = queue_add__ }, + { .name = "seek", .call = queue_seek__ }, + { .name = "delete", .call = queue_delete__ }, + { .name = "clear", .call = queue_clear__ }, + { .name = "crop", .call = queue_crop__ }, + LKT_OPT_DEFAULT(queue_list__), +}; + static struct lkt_cmd_opt options_plt[] = { { .name = "help", .call = help__ }, { .name = "add", .call = plt_add__ }, @@ -828,6 +970,15 @@ static struct lkt_cmd_opt options_search[] = { LKT_OPT_NULL, }; +noreturn void +queue__(struct lkt_cmd_args *args) +{ + if (args->argc == 0) + queue_list__(args); + + lkt_cmd_parse(options_queue, args->argc, args->argv, help); +} + noreturn void search__(struct lkt_cmd_args *args) { @@ -848,14 +999,11 @@ plt__(struct lkt_cmd_args *args) static struct lkt_cmd_opt options_[] = { { .name = "help", .call = help__ }, - { .name = "clear", .call = clear__ }, { .name = "current", .call = current__ }, { .name = "play", .call = play__ }, - { .name = "delete", .call = delete__ }, { .name = "next", .call = next__ }, { .name = "previous", .call = prev__ }, - { .name = "queue", .call = list__ }, - { .name = "add", .call = add__ }, + { .name = "queue", .call = queue__ }, { .name = "shuffle", .call = shuffle__ }, { .name = "status", .call = status__ }, { .name = "stop", .call = stop__ }, diff --git a/src/mkv/write.c b/src/mkv/write.c index bb5ec481699eeb72e03b24664ec9f95bde5a6b6a..c29dd79ff08ee87b66cad1430dd10b167aaad400 100644 --- a/src/mkv/write.c +++ b/src/mkv/write.c @@ -72,12 +72,16 @@ mkvpropedit__(const char *const args[]) return false; } - execv("/usr/bin/mkvpropedit", (char *const *) args); + execv(args[0], (char *const *) args); exit(EXIT_FAILURE); - } else if (pid < 0) { + } + + else if (pid < 0) { fprintf(stderr, " ! metadata_write: failed to fork: %s\n", strerror(errno)); return false; - } else { + } + + else { do { if (waitpid(pid, &wstatus, WUNTRACED | WCONTINUED) == -1) { fprintf(stderr, " ! metadata_write: Failed to wait children: %s\n", @@ -121,12 +125,7 @@ kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char goto error; } - // First command // - if (!mkvpropedit__(args1)) - goto error; - - // Second command // - if (!mkvpropedit__(args2)) + if (!mkvpropedit__(args1) || !mkvpropedit__(args2)) goto error; sta = true; @@ -172,30 +171,8 @@ metadata_from_path(char *const mkvfile, struct kara_metadata *meta) sub_str_vec, sub_str_vec_len); if (pcre_exec_ret < 0) { - // Error // - switch (pcre_exec_ret) { - case PCRE_ERROR_NOMATCH: - fprintf(stderr, " ! metadata_from_path: No pattern match for file %s\n", mkvfile); - goto error; - case PCRE_ERROR_NULL: - fprintf(stderr, " ! metadata_from_path: Something was null for file %s\n", mkvfile); - goto error; - case PCRE_ERROR_BADOPTION: - fprintf(stderr, " ! metadata_from_path: Bad option passed for file %s\n", mkvfile); - goto error; - case PCRE_ERROR_BADMAGIC: - fprintf(stderr, " ! metadata_from_path: Magic number bad for file %s\n", mkvfile); - goto error; - case PCRE_ERROR_UNKNOWN_NODE: - fprintf(stderr, " ! metadata_from_path: Something kooky for file %s\n", mkvfile); - goto error; - case PCRE_ERROR_NOMEMORY: - fprintf(stderr, " ! metadata_from_path: Ran out of memory for file %s\n", mkvfile); - goto error; - default: - fprintf(stderr, " ! metadata_from_path: Unknown error for file %s\n", mkvfile); - goto error; - } + fprintf(stderr, " ! metadata_from_path: PCRE error\n"); + goto error; } if (pcre_exec_ret == 0) { diff --git a/src/net/listen.c b/src/net/listen.c index 3ec2fdf1e321ecd212cfec5c20a9827065e1be4f..dbb96795d8dd8e54580f4dbc82f0e87539d21590 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -200,8 +200,9 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (!strcmp(cmd.name, "previous")) err = !command_previous(srv->db, &srv->win, &srv->mpd_idle_events); else if (!strcmp(cmd.name, "play")) - err = ! (command_stop(srv->db, &srv->win, &srv->mpd_idle_events) - && command_play(srv->db, &srv->win, cmd.args, &srv->mpd_idle_events)); + err = ! command_play(srv->db, &srv->win, cmd.args, &srv->mpd_idle_events); + else if (!strcmp(cmd.name, "playid")) + err = ! command_playid(srv->db, &srv->win, cmd.args, &srv->mpd_idle_events); else if (!strcmp(cmd.name, "stop")) err = !command_stop(srv->db, &srv->win, &srv->mpd_idle_events); else if (!strcmp(cmd.name, "clear")) @@ -215,6 +216,8 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (!strcmp(cmd.name, "playlist") || !strcmp(cmd.name, "playlistinfo")) err = !command_queue_list(srv, c, cmd.args); + else if (!strcmp(cmd.name, "playlistfind") || !strcmp(cmd.name, "playlistsearch")) + err = ! command_queue_find(srv, c, cmd.args, cmd.cont); else if (!strcmp(cmd.name, "sticker") && cmd.args[0]) { if (!strcmp(cmd.args[0], "get")) diff --git a/src/uri.c b/src/uri.c index e75ae92a038eed89ad907525c94f85c76b76490f..68d34b210babb154e8c691d602f2e029a7121993 100644 --- a/src/uri.c +++ b/src/uri.c @@ -75,7 +75,9 @@ lkt_uri_from(struct lkt_uri_t *ret, char *const str) *(int *) ret->value = id; ret->_allocated = true; - } else { + } + + else { ret->_allocated = false; ret->value = val; } diff --git a/src/utils.c b/src/utils.c index 9ca3644a143705028df4548cafbfa761faebf8a0..c01ce5a628ed3c640f8bf76051d1b31653defefe 100644 --- a/src/utils.c +++ b/src/utils.c @@ -6,10 +6,8 @@ uint32_t be_uint32_t(const uint8_t bytes[], size_t n) { uint32_t res = 0; - for (size_t i = 0; i < n; i++) res = (res << 8u) | bytes[i]; - return res; } @@ -17,10 +15,8 @@ uint64_t be_uint64_t(const uint8_t bytes[], size_t n) { uint64_t res = 0; - for (size_t i = 0; i < n; i++) res = (res << 8u) | bytes[i]; - return res; } @@ -111,11 +107,8 @@ get_stdin_line(const char *prompt, char *buf, size_t len) { if (prompt) fprintf(stdout, "%s", prompt); - if (!fgets(buf, len, stdin)) return 1; - buf[len - 1] = 0u; - return is_utf8(buf); }