dbUtils.c 7.07 KB
Newer Older
1
/* the Music Player Daemon (MPD)
2
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

19
#include "dbUtils.h"
20
#include "locate.h"
21
#include "directory.h"
22
#include "database.h"
23
#include "client.h"
24
#include "playlist.h"
25
#include "song.h"
26
#include "song_print.h"
27
#include "tag.h"
28
#include "strset.h"
29
#include "log.h"
30
#include "stored_playlist.h"
31

32 33
#include <glib.h>

34 35
#include <stdlib.h>

36
typedef struct _ListCommandItem {
37
	int8_t tagType;
38
	const struct locate_item_list *criteria;
39 40
} ListCommandItem;

41
typedef struct _SearchStats {
42
	const struct locate_item_list *criteria;
43
	int numberOfSongs;
44
	unsigned long playTime;
45 46
} SearchStats;

47 48
static int
printDirectoryInDirectory(struct directory *directory, void *data)
Avuton Olrich's avatar
Avuton Olrich committed
49
{
50
	struct client *client = data;
51 52

	if (!directory_is_root(directory))
53
		client_printf(client, "directory: %s\n", directory_get_path(directory));
54

Avuton Olrich's avatar
Avuton Olrich committed
55
	return 0;
56 57
}

58
static int
59
printSongInDirectory(struct song *song, G_GNUC_UNUSED void *data)
Avuton Olrich's avatar
Avuton Olrich committed
60
{
61
	struct client *client = data;
62
	song_print_url(client, song);
Avuton Olrich's avatar
Avuton Olrich committed
63
	return 0;
64 65
}

66
struct search_data {
67
	struct client *client;
68
	const struct locate_item_list *criteria;
69 70
};

71 72
static int
searchInDirectory(struct song *song, void *_data)
Avuton Olrich's avatar
Avuton Olrich committed
73
{
74
	struct search_data *data = _data;
75

76
	if (locate_song_search(song, data->criteria))
77
		return song_print_info(data->client, song);
78

79 80 81
	return 0;
}

82 83
int
searchForSongsIn(struct client *client, const char *name,
84
		 const struct locate_item_list *criteria)
85
{
86
	int ret;
87 88
	struct locate_item_list *new_list
		= locate_item_list_casefold(criteria);
89
	struct search_data data;
90

91
	data.client = client;
92
	data.criteria = new_list;
93

94
	ret = db_walk(name, searchInDirectory, NULL, &data);
95

96
	locate_item_list_free(new_list);
97 98 99 100

	return ret;
}

101 102
static int
findInDirectory(struct song *song, void *_data)
Avuton Olrich's avatar
Avuton Olrich committed
103
{
104
	struct search_data *data = _data;
105

106
	if (locate_song_match(song, data->criteria))
107
		return song_print_info(data->client, song);
108

109 110 111
	return 0;
}

112 113
int
findSongsIn(struct client *client, const char *name,
114
	    const struct locate_item_list *criteria)
Avuton Olrich's avatar
Avuton Olrich committed
115
{
116
	struct search_data data;
117

118
	data.client = client;
119
	data.criteria = criteria;
Avuton Olrich's avatar
Avuton Olrich committed
120

121
	return db_walk(name, findInDirectory, NULL, &data);
122 123
}

124
static void printSearchStats(struct client *client, SearchStats *stats)
125
{
126 127
	client_printf(client, "songs: %i\n", stats->numberOfSongs);
	client_printf(client, "playtime: %li\n", stats->playTime);
128 129
}

130 131
static int
searchStatsInDirectory(struct song *song, void *data)
132 133 134
{
	SearchStats *stats = data;

135
	if (locate_song_match(song, stats->criteria)) {
136 137 138 139 140 141 142 143
		stats->numberOfSongs++;
		if (song->tag->time > 0)
			stats->playTime += song->tag->time;
	}

	return 0;
}

144 145
int
searchStatsForSongsIn(struct client *client, const char *name,
146
		      const struct locate_item_list *criteria)
147 148 149 150
{
	SearchStats stats;
	int ret;

151
	stats.criteria = criteria;
152 153 154
	stats.numberOfSongs = 0;
	stats.playTime = 0;

155
	ret = db_walk(name, searchStatsInDirectory, NULL, &stats);
156
	if (ret == 0)
157
		printSearchStats(client, &stats);
158 159 160 161

	return ret;
}

162
int printAllIn(struct client *client, const char *name)
Avuton Olrich's avatar
Avuton Olrich committed
163
{
164 165
	return db_walk(name, printSongInDirectory,
		       printDirectoryInDirectory, client);
166 167
}

168
static int
169
directoryAddSongToPlaylist(struct song *song, G_GNUC_UNUSED void *data)
Avuton Olrich's avatar
Avuton Olrich committed
170
{
171
	return addSongToPlaylist(&g_playlist, song, NULL);
172 173
}

174 175 176 177
struct add_data {
	const char *path;
};

178 179
static int
directoryAddSongToStoredPlaylist(struct song *song, void *_data)
180
{
181 182
	struct add_data *data = _data;

183
	if (spl_append_song(data->path, song) != 0)
184 185
		return -1;
	return 0;
186 187
}

188
int addAllIn(const char *name)
Avuton Olrich's avatar
Avuton Olrich committed
189
{
190
	return db_walk(name, directoryAddSongToPlaylist, NULL, NULL);
191 192
}

193
int addAllInToStoredPlaylist(const char *name, const char *utf8file)
194
{
195 196 197 198
	struct add_data data = {
		.path = utf8file,
	};

199
	return db_walk(name, directoryAddSongToStoredPlaylist, NULL, &data);
200 201
}

202 203
static int
directoryPrintSongInfo(struct song *song, void *data)
Avuton Olrich's avatar
Avuton Olrich committed
204
{
205
	struct client *client = data;
206 207
	song_print_info(client, song);
	return 0;
208 209
}

210
int printInfoForAllIn(struct client *client, const char *name)
Avuton Olrich's avatar
Avuton Olrich committed
211
{
212
	return db_walk(name, directoryPrintSongInfo,
213
			     printDirectoryInDirectory, client);
214 215
}

216
static ListCommandItem *
217
newListCommandItem(int tagType, const struct locate_item_list *criteria)
218
{
219
	ListCommandItem *item = g_new(ListCommandItem, 1);
220 221

	item->tagType = tagType;
222
	item->criteria = criteria;
223 224 225 226

	return item;
}

Avuton Olrich's avatar
Avuton Olrich committed
227 228
static void freeListCommandItem(ListCommandItem * item)
{
229
	g_free(item);
230 231
}

232 233 234
static void
visitTag(struct client *client, struct strset *set,
	 struct song *song, enum tag_type tagType)
Avuton Olrich's avatar
Avuton Olrich committed
235
{
236
	int i;
237
	struct tag *tag = song->tag;
238

Avuton Olrich's avatar
Avuton Olrich committed
239
	if (tagType == LOCATE_TAG_FILE_TYPE) {
240
		song_print_url(client, song);
241 242 243
		return;
	}

Avuton Olrich's avatar
Avuton Olrich committed
244 245
	if (!tag)
		return;
246

Avuton Olrich's avatar
Avuton Olrich committed
247
	for (i = 0; i < tag->numOfItems; i++) {
248
		if (tag->items[i]->type == tagType) {
249
			strset_add(set, tag->items[i]->value);
250
			return;
251 252
		}
	}
253
	strset_add(set, "");
254 255
}

256
struct list_tags_data {
257
	struct client *client;
258
	ListCommandItem *item;
259
	struct strset *set;
260 261
};

262 263
static int
listUniqueTagsInDirectory(struct song *song, void *_data)
Avuton Olrich's avatar
Avuton Olrich committed
264
{
265 266
	struct list_tags_data *data = _data;
	ListCommandItem *item = data->item;
267

268
	if (locate_song_match(song, item->criteria))
269
		visitTag(data->client, data->set, song, item->tagType);
270 271 272 273

	return 0;
}

274 275
int listAllUniqueTags(struct client *client, int type,
		      const struct locate_item_list *criteria)
276 277
{
	int ret;
278
	ListCommandItem *item = newListCommandItem(type, criteria);
279
	struct list_tags_data data = {
280
		.client = client,
281 282
		.item = item,
	};
Avuton Olrich's avatar
Avuton Olrich committed
283 284

	if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
285
		data.set = strset_new();
286 287
	}

288
	ret = db_walk(NULL, listUniqueTagsInDirectory, NULL, &data);
289

Avuton Olrich's avatar
Avuton Olrich committed
290
	if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
291 292 293 294 295 296 297 298 299 300
		const char *value;

		strset_rewind(data.set);

		while ((value = strset_next(data.set)) != NULL)
			client_printf(client, "%s: %s\n",
				      mpdTagItemKeys[type],
				      value);

		strset_free(data.set);
301 302
	}

303 304 305 306
	freeListCommandItem(item);

	return ret;
}
307

308 309
static int
sumSavedFilenameMemoryInDirectory(struct directory *dir, void *data)
Avuton Olrich's avatar
Avuton Olrich committed
310 311
{
	int *sum = data;
312

313
	if (directory_is_root(dir))
Avuton Olrich's avatar
Avuton Olrich committed
314
		return 0;
315

316
	*sum += (strlen(directory_get_path(dir)) + 1
317
		 - sizeof(struct directory *)) * dir->songs.nr;
318 319 320 321

	return 0;
}

322 323
static int
sumSavedFilenameMemoryInSong(struct song *song, void *data)
Avuton Olrich's avatar
Avuton Olrich committed
324 325 326 327
{
	int *sum = data;

	*sum += strlen(song->url) + 1;
328

329 330 331
	return 0;
}

Avuton Olrich's avatar
Avuton Olrich committed
332 333
void printSavedMemoryFromFilenames(void)
{
334
	int sum = 0;
335

336 337
	db_walk(NULL, sumSavedFilenameMemoryInSong,
		sumSavedFilenameMemoryInDirectory, (void *)&sum);
338 339 340

	DEBUG("saved memory from filenames: %i\n", sum);
}