Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
2cfccc1c
Commit
2cfccc1c
authored
Jul 25, 2018
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SongFilter: make Item an interface
Prepare to allow more complex expressions.
parent
438366ef
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
296 additions
and
186 deletions
+296
-186
SongFilter.cxx
src/SongFilter.cxx
+130
-79
SongFilter.hxx
src/SongFilter.hxx
+123
-62
DatabaseCommands.cxx
src/command/DatabaseCommands.cxx
+1
-1
ProxyDatabasePlugin.cxx
src/db/plugins/ProxyDatabasePlugin.cxx
+31
-27
UpnpDatabasePlugin.cxx
src/db/plugins/upnp/UpnpDatabasePlugin.cxx
+11
-17
No files found.
src/SongFilter.cxx
View file @
2cfccc1c
This diff is collapsed.
Click to expand it.
src/SongFilter.hxx
View file @
2cfccc1c
/*
* Copyright 2003-201
7
The Music Player Daemon Project
* Copyright 2003-201
8
The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
...
...
@@ -23,10 +23,13 @@
#include "lib/icu/Compare.hxx"
#include "Compiler.h"
#include <memory>
#include <string>
#include <list>
#include <chrono>
#include <stdint.h>
/**
* Limit the search to files within the given directory.
*/
...
...
@@ -42,9 +45,28 @@
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
template
<
typename
T
>
struct
ConstBuffer
;
enum
TagType
:
uint8_t
;
struct
Tag
;
struct
TagItem
;
struct
LightSong
;
class
ISongFilter
;
using
ISongFilterPtr
=
std
::
unique_ptr
<
ISongFilter
>
;
class
ISongFilter
{
public
:
virtual
~
ISongFilter
()
noexcept
{}
virtual
ISongFilterPtr
Clone
()
const
noexcept
=
0
;
/**
* Convert this object into an "expression". This is
* only useful for debugging.
*/
virtual
std
::
string
ToExpression
()
const
noexcept
=
0
;
gcc_pure
virtual
bool
Match
(
const
LightSong
&
song
)
const
noexcept
=
0
;
};
class
StringFilter
{
std
::
string
value
;
...
...
@@ -55,8 +77,6 @@ class StringFilter {
IcuCompare
fold_case
;
public
:
StringFilter
()
=
default
;
template
<
typename
V
>
StringFilter
(
V
&&
_value
,
bool
_fold_case
)
:
value
(
std
::
forward
<
V
>
(
_value
)),
...
...
@@ -80,82 +100,129 @@ public:
bool
Match
(
const
char
*
s
)
const
noexcept
;
};
class
SongFilter
{
class
UriSongFilter
final
:
public
ISongFilter
{
StringFilter
filter
;
bool
negated
;
public
:
class
Item
{
unsigned
tag
;
template
<
typename
V
>
UriSongFilter
(
V
&&
_value
,
bool
fold_case
,
bool
_negated
)
:
filter
(
std
::
forward
<
V
>
(
_value
),
fold_case
),
negated
(
_negated
)
{}
const
auto
&
GetValue
()
const
noexcept
{
return
filter
.
GetValue
();
}
bool
GetFoldCase
()
const
{
return
filter
.
GetFoldCase
();
}
bool
IsNegated
()
const
noexcept
{
return
negated
;
}
ISongFilterPtr
Clone
()
const
noexcept
override
{
return
std
::
make_unique
<
UriSongFilter
>
(
*
this
);
}
std
::
string
ToExpression
()
const
noexcept
override
;
bool
Match
(
const
LightSong
&
song
)
const
noexcept
override
;
};
bool
negated
=
false
;
class
BaseSongFilter
final
:
public
ISongFilter
{
std
::
string
value
;
StringFilter
string_filter
;
public
:
BaseSongFilter
(
const
BaseSongFilter
&
)
=
default
;
/**
* For #LOCATE_TAG_MODIFIED_SINCE
*/
std
::
chrono
::
system_clock
::
time_point
time
;
template
<
typename
V
>
explicit
BaseSongFilter
(
V
&&
_value
)
:
value
(
std
::
forward
<
V
>
(
_value
))
{}
public
:
Item
(
unsigned
tag
,
std
::
string
&&
_value
,
bool
fold_case
=
false
);
Item
(
unsigned
tag
,
std
::
chrono
::
system_clock
::
time_point
time
);
const
char
*
GetValue
()
const
noexcept
{
return
value
.
c_str
(
);
}
/**
* Convert this object into an "expression". This is
* only useful for debugging.
*/
std
::
string
ToExpression
()
const
noexcept
;
ISongFilterPtr
Clone
()
const
noexcept
override
{
return
std
::
make_unique
<
BaseSongFilter
>
(
*
this
);
}
std
::
string
ToExpression
()
const
noexcept
override
;
bool
Match
(
const
LightSong
&
song
)
const
noexcept
override
;
};
unsigned
GetTag
()
const
{
return
tag
;
}
class
TagSongFilter
final
:
public
ISongFilter
{
TagType
type
;
bool
IsNegated
()
const
noexcept
{
return
negated
;
}
bool
negated
;
void
SetNegated
(
bool
_negated
=
true
)
noexcept
{
negated
=
_negated
;
}
StringFilter
filter
;
bool
GetFoldCase
()
const
{
return
string_filter
.
GetFoldCase
();
}
public
:
template
<
typename
V
>
TagSongFilter
(
TagType
_type
,
V
&&
_value
,
bool
fold_case
,
bool
_negated
)
:
type
(
_type
),
negated
(
_negated
),
filter
(
std
::
forward
<
V
>
(
_value
),
fold_case
)
{}
const
char
*
GetValu
e
()
const
{
return
string_filter
.
GetValue
().
c_str
()
;
}
TagType
GetTagTyp
e
()
const
{
return
type
;
}
private
:
/* note: the "NN" suffix means "no negation", i.e. the
method pretends negation is unset, and the caller
is responsibly for considering it */
const
auto
&
GetValue
()
const
noexcept
{
return
filter
.
GetValue
();
}
gcc_pure
bool
MatchNN
(
const
TagItem
&
tag_item
)
const
noexcept
;
bool
GetFoldCase
()
const
{
return
filter
.
GetFoldCase
();
}
gcc_pure
bool
MatchNN
(
const
Tag
&
tag
)
const
noexcept
;
bool
IsNegated
()
const
noexcept
{
return
negated
;
}
gcc_pure
bool
MatchNN
(
const
LightSong
&
song
)
const
noexcept
;
ISongFilterPtr
Clone
()
const
noexcept
override
{
return
std
::
make_unique
<
TagSongFilter
>
(
*
this
);
}
public
:
gcc_pure
bool
Match
(
const
LightSong
&
song
)
const
noexcept
{
return
MatchNN
(
song
)
!=
IsNegated
();
}
};
std
::
string
ToExpression
()
const
noexcept
override
;
bool
Match
(
const
LightSong
&
song
)
const
noexcept
override
;
private
:
std
::
list
<
Item
>
items
;
bool
MatchNN
(
const
Tag
&
tag
)
const
noexcept
;
bool
MatchNN
(
const
TagItem
&
tag
)
const
noexcept
;
};
class
ModifiedSinceSongFilter
final
:
public
ISongFilter
{
std
::
chrono
::
system_clock
::
time_point
value
;
public
:
explicit
ModifiedSinceSongFilter
(
std
::
chrono
::
system_clock
::
time_point
_value
)
noexcept
:
value
(
_value
)
{}
ISongFilterPtr
Clone
()
const
noexcept
override
{
return
std
::
make_unique
<
ModifiedSinceSongFilter
>
(
*
this
);
}
std
::
string
ToExpression
()
const
noexcept
override
;
bool
Match
(
const
LightSong
&
song
)
const
noexcept
override
;
};
class
SongFilter
{
std
::
list
<
ISongFilterPtr
>
items
;
public
:
SongFilter
()
=
default
;
gcc_nonnull
(
3
)
SongFilter
(
unsigned
tag
,
const
char
*
value
,
bool
fold_case
=
false
);
SongFilter
(
TagType
tag
,
const
char
*
value
,
bool
fold_case
=
false
);
~
SongFilter
();
SongFilter
(
SongFilter
&&
)
=
default
;
SongFilter
&
operator
=
(
SongFilter
&&
)
=
default
;
/**
* Convert this object into an "expression". This is
* only useful for debugging.
...
...
@@ -163,7 +230,7 @@ public:
std
::
string
ToExpression
()
const
noexcept
;
private
:
const
char
*
ParseExpression
(
const
char
*
s
,
bool
fold_case
=
false
);
ISongFilterPtr
ParseExpression
(
const
char
*&
s
,
bool
fold_case
=
false
);
gcc_nonnull
(
2
,
3
)
void
Parse
(
const
char
*
tag
,
const
char
*
value
,
bool
fold_case
=
false
);
...
...
@@ -177,7 +244,7 @@ public:
gcc_pure
bool
Match
(
const
LightSong
&
song
)
const
noexcept
;
const
std
::
list
<
Item
>
&
GetItems
()
const
noexcept
{
const
auto
&
GetItems
()
const
noexcept
{
return
items
;
}
...
...
@@ -190,13 +257,7 @@ public:
* Is there at least one item with "fold case" enabled?
*/
gcc_pure
bool
HasFoldCase
()
const
noexcept
{
for
(
const
auto
&
i
:
items
)
if
(
i
.
GetFoldCase
())
return
true
;
return
false
;
}
bool
HasFoldCase
()
const
noexcept
;
/**
* Does this filter contain constraints other than "base"?
...
...
src/command/DatabaseCommands.cxx
View file @
2cfccc1c
...
...
@@ -248,7 +248,7 @@ handle_list(Client &client, Request args, Response &r)
return
CommandResult
::
ERROR
;
}
filter
.
reset
(
new
SongFilter
(
(
unsigned
)
TAG_ARTIST
,
filter
.
reset
(
new
SongFilter
(
TAG_ARTIST
,
args
.
shift
()));
}
...
...
src/db/plugins/ProxyDatabasePlugin.cxx
View file @
2cfccc1c
...
...
@@ -268,49 +268,53 @@ CheckError(struct mpd_connection *connection)
}
static
bool
SendConstraints
(
mpd_connection
*
connection
,
const
SongFilter
::
Item
&
item
)
SendConstraints
(
mpd_connection
*
connection
,
const
ISongFilter
&
f
)
{
switch
(
item
.
GetTag
())
{
mpd_tag_type
tag
;
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
case
LOCATE_TAG_BASE_TYPE
:
if
(
mpd_connection_cmp_server_version
(
connection
,
0
,
18
,
0
)
<
0
)
/* requires MPD 0.18 */
if
(
auto
t
=
dynamic_cast
<
const
TagSongFilter
*>
(
&
f
))
{
if
(
t
->
IsNegated
())
// TODO implement
return
true
;
return
mpd_search_add_base_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
item
.
GetValue
());
#endif
case
LOCATE_TAG_FILE_TYPE
:
return
mpd_search_add_uri_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
item
.
GetValue
());
case
LOCATE_TAG_ANY_TYPE
:
return
mpd_search_add_any_tag_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
item
.
GetValue
());
if
(
t
->
GetTagType
()
==
TAG_NUM_OF_ITEM_TYPES
)
return
mpd_search_add_any_tag_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
t
->
GetValue
().
c_str
());
default
:
tag
=
Convert
(
TagType
(
item
.
GetTag
()));
const
auto
tag
=
Convert
(
t
->
GetTagType
());
if
(
tag
==
MPD_TAG_COUNT
)
return
true
;
return
mpd_search_add_tag_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
tag
,
item
.
GetValue
());
}
t
->
GetValue
().
c_str
());
}
else
if
(
auto
u
=
dynamic_cast
<
const
UriSongFilter
*>
(
&
f
))
{
if
(
u
->
IsNegated
())
// TODO implement
return
true
;
return
mpd_search_add_uri_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
u
->
GetValue
().
c_str
());
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
}
else
if
(
auto
b
=
dynamic_cast
<
const
BaseSongFilter
*>
(
&
f
))
{
if
(
mpd_connection_cmp_server_version
(
connection
,
0
,
18
,
0
)
<
0
)
/* requires MPD 0.18 */
return
true
;
return
mpd_search_add_base_constraint
(
connection
,
MPD_OPERATOR_DEFAULT
,
b
->
GetValue
());
#endif
}
else
return
true
;
}
static
bool
SendConstraints
(
mpd_connection
*
connection
,
const
SongFilter
&
filter
)
{
for
(
const
auto
&
i
:
filter
.
GetItems
())
if
(
!
SendConstraints
(
connection
,
i
))
if
(
!
SendConstraints
(
connection
,
*
i
))
return
false
;
return
true
;
...
...
src/db/plugins/upnp/UpnpDatabasePlugin.cxx
View file @
2cfccc1c
...
...
@@ -254,9 +254,9 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
std
::
string
cond
;
for
(
const
auto
&
item
:
filter
->
GetItems
())
{
switch
(
auto
tag
=
item
.
GetTag
(
))
{
case
LOCATE_TAG_ANY_TYPE
:
{
if
(
auto
t
=
dynamic_cast
<
const
TagSongFilter
*>
(
item
.
get
()
))
{
auto
tag
=
t
->
GetTagType
();
if
(
tag
==
TAG_NUM_OF_ITEM_TYPES
)
{
if
(
!
cond
.
empty
())
{
cond
+=
" and "
;
}
...
...
@@ -268,29 +268,21 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
else
cond
+=
" or "
;
cond
+=
cap
;
if
(
item
.
GetFoldCase
())
{
if
(
t
->
GetFoldCase
())
{
cond
+=
" contains "
;
}
else
{
cond
+=
" = "
;
}
dquote
(
cond
,
item
.
GetValue
());
dquote
(
cond
,
t
->
GetValue
().
c_str
());
}
cond
+=
')'
;
continue
;
}
break
;
default
:
/* Unhandled conditions like
LOCATE_TAG_BASE_TYPE or
LOCATE_TAG_FILE_TYPE won't have a
corresponding upnp prop, so they will be
skipped */
if
(
tag
==
TAG_ALBUM_ARTIST
)
tag
=
TAG_ARTIST
;
// TODO: support LOCATE_TAG_ANY_TYPE etc.
const
char
*
name
=
tag_table_lookup
(
upnp_tags
,
TagType
(
tag
));
const
char
*
name
=
tag_table_lookup
(
upnp_tags
,
tag
);
if
(
name
==
nullptr
)
continue
;
...
...
@@ -304,13 +296,15 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
case-insensitive, but at least some servers
have the same convention as mpd (e.g.:
minidlna) */
if
(
item
.
GetFoldCase
())
{
if
(
t
->
GetFoldCase
())
{
cond
+=
" contains "
;
}
else
{
cond
+=
" = "
;
}
dquote
(
cond
,
item
.
GetValue
());
dquote
(
cond
,
t
->
GetValue
().
c_str
());
}
// TODO: support other ISongFilter implementations
}
return
server
.
search
(
handle
,
objid
,
cond
.
c_str
());
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment