summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Soffke <christian.soffke@gmail.com>2024-05-28 00:01:57 +0200
committerChristian Soffke <christian.soffke@gmail.com>2024-06-01 11:55:36 -0400
commit3d7d1d4d5b0289c6357e02be70efe2958ae55e0a (patch)
tree77da477194a3f068114d615d52e9a36f6c0c98fa
parentef1e7d88963aa411f06448f10b3b63886c157c9c (diff)
downloadrockbox-3d7d1d4d5b0289c6357e02be70efe2958ae55e0a.tar.gz
rockbox-3d7d1d4d5b0289c6357e02be70efe2958ae55e0a.zip
plugins: properties: show track info for whole playlist
Track Info can now be displayed for the set of all tracks contained in a playlist. This lets you calculate a playlist's length, for example, even if it is not currently playing. This functionality can be accessed from the existing "Properties" screen for a selected playlist file. A line has been added at the very bottom to show Track Info. Change-Id: I311532b7cfa9e29d46c0cd5623ba4c06c1dd5b5f
-rw-r--r--apps/misc.c23
-rw-r--r--apps/misc.h2
-rw-r--r--apps/playlist.c115
-rw-r--r--apps/playlist.h3
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h3
-rw-r--r--apps/plugins/properties.c107
-rw-r--r--apps/tagtree.c24
8 files changed, 175 insertions, 103 deletions
diff --git a/apps/misc.c b/apps/misc.c
index 7ba229a6f3..b8e69d09c6 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -200,6 +200,29 @@ bool warn_on_pl_erase(void)
200 return true; 200 return true;
201} 201}
202 202
203bool show_search_progress(bool init, int count)
204{
205 static int last_tick = 0;
206
207 /* Don't show splashes for 1/2 second after starting search */
208 if (init)
209 {
210 last_tick = current_tick + HZ/2;
211 return true;
212 }
213
214 /* Update progress every 1/10 of a second */
215 if (TIME_AFTER(current_tick, last_tick + HZ/10))
216 {
217 splashf(0, str(LANG_PLAYLIST_SEARCH_MSG), count, str(LANG_OFF_ABORT));
218 if (action_userabort(TIMEOUT_NOBLOCK))
219 return false;
220 last_tick = current_tick;
221 yield();
222 }
223
224 return true;
225}
203 226
204/* Performance optimized version of the read_line() (see below) function. */ 227/* Performance optimized version of the read_line() (see below) function. */
205int fast_readline(int fd, char *buf, int buf_size, void *parameters, 228int fast_readline(int fd, char *buf, int buf_size, void *parameters,
diff --git a/apps/misc.h b/apps/misc.h
index 28a982d1da..c6485db4ff 100644
--- a/apps/misc.h
+++ b/apps/misc.h
@@ -110,6 +110,8 @@ void talk_timedate(void);
110 * returns true if the playlist should be replaced */ 110 * returns true if the playlist should be replaced */
111bool warn_on_pl_erase(void); 111bool warn_on_pl_erase(void);
112 112
113bool show_search_progress(bool init, int count);
114
113/* Read (up to) a line of text from fd into buffer and return number of bytes 115/* Read (up to) a line of text from fd into buffer and return number of bytes
114 * read (which may be larger than the number of bytes stored in buffer). If 116 * read (which may be larger than the number of bytes stored in buffer). If
115 * an error occurs, -1 is returned (and buffer contains whatever could be 117 * an error occurs, -1 is returned (and buffer contains whatever could be
diff --git a/apps/playlist.c b/apps/playlist.c
index 5a3ada8efc..3600918eb3 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -2498,75 +2498,106 @@ int playlist_insert_directory(struct playlist_info* playlist,
2498} 2498}
2499 2499
2500/* 2500/*
2501 * Insert all tracks from specified playlist into dynamic playlist. 2501 * If action_cb is *not* NULL, it will be called for every track contained
2502 * in the playlist specified by filename. If action_cb is NULL, you must
2503 * instead provide a playlist insert context to use for adding each track
2504 * into a dynamic playlist.
2502 */ 2505 */
2503int playlist_insert_playlist(struct playlist_info* playlist, const char *filename, 2506bool playlist_entries_iterate(const char *filename,
2504 int position, bool queue) 2507 struct playlist_insert_context *pl_context,
2508 bool (*action_cb)(const char *file_name))
2505{ 2509{
2506 int fd = -1; 2510 int fd = -1, i = 0;
2511 bool ret = false;
2507 int max; 2512 int max;
2508 char *dir; 2513 char *dir;
2509 2514
2510 char temp_buf[MAX_PATH+1]; 2515 char temp_buf[MAX_PATH+1];
2511 char trackname[MAX_PATH+1]; 2516 char trackname[MAX_PATH+1];
2512 2517
2513 int result = -1;
2514 bool utf8 = is_m3u8_name(filename); 2518 bool utf8 = is_m3u8_name(filename);
2515 2519
2516 struct playlist_insert_context pl_context;
2517 cpu_boost(true); 2520 cpu_boost(true);
2518 2521
2519 if (playlist_insert_context_create(playlist, &pl_context, position, queue, true) >= 0) 2522 fd = open_utf8(filename, O_RDONLY);
2523 if (fd < 0)
2520 { 2524 {
2521 fd = open_utf8(filename, O_RDONLY); 2525 notify_access_error();
2522 if (fd < 0) 2526 goto out;
2523 { 2527 }
2524 notify_access_error();
2525 goto out;
2526 }
2527 2528
2528 /* we need the directory name for formatting purposes */ 2529 /* we need the directory name for formatting purposes */
2529 size_t dirlen = path_dirname(filename, (const char **)&dir); 2530 size_t dirlen = path_dirname(filename, (const char **)&dir);
2530 //dir = strmemdupa(dir, dirlen); 2531 //dir = strmemdupa(dir, dirlen);
2531 2532
2532 while ((max = read_line(fd, temp_buf, sizeof(temp_buf))) > 0)
2533 {
2534 /* user abort */
2535 if (action_userabort(TIMEOUT_NOBLOCK))
2536 break;
2537 2533
2538 if (temp_buf[0] != '#' && temp_buf[0] != '\0') 2534 if (action_cb)
2535 show_search_progress(true, 0);
2536
2537 while ((max = read_line(fd, temp_buf, sizeof(temp_buf))) > 0)
2538 {
2539 /* user abort */
2540 if (!action_cb && action_userabort(TIMEOUT_NOBLOCK))
2541 break;
2542
2543 if (temp_buf[0] != '#' && temp_buf[0] != '\0')
2544 {
2545 i++;
2546 if (!utf8)
2539 { 2547 {
2540 if (!utf8) 2548 /* Use trackname as a temporay buffer. Note that trackname must
2541 { 2549 * be as large as temp_buf.
2542 /* Use trackname as a temporay buffer. Note that trackname must 2550 */
2543 * be as large as temp_buf. 2551 max = convert_m3u_name(temp_buf, max, sizeof(temp_buf), trackname);
2544 */ 2552 }
2545 max = convert_m3u_name(temp_buf, max, sizeof(temp_buf), trackname);
2546 }
2547 2553
2548 /* we need to format so that relative paths are correctly 2554 /* we need to format so that relative paths are correctly
2549 handled */ 2555 handled */
2550 if (format_track_path(trackname, temp_buf, 2556 if (format_track_path(trackname, temp_buf,
2551 sizeof(trackname), dir, dirlen) < 0) 2557 sizeof(trackname), dir, dirlen) < 0)
2552 { 2558 {
2553 goto out; 2559 goto out;
2554 } 2560 }
2555 2561
2556 if (playlist_insert_context_add(&pl_context, trackname) < 0) 2562 if (action_cb)
2563 {
2564 if (!action_cb(trackname))
2557 goto out; 2565 goto out;
2566 else if (!show_search_progress(false, i))
2567 break;
2558 } 2568 }
2559 2569 else if (playlist_insert_context_add(pl_context, trackname) < 0)
2560 /* let the other threads work */ 2570 goto out;
2561 yield();
2562 } 2571 }
2563 }
2564 2572
2565 result = 0; 2573 /* let the other threads work */
2574 yield();
2575 }
2576 ret = true;
2566 2577
2567out: 2578out:
2568 close(fd); 2579 close(fd);
2569 cpu_boost(false); 2580 cpu_boost(false);
2581 return ret;
2582}
2583
2584/*
2585 * Insert all tracks from specified playlist into dynamic playlist.
2586 */
2587int playlist_insert_playlist(struct playlist_info* playlist, const char *filename,
2588 int position, bool queue)
2589{
2590
2591 int result = -1;
2592
2593 struct playlist_insert_context pl_context;
2594 cpu_boost(true);
2595
2596 if (playlist_insert_context_create(playlist, &pl_context, position, queue, true) >= 0
2597 && playlist_entries_iterate(filename, &pl_context, NULL))
2598 result = 0;
2599
2600 cpu_boost(false);
2570 playlist_insert_context_release(&pl_context); 2601 playlist_insert_context_release(&pl_context);
2571 return result; 2602 return result;
2572} 2603}
diff --git a/apps/playlist.h b/apps/playlist.h
index 4d814c7523..f7426df9a3 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -159,6 +159,9 @@ int playlist_insert_directory(struct playlist_info* playlist,
159 bool recurse); 159 bool recurse);
160int playlist_insert_playlist(struct playlist_info* playlist, const char *filename, 160int playlist_insert_playlist(struct playlist_info* playlist, const char *filename,
161 int position, bool queue); 161 int position, bool queue);
162bool playlist_entries_iterate(const char *filename,
163 struct playlist_insert_context *pl_context,
164 bool (*action_cb)(const char *file_name));
162void playlist_skip_entry(struct playlist_info *playlist, int steps); 165void playlist_skip_entry(struct playlist_info *playlist, int steps);
163int playlist_delete(struct playlist_info* playlist, int index); 166int playlist_delete(struct playlist_info* playlist, int index);
164int playlist_move(struct playlist_info* playlist, int index, int new_index); 167int playlist_move(struct playlist_info* playlist, int index, int new_index);
diff --git a/apps/plugin.c b/apps/plugin.c
index 931b8f1fd4..7934cc1754 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -838,6 +838,7 @@ static const struct plugin_api rockbox_api = {
838 playlist_get_first_index, 838 playlist_get_first_index,
839 playlist_get_display_index, 839 playlist_get_display_index,
840 filetype_get_plugin, 840 filetype_get_plugin,
841 playlist_entries_iterate,
841}; 842};
842 843
843static int plugin_buffer_handle; 844static int plugin_buffer_handle;
diff --git a/apps/plugin.h b/apps/plugin.h
index df519f28cf..e9dedf02a1 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -975,6 +975,9 @@ struct plugin_api {
975 int (*playlist_get_first_index)(const struct playlist_info* playlist); 975 int (*playlist_get_first_index)(const struct playlist_info* playlist);
976 int (*playlist_get_display_index)(void); 976 int (*playlist_get_display_index)(void);
977 char* (*filetype_get_plugin)(int attr, char *buffer, size_t buffer_len); 977 char* (*filetype_get_plugin)(int attr, char *buffer, size_t buffer_len);
978 bool (*playlist_entries_iterate)(const char *filename,
979 struct playlist_insert_context *pl_context,
980 bool (*action_cb)(const char *file_name));
978}; 981};
979 982
980/* plugin header */ 983/* plugin header */
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index ce3c03694c..32bc8b9150 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -19,10 +19,7 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "plugin.h" 21#include "plugin.h"
22
23#ifdef HAVE_TAGCACHE
24#include "lib/mul_id3.h" 22#include "lib/mul_id3.h"
25#endif
26 23
27#if !defined(ARRAY_SIZE) 24#if !defined(ARRAY_SIZE)
28 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) 25 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
@@ -38,6 +35,7 @@ struct dir_stats {
38 35
39enum props_types { 36enum props_types {
40 PROPS_FILE = 0, 37 PROPS_FILE = 0,
38 PROPS_PLAYLIST,
41 PROPS_ID3, 39 PROPS_ID3,
42 PROPS_MUL_ID3, 40 PROPS_MUL_ID3,
43 PROPS_DIR 41 PROPS_DIR
@@ -46,10 +44,8 @@ enum props_types {
46static int props_type = PROPS_FILE; 44static int props_type = PROPS_FILE;
47 45
48static struct mp3entry id3; 46static struct mp3entry id3;
49#ifdef HAVE_TAGCACHE
50static int mul_id3_count; 47static int mul_id3_count;
51static int skipped_count; 48static int skipped_count;
52#endif
53 49
54static char str_filename[MAX_PATH]; 50static char str_filename[MAX_PATH];
55static char str_dirname[MAX_PATH]; 51static char str_dirname[MAX_PATH];
@@ -64,6 +60,7 @@ static int32_t size_unit;
64static struct tm tm; 60static struct tm tm;
65 61
66#define NUM_FILE_PROPERTIES 5 62#define NUM_FILE_PROPERTIES 5
63#define NUM_PLAYLIST_PROPERTIES 1 + NUM_FILE_PROPERTIES
67static const unsigned char* const props_file[] = 64static const unsigned char* const props_file[] =
68{ 65{
69 ID2P(LANG_PROPERTIES_PATH), str_dirname, 66 ID2P(LANG_PROPERTIES_PATH), str_dirname,
@@ -71,6 +68,7 @@ static const unsigned char* const props_file[] =
71 ID2P(LANG_PROPERTIES_SIZE), str_size, 68 ID2P(LANG_PROPERTIES_SIZE), str_size,
72 ID2P(LANG_PROPERTIES_DATE), str_date, 69 ID2P(LANG_PROPERTIES_DATE), str_date,
73 ID2P(LANG_PROPERTIES_TIME), str_time, 70 ID2P(LANG_PROPERTIES_TIME), str_time,
71 ID2P(LANG_MENU_SHOW_ID3_INFO), "...",
74}; 72};
75 73
76#define NUM_DIR_PROPERTIES 4 74#define NUM_DIR_PROPERTIES 4
@@ -120,7 +118,8 @@ static bool file_properties(const char* selected_file)
120 log = human_size_log((unsigned long)info.size); 118 log = human_size_log((unsigned long)info.size);
121 nsize = ((unsigned long)info.size) >> (log*10); 119 nsize = ((unsigned long)info.size) >> (log*10);
122 size_unit = units[log]; 120 size_unit = units[log];
123 rb->snprintf(str_size, sizeof str_size, "%lu %s", nsize, rb->str(size_unit)); 121 rb->snprintf(str_size, sizeof str_size, "%lu %s",
122 nsize, rb->str(size_unit));
124 rb->gmtime_r(&info.mtime, &tm); 123 rb->gmtime_r(&info.mtime, &tm);
125 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", 124 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d",
126 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 125 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
@@ -249,7 +248,7 @@ static const char * get_props(int selected_item, void* data,
249 if (PROPS_DIR == props_type) 248 if (PROPS_DIR == props_type)
250 rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_dir)) ? "ERROR" : 249 rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_dir)) ? "ERROR" :
251 (char *) p2str(props_dir[selected_item]), buffer_len); 250 (char *) p2str(props_dir[selected_item]), buffer_len);
252 else if (PROPS_FILE == props_type) 251 else
253 rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_file)) ? "ERROR" : 252 rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_file)) ? "ERROR" :
254 (char *) p2str(props_file[selected_item]), buffer_len); 253 (char *) p2str(props_file[selected_item]), buffer_len);
255 254
@@ -259,7 +258,8 @@ static const char * get_props(int selected_item, void* data,
259static int speak_property_selection(int selected_item, void *data) 258static int speak_property_selection(int selected_item, void *data)
260{ 259{
261 struct dir_stats *stats = data; 260 struct dir_stats *stats = data;
262 int32_t id = P2ID((props_type == PROPS_DIR ? props_dir : props_file)[selected_item]); 261 int32_t id = P2ID((props_type == PROPS_DIR ?
262 props_dir : props_file)[selected_item]);
263 rb->talk_id(id, false); 263 rb->talk_id(id, false);
264 switch (id) 264 switch (id)
265 { 265 {
@@ -326,7 +326,8 @@ static int browse_file_or_dir(struct dir_stats *stats)
326 rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection); 326 rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection);
327 rb->gui_synclist_set_nb_items(&properties_lists, 327 rb->gui_synclist_set_nb_items(&properties_lists,
328 2 * (props_type == PROPS_FILE ? NUM_FILE_PROPERTIES : 328 2 * (props_type == PROPS_FILE ? NUM_FILE_PROPERTIES :
329 NUM_DIR_PROPERTIES)); 329 props_type == PROPS_PLAYLIST ?
330 NUM_PLAYLIST_PROPERTIES : NUM_DIR_PROPERTIES));
330 rb->gui_synclist_select_item(&properties_lists, 0); 331 rb->gui_synclist_select_item(&properties_lists, 0);
331 rb->gui_synclist_draw(&properties_lists); 332 rb->gui_synclist_draw(&properties_lists);
332 rb->gui_synclist_speak_item(&properties_lists); 333 rb->gui_synclist_speak_item(&properties_lists);
@@ -339,11 +340,17 @@ static int browse_file_or_dir(struct dir_stats *stats)
339 continue; 340 continue;
340 switch(button) 341 switch(button)
341 { 342 {
343 case ACTION_STD_OK:
344 if (props_type == PROPS_PLAYLIST &&
345 rb->gui_synclist_get_sel_pos(&properties_lists)
346 == ARRAY_SIZE(props_file) - 2)
347 return -1;
348 break;
342 case ACTION_STD_CANCEL: 349 case ACTION_STD_CANCEL:
343 return false; 350 return 0;
344 default: 351 default:
345 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) 352 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
346 return true; 353 return 1;
347 break; 354 break;
348 } 355 }
349 } 356 }
@@ -372,7 +379,6 @@ static bool determine_file_or_dir(void)
372 return false; 379 return false;
373} 380}
374 381
375#ifdef HAVE_TAGCACHE
376bool mul_id3_add(const char *file_name) 382bool mul_id3_add(const char *file_name)
377{ 383{
378 if (!file_name || rb->mp3info(&id3, file_name)) 384 if (!file_name || rb->mp3info(&id3, file_name))
@@ -385,10 +391,37 @@ bool mul_id3_add(const char *file_name)
385 391
386 return true; 392 return true;
387} 393}
394
395static bool has_pl_extension(const char* filename)
396{
397 char *dot = rb->strrchr(filename, '.');
398 return (dot && (!rb->strcasecmp(dot, ".m3u") || !rb->strcasecmp(dot, ".m3u8")));
399}
400
401/* Assemble track info from a database table or the contents of a playlist file */
402static bool assemble_track_info(const char *filename)
403{
404 props_type = PROPS_MUL_ID3;
405 mul_id3_count = skipped_count = 0;
406
407 if ( (filename && !rb->playlist_entries_iterate(filename, NULL, &mul_id3_add))
408#ifdef HAVE_TAGCACHE
409 || (!filename && !rb->tagtree_subentries_do_action(&mul_id3_add))
388#endif 410#endif
411 || mul_id3_count == 0)
412 return false;
413 else if (mul_id3_count > 1) /* otherwise, the retrieved id3 can be used as-is */
414 finalize_id3(&id3);
415
416 if (skipped_count > 0)
417 rb->splashf(HZ*2, "Skipped %d", skipped_count);
418
419 return true;
420}
389 421
390enum plugin_status plugin_start(const void* parameter) 422enum plugin_status plugin_start(const void* parameter)
391{ 423{
424 int ret;
392 static struct dir_stats stats = 425 static struct dir_stats stats =
393 { 426 {
394 .len = MAX_PATH, 427 .len = MAX_PATH,
@@ -405,23 +438,7 @@ enum plugin_status plugin_start(const void* parameter)
405 rb->touchscreen_set_mode(rb->global_settings->touch_mode); 438 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
406#endif 439#endif
407 440
408#ifdef HAVE_TAGCACHE 441 if (file[0] == '/') /* single file selected */
409 if (!rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))) /* db table selected */
410 {
411 props_type = PROPS_MUL_ID3;
412 mul_id3_count = skipped_count = 0;
413
414 if (!rb->tagtree_subentries_do_action(&mul_id3_add) || mul_id3_count == 0)
415 return PLUGIN_ERROR;
416 else if (mul_id3_count > 1) /* otherwise, the retrieved id3 can be used as-is */
417 finalize_id3(&id3);
418
419 if (skipped_count > 0)
420 rb->splashf(HZ*2, "Skipped %d", skipped_count);
421 }
422 else
423#endif
424 if (file[0] == '/') /* single track selected */
425 { 442 {
426 const char* file_name = rb->strrchr(file, '/') + 1; 443 const char* file_name = rb->strrchr(file, '/') + 1;
427 int dirlen = (file_name - file); 444 int dirlen = (file_name - file);
@@ -437,8 +454,12 @@ enum plugin_status plugin_start(const void* parameter)
437 return PLUGIN_OK; 454 return PLUGIN_OK;
438 } 455 }
439 456
457 if (props_type == PROPS_FILE && has_pl_extension(file))
458 props_type = PROPS_PLAYLIST;
459
440 /* get the info depending on its_a_dir */ 460 /* get the info depending on its_a_dir */
441 if(!(props_type == PROPS_DIR ? dir_properties(file, &stats) : file_properties(file))) 461 if(!(props_type == PROPS_DIR ?
462 dir_properties(file, &stats) : file_properties(file)))
442 { 463 {
443 /* something went wrong (to do: tell user what it was (nesting,...) */ 464 /* something went wrong (to do: tell user what it was (nesting,...) */
444 rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); 465 rb->splash(0, ID2P(LANG_PROPERTIES_FAIL));
@@ -446,20 +467,32 @@ enum plugin_status plugin_start(const void* parameter)
446 return PLUGIN_OK; 467 return PLUGIN_OK;
447 } 468 }
448 } 469 }
449 else 470 /* database table selected */
471 else if (rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))
472 || !assemble_track_info(NULL))
450 return PLUGIN_ERROR; 473 return PLUGIN_ERROR;
451 474
452 FOR_NB_SCREENS(i) 475 FOR_NB_SCREENS(i)
453 rb->viewportmanager_theme_enable(i, true, NULL); 476 rb->viewportmanager_theme_enable(i, true, NULL);
454 477
455 bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm, 1) : 478 if (props_type == PROPS_ID3)
456#ifdef HAVE_TAGCACHE 479 ret = rb->browse_id3(&id3, 0, 0, &tm, 1); /* Track Info for single file */
457 props_type == PROPS_MUL_ID3 ? rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count) : 480 else if (props_type == PROPS_MUL_ID3)
458#endif 481 ret = rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count); /* database tracks */
459 browse_file_or_dir(&stats); 482 else if ((ret = browse_file_or_dir(&stats)) < 0)
483 ret = assemble_track_info(file) ? /* playlist tracks */
484 rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count) : -1;
460 485
461 FOR_NB_SCREENS(i) 486 FOR_NB_SCREENS(i)
462 rb->viewportmanager_theme_undo(i, false); 487 rb->viewportmanager_theme_undo(i, false);
463 488
464 return usb ? PLUGIN_USB_CONNECTED : PLUGIN_OK; 489 switch (ret)
490 {
491 case 1:
492 return PLUGIN_USB_CONNECTED;
493 case -1:
494 return PLUGIN_ERROR;
495 default:
496 return PLUGIN_OK;
497 }
465} 498}
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 3a875d6da6..be728dcc95 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -1312,30 +1312,6 @@ void tagtree_init(void)
1312 initialize_tagtree(); 1312 initialize_tagtree();
1313} 1313}
1314 1314
1315static bool show_search_progress(bool init, int count)
1316{
1317 static int last_tick = 0;
1318
1319 /* Don't show splashes for 1/2 second after starting search */
1320 if (init)
1321 {
1322 last_tick = current_tick + HZ/2;
1323 return true;
1324 }
1325
1326 /* Update progress every 1/10 of a second */
1327 if (TIME_AFTER(current_tick, last_tick + HZ/10))
1328 {
1329 splashf(0, str(LANG_PLAYLIST_SEARCH_MSG), count, str(LANG_OFF_ABORT));
1330 if (action_userabort(TIMEOUT_NOBLOCK))
1331 return false;
1332 last_tick = current_tick;
1333 yield();
1334 }
1335
1336 return true;
1337}
1338
1339static int format_str(struct tagcache_search *tcs, struct display_format *fmt, 1315static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
1340 char *buf, int buf_size) 1316 char *buf, int buf_size)
1341{ 1317{