Merge branch 'stickernames-types' of https://github.com/jcorporation/MPD
This commit is contained in:
commit
38b46e680a
2
NEWS
2
NEWS
|
@ -10,7 +10,7 @@ ver 0.24 (not yet released)
|
||||||
- show PCRE support in "config" response
|
- show PCRE support in "config" response
|
||||||
- apply Unicode normalization to case-insensitive filter expressions
|
- apply Unicode normalization to case-insensitive filter expressions
|
||||||
- stickers on playlists and some tag types
|
- stickers on playlists and some tag types
|
||||||
- new commands "stickernames", "stickertypes", "playlistlength", "searchplaylist"
|
- new commands "stickernames", "stickertypes", "stickernamestypes", "playlistlength", "searchplaylist"
|
||||||
- new "search"/"find" filter "added-since"
|
- new "search"/"find" filter "added-since"
|
||||||
- allow range in listplaylist and listplaylistinfo
|
- allow range in listplaylist and listplaylistinfo
|
||||||
- "sticker find" supports sort and window parameter and new sticker compare operators "eq", "lt", "gt", "contains" and "starts_with"
|
- "sticker find" supports sort and window parameter and new sticker compare operators "eq", "lt", "gt", "contains" and "starts_with"
|
||||||
|
|
|
@ -1591,6 +1591,9 @@ Examples:
|
||||||
:command:`stickertypes`
|
:command:`stickertypes`
|
||||||
Shows a list of available sticker types.
|
Shows a list of available sticker types.
|
||||||
|
|
||||||
|
:command:`stickernamestypes [TYPE]`
|
||||||
|
Gets a list of uniq sticker names and their types.
|
||||||
|
|
||||||
Connection settings
|
Connection settings
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,7 @@ static constexpr struct command commands[] = {
|
||||||
{ "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker },
|
{ "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker },
|
||||||
{ "stickernames", PERMISSION_ADMIN, 0, 0, handle_sticker_names },
|
{ "stickernames", PERMISSION_ADMIN, 0, 0, handle_sticker_names },
|
||||||
{ "stickertypes", PERMISSION_ADMIN, 0, 0, handle_sticker_types },
|
{ "stickertypes", PERMISSION_ADMIN, 0, 0, handle_sticker_types },
|
||||||
|
{ "stickernamestypes", PERMISSION_ADMIN, 0, 1, handle_sticker_names_types },
|
||||||
#endif
|
#endif
|
||||||
{ "stop", PERMISSION_PLAYER, 0, 0, handle_stop },
|
{ "stop", PERMISSION_PLAYER, 0, 0, handle_stop },
|
||||||
{ "subscribe", PERMISSION_READ, 1, 1, handle_subscribe },
|
{ "subscribe", PERMISSION_READ, 1, 1, handle_subscribe },
|
||||||
|
|
|
@ -124,6 +124,25 @@ public:
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CommandResult NamesTypes(const char *type) {
|
||||||
|
auto data = CallbackContext{
|
||||||
|
.name = "",
|
||||||
|
.sticker_type = sticker_type,
|
||||||
|
.response = response,
|
||||||
|
.is_song = StringIsEqual("song", sticker_type)
|
||||||
|
};
|
||||||
|
|
||||||
|
auto callback = [](const char *found_value, const char *found_type, void *user_data) {
|
||||||
|
auto context = reinterpret_cast<CallbackContext *>(user_data);
|
||||||
|
context->response.Fmt("name: {}\n", found_value);
|
||||||
|
context->response.Fmt("type: {}\n", found_type);
|
||||||
|
};
|
||||||
|
|
||||||
|
sticker_database.NamesTypes(type, callback, &data);
|
||||||
|
|
||||||
|
return CommandResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DomainHandler(Response &_response,
|
DomainHandler(Response &_response,
|
||||||
const Database &_database,
|
const Database &_database,
|
||||||
|
@ -334,6 +353,43 @@ handle_sticker_names(Client &client, Request args, Response &r)
|
||||||
return handler->Names();
|
return handler->Names();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CommandResult
|
||||||
|
handle_sticker_names_types(Client &client, Request args, Response &r)
|
||||||
|
{
|
||||||
|
auto &instance = client.GetInstance();
|
||||||
|
if (!instance.HasStickerDatabase()) {
|
||||||
|
r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled");
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &db = client.GetPartition().GetDatabaseOrThrow();
|
||||||
|
auto &sticker_database = *instance.sticker_database;
|
||||||
|
|
||||||
|
auto type = args.GetOptional(0);
|
||||||
|
std::unique_ptr<DomainHandler> handler = std::make_unique<SongHandler>(r, db, sticker_database);
|
||||||
|
|
||||||
|
if (type == nullptr ||
|
||||||
|
StringIsEqual(type, "song") ||
|
||||||
|
StringIsEqual(type, "playlist") ||
|
||||||
|
StringIsEqual(type, "filter")) {
|
||||||
|
return handler->NamesTypes(type);
|
||||||
|
}
|
||||||
|
auto tag_type = tag_name_parse(type);
|
||||||
|
if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
|
||||||
|
r.FmtError(ACK_ERROR_ARG, "no such tag {:?}", type);
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
|
else if (sticker_allowed_tags.Test(tag_type)) {
|
||||||
|
return handler->NamesTypes(type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r.FmtError(ACK_ERROR_ARG, "unsupported tag {:?}", type);
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
|
r.FmtError(ACK_ERROR_ARG, "unknown sticker domain {:?}", type);
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_sticker(Client &client, Request args, Response &r)
|
handle_sticker(Client &client, Request args, Response &r)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,5 +16,7 @@ CommandResult
|
||||||
handle_sticker_names(Client &client, Request request, Response &response);
|
handle_sticker_names(Client &client, Request request, Response &response);
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_sticker_types(Client &client, Request request, Response &response);
|
handle_sticker_types(Client &client, Request request, Response &response);
|
||||||
|
CommandResult
|
||||||
|
handle_sticker_names_types(Client &client, Request request, Response &response);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -46,6 +46,8 @@ enum sticker_sql {
|
||||||
STICKER_SQL_TRANSACTION_COMMIT,
|
STICKER_SQL_TRANSACTION_COMMIT,
|
||||||
STICKER_SQL_TRANSACTION_ROLLBACK,
|
STICKER_SQL_TRANSACTION_ROLLBACK,
|
||||||
STICKER_SQL_NAMES,
|
STICKER_SQL_NAMES,
|
||||||
|
STICKER_SQL_NAMES_TYPES,
|
||||||
|
STICKER_SQL_NAMES_TYPES_BY_TYPE,
|
||||||
|
|
||||||
STICKER_SQL_COUNT
|
STICKER_SQL_COUNT
|
||||||
};
|
};
|
||||||
|
@ -106,7 +108,13 @@ static constexpr auto sticker_sql = std::array {
|
||||||
"ROLLBACK",
|
"ROLLBACK",
|
||||||
|
|
||||||
//[STICKER_SQL_NAMES]
|
//[STICKER_SQL_NAMES]
|
||||||
"SELECT DISTINCT name FROM sticker order by name",
|
"SELECT DISTINCT name FROM sticker ORDER BY name",
|
||||||
|
|
||||||
|
//[STICKER_SQL_NAMES_TYPES]
|
||||||
|
"SELECT name,type FROM sticker GROUP BY name,type ORDER BY name",
|
||||||
|
|
||||||
|
//[STICKER_SQL_NAMES_TYPES_BY_TYPE]
|
||||||
|
"SELECT name,type FROM sticker WHERE type = ? GROUP BY name,type ORDER BY name",
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr const char sticker_sql_create[] =
|
static constexpr const char sticker_sql_create[] =
|
||||||
|
@ -478,6 +486,29 @@ StickerDatabase::Names(void (*func)(const char *value, void *user_data), void *u
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StickerDatabase::NamesTypes(const char *type, void (*func)(const char *value, const char *type, void *user_data), void *user_data)
|
||||||
|
{
|
||||||
|
assert(func != nullptr);
|
||||||
|
|
||||||
|
sqlite3_stmt *const s = type == nullptr
|
||||||
|
? stmt[STICKER_SQL_NAMES_TYPES]
|
||||||
|
: stmt[STICKER_SQL_NAMES_TYPES_BY_TYPE];
|
||||||
|
assert(s != nullptr);
|
||||||
|
|
||||||
|
if (type != nullptr)
|
||||||
|
BindAll(s, type);
|
||||||
|
|
||||||
|
AtScopeExit(s) {
|
||||||
|
sqlite3_reset(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
ExecuteForEach(s, [s, func, user_data](){
|
||||||
|
func((const char*)sqlite3_column_text(s, 0),
|
||||||
|
(const char*)sqlite3_column_text(s, 1), user_data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StickerDatabase::BatchDeleteNoIdle(const std::list<StickerTypeUriPair> &stickers)
|
StickerDatabase::BatchDeleteNoIdle(const std::list<StickerTypeUriPair> &stickers)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,6 +52,8 @@ class StickerDatabase {
|
||||||
SQL_TRANSACTION_COMMIT,
|
SQL_TRANSACTION_COMMIT,
|
||||||
SQL_TRANSACTION_ROLLBACK,
|
SQL_TRANSACTION_ROLLBACK,
|
||||||
SQL_NAMES,
|
SQL_NAMES,
|
||||||
|
SQL_NAMES_TYPES,
|
||||||
|
SQL_NAMES_TYPES_BY_TYPE,
|
||||||
|
|
||||||
SQL_COUNT
|
SQL_COUNT
|
||||||
};
|
};
|
||||||
|
@ -166,6 +168,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void Names(void (*func)(const char *value, void *user_data), void *user_data);
|
void Names(void (*func)(const char *value, void *user_data), void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uniq and sorted list of all sticker names by type
|
||||||
|
*/
|
||||||
|
void NamesTypes(const char *type, void (*func)(const char *value, const char *type, void *user_data), void *user_data);
|
||||||
|
|
||||||
using StickerTypeUriPair = std::pair<std::string, std::string>;
|
using StickerTypeUriPair = std::pair<std::string, std::string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue