DatabasePrint.cxx 5.82 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2013 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"
22
#include "DatabaseSelection.hxx"
23
#include "SongFilter.hxx"
24
#include "PlaylistVector.hxx"
Max Kellermann's avatar
Max Kellermann committed
25 26
#include "SongPrint.hxx"
#include "TimePrint.hxx"
27
#include "Directory.hxx"
Max Kellermann's avatar
Max Kellermann committed
28
#include "Client.hxx"
29
#include "tag/Tag.hxx"
30
#include "Song.hxx"
31 32
#include "DatabaseGlue.hxx"
#include "DatabasePlugin.hxx"
33

34
#include <functional>
35

36
static bool
37
PrintDirectoryBrief(Client &client, const Directory &directory)
38
{
39 40
	if (!directory.IsRoot())
		client_printf(client, "directory: %s\n", directory.GetPath());
41

42
	return true;
43 44
}

45
static bool
46
PrintDirectoryFull(Client &client, const Directory &directory)
47 48 49 50 51 52 53 54 55 56
{
	if (!directory.IsRoot()) {
		client_printf(client, "directory: %s\n", directory.GetPath());
		time_print(client, "Last-Modified", directory.mtime);
	}

	return true;
}


57
static void
58
print_playlist_in_directory(Client &client,
59
			    const Directory &directory,
60 61
			    const char *name_utf8)
{
62
	if (directory.IsRoot())
63 64 65
		client_printf(client, "playlist: %s\n", name_utf8);
	else
		client_printf(client, "playlist: %s/%s\n",
66
			      directory.GetPath(), name_utf8);
67 68
}

69
static bool
70
PrintSongBrief(Client &client, const Song &song)
71
{
72
	assert(song.parent != nullptr);
73

74
	song_print_uri(client, song);
75

76
	if (song.tag != nullptr && song.tag->has_playlist)
77
		/* this song file has an embedded CUE sheet */
78
		print_playlist_in_directory(client, *song.parent, song.uri);
79

80
	return true;
81 82
}

83
static bool
84
PrintSongFull(Client &client, const Song &song)
85
{
86
	assert(song.parent != nullptr);
87

88
	song_print_info(client, song);
89

90
	if (song.tag != nullptr && song.tag->has_playlist)
91
		/* this song file has an embedded CUE sheet */
92
		print_playlist_in_directory(client, *song.parent, song.uri);
93 94

	return true;
95 96
}

97
static bool
98
PrintPlaylistBrief(Client &client,
99
		   const PlaylistInfo &playlist,
100
		   const Directory &directory)
101
{
102
	print_playlist_in_directory(client, directory, playlist.name.c_str());
103 104 105 106
	return true;
}

static bool
107
PrintPlaylistFull(Client &client,
108
		  const PlaylistInfo &playlist,
109
		  const Directory &directory)
110
{
111
	print_playlist_in_directory(client, directory, playlist.name.c_str());
112

113 114
	if (playlist.mtime > 0)
		time_print(client, "Last-Modified", playlist.mtime);
115 116 117 118

	return true;
}

119
bool
120
db_selection_print(Client &client, const DatabaseSelection &selection,
121
		   bool full, Error &error)
122
{
123
	const Database *db = GetDatabase(error);
124 125 126
	if (db == nullptr)
		return false;

127
	using namespace std::placeholders;
128
	const auto d = selection.filter == nullptr
129
		? std::bind(full ? PrintDirectoryFull : PrintDirectoryBrief,
130
			    std::ref(client), _1)
131
		: VisitDirectory();
132
	const auto s = std::bind(full ? PrintSongFull : PrintSongBrief,
133
				 std::ref(client), _1);
134
	const auto p = selection.filter == nullptr
135
		? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief,
136
			    std::ref(client), _1, _2)
137
		: VisitPlaylist();
138

139
	return db->Visit(selection, d, s, p, error);
140 141
}

142 143 144 145 146
struct SearchStats {
	int numberOfSongs;
	unsigned long playTime;
};

147
static void printSearchStats(Client &client, SearchStats *stats)
148 149 150 151 152
{
	client_printf(client, "songs: %i\n", stats->numberOfSongs);
	client_printf(client, "playtime: %li\n", stats->playTime);
}

153
static bool
154
stats_visitor_song(SearchStats &stats, Song &song)
155
{
156
	stats.numberOfSongs++;
157
	stats.playTime += song.GetDuration();
158

159
	return true;
160 161
}

162
bool
163
searchStatsForSongsIn(Client &client, const char *name,
164
		      const SongFilter *filter,
165
		      Error &error)
166
{
167
	const Database *db = GetDatabase(error);
168 169 170
	if (db == nullptr)
		return false;

171
	const DatabaseSelection selection(name, true, filter);
172

173
	SearchStats stats;
174 175 176
	stats.numberOfSongs = 0;
	stats.playTime = 0;

177
	using namespace std::placeholders;
178
	const auto f = std::bind(stats_visitor_song, std::ref(stats),
179
				 _1);
180
	if (!db->Visit(selection, f, error))
181
		return false;
182

183 184
	printSearchStats(client, &stats);
	return true;
185 186
}

187
bool
188
printAllIn(Client &client, const char *uri_utf8, Error &error)
189
{
190
	const DatabaseSelection selection(uri_utf8, true);
191
	return db_selection_print(client, selection, false, error);
192 193
}

194
bool
195
printInfoForAllIn(Client &client, const char *uri_utf8,
196
		  Error &error)
197
{
198
	const DatabaseSelection selection(uri_utf8, true);
199
	return db_selection_print(client, selection, true, error);
200 201
}

202
static bool
203
PrintSongURIVisitor(Client &client, Song &song)
204
{
205
	song_print_uri(client, song);
206

207
	return true;
208 209
}

210
static bool
211
PrintUniqueTag(Client &client, TagType tag_type,
212
	       const char *value)
213
{
214
	client_printf(client, "%s: %s\n", tag_item_names[tag_type], value);
215
	return true;
216 217
}

218
bool
219
listAllUniqueTags(Client &client, int type,
220
		  const SongFilter *filter,
221
		  Error &error)
222
{
223
	const Database *db = 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 235
	} else {
		using namespace std::placeholders;
236
		const auto f = std::bind(PrintUniqueTag, std::ref(client),
237 238
					 (TagType)type, _1);
		return db->VisitUniqueTags(selection, (TagType)type,
239
					   f, error);
240
	}
241
}