command: add command "listfiles"
Lists files and directories. Supports storage plugins.
This commit is contained in:
parent
797bbeabeb
commit
96afa8bd2b
2
NEWS
2
NEWS
|
@ -1,6 +1,6 @@
|
|||
ver 0.19 (not yet released)
|
||||
* protocol
|
||||
- new commands "addtagid", "cleartagid"
|
||||
- new commands "addtagid", "cleartagid", "listfiles"
|
||||
- "lsinfo" and "readcomments" allowed for remote files
|
||||
- "listneighbors" lists file servers on the local network
|
||||
- "playlistadd" supports file:///
|
||||
|
|
|
@ -1600,6 +1600,31 @@ OK
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="command_listfiles">
|
||||
<term>
|
||||
<cmdsynopsis>
|
||||
<command>listfiles</command>
|
||||
<arg><replaceable>URI</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Lists the contents of the directory
|
||||
<varname>URI</varname>, including files are not
|
||||
recognized by MPD. <varname>URI</varname> can be a path
|
||||
relative to the music directory or an URI understood by
|
||||
one of the storage plugins. The response contains at
|
||||
least one line for each directory entry with the prefix
|
||||
"file: " or "directory: ", and may be followed by file
|
||||
attributes such as "Last-Modified" and "size".
|
||||
</para>
|
||||
<para>
|
||||
For example, "smb://SERVER" returns a list of all shares
|
||||
on the given SMB/CIFS server; "nfs://servername/path"
|
||||
obtains a directory listing from the NFS server.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="command_lsinfo">
|
||||
<term>
|
||||
<cmdsynopsis>
|
||||
|
|
|
@ -30,44 +30,50 @@
|
|||
#define SONG_FILE "file: "
|
||||
|
||||
static void
|
||||
song_print_uri(Client &client, const char *uri)
|
||||
song_print_uri(Client &client, const char *uri, bool base)
|
||||
{
|
||||
std::string allocated;
|
||||
|
||||
if (base) {
|
||||
uri = PathTraitsUTF8::GetBase(uri);
|
||||
} else {
|
||||
#ifdef ENABLE_DATABASE
|
||||
const Storage *storage = client.GetStorage();
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
uri = suffix;
|
||||
}
|
||||
const Storage *storage = client.GetStorage();
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
uri = suffix;
|
||||
}
|
||||
#endif
|
||||
|
||||
const std::string allocated = uri_remove_auth(uri);
|
||||
if (!allocated.empty())
|
||||
uri = allocated.c_str();
|
||||
allocated = uri_remove_auth(uri);
|
||||
if (!allocated.empty())
|
||||
uri = allocated.c_str();
|
||||
}
|
||||
|
||||
client_printf(client, "%s%s\n", SONG_FILE, uri);
|
||||
}
|
||||
|
||||
void
|
||||
song_print_uri(Client &client, const LightSong &song)
|
||||
song_print_uri(Client &client, const LightSong &song, bool base)
|
||||
{
|
||||
if (song.directory != nullptr) {
|
||||
if (!base && song.directory != nullptr) {
|
||||
client_printf(client, "%s%s/%s\n", SONG_FILE,
|
||||
song.directory, song.uri);
|
||||
} else
|
||||
song_print_uri(client, song.uri);
|
||||
song_print_uri(client, song.uri, base);
|
||||
}
|
||||
|
||||
void
|
||||
song_print_uri(Client &client, const DetachedSong &song)
|
||||
song_print_uri(Client &client, const DetachedSong &song, bool base)
|
||||
{
|
||||
song_print_uri(client, song.GetURI());
|
||||
song_print_uri(client, song.GetURI(), base);
|
||||
}
|
||||
|
||||
void
|
||||
song_print_info(Client &client, const LightSong &song)
|
||||
song_print_info(Client &client, const LightSong &song, bool base)
|
||||
{
|
||||
song_print_uri(client, song);
|
||||
song_print_uri(client, song, base);
|
||||
|
||||
if (song.end_ms > 0)
|
||||
client_printf(client, "Range: %u.%03u-%u.%03u\n",
|
||||
|
@ -87,9 +93,9 @@ song_print_info(Client &client, const LightSong &song)
|
|||
}
|
||||
|
||||
void
|
||||
song_print_info(Client &client, const DetachedSong &song)
|
||||
song_print_info(Client &client, const DetachedSong &song, bool base)
|
||||
{
|
||||
song_print_uri(client, song);
|
||||
song_print_uri(client, song, base);
|
||||
|
||||
const unsigned start_ms = song.GetStartMS();
|
||||
const unsigned end_ms = song.GetEndMS();
|
||||
|
|
|
@ -25,15 +25,15 @@ class DetachedSong;
|
|||
class Client;
|
||||
|
||||
void
|
||||
song_print_info(Client &client, const DetachedSong &song);
|
||||
song_print_info(Client &client, const DetachedSong &song, bool base=false);
|
||||
|
||||
void
|
||||
song_print_info(Client &client, const LightSong &song);
|
||||
song_print_info(Client &client, const LightSong &song, bool base=false);
|
||||
|
||||
void
|
||||
song_print_uri(Client &client, const LightSong &song);
|
||||
song_print_uri(Client &client, const LightSong &song, bool base=false);
|
||||
|
||||
void
|
||||
song_print_uri(Client &client, const DetachedSong &song);
|
||||
song_print_uri(Client &client, const DetachedSong &song, bool base=false);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -107,6 +107,9 @@ static const struct command commands[] = {
|
|||
{ "list", PERMISSION_READ, 1, -1, handle_list },
|
||||
{ "listall", PERMISSION_READ, 0, 1, handle_listall },
|
||||
{ "listallinfo", PERMISSION_READ, 0, 1, handle_listallinfo },
|
||||
#endif
|
||||
{ "listfiles", PERMISSION_READ, 0, 1, handle_listfiles },
|
||||
#ifdef ENABLE_DATABASE
|
||||
{ "listmounts", PERMISSION_READ, 0, 0, handle_listmounts },
|
||||
#endif
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
|
|
|
@ -31,6 +31,18 @@
|
|||
#include "SongFilter.hxx"
|
||||
#include "protocol/Result.hxx"
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_db(Client &client, const char *uri)
|
||||
{
|
||||
const DatabaseSelection selection(uri, false);
|
||||
|
||||
Error error;
|
||||
if (!db_selection_print(client, selection, false, true, error))
|
||||
return print_error(client, error);
|
||||
|
||||
return CommandResult::OK;
|
||||
}
|
||||
|
||||
CommandResult
|
||||
handle_lsinfo2(Client &client, int argc, char *argv[])
|
||||
{
|
||||
|
@ -42,7 +54,7 @@ handle_lsinfo2(Client &client, int argc, char *argv[])
|
|||
const DatabaseSelection selection(uri, false);
|
||||
|
||||
Error error;
|
||||
if (!db_selection_print(client, selection, true, error))
|
||||
if (!db_selection_print(client, selection, true, false, error))
|
||||
return print_error(client, error);
|
||||
|
||||
return CommandResult::OK;
|
||||
|
@ -60,7 +72,7 @@ handle_match(Client &client, int argc, char *argv[], bool fold_case)
|
|||
const DatabaseSelection selection("", true, &filter);
|
||||
|
||||
Error error;
|
||||
return db_selection_print(client, selection, true, error)
|
||||
return db_selection_print(client, selection, true, false, error)
|
||||
? CommandResult::OK
|
||||
: print_error(client, error);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
|
||||
class Client;
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_db(Client &client, const char *uri);
|
||||
|
||||
CommandResult
|
||||
handle_lsinfo2(Client &client, int argc, char *argv[]);
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS /* for PRIu64 */
|
||||
|
||||
#include "config.h"
|
||||
#include "FileCommands.hxx"
|
||||
#include "CommandError.hxx"
|
||||
|
@ -33,9 +35,79 @@
|
|||
#include "TagFile.hxx"
|
||||
#include "storage/StorageInterface.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "TimePrint.hxx"
|
||||
#include "ls.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <inttypes.h> /* for PRIu64 */
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
SkipNameFS(const char *name_fs)
|
||||
{
|
||||
return name_fs[0] == '.' &&
|
||||
(name_fs[1] == 0 ||
|
||||
(name_fs[1] == '.' && name_fs[2] == 0));
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
skip_path(const char *name_fs)
|
||||
{
|
||||
return strchr(name_fs, '\n') != nullptr;
|
||||
}
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_local(Client &client, const char *path_utf8)
|
||||
{
|
||||
const auto path_fs = AllocatedPath::FromUTF8(path_utf8);
|
||||
if (path_fs.IsNull()) {
|
||||
command_error(client, ACK_ERROR_NO_EXIST,
|
||||
"unsupported file name");
|
||||
return CommandResult::ERROR;
|
||||
}
|
||||
|
||||
Error error;
|
||||
if (!client.AllowFile(path_fs, error))
|
||||
return print_error(client, error);
|
||||
|
||||
DirectoryReader reader(path_fs);
|
||||
if (reader.HasFailed()) {
|
||||
error.FormatErrno("Failed to open '%s'", path_utf8);
|
||||
return print_error(client, error);
|
||||
}
|
||||
|
||||
while (reader.ReadEntry()) {
|
||||
const Path name_fs = reader.GetEntry();
|
||||
if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs.c_str()))
|
||||
continue;
|
||||
|
||||
std::string name_utf8 = name_fs.ToUTF8();
|
||||
if (name_utf8.empty())
|
||||
continue;
|
||||
|
||||
const AllocatedPath full_fs =
|
||||
AllocatedPath::Build(path_fs, name_fs);
|
||||
struct stat st;
|
||||
if (!StatFile(full_fs, st, false))
|
||||
continue;
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
client_printf(client, "file: %s\n"
|
||||
"size: %" PRIu64 "\n",
|
||||
name_utf8.c_str(),
|
||||
uint64_t(st.st_size));
|
||||
} else if (S_ISDIR(st.st_mode))
|
||||
client_printf(client, "directory: %s\n",
|
||||
name_utf8.c_str());
|
||||
|
||||
time_print(client, "Last-Modified", st.st_mtime);
|
||||
}
|
||||
|
||||
return CommandResult::OK;
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
|
||||
class Client;
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_local(Client &client, const char *path_utf8);
|
||||
|
||||
CommandResult
|
||||
handle_read_comments(Client &client, int argc, char *argv[]);
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "OtherCommands.hxx"
|
||||
#include "FileCommands.hxx"
|
||||
#include "StorageCommands.hxx"
|
||||
#include "CommandError.hxx"
|
||||
#include "db/Uri.hxx"
|
||||
#include "storage/StorageInterface.hxx"
|
||||
|
@ -112,6 +114,41 @@ print_tag(TagType type, const char *value, void *ctx)
|
|||
tag_print(client, type, value);
|
||||
}
|
||||
|
||||
CommandResult
|
||||
handle_listfiles(Client &client, int argc, char *argv[])
|
||||
{
|
||||
const char *const uri = argc == 2
|
||||
? argv[1]
|
||||
/* default is root directory */
|
||||
: "";
|
||||
|
||||
if (memcmp(uri, "file:///", 8) == 0)
|
||||
/* list local directory */
|
||||
return handle_listfiles_local(client, uri + 7);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (uri_has_scheme(uri))
|
||||
/* use storage plugin to list remote directory */
|
||||
return handle_listfiles_storage(client, uri);
|
||||
|
||||
/* must be a path relative to the configured
|
||||
music_directory */
|
||||
|
||||
if (client.partition.instance.storage != nullptr)
|
||||
/* if we have a storage instance, obtain a list of
|
||||
files from it */
|
||||
return handle_listfiles_storage(client,
|
||||
*client.partition.instance.storage,
|
||||
uri);
|
||||
|
||||
/* fall back to entries from database if we have no storage */
|
||||
return handle_listfiles_db(client, uri);
|
||||
#else
|
||||
command_error(client, ACK_ERROR_NO_EXIST, "No database");
|
||||
return CommandResult::ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
static constexpr tag_handler print_tag_handler = {
|
||||
nullptr,
|
||||
print_tag,
|
||||
|
|
|
@ -39,6 +39,9 @@ handle_kill(Client &client, int argc, char *argv[]);
|
|||
CommandResult
|
||||
handle_close(Client &client, int argc, char *argv[]);
|
||||
|
||||
CommandResult
|
||||
handle_listfiles(Client &client, int argc, char *argv[]);
|
||||
|
||||
CommandResult
|
||||
handle_lsinfo(Client &client, int argc, char *argv[]);
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS /* for PRIu64 */
|
||||
|
||||
#include "config.h"
|
||||
#include "StorageCommands.hxx"
|
||||
#include "CommandError.hxx"
|
||||
|
@ -29,10 +31,103 @@
|
|||
#include "Instance.hxx"
|
||||
#include "storage/Registry.hxx"
|
||||
#include "storage/CompositeStorage.hxx"
|
||||
#include "storage/FileInfo.hxx"
|
||||
#include "db/plugins/simple/SimpleDatabasePlugin.hxx"
|
||||
#include "db/update/Service.hxx"
|
||||
#include "TimePrint.hxx"
|
||||
#include "Idle.hxx"
|
||||
|
||||
#include <inttypes.h> /* for PRIu64 */
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
skip_path(const char *name_utf8)
|
||||
{
|
||||
return strchr(name_utf8, '\n') != nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
|
||||
Error &error)
|
||||
{
|
||||
const char *name_utf8;
|
||||
while ((name_utf8 = reader.Read()) != nullptr) {
|
||||
if (skip_path(name_utf8))
|
||||
continue;
|
||||
|
||||
FileInfo info;
|
||||
if (!reader.GetInfo(false, info, error))
|
||||
continue;
|
||||
|
||||
switch (info.type) {
|
||||
case FileInfo::Type::OTHER:
|
||||
/* ignore */
|
||||
continue;
|
||||
|
||||
case FileInfo::Type::REGULAR:
|
||||
client_printf(client, "file: %s\n"
|
||||
"size: %" PRIu64 "\n",
|
||||
name_utf8,
|
||||
info.size);
|
||||
break;
|
||||
|
||||
case FileInfo::Type::DIRECTORY:
|
||||
client_printf(client, "directory: %s\n", name_utf8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (info.mtime != 0)
|
||||
time_print(client, "Last-Modified", info.mtime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_listfiles_storage(Client &client, Storage &storage, const char *uri,
|
||||
Error &error)
|
||||
{
|
||||
auto reader = storage.OpenDirectory(uri, error);
|
||||
if (reader == nullptr)
|
||||
return false;
|
||||
|
||||
bool success = handle_listfiles_storage(client, *reader, error);
|
||||
delete reader;
|
||||
return success;
|
||||
}
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_storage(Client &client, Storage &storage, const char *uri)
|
||||
{
|
||||
Error error;
|
||||
if (!handle_listfiles_storage(client, storage, uri, error))
|
||||
return print_error(client, error);
|
||||
|
||||
return CommandResult::OK;
|
||||
}
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_storage(Client &client, const char *uri)
|
||||
{
|
||||
Error error;
|
||||
Storage *storage = CreateStorageURI(uri, error);
|
||||
if (storage == nullptr) {
|
||||
if (error.IsDefined())
|
||||
return print_error(client, error);
|
||||
|
||||
command_error(client, ACK_ERROR_ARG,
|
||||
"Unrecognized storage URI");
|
||||
return CommandResult::ERROR;
|
||||
}
|
||||
|
||||
bool success = handle_listfiles_storage(client, *storage, "", error);
|
||||
delete storage;
|
||||
if (!success)
|
||||
return print_error(client, error);
|
||||
|
||||
return CommandResult::OK;
|
||||
}
|
||||
|
||||
static void
|
||||
print_storage_uri(Client &client, const Storage &storage)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
#include "CommandResult.hxx"
|
||||
|
||||
class Client;
|
||||
class Storage;
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_storage(Client &client, Storage &storage, const char *uri);
|
||||
|
||||
CommandResult
|
||||
handle_listfiles_storage(Client &client, const char *uri);
|
||||
|
||||
CommandResult
|
||||
handle_listmounts(Client &client, int argc, char *argv[]);
|
||||
|
|
|
@ -29,29 +29,39 @@
|
|||
#include "LightDirectory.hxx"
|
||||
#include "PlaylistInfo.hxx"
|
||||
#include "Interface.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
|
||||
#include <functional>
|
||||
|
||||
static void
|
||||
PrintDirectoryURI(Client &client, const LightDirectory &directory)
|
||||
static const char *
|
||||
ApplyBaseFlag(const char *uri, bool base)
|
||||
{
|
||||
client_printf(client, "directory: %s\n", directory.GetPath());
|
||||
if (base)
|
||||
uri = PathTraitsUTF8::GetBase(uri);
|
||||
return uri;
|
||||
}
|
||||
|
||||
static void
|
||||
PrintDirectoryURI(Client &client, bool base, const LightDirectory &directory)
|
||||
{
|
||||
client_printf(client, "directory: %s\n",
|
||||
ApplyBaseFlag(directory.GetPath(), base));
|
||||
}
|
||||
|
||||
static bool
|
||||
PrintDirectoryBrief(Client &client, const LightDirectory &directory)
|
||||
PrintDirectoryBrief(Client &client, bool base, const LightDirectory &directory)
|
||||
{
|
||||
if (!directory.IsRoot())
|
||||
PrintDirectoryURI(client, directory);
|
||||
PrintDirectoryURI(client, base, directory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrintDirectoryFull(Client &client, const LightDirectory &directory)
|
||||
PrintDirectoryFull(Client &client, bool base, const LightDirectory &directory)
|
||||
{
|
||||
if (!directory.IsRoot()) {
|
||||
PrintDirectoryURI(client, directory);
|
||||
PrintDirectoryURI(client, base, directory);
|
||||
|
||||
if (directory.mtime > 0)
|
||||
time_print(client, "Last-Modified", directory.mtime);
|
||||
|
@ -61,23 +71,24 @@ PrintDirectoryFull(Client &client, const LightDirectory &directory)
|
|||
}
|
||||
|
||||
static void
|
||||
print_playlist_in_directory(Client &client,
|
||||
print_playlist_in_directory(Client &client, bool base,
|
||||
const char *directory,
|
||||
const char *name_utf8)
|
||||
{
|
||||
if (directory == nullptr)
|
||||
client_printf(client, "playlist: %s\n", name_utf8);
|
||||
if (base || directory == nullptr)
|
||||
client_printf(client, "playlist: %s\n",
|
||||
ApplyBaseFlag(name_utf8, base));
|
||||
else
|
||||
client_printf(client, "playlist: %s/%s\n",
|
||||
directory, name_utf8);
|
||||
}
|
||||
|
||||
static void
|
||||
print_playlist_in_directory(Client &client,
|
||||
print_playlist_in_directory(Client &client, bool base,
|
||||
const LightDirectory *directory,
|
||||
const char *name_utf8)
|
||||
{
|
||||
if (directory == nullptr || directory->IsRoot())
|
||||
if (base || directory == nullptr || directory->IsRoot())
|
||||
client_printf(client, "playlist: %s\n", name_utf8);
|
||||
else
|
||||
client_printf(client, "playlist: %s/%s\n",
|
||||
|
@ -85,44 +96,48 @@ print_playlist_in_directory(Client &client,
|
|||
}
|
||||
|
||||
static bool
|
||||
PrintSongBrief(Client &client, const LightSong &song)
|
||||
PrintSongBrief(Client &client, bool base, const LightSong &song)
|
||||
{
|
||||
song_print_uri(client, song);
|
||||
song_print_uri(client, song, base);
|
||||
|
||||
if (song.tag->has_playlist)
|
||||
/* this song file has an embedded CUE sheet */
|
||||
print_playlist_in_directory(client, song.directory, song.uri);
|
||||
print_playlist_in_directory(client, base,
|
||||
song.directory, song.uri);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrintSongFull(Client &client, const LightSong &song)
|
||||
PrintSongFull(Client &client, bool base, const LightSong &song)
|
||||
{
|
||||
song_print_info(client, song);
|
||||
song_print_info(client, song, base);
|
||||
|
||||
if (song.tag->has_playlist)
|
||||
/* this song file has an embedded CUE sheet */
|
||||
print_playlist_in_directory(client, song.directory, song.uri);
|
||||
print_playlist_in_directory(client, base,
|
||||
song.directory, song.uri);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrintPlaylistBrief(Client &client,
|
||||
PrintPlaylistBrief(Client &client, bool base,
|
||||
const PlaylistInfo &playlist,
|
||||
const LightDirectory &directory)
|
||||
{
|
||||
print_playlist_in_directory(client, &directory, playlist.name.c_str());
|
||||
print_playlist_in_directory(client, base,
|
||||
&directory, playlist.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrintPlaylistFull(Client &client,
|
||||
PrintPlaylistFull(Client &client, bool base,
|
||||
const PlaylistInfo &playlist,
|
||||
const LightDirectory &directory)
|
||||
{
|
||||
print_playlist_in_directory(client, &directory, playlist.name.c_str());
|
||||
print_playlist_in_directory(client, base,
|
||||
&directory, playlist.name.c_str());
|
||||
|
||||
if (playlist.mtime > 0)
|
||||
time_print(client, "Last-Modified", playlist.mtime);
|
||||
|
@ -132,7 +147,7 @@ PrintPlaylistFull(Client &client,
|
|||
|
||||
bool
|
||||
db_selection_print(Client &client, const DatabaseSelection &selection,
|
||||
bool full, Error &error)
|
||||
bool full, bool base, Error &error)
|
||||
{
|
||||
const Database *db = client.GetDatabase(error);
|
||||
if (db == nullptr)
|
||||
|
@ -141,13 +156,13 @@ db_selection_print(Client &client, const DatabaseSelection &selection,
|
|||
using namespace std::placeholders;
|
||||
const auto d = selection.filter == nullptr
|
||||
? std::bind(full ? PrintDirectoryFull : PrintDirectoryBrief,
|
||||
std::ref(client), _1)
|
||||
std::ref(client), base, _1)
|
||||
: VisitDirectory();
|
||||
const auto s = std::bind(full ? PrintSongFull : PrintSongBrief,
|
||||
std::ref(client), _1);
|
||||
std::ref(client), base, _1);
|
||||
const auto p = selection.filter == nullptr
|
||||
? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief,
|
||||
std::ref(client), _1, _2)
|
||||
std::ref(client), base, _1, _2)
|
||||
: VisitPlaylist();
|
||||
|
||||
return db->Visit(selection, d, s, p, error);
|
||||
|
@ -202,7 +217,7 @@ bool
|
|||
printAllIn(Client &client, const char *uri_utf8, Error &error)
|
||||
{
|
||||
const DatabaseSelection selection(uri_utf8, true);
|
||||
return db_selection_print(client, selection, false, error);
|
||||
return db_selection_print(client, selection, false, false, error);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -210,7 +225,7 @@ printInfoForAllIn(Client &client, const char *uri_utf8,
|
|||
Error &error)
|
||||
{
|
||||
const DatabaseSelection selection(uri_utf8, true);
|
||||
return db_selection_print(client, selection, true, error);
|
||||
return db_selection_print(client, selection, true, false, error);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
@ -29,10 +29,11 @@ class Error;
|
|||
|
||||
/**
|
||||
* @param full print attributes/tags
|
||||
* @param base print only base name of songs/directories?
|
||||
*/
|
||||
bool
|
||||
db_selection_print(Client &client, const DatabaseSelection &selection,
|
||||
bool full, Error &error);
|
||||
bool full, bool base, Error &error);
|
||||
|
||||
gcc_nonnull(2)
|
||||
bool
|
||||
|
|
Loading…
Reference in New Issue