client: add tag_mask attribute
The "tagtypes" command now has several sub commands which can be used to edit that mask.
This commit is contained in:
parent
599d77643b
commit
29453ba196
2
NEWS
2
NEWS
|
@ -1,4 +1,6 @@
|
||||||
ver 0.21 (not yet released)
|
ver 0.21 (not yet released)
|
||||||
|
* protocol
|
||||||
|
- "tagtypes" can be used to hide tags
|
||||||
|
|
||||||
ver 0.20.5 (not yet released)
|
ver 0.20.5 (not yet released)
|
||||||
* tags
|
* tags
|
||||||
|
|
101
doc/protocol.xml
101
doc/protocol.xml
|
@ -2252,6 +2252,95 @@ OK
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="command_tagtypes">
|
||||||
|
<term>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>tagtypes</command>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Shows a list of available tag types. It is an
|
||||||
|
intersection of the <varname>metadata_to_use</varname>
|
||||||
|
setting and this client's tag mask.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
About the tag mask: each client can decide to disable
|
||||||
|
any number of tag types, which will be omitted from
|
||||||
|
responses to this client. That is a good idea, because
|
||||||
|
it makes responses smaller. The following
|
||||||
|
<command>tagtypes</command> sub commands configure this
|
||||||
|
list.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="command_tagtypes_disable">
|
||||||
|
<term>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>tagtypes</command>
|
||||||
|
<arg choice="plain">disable</arg>
|
||||||
|
<arg choice="req" rep="repeat"><replaceable>NAME</replaceable></arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Remove one or more tags from the list of tag types the
|
||||||
|
client is interested in. These will be omitted from
|
||||||
|
responses to this client.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="command_tagtypes_enable">
|
||||||
|
<term>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>tagtypes</command>
|
||||||
|
<arg choice="plain">enable</arg>
|
||||||
|
<arg choice="req" rep="repeat"><replaceable>NAME</replaceable></arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Re-enable one or more tags from the list of tag types
|
||||||
|
for this client. These will no longer be hidden from
|
||||||
|
responses to this client.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="command_tagtypes_clear">
|
||||||
|
<term>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>tagtypes</command>
|
||||||
|
<arg choice="plain">clear</arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Clear the list of tag types this client is interested
|
||||||
|
in. This means that <application>MPD</application> will
|
||||||
|
not send any tags to this client.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="command_tagtypes_all">
|
||||||
|
<term>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>tagtypes</command>
|
||||||
|
<arg choice="plain">all</arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Announce that this client is interested in all tag
|
||||||
|
types. This is the default setting for new clients.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -2410,18 +2499,6 @@ OK
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry id="command_tagtypes">
|
|
||||||
<term>
|
|
||||||
<cmdsynopsis>
|
|
||||||
<command>tagtypes</command>
|
|
||||||
</cmdsynopsis>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Shows a list of available song metadata.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry id="command_urlhandlers">
|
<varlistentry id="command_urlhandlers">
|
||||||
<term>
|
<term>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
|
|
|
@ -40,7 +40,9 @@ tag_print(Response &r, TagType type, const char *value)
|
||||||
void
|
void
|
||||||
tag_print_values(Response &r, const Tag &tag)
|
tag_print_values(Response &r, const Tag &tag)
|
||||||
{
|
{
|
||||||
|
const auto tag_mask = r.GetTagMask();
|
||||||
for (const auto &i : tag)
|
for (const auto &i : tag)
|
||||||
|
if (tag_mask.Test(i.type))
|
||||||
tag_print(r, i.type, i.value);
|
tag_print(r, i.type, i.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "ClientMessage.hxx"
|
#include "ClientMessage.hxx"
|
||||||
#include "command/CommandListBuilder.hxx"
|
#include "command/CommandListBuilder.hxx"
|
||||||
|
#include "tag/Mask.hxx"
|
||||||
#include "event/FullyBufferedSocket.hxx"
|
#include "event/FullyBufferedSocket.hxx"
|
||||||
#include "event/TimeoutMonitor.hxx"
|
#include "event/TimeoutMonitor.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
@ -70,6 +71,11 @@ public:
|
||||||
/** idle flags that the client wants to receive */
|
/** idle flags that the client wants to receive */
|
||||||
unsigned idle_subscriptions;
|
unsigned idle_subscriptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tags this client is interested in.
|
||||||
|
*/
|
||||||
|
TagMask tag_mask = TagMask::All();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of channel names this client is subscribed to.
|
* A list of channel names this client is subscribed to.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,6 +23,12 @@
|
||||||
#include "util/FormatString.hxx"
|
#include "util/FormatString.hxx"
|
||||||
#include "util/AllocatedString.hxx"
|
#include "util/AllocatedString.hxx"
|
||||||
|
|
||||||
|
TagMask
|
||||||
|
Response::GetTagMask() const
|
||||||
|
{
|
||||||
|
return GetClient().tag_mask;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Response::Write(const void *data, size_t length)
|
Response::Write(const void *data, size_t length)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,11 +22,13 @@
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "protocol/Ack.hxx"
|
#include "protocol/Ack.hxx"
|
||||||
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
|
class TagMask;
|
||||||
|
|
||||||
class Response {
|
class Response {
|
||||||
Client &client;
|
Client &client;
|
||||||
|
@ -59,6 +61,13 @@ public:
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessor for Client::tag_mask. Can be used if caller wants
|
||||||
|
* to avoid including Client.hxx.
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
TagMask GetTagMask() const;
|
||||||
|
|
||||||
void SetCommand(const char *_command) {
|
void SetCommand(const char *_command) {
|
||||||
command = _command;
|
command = _command;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,7 @@ static constexpr struct command commands[] = {
|
||||||
{ "subscribe", PERMISSION_READ, 1, 1, handle_subscribe },
|
{ "subscribe", PERMISSION_READ, 1, 1, handle_subscribe },
|
||||||
{ "swap", PERMISSION_CONTROL, 2, 2, handle_swap },
|
{ "swap", PERMISSION_CONTROL, 2, 2, handle_swap },
|
||||||
{ "swapid", PERMISSION_CONTROL, 2, 2, handle_swapid },
|
{ "swapid", PERMISSION_CONTROL, 2, 2, handle_swapid },
|
||||||
{ "tagtypes", PERMISSION_READ, 0, 0, handle_tagtypes },
|
{ "tagtypes", PERMISSION_READ, 0, -1, handle_tagtypes },
|
||||||
{ "toggleoutput", PERMISSION_ADMIN, 1, 1, handle_toggleoutput },
|
{ "toggleoutput", PERMISSION_ADMIN, 1, 1, handle_toggleoutput },
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
{ "unmount", PERMISSION_ADMIN, 1, 1, handle_unmount },
|
{ "unmount", PERMISSION_ADMIN, 1, 1, handle_unmount },
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include "client/Client.hxx"
|
#include "client/Client.hxx"
|
||||||
#include "client/Response.hxx"
|
#include "client/Response.hxx"
|
||||||
#include "TagPrint.hxx"
|
#include "TagPrint.hxx"
|
||||||
|
#include "tag/ParseName.hxx"
|
||||||
|
#include "util/StringAPI.hxx"
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_close(gcc_unused Client &client, gcc_unused Request args,
|
handle_close(gcc_unused Client &client, gcc_unused Request args,
|
||||||
|
@ -53,10 +55,58 @@ handle_password(Client &client, Request args, Response &r)
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandResult
|
static TagMask
|
||||||
handle_tagtypes(gcc_unused Client &client, gcc_unused Request request,
|
ParseTagMask(Request request)
|
||||||
Response &r)
|
|
||||||
{
|
{
|
||||||
|
if (request.IsEmpty())
|
||||||
|
throw ProtocolError(ACK_ERROR_ARG, "Not enough arguments");
|
||||||
|
|
||||||
|
TagMask result = TagMask::None();
|
||||||
|
|
||||||
|
for (const char *name : request) {
|
||||||
|
auto type = tag_name_parse_i(name);
|
||||||
|
if (type == TAG_NUM_OF_ITEM_TYPES)
|
||||||
|
throw ProtocolError(ACK_ERROR_ARG, "Unknown tag type");
|
||||||
|
|
||||||
|
result |= type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandResult
|
||||||
|
handle_tagtypes(Client &client, Request request, Response &r)
|
||||||
|
{
|
||||||
|
if (request.IsEmpty()) {
|
||||||
tag_print_types(r);
|
tag_print_types(r);
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cmd = request.shift();
|
||||||
|
if (StringIsEqual(cmd, "all")) {
|
||||||
|
if (!request.IsEmpty()) {
|
||||||
|
r.Error(ACK_ERROR_ARG, "Too many arguments");
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.tag_mask = TagMask::All();
|
||||||
|
return CommandResult::OK;
|
||||||
|
} else if (StringIsEqual(cmd, "clear")) {
|
||||||
|
if (!request.IsEmpty()) {
|
||||||
|
r.Error(ACK_ERROR_ARG, "Too many arguments");
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.tag_mask = TagMask::None();
|
||||||
|
return CommandResult::OK;
|
||||||
|
} else if (StringIsEqual(cmd, "enable")) {
|
||||||
|
client.tag_mask |= ParseTagMask(request);
|
||||||
|
return CommandResult::OK;
|
||||||
|
} else if (StringIsEqual(cmd, "disable")) {
|
||||||
|
client.tag_mask &= ~ParseTagMask(request);
|
||||||
|
return CommandResult::OK;
|
||||||
|
} else {
|
||||||
|
r.Error(ACK_ERROR_ARG, "Unknown sub command");
|
||||||
|
return CommandResult::ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,7 @@ print_tag(TagType type, const char *value, void *ctx)
|
||||||
{
|
{
|
||||||
auto &r = *(Response *)ctx;
|
auto &r = *(Response *)ctx;
|
||||||
|
|
||||||
|
if (r.GetClient().tag_mask.Test(type))
|
||||||
tag_print(r, type, value);
|
tag_print(r, type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,8 +196,9 @@ PrintUniqueTag(Response &r, TagType tag_type,
|
||||||
assert(value != nullptr);
|
assert(value != nullptr);
|
||||||
tag_print(r, tag_type, value);
|
tag_print(r, tag_type, value);
|
||||||
|
|
||||||
|
const auto tag_mask = r.GetTagMask();
|
||||||
for (const auto &item : tag)
|
for (const auto &item : tag)
|
||||||
if (item.type != tag_type)
|
if (item.type != tag_type && tag_mask.Test(item.type))
|
||||||
tag_print(r, item.type, item.value);
|
tag_print(r, item.type, item.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue