1 /*
2  * Copyright 2008-2013 Various Authors
3  * Copyright 2004-2006 Timo Hirvonen
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "lib.h"
20 #include "editable.h"
21 #include "track_info.h"
22 #include "options.h"
23 #include "xmalloc.h"
24 #include "rbtree.h"
25 #include "debug.h"
26 #include "utils.h"
27 #include "ui_curses.h" /* cur_view */
28 
29 #include <pthread.h>
30 #include <string.h>
31 
32 struct editable lib_editable;
33 static struct editable_shared lib_editable_shared;
34 
35 struct tree_track *lib_cur_track = NULL;
36 unsigned int play_sorted = 0;
37 enum aaa_mode aaa_mode = AAA_MODE_ALL;
38 /* used in ui_curses.c for status display */
39 char *lib_live_filter = NULL;
40 
41 struct rb_root lib_shuffle_root;
42 static struct expr *filter = NULL;
43 static struct expr *add_filter = NULL;
44 static int remove_from_hash = 1;
45 
46 static struct expr *live_filter_expr = NULL;
47 static struct track_info *cur_track_ti = NULL;
48 static struct track_info *sel_track_ti = NULL;
49 
artist_sort_name(const struct artist * a)50 const char *artist_sort_name(const struct artist *a)
51 {
52 	if (a->sort_name)
53 		return a->sort_name;
54 
55 	if (smart_artist_sort && a->auto_sort_name)
56 		return a->auto_sort_name;
57 
58 	return a->name;
59 }
60 
sorted_track_to_iter(struct tree_track * track,struct iter * iter)61 static inline void sorted_track_to_iter(struct tree_track *track, struct iter *iter)
62 {
63 	iter->data0 = &lib_editable.head;
64 	iter->data1 = track;
65 	iter->data2 = NULL;
66 }
67 
all_wins_changed(void)68 static void all_wins_changed(void)
69 {
70 	lib_tree_win->changed = 1;
71 	lib_track_win->changed = 1;
72 	lib_editable.shared->win->changed = 1;
73 }
74 
shuffle_add(struct tree_track * track)75 static void shuffle_add(struct tree_track *track)
76 {
77 	shuffle_list_add(&track->shuffle_track, &lib_shuffle_root);
78 }
79 
views_add_track(struct track_info * ti)80 static void views_add_track(struct track_info *ti)
81 {
82 	struct tree_track *track = xnew(struct tree_track, 1);
83 
84 	/* NOTE: does not ref ti */
85 	simple_track_init((struct simple_track *)track, ti);
86 
87 	/* both the hash table and views have refs */
88 	track_info_ref(ti);
89 
90 	tree_add_track(track);
91 	shuffle_add(track);
92 	editable_add(&lib_editable, (struct simple_track *)track);
93 }
94 
95 struct fh_entry {
96 	struct fh_entry *next;
97 
98 	/* ref count is increased when added to this hash */
99 	struct track_info *ti;
100 };
101 
102 #define FH_SIZE (1024)
103 static struct fh_entry *ti_hash[FH_SIZE] = { NULL, };
104 
hash_insert(struct track_info * ti)105 static int hash_insert(struct track_info *ti)
106 {
107 	const char *filename = ti->filename;
108 	unsigned int pos = hash_str(filename) % FH_SIZE;
109 	struct fh_entry **entryp;
110 	struct fh_entry *e;
111 
112 	entryp = &ti_hash[pos];
113 	e = *entryp;
114 	while (e) {
115 		if (strcmp(e->ti->filename, filename) == 0) {
116 			/* found, don't insert */
117 			return 0;
118 		}
119 		e = e->next;
120 	}
121 
122 	e = xnew(struct fh_entry, 1);
123 	track_info_ref(ti);
124 	e->ti = ti;
125 	e->next = *entryp;
126 	*entryp = e;
127 	return 1;
128 }
129 
hash_remove(struct track_info * ti)130 static void hash_remove(struct track_info *ti)
131 {
132 	const char *filename = ti->filename;
133 	unsigned int pos = hash_str(filename) % FH_SIZE;
134 	struct fh_entry **entryp;
135 
136 	entryp = &ti_hash[pos];
137 	while (1) {
138 		struct fh_entry *e = *entryp;
139 
140 		BUG_ON(e == NULL);
141 		if (strcmp(e->ti->filename, filename) == 0) {
142 			*entryp = e->next;
143 			track_info_unref(e->ti);
144 			free(e);
145 			break;
146 		}
147 		entryp = &e->next;
148 	}
149 }
150 
is_filtered(struct track_info * ti)151 static int is_filtered(struct track_info *ti)
152 {
153 	if (live_filter_expr && !expr_eval(live_filter_expr, ti))
154 		return 1;
155 	if (!live_filter_expr && lib_live_filter && !track_info_matches(ti, lib_live_filter, TI_MATCH_ALL))
156 		return 1;
157 	if (filter && !expr_eval(filter, ti))
158 		return 1;
159 	return 0;
160 }
161 
lib_add_track(struct track_info * ti,void * opaque)162 void lib_add_track(struct track_info *ti, void *opaque)
163 {
164 	if (add_filter && !expr_eval(add_filter, ti)) {
165 		/* filter any files excluded by lib_add_filter */
166 		return;
167 	}
168 
169 	if (!hash_insert(ti)) {
170 		/* duplicate files not allowed */
171 		return;
172 	}
173 
174 	if (!is_filtered(ti))
175 		views_add_track(ti);
176 }
177 
album_first_track(const struct album * album)178 static struct tree_track *album_first_track(const struct album *album)
179 {
180 	return to_tree_track(rb_first(&album->track_root));
181 }
182 
artist_first_track(const struct artist * artist)183 static struct tree_track *artist_first_track(const struct artist *artist)
184 {
185 	return album_first_track(to_album(rb_first(&artist->album_root)));
186 }
187 
normal_get_first(void)188 static struct tree_track *normal_get_first(void)
189 {
190 	return artist_first_track(to_artist(rb_first(&lib_artist_root)));
191 }
192 
album_last_track(const struct album * album)193 static struct tree_track *album_last_track(const struct album *album)
194 {
195 	return to_tree_track(rb_last(&album->track_root));
196 }
197 
artist_last_track(const struct artist * artist)198 static struct tree_track *artist_last_track(const struct artist *artist)
199 {
200 	return album_last_track(to_album(rb_last(&artist->album_root)));
201 }
202 
aaa_mode_filter(const struct simple_track * track)203 static int aaa_mode_filter(const struct simple_track *track)
204 {
205 	const struct album *album = ((struct tree_track *)track)->album;
206 
207 	if (aaa_mode == AAA_MODE_ALBUM)
208 		return CUR_ALBUM == album;
209 
210 	if (aaa_mode == AAA_MODE_ARTIST)
211 		return CUR_ARTIST == album->artist;
212 
213 	/* AAA_MODE_ALL */
214 	return 1;
215 }
216 
217 /* set next/prev (tree) {{{ */
218 
normal_get_next(void)219 static struct tree_track *normal_get_next(void)
220 {
221 	if (lib_cur_track == NULL)
222 		return normal_get_first();
223 
224 	/* not last track of the album? */
225 	if (rb_next(&lib_cur_track->tree_node)) {
226 		/* next track of the current album */
227 		return to_tree_track(rb_next(&lib_cur_track->tree_node));
228 	}
229 
230 	if (aaa_mode == AAA_MODE_ALBUM) {
231 		if (!repeat)
232 			return NULL;
233 		/* first track of the current album */
234 		return album_first_track(CUR_ALBUM);
235 	}
236 
237 	/* not last album of the artist? */
238 	if (rb_next(&CUR_ALBUM->tree_node) != NULL) {
239 		/* first track of the next album */
240 		return album_first_track(to_album(rb_next(&CUR_ALBUM->tree_node)));
241 	}
242 
243 	if (aaa_mode == AAA_MODE_ARTIST) {
244 		if (!repeat)
245 			return NULL;
246 		/* first track of the first album of the current artist */
247 		return artist_first_track(CUR_ARTIST);
248 	}
249 
250 	/* not last artist of the library? */
251 	if (rb_next(&CUR_ARTIST->tree_node) != NULL) {
252 		/* first track of the next artist */
253 		return artist_first_track(to_artist(rb_next(&CUR_ARTIST->tree_node)));
254 	}
255 
256 	if (!repeat)
257 		return NULL;
258 
259 	/* first track */
260 	return normal_get_first();
261 }
262 
normal_get_prev(void)263 static struct tree_track *normal_get_prev(void)
264 {
265 	if (lib_cur_track == NULL)
266 		return normal_get_first();
267 
268 	/* not first track of the album? */
269 	if (rb_prev(&lib_cur_track->tree_node)) {
270 		/* prev track of the album */
271 		return to_tree_track(rb_prev(&lib_cur_track->tree_node));
272 	}
273 
274 	if (aaa_mode == AAA_MODE_ALBUM) {
275 		if (!repeat)
276 			return NULL;
277 		/* last track of the album */
278 		return album_last_track(CUR_ALBUM);
279 	}
280 
281 	/* not first album of the artist? */
282 	if (rb_prev(&CUR_ALBUM->tree_node) != NULL) {
283 		/* last track of the prev album of the artist */
284 		return album_last_track(to_album(rb_prev(&CUR_ALBUM->tree_node)));
285 	}
286 
287 	if (aaa_mode == AAA_MODE_ARTIST) {
288 		if (!repeat)
289 			return NULL;
290 		/* last track of the last album of the artist */
291 		return album_last_track(to_album(rb_last(&CUR_ARTIST->album_root)));
292 	}
293 
294 	/* not first artist of the library? */
295 	if (rb_prev(&CUR_ARTIST->tree_node) != NULL) {
296 		/* last track of the last album of the prev artist */
297 		return artist_last_track(to_artist(rb_prev(&CUR_ARTIST->tree_node)));
298 	}
299 
300 	if (!repeat)
301 		return NULL;
302 
303 	/* last track */
304 	return artist_last_track(to_artist(rb_last(&lib_artist_root)));
305 }
306 
307 /* set next/prev (tree) }}} */
308 
lib_reshuffle(void)309 void lib_reshuffle(void)
310 {
311 	shuffle_list_reshuffle(&lib_shuffle_root);
312 }
313 
free_lib_track(struct editable * e,struct list_head * item)314 static void free_lib_track(struct editable *e, struct list_head *item)
315 {
316 	struct tree_track *track = (struct tree_track *)to_simple_track(item);
317 	struct track_info *ti = tree_track_info(track);
318 
319 	if (track == lib_cur_track)
320 		lib_cur_track = NULL;
321 
322 	if (remove_from_hash)
323 		hash_remove(ti);
324 
325 	rb_erase(&track->shuffle_track.tree_node, &lib_shuffle_root);
326 	tree_remove(track);
327 
328 	track_info_unref(ti);
329 	free(track);
330 }
331 
lib_init(void)332 void lib_init(void)
333 {
334 	editable_shared_init(&lib_editable_shared, free_lib_track);
335 	editable_init(&lib_editable, &lib_editable_shared, 1);
336 	tree_init();
337 	srand(time(NULL));
338 }
339 
lib_set_track(struct tree_track * track)340 struct track_info *lib_set_track(struct tree_track *track)
341 {
342 	struct track_info *ti = NULL;
343 
344 	if (track) {
345 		lib_cur_track = track;
346 		ti = tree_track_info(track);
347 		track_info_ref(ti);
348 		if (follow) {
349 			tree_sel_current(auto_expand_albums_follow);
350 			sorted_sel_current();
351 		}
352 		all_wins_changed();
353 	}
354 	return ti;
355 }
356 
lib_goto_next(void)357 struct track_info *lib_goto_next(void)
358 {
359 	struct tree_track *track;
360 
361 	if (rb_root_empty(&lib_artist_root)) {
362 		BUG_ON(lib_cur_track != NULL);
363 		return NULL;
364 	}
365 	if (shuffle) {
366 		track = (struct tree_track *)shuffle_list_get_next(&lib_shuffle_root,
367 				(struct shuffle_track *)lib_cur_track, aaa_mode_filter);
368 	} else if (play_sorted) {
369 		track = (struct tree_track *)simple_list_get_next(&lib_editable.head,
370 				(struct simple_track *)lib_cur_track, aaa_mode_filter);
371 	} else {
372 		track = normal_get_next();
373 	}
374 	return lib_set_track(track);
375 }
376 
lib_goto_prev(void)377 struct track_info *lib_goto_prev(void)
378 {
379 	struct tree_track *track;
380 
381 	if (rb_root_empty(&lib_artist_root)) {
382 		BUG_ON(lib_cur_track != NULL);
383 		return NULL;
384 	}
385 	if (shuffle) {
386 		track = (struct tree_track *)shuffle_list_get_prev(&lib_shuffle_root,
387 				(struct shuffle_track *)lib_cur_track, aaa_mode_filter);
388 	} else if (play_sorted) {
389 		track = (struct tree_track *)simple_list_get_prev(&lib_editable.head,
390 				(struct simple_track *)lib_cur_track, aaa_mode_filter);
391 	} else {
392 		track = normal_get_prev();
393 	}
394 	return lib_set_track(track);
395 }
396 
sorted_get_selected(void)397 static struct tree_track *sorted_get_selected(void)
398 {
399 	struct iter sel;
400 
401 	if (list_empty(&lib_editable.head))
402 		return NULL;
403 
404 	window_get_sel(lib_editable.shared->win, &sel);
405 	return iter_to_sorted_track(&sel);
406 }
407 
sorted_activate_selected(void)408 struct track_info *sorted_activate_selected(void)
409 {
410 	return lib_set_track(sorted_get_selected());
411 }
412 
hash_add_to_views(void)413 static void hash_add_to_views(void)
414 {
415 	int i;
416 	for (i = 0; i < FH_SIZE; i++) {
417 		struct fh_entry *e;
418 
419 		e = ti_hash[i];
420 		while (e) {
421 			struct track_info *ti = e->ti;
422 
423 			if (!is_filtered(ti))
424 				views_add_track(ti);
425 			e = e->next;
426 		}
427 	}
428 }
429 
lib_find_track(struct track_info * ti)430 struct tree_track *lib_find_track(struct track_info *ti)
431 {
432 	struct simple_track *track;
433 
434 	list_for_each_entry(track, &lib_editable.head, node) {
435 		if (strcmp(track->info->filename, ti->filename) == 0) {
436 			struct tree_track *tt = (struct tree_track *)track;
437 			return tt;
438 		}
439 	}
440 	return NULL;
441 }
442 
lib_store_cur_track(struct track_info * ti)443 void lib_store_cur_track(struct track_info *ti)
444 {
445 	if (cur_track_ti)
446 		track_info_unref(cur_track_ti);
447 	cur_track_ti = ti;
448 	track_info_ref(cur_track_ti);
449 }
450 
lib_get_cur_stored_track(void)451 struct track_info *lib_get_cur_stored_track(void)
452 {
453 	if (cur_track_ti && lib_find_track(cur_track_ti))
454 		return cur_track_ti;
455 	return NULL;
456 }
457 
restore_cur_track(struct track_info * ti)458 static void restore_cur_track(struct track_info *ti)
459 {
460 	struct tree_track *tt = lib_find_track(ti);
461 	if (tt)
462 		lib_cur_track = tt;
463 }
464 
is_filtered_cb(void * data,struct track_info * ti)465 static int is_filtered_cb(void *data, struct track_info *ti)
466 {
467 	return is_filtered(ti);
468 }
469 
do_lib_filter(int clear_before)470 static void do_lib_filter(int clear_before)
471 {
472 	/* try to save cur_track */
473 	if (lib_cur_track)
474 		lib_store_cur_track(tree_track_info(lib_cur_track));
475 
476 	if (clear_before)
477 		d_print("filter results could grow, clear tracks and re-add (slow)\n");
478 
479 	remove_from_hash = 0;
480 	if (clear_before) {
481 		editable_clear(&lib_editable);
482 		hash_add_to_views();
483 	} else
484 		editable_remove_matching_tracks(&lib_editable, is_filtered_cb, NULL);
485 	remove_from_hash = 1;
486 
487 	window_changed(lib_editable.shared->win);
488 	window_goto_top(lib_editable.shared->win);
489 	lib_cur_win = lib_tree_win;
490 	window_goto_top(lib_tree_win);
491 
492 	/* restore cur_track */
493 	if (cur_track_ti && !lib_cur_track)
494 		restore_cur_track(cur_track_ti);
495 }
496 
unset_live_filter(void)497 static void unset_live_filter(void)
498 {
499 	free(lib_live_filter);
500 	lib_live_filter = NULL;
501 	free(live_filter_expr);
502 	live_filter_expr = NULL;
503 }
504 
lib_set_filter(struct expr * expr)505 void lib_set_filter(struct expr *expr)
506 {
507 	int clear_before = lib_live_filter || filter;
508 	unset_live_filter();
509 	if (filter)
510 		expr_free(filter);
511 	filter = expr;
512 	do_lib_filter(clear_before);
513 }
514 
lib_set_add_filter(struct expr * expr)515 void lib_set_add_filter(struct expr *expr)
516 {
517 	if (add_filter)
518 		expr_free(add_filter);
519 	add_filter = expr;
520 }
521 
get_sel_track(void)522 static struct tree_track *get_sel_track(void)
523 {
524 	switch (cur_view) {
525 	case TREE_VIEW:
526 		return tree_get_selected();
527 	case SORTED_VIEW:
528 		return sorted_get_selected();
529 	}
530 	return NULL;
531 }
532 
set_sel_track(struct tree_track * tt)533 static void set_sel_track(struct tree_track *tt)
534 {
535 	struct iter iter;
536 
537 	switch (cur_view) {
538 	case TREE_VIEW:
539 		tree_sel_track(tt, auto_expand_albums_selcur);
540 		break;
541 	case SORTED_VIEW:
542 		sorted_track_to_iter(tt, &iter);
543 		window_set_sel(lib_editable.shared->win, &iter);
544 		break;
545 	}
546 }
547 
store_sel_track(void)548 static void store_sel_track(void)
549 {
550 	struct tree_track *tt = get_sel_track();
551 	if (tt) {
552 		sel_track_ti = tree_track_info(tt);
553 		track_info_ref(sel_track_ti);
554 	}
555 }
556 
restore_sel_track(void)557 static void restore_sel_track(void)
558 {
559 	if (sel_track_ti) {
560 		struct tree_track *tt = lib_find_track(sel_track_ti);
561 		if (tt) {
562 			set_sel_track(tt);
563 			track_info_unref(sel_track_ti);
564 			sel_track_ti = NULL;
565 		}
566 	}
567 }
568 
569 /* determine if filter results could grow, in which case all tracks must be cleared and re-added */
do_clear_before(const char * str,struct expr * expr)570 static int do_clear_before(const char *str, struct expr *expr)
571 {
572 	if (!lib_live_filter)
573 		return 0;
574 	if (!str)
575 		return 1;
576 	if ((!expr && live_filter_expr) || (expr && !live_filter_expr))
577 		return 1;
578 	if (!expr || expr_is_harmless(expr))
579 		return !strstr(str, lib_live_filter);
580 	return 1;
581 }
582 
lib_set_live_filter(const char * str)583 void lib_set_live_filter(const char *str)
584 {
585 	int clear_before;
586 	struct expr *expr = NULL;
587 
588 	if (strcmp0(str, lib_live_filter) == 0)
589 		return;
590 
591 	if (str && expr_is_short(str)) {
592 		expr = expr_parse(str);
593 		if (!expr)
594 			return;
595 	}
596 
597 	clear_before = do_clear_before(str, expr);
598 
599 	if (!str)
600 		store_sel_track();
601 
602 	unset_live_filter();
603 	lib_live_filter = str ? xstrdup(str) : NULL;
604 	live_filter_expr = expr;
605 	do_lib_filter(clear_before);
606 
607 	if (expr) {
608 		unsigned int match_type = expr_get_match_type(expr);
609 		if (match_type & TI_MATCH_ALBUM)
610 			tree_expand_all();
611 		if (match_type & TI_MATCH_TITLE)
612 			tree_sel_first();
613 	} else if (str)
614 		tree_expand_matching(str);
615 
616 	if (!str)
617 		restore_sel_track();
618 }
619 
lib_remove(struct track_info * ti)620 int lib_remove(struct track_info *ti)
621 {
622 	struct simple_track *track;
623 
624 	list_for_each_entry(track, &lib_editable.head, node) {
625 		if (track->info == ti) {
626 			editable_remove_track(&lib_editable, track);
627 			return 1;
628 		}
629 	}
630 	return 0;
631 }
632 
lib_clear_store(void)633 void lib_clear_store(void)
634 {
635 	int i;
636 
637 	for (i = 0; i < FH_SIZE; i++) {
638 		struct fh_entry *e, *next;
639 
640 		e = ti_hash[i];
641 		while (e) {
642 			next = e->next;
643 			track_info_unref(e->ti);
644 			free(e);
645 			e = next;
646 		}
647 		ti_hash[i] = NULL;
648 	}
649 }
650 
sorted_sel_current(void)651 void sorted_sel_current(void)
652 {
653 	if (lib_cur_track) {
654 		struct iter iter;
655 
656 		sorted_track_to_iter(lib_cur_track, &iter);
657 		window_set_sel(lib_editable.shared->win, &iter);
658 	}
659 }
660 
ti_cmp(const void * a,const void * b)661 static int ti_cmp(const void *a, const void *b)
662 {
663 	const struct track_info *ai = *(const struct track_info **)a;
664 	const struct track_info *bi = *(const struct track_info **)b;
665 
666 	return track_info_cmp(ai, bi, lib_editable.shared->sort_keys);
667 }
668 
do_lib_for_each(int (* cb)(void * data,struct track_info * ti),void * data,int filtered)669 static int do_lib_for_each(int (*cb)(void *data, struct track_info *ti), void *data, int filtered)
670 {
671 	int i, rc = 0, count = 0, size = 1024;
672 	struct track_info **tis;
673 
674 	tis = xnew(struct track_info *, size);
675 
676 	/* collect all track_infos */
677 	for (i = 0; i < FH_SIZE; i++) {
678 		struct fh_entry *e;
679 
680 		e = ti_hash[i];
681 		while (e) {
682 			if (count == size) {
683 				size *= 2;
684 				tis = xrenew(struct track_info *, tis, size);
685 			}
686 			if (!filtered || !filter || expr_eval(filter, e->ti))
687 				tis[count++] = e->ti;
688 			e = e->next;
689 		}
690 	}
691 
692 	/* sort to speed up playlist loading */
693 	qsort(tis, count, sizeof(struct track_info *), ti_cmp);
694 	for (i = 0; i < count; i++) {
695 		rc = cb(data, tis[i]);
696 		if (rc)
697 			break;
698 	}
699 
700 	free(tis);
701 	return rc;
702 }
703 
lib_for_each(int (* cb)(void * data,struct track_info * ti),void * data,void * opaque)704 int lib_for_each(int (*cb)(void *data, struct track_info *ti), void *data,
705 		void *opaque)
706 {
707 	return do_lib_for_each(cb, data, 0);
708 }
709 
lib_for_each_filtered(int (* cb)(void * data,struct track_info * ti),void * data,void * opaque)710 int lib_for_each_filtered(int (*cb)(void *data, struct track_info *ti),
711 		void *data, void *opaque)
712 {
713 	return do_lib_for_each(cb, data, 1);
714 }
715