SongFilter: new filter "modified-since"
This commit is contained in:
parent
14908b7f28
commit
5d2506e697
1
NEWS
1
NEWS
|
@ -7,6 +7,7 @@ ver 0.19 (not yet released)
|
||||||
- "idle" with unrecognized event name fails
|
- "idle" with unrecognized event name fails
|
||||||
- "list" on album artist falls back to the artist tag
|
- "list" on album artist falls back to the artist tag
|
||||||
- "list" and "count" allow grouping
|
- "list" and "count" allow grouping
|
||||||
|
- new "search"/"find" filter "modified-since"
|
||||||
* database
|
* database
|
||||||
- proxy: forward "idle" events
|
- proxy: forward "idle" events
|
||||||
- proxy: forward the "update" command
|
- proxy: forward the "update" command
|
||||||
|
|
|
@ -1553,7 +1553,7 @@ 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 three special
|
be any tag supported by MPD, or one of the special
|
||||||
parameters:
|
parameters:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -1578,6 +1578,14 @@ OK
|
||||||
music directory)
|
music directory)
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<parameter>modified-since</parameter> compares the
|
||||||
|
file's time stamp with the given value (ISO 8601 or
|
||||||
|
UNIX time stamp)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -48,6 +48,9 @@ locate_parse_type(const char *str)
|
||||||
if (strcmp(str, "base") == 0)
|
if (strcmp(str, "base") == 0)
|
||||||
return LOCATE_TAG_BASE_TYPE;
|
return LOCATE_TAG_BASE_TYPE;
|
||||||
|
|
||||||
|
if (strcmp(str, "modified-since") == 0)
|
||||||
|
return LOCATE_TAG_MODIFIED_SINCE;
|
||||||
|
|
||||||
return tag_name_parse_i(str);
|
return tag_name_parse_i(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +69,11 @@ SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SongFilter::Item::Item(unsigned _tag, time_t _time)
|
||||||
|
:tag(_tag), time(_time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Item::StringMatch(const char *s) const
|
SongFilter::Item::StringMatch(const char *s) const
|
||||||
{
|
{
|
||||||
|
@ -128,6 +136,9 @@ SongFilter::Item::Match(const DetachedSong &song) const
|
||||||
if (tag == LOCATE_TAG_BASE_TYPE)
|
if (tag == LOCATE_TAG_BASE_TYPE)
|
||||||
return uri_is_child_or_same(value.c_str(), song.GetURI());
|
return uri_is_child_or_same(value.c_str(), song.GetURI());
|
||||||
|
|
||||||
|
if (tag == LOCATE_TAG_MODIFIED_SINCE)
|
||||||
|
return song.GetLastModified() >= time;
|
||||||
|
|
||||||
if (tag == LOCATE_TAG_FILE_TYPE)
|
if (tag == LOCATE_TAG_FILE_TYPE)
|
||||||
return StringMatch(song.GetURI());
|
return StringMatch(song.GetURI());
|
||||||
|
|
||||||
|
@ -142,6 +153,9 @@ SongFilter::Item::Match(const LightSong &song) const
|
||||||
return uri_is_child_or_same(value.c_str(), uri.c_str());
|
return uri_is_child_or_same(value.c_str(), uri.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag == LOCATE_TAG_MODIFIED_SINCE)
|
||||||
|
return song.mtime >= time;
|
||||||
|
|
||||||
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());
|
||||||
|
@ -160,6 +174,58 @@ SongFilter::~SongFilter()
|
||||||
/* this destructor exists here just so it won't get inlined */
|
/* this destructor exists here just so it won't get inlined */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(__GLIBC__) && !defined(WIN32)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the time zone offset in a portable way.
|
||||||
|
*/
|
||||||
|
gcc_const
|
||||||
|
static time_t
|
||||||
|
GetTimeZoneOffset()
|
||||||
|
{
|
||||||
|
time_t t = 1234567890;
|
||||||
|
struct tm tm;
|
||||||
|
tm.tm_isdst = 0;
|
||||||
|
gmtime_r(&t, &tm);
|
||||||
|
return t - mktime(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
static time_t
|
||||||
|
ParseTimeStamp(const char *s)
|
||||||
|
{
|
||||||
|
assert(s != nullptr);
|
||||||
|
|
||||||
|
char *endptr;
|
||||||
|
unsigned long long value = strtoull(s, &endptr, 10);
|
||||||
|
if (*endptr == 0 && endptr > s)
|
||||||
|
/* it's an integral UNIX time stamp */
|
||||||
|
return (time_t)value;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/* TODO: emulate strptime()? */
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
/* try ISO 8601 */
|
||||||
|
|
||||||
|
struct tm tm;
|
||||||
|
const char *end = strptime(s, "%FT%TZ", &tm);
|
||||||
|
if (end == nullptr || *end != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
/* timegm() is a GNU extension */
|
||||||
|
return timegm(&tm);
|
||||||
|
#else
|
||||||
|
tm.tm_isdst = 0;
|
||||||
|
return mktime(&tm) + GetTimeZoneOffset();
|
||||||
|
#endif /* !__GLIBC__ */
|
||||||
|
|
||||||
|
#endif /* !WIN32 */
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
|
SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
|
||||||
{
|
{
|
||||||
|
@ -175,6 +241,15 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
|
||||||
fold_case = false;
|
fold_case = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag == LOCATE_TAG_MODIFIED_SINCE) {
|
||||||
|
time_t t = ParseTimeStamp(value);
|
||||||
|
if (t == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
items.push_back(Item(tag, t));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
items.push_back(Item(tag, value, fold_case));
|
items.push_back(Item(tag, value, fold_case));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,13 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limit the search to files within the given directory.
|
* Limit the search to files within the given directory.
|
||||||
*/
|
*/
|
||||||
#define LOCATE_TAG_BASE_TYPE (TAG_NUM_OF_ITEM_TYPES + 1)
|
#define LOCATE_TAG_BASE_TYPE (TAG_NUM_OF_ITEM_TYPES + 1)
|
||||||
|
#define LOCATE_TAG_MODIFIED_SINCE (TAG_NUM_OF_ITEM_TYPES + 2)
|
||||||
|
|
||||||
#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
|
||||||
|
@ -51,9 +53,15 @@ public:
|
||||||
|
|
||||||
std::string value;
|
std::string value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For #LOCATE_TAG_MODIFIED_SINCE
|
||||||
|
*/
|
||||||
|
time_t time;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
gcc_nonnull(3)
|
gcc_nonnull(3)
|
||||||
Item(unsigned tag, const char *value, bool fold_case=false);
|
Item(unsigned tag, const char *value, bool fold_case=false);
|
||||||
|
Item(unsigned tag, time_t time);
|
||||||
|
|
||||||
Item(const Item &other) = delete;
|
Item(const Item &other) = delete;
|
||||||
Item(Item &&) = default;
|
Item(Item &&) = default;
|
||||||
|
|
Loading…
Reference in New Issue