Commit 2aee1b86 authored by Max Kellermann's avatar Max Kellermann

SongFilter: add special keyword "base"

Restores the features from the previous draft commands "findin" / "searchin".
parent b5fc21b9
...@@ -6,6 +6,7 @@ ver 0.18 (2012/??/??) ...@@ -6,6 +6,7 @@ ver 0.18 (2012/??/??)
- new command "readcomments" lists arbitrary file tags - new command "readcomments" lists arbitrary file tags
- new command "toggleoutput" - new command "toggleoutput"
- "find"/"search" with "any" does not match file name - "find"/"search" with "any" does not match file name
- "search" and "find" with base URI (keyword "base")
- search for album artist falls back to the artist tag - search for album artist falls back to the artist tag
- re-add the "volume" command - re-add the "volume" command
* input: * input:
......
...@@ -1483,9 +1483,13 @@ OK ...@@ -1483,9 +1483,13 @@ OK
<para> <para>
Finds songs in the db that are exactly Finds songs in the db that are exactly
<varname>WHAT</varname>. <varname>TYPE</varname> can <varname>WHAT</varname>. <varname>TYPE</varname> can
be any tag supported by MPD, or one of the two special be any tag supported by MPD, or one of the three special
parameters — <parameter>file</parameter> to search by parameters — <parameter>file</parameter> to search by
full path (relative to database root), and
full path (relative to the music directory),
<parameter>in</parameter> to restrict the search to
songs in the given directory (also relative to the music
directory) and
<parameter>any</parameter> to match against all <parameter>any</parameter> to match against all
available tags. <varname>WHAT</varname> is what to find. available tags. <varname>WHAT</varname> is what to find.
</para> </para>
......
...@@ -20,6 +20,16 @@ ...@@ -20,6 +20,16 @@
#include "DatabaseSelection.hxx" #include "DatabaseSelection.hxx"
#include "SongFilter.hxx" #include "SongFilter.hxx"
DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
const SongFilter *_filter)
:uri(_uri), recursive(_recursive), filter(_filter)
{
/* optimization: if the caller didn't specify a base URI, pick
the one from SongFilter */
if (uri.empty() && filter != nullptr)
uri = filter->GetBase();
}
bool bool
DatabaseSelection::Match(const Song &song) const DatabaseSelection::Match(const Song &song) const
{ {
......
...@@ -42,9 +42,7 @@ struct DatabaseSelection { ...@@ -42,9 +42,7 @@ struct DatabaseSelection {
const SongFilter *filter; const SongFilter *filter;
DatabaseSelection(const char *_uri, bool _recursive, DatabaseSelection(const char *_uri, bool _recursive,
const SongFilter *_filter=nullptr) const SongFilter *_filter=nullptr);
:uri(_uri), recursive(_recursive), filter(_filter) {
}
gcc_pure gcc_pure
bool Match(const Song &song) const; bool Match(const Song &song) const;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "Song.hxx" #include "Song.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
#include "util/UriUtil.hxx"
#include <glib.h> #include <glib.h>
...@@ -43,6 +44,9 @@ locate_parse_type(const char *str) ...@@ -43,6 +44,9 @@ locate_parse_type(const char *str)
if (StringEqualsCaseASCII(str, LOCATE_TAG_ANY_KEY)) if (StringEqualsCaseASCII(str, LOCATE_TAG_ANY_KEY))
return LOCATE_TAG_ANY_TYPE; return LOCATE_TAG_ANY_TYPE;
if (strcmp(str, "base") == 0)
return LOCATE_TAG_BASE_TYPE;
return tag_name_parse_i(str); return tag_name_parse_i(str);
} }
...@@ -134,6 +138,11 @@ SongFilter::Item::Match(const Tag &_tag) const ...@@ -134,6 +138,11 @@ SongFilter::Item::Match(const Tag &_tag) const
bool bool
SongFilter::Item::Match(const Song &song) const SongFilter::Item::Match(const Song &song) const
{ {
if (tag == LOCATE_TAG_BASE_TYPE) {
const auto uri = song.GetURI();
return uri_is_child_or_same(value.c_str(), uri.c_str());
}
if (tag == LOCATE_TAG_FILE_TYPE) { if (tag == LOCATE_TAG_FILE_TYPE) {
const auto uri = song.GetURI(); const auto uri = song.GetURI();
return StringMatch(uri.c_str()); return StringMatch(uri.c_str());
...@@ -159,6 +168,14 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) ...@@ -159,6 +168,14 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
if (tag == TAG_NUM_OF_ITEM_TYPES) if (tag == TAG_NUM_OF_ITEM_TYPES)
return false; return false;
if (tag == LOCATE_TAG_BASE_TYPE) {
if (!uri_safe_local(value))
return false;
/* case folding doesn't work with "base" */
fold_case = false;
}
items.push_back(Item(tag, value, fold_case)); items.push_back(Item(tag, value, fold_case));
return true; return true;
} }
...@@ -185,3 +202,13 @@ SongFilter::Match(const Song &song) const ...@@ -185,3 +202,13 @@ SongFilter::Match(const Song &song) const
return true; return true;
} }
std::string
SongFilter::GetBase() const
{
for (const auto &i : items)
if (i.GetTag() == LOCATE_TAG_BASE_TYPE)
return i.GetValue();
return std::string();
}
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
#include <stdint.h> #include <stdint.h>
/**
* Limit the search to files within the given directory.
*/
#define LOCATE_TAG_BASE_TYPE (TAG_NUM_OF_ITEM_TYPES + 1)
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
...@@ -99,6 +104,13 @@ public: ...@@ -99,6 +104,13 @@ public:
const std::list<Item> &GetItems() const { const std::list<Item> &GetItems() const {
return items; return items;
} }
/**
* Returns the "base" specification (if there is one) or an
* empty string.
*/
gcc_pure
std::string GetBase() const;
}; };
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment