DatabasePrint.cxx 6.67 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
		   bool full, bool base, Error &error)
151
{
152
	const Database *db = client.GetDatabase(error);
153 154 155
	if (db == nullptr)
		return false;

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

168
	return db->Visit(selection, d, s, p, error);
169 170
}

171 172 173 174 175
struct SearchStats {
	int numberOfSongs;
	unsigned long playTime;
};

176
static void printSearchStats(Client &client, SearchStats *stats)
177 178 179 180 181
{
	client_printf(client, "songs: %i\n", stats->numberOfSongs);
	client_printf(client, "playtime: %li\n", stats->playTime);
}

182
static bool
183
stats_visitor_song(SearchStats &stats, const LightSong &song)
184
{
185
	stats.numberOfSongs++;
186
	stats.playTime += song.GetDuration();
187

188
	return true;
189 190
}

191
bool
192
searchStatsForSongsIn(Client &client, const char *name,
193
		      const SongFilter *filter,
194
		      Error &error)
195
{
196
	const Database *db = client.GetDatabase(error);
197 198 199
	if (db == nullptr)
		return false;

200
	const DatabaseSelection selection(name, true, filter);
201

202
	SearchStats stats;
203 204 205
	stats.numberOfSongs = 0;
	stats.playTime = 0;

206
	using namespace std::placeholders;
207
	const auto f = std::bind(stats_visitor_song, std::ref(stats),
208
				 _1);
209
	if (!db->Visit(selection, f, error))
210
		return false;
211

212 213
	printSearchStats(client, &stats);
	return true;
214 215
}

216
bool
217
printAllIn(Client &client, const char *uri_utf8, Error &error)
218
{
219
	const DatabaseSelection selection(uri_utf8, true);
220
	return db_selection_print(client, selection, false, false, error);
221 222
}

223
bool
224
printInfoForAllIn(Client &client, const char *uri_utf8,
225
		  Error &error)
226
{
227
	const DatabaseSelection selection(uri_utf8, true);
228
	return db_selection_print(client, selection, true, false, error);
229 230
}

231
static bool
232
PrintSongURIVisitor(Client &client, const LightSong &song)
233
{
234
	song_print_uri(client, song);
235

236
	return true;
237 238
}

239
static bool
240
PrintUniqueTag(Client &client, TagType tag_type,
241
	       const char *value)
242
{
243
	client_printf(client, "%s: %s\n", tag_item_names[tag_type], value);
244
	return true;
245 246
}

247
bool
248
listAllUniqueTags(Client &client, unsigned type,
249
		  const SongFilter *filter,
250
		  Error &error)
251
{
252
	const Database *db = client.GetDatabase(error);
253 254 255
	if (db == nullptr)
		return false;

256
	const DatabaseSelection selection("", true, filter);
257

258 259
	if (type == LOCATE_TAG_FILE_TYPE) {
		using namespace std::placeholders;
260 261
		const auto f = std::bind(PrintSongURIVisitor,
					 std::ref(client), _1);
262
		return db->Visit(selection, f, error);
263
	} else {
264 265
		assert(type < TAG_NUM_OF_ITEM_TYPES);

266
		using namespace std::placeholders;
267
		const auto f = std::bind(PrintUniqueTag, std::ref(client),
268 269
					 (TagType)type, _1);
		return db->VisitUniqueTags(selection, (TagType)type,
270
					   f, error);
271
	}
272
}