DatabasePrint.cxx 6.18 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"
21
#include "DatabasePrint.hxx"
Max Kellermann's avatar
Max Kellermann committed
22
#include "Selection.hxx"
23
#include "SongFilter.hxx"
Max Kellermann's avatar
Max Kellermann committed
24 25
#include "SongPrint.hxx"
#include "TimePrint.hxx"
26
#include "client/Client.hxx"
27
#include "tag/Tag.hxx"
28
#include "LightSong.hxx"
29 30
#include "LightDirectory.hxx"
#include "PlaylistInfo.hxx"
31
#include "Interface.hxx"
32
#include "fs/Traits.hxx"
33

34
#include <functional>
35

36 37 38 39 40 41 42 43
static const char *
ApplyBaseFlag(const char *uri, bool base)
{
	if (base)
		uri = PathTraitsUTF8::GetBase(uri);
	return uri;
}

44
static void
45
PrintDirectoryURI(Client &client, bool base, const LightDirectory &directory)
46
{
47 48
	client_printf(client, "directory: %s\n",
		      ApplyBaseFlag(directory.GetPath(), base));
49 50
}

51
static bool
52
PrintDirectoryBrief(Client &client, bool base, const LightDirectory &directory)
53
{
54
	if (!directory.IsRoot())
55
		PrintDirectoryURI(client, base, directory);
56

57
	return true;
58 59
}

60
static bool
61
PrintDirectoryFull(Client &client, bool base, const LightDirectory &directory)
62 63
{
	if (!directory.IsRoot()) {
64
		PrintDirectoryURI(client, base, directory);
65 66 67

		if (directory.mtime > 0)
			time_print(client, "Last-Modified", directory.mtime);
68 69 70 71 72
	}

	return true;
}

73
static void
74
print_playlist_in_directory(Client &client, bool base,
75 76 77
			    const char *directory,
			    const char *name_utf8)
{
78 79 80
	if (base || directory == nullptr)
		client_printf(client, "playlist: %s\n",
			      ApplyBaseFlag(name_utf8, base));
81 82 83 84
	else
		client_printf(client, "playlist: %s/%s\n",
			      directory, name_utf8);
}
85

86
static void
87
print_playlist_in_directory(Client &client, bool base,
88
			    const LightDirectory *directory,
89 90
			    const char *name_utf8)
{
91
	if (base || directory == nullptr || directory->IsRoot())
92 93 94
		client_printf(client, "playlist: %s\n", name_utf8);
	else
		client_printf(client, "playlist: %s/%s\n",
95
			      directory->GetPath(), name_utf8);
96 97
}

98
static bool
99
PrintSongBrief(Client &client, bool base, const LightSong &song)
100
{
101
	song_print_uri(client, song, base);
102

103
	if (song.tag->has_playlist)
104
		/* this song file has an embedded CUE sheet */
105 106
		print_playlist_in_directory(client, base,
					    song.directory, song.uri);
107

108
	return true;
109 110
}

111
static bool
112
PrintSongFull(Client &client, bool base, const LightSong &song)
113
{
114
	song_print_info(client, song, base);
115

116
	if (song.tag->has_playlist)
117
		/* this song file has an embedded CUE sheet */
118 119
		print_playlist_in_directory(client, base,
					    song.directory, song.uri);
120 121

	return true;
122 123
}

124
static bool
125
PrintPlaylistBrief(Client &client, bool base,
126
		   const PlaylistInfo &playlist,
127
		   const LightDirectory &directory)
128
{
129 130
	print_playlist_in_directory(client, base,
				    &directory, playlist.name.c_str());
131 132 133 134
	return true;
}

static bool
135
PrintPlaylistFull(Client &client, bool base,
136
		  const PlaylistInfo &playlist,
137
		  const LightDirectory &directory)
138
{
139 140
	print_playlist_in_directory(client, base,
				    &directory, playlist.name.c_str());
141

142 143
	if (playlist.mtime > 0)
		time_print(client, "Last-Modified", playlist.mtime);
144 145 146 147

	return true;
}

148
bool
149
db_selection_print(Client &client, const DatabaseSelection &selection,
150 151 152
		   bool full, bool base,
		   unsigned window_start, unsigned window_end,
		   Error &error)
153
{
154
	const Database *db = client.GetDatabase(error);
155 156 157
	if (db == nullptr)
		return false;

158 159
	unsigned i = 0;

160
	using namespace std::placeholders;
161
	const auto d = selection.filter == nullptr
162
		? std::bind(full ? PrintDirectoryFull : PrintDirectoryBrief,
163
			    std::ref(client), base, _1)
164
		: VisitDirectory();
165 166
	VisitSong s = std::bind(full ? PrintSongFull : PrintSongBrief,
				std::ref(client), base, _1);
167
	const auto p = selection.filter == nullptr
168
		? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief,
169
			    std::ref(client), base, _1, _2)
170
		: VisitPlaylist();
171

172 173
	if (window_start > 0 ||
	    window_end < (unsigned)std::numeric_limits<int>::max())
174 175 176 177 178 179 180
		s = [s, window_start, window_end, &i](const LightSong &song,
						      Error &error2){
			const bool in_window = i >= window_start && i < window_end;
			++i;
			return !in_window || s(song, error2);
		};

181
	return db->Visit(selection, d, s, p, error);
182 183
}

184 185 186 187 188 189 190 191 192 193
bool
db_selection_print(Client &client, const DatabaseSelection &selection,
		   bool full, bool base,
		   Error &error)
{
	return db_selection_print(client, selection, full, base,
				  0, std::numeric_limits<int>::max(),
				  error);
}

194
static bool
195
PrintSongURIVisitor(Client &client, const LightSong &song)
196
{
197
	song_print_uri(client, song);
198

199
	return true;
200 201
}

202
static bool
203
PrintUniqueTag(Client &client, TagType tag_type,
204
	       const Tag &tag)
205
{
206 207
	const char *value = tag.GetValue(tag_type);
	assert(value != nullptr);
208
	client_printf(client, "%s: %s\n", tag_item_names[tag_type], value);
209

210
	for (const auto &item : tag)
211 212 213 214
		if (item.type != tag_type)
			client_printf(client, "%s: %s\n",
				      tag_item_names[item.type], item.value);

215
	return true;
216 217
}

218
bool
219 220 221
PrintUniqueTags(Client &client, unsigned type, uint32_t group_mask,
		const SongFilter *filter,
		Error &error)
222
{
223
	const Database *db = client.GetDatabase(error);
224 225 226
	if (db == nullptr)
		return false;

227
	const DatabaseSelection selection("", true, filter);
228

229 230
	if (type == LOCATE_TAG_FILE_TYPE) {
		using namespace std::placeholders;
231 232
		const auto f = std::bind(PrintSongURIVisitor,
					 std::ref(client), _1);
233
		return db->Visit(selection, f, error);
234
	} else {
235 236
		assert(type < TAG_NUM_OF_ITEM_TYPES);

237
		using namespace std::placeholders;
238
		const auto f = std::bind(PrintUniqueTag, std::ref(client),
239 240
					 (TagType)type, _1);
		return db->VisitUniqueTags(selection, (TagType)type,
241
					   group_mask,
242
					   f, error);
243
	}
244
}