summaryrefslogtreecommitdiff
path: root/apps/playlist_viewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playlist_viewer.c')
-rw-r--r--apps/playlist_viewer.c208
1 files changed, 154 insertions, 54 deletions
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index b0435365e2..d556f3b557 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -50,6 +50,7 @@
50#include "playlist_menu.h" 50#include "playlist_menu.h"
51#include "menus/exported_menus.h" 51#include "menus/exported_menus.h"
52#include "yesno.h" 52#include "yesno.h"
53#include "playback.h"
53 54
54/* Maximum number of tracks we can have loaded at one time */ 55/* Maximum number of tracks we can have loaded at one time */
55#define MAX_PLAYLIST_ENTRIES 200 56#define MAX_PLAYLIST_ENTRIES 200
@@ -142,7 +143,7 @@ static bool playlist_viewer_init(struct playlist_viewer * viewer,
142 const char* filename, bool reload, 143 const char* filename, bool reload,
143 int *most_recent_selection); 144 int *most_recent_selection);
144 145
145static void format_line(const struct playlist_entry* track, char* str, 146static void format_line(struct playlist_entry* track, char* str,
146 int len); 147 int len);
147 148
148static bool update_playlist(bool force); 149static bool update_playlist(bool force);
@@ -159,6 +160,27 @@ static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
159 pb->num_loaded = 0; 160 pb->num_loaded = 0;
160} 161}
161 162
163static int playlist_buffer_get_index(struct playlist_buffer *pb, int index)
164{
165 int buffer_index;
166 if (pb->direction == FORWARD)
167 {
168 if (index >= pb->first_index)
169 buffer_index = index-pb->first_index;
170 else /* rotation : track0 in buffer + requested track */
171 buffer_index = viewer.num_tracks-pb->first_index+index;
172 }
173 else
174 {
175 if (index <= pb->first_index)
176 buffer_index = pb->first_index-index;
177 else /* rotation : track0 in buffer + dist from the last track
178 to the requested track (num_tracks-requested track) */
179 buffer_index = pb->first_index+viewer.num_tracks-index;
180 }
181 return buffer_index;
182}
183
162/* 184/*
163 * Loads the entries following 'index' in the playlist buffer 185 * Loads the entries following 'index' in the playlist buffer
164 */ 186 */
@@ -227,6 +249,25 @@ static void playlist_buffer_load_entries_screen(struct playlist_buffer * pb,
227 playlist_buffer_load_entries(pb, start, direction); 249 playlist_buffer_load_entries(pb, start, direction);
228} 250}
229 251
252static bool retrieve_id3_tags(const int index, const char* name, struct mp3entry *id3, int flags)
253{
254 bool id3_retrieval_successful = false;
255
256 if (!viewer.playlist &&
257 (audio_status() & AUDIO_STATUS_PLAY) &&
258 (playlist_get_resume_info(&viewer.current_playing_track) == index))
259 {
260 copy_mp3entry(id3, audio_current_track()); /* retrieve id3 from RAM */
261 id3_retrieval_successful = true;
262 }
263 else
264 {
265 /* Read from disk, the database, doesn't store frequency, file size or codec (g4470) ChrisS*/
266 id3_retrieval_successful = get_metadata_ex(id3, -1, name, flags);
267 }
268 return id3_retrieval_successful;
269}
270
230static int playlist_entry_load(struct playlist_entry *entry, int index, 271static int playlist_entry_load(struct playlist_entry *entry, int index,
231 char* name_buffer, int remaining_size) 272 char* name_buffer, int remaining_size)
232{ 273{
@@ -242,6 +283,13 @@ static int playlist_entry_load(struct playlist_entry *entry, int index,
242 283
243 len = strlcpy(name_buffer, info.filename, remaining_size) + 1; 284 len = strlcpy(name_buffer, info.filename, remaining_size) + 1;
244 285
286 if (global_settings.playlist_viewer_track_display >
287 PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH && len <= remaining_size)
288 {
289 /* Allocate space for the id3viewc if the option is enabled */
290 len += MAX_PATH + 1;
291 }
292
245 if (len <= remaining_size) 293 if (len <= remaining_size)
246 { 294 {
247 entry->name = name_buffer; 295 entry->name = name_buffer;
@@ -253,27 +301,6 @@ static int playlist_entry_load(struct playlist_entry *entry, int index,
253 return -1; 301 return -1;
254} 302}
255 303
256static int playlist_buffer_get_index(struct playlist_buffer *pb, int index)
257{
258 int buffer_index;
259 if (pb->direction == FORWARD)
260 {
261 if (index >= pb->first_index)
262 buffer_index = index-pb->first_index;
263 else /* rotation : track0 in buffer + requested track */
264 buffer_index = viewer.num_tracks-pb->first_index+index;
265 }
266 else
267 {
268 if (index <= pb->first_index)
269 buffer_index = pb->first_index-index;
270 else /* rotation : track0 in buffer + dist from the last track
271 to the requested track (num_tracks-requested track) */
272 buffer_index = pb->first_index+viewer.num_tracks-index;
273 }
274 return buffer_index;
275}
276
277#define distance(a, b) \ 304#define distance(a, b) \
278 a>b? (a) - (b) : (b) - (a) 305 a>b? (a) - (b) : (b) - (a)
279static bool playlist_buffer_needs_reload(struct playlist_buffer* pb, 306static bool playlist_buffer_needs_reload(struct playlist_buffer* pb,
@@ -440,7 +467,9 @@ static void format_name(char* dest, const char* src, size_t bufsz)
440{ 467{
441 switch (global_settings.playlist_viewer_track_display) 468 switch (global_settings.playlist_viewer_track_display)
442 { 469 {
443 case 0: 470 case PLAYLIST_VIEWER_ENTRY_SHOW_FILE_NAME:
471 case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM: /* If loading from tags failed, only display the file name */
472 case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE: /* If loading from tags failed, only display the file name */
444 default: 473 default:
445 { 474 {
446 /* Only display the filename */ 475 /* Only display the filename */
@@ -450,7 +479,7 @@ static void format_name(char* dest, const char* src, size_t bufsz)
450 strrsplt(dest, '.'); 479 strrsplt(dest, '.');
451 break; 480 break;
452 } 481 }
453 case 1: 482 case PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH:
454 /* Full path */ 483 /* Full path */
455 strlcpy(dest, src, bufsz); 484 strlcpy(dest, src, bufsz);
456 break; 485 break;
@@ -458,22 +487,99 @@ static void format_name(char* dest, const char* src, size_t bufsz)
458} 487}
459 488
460/* Format display line */ 489/* Format display line */
461static void format_line(const struct playlist_entry* track, char* str, 490static void format_line(struct playlist_entry* track, char* str,
462 int len) 491 int len)
463{ 492{
464 char name[MAX_PATH]; 493 char *id3viewc = NULL;
465 char *skipped = ""; 494 char *skipped = "";
466 format_name(name, track->name, sizeof(name));
467
468 if (track->attr & PLAYLIST_ATTR_SKIPPED) 495 if (track->attr & PLAYLIST_ATTR_SKIPPED)
469 skipped = "(ERR) "; 496 skipped = "(ERR) ";
470 497 if (!(track->attr & PLAYLIST_ATTR_RETRIEVE_ID3_ATTEMPTED) &&
471 if (global_settings.playlist_viewer_indices) 498 (global_settings.playlist_viewer_track_display ==
472 /* Display playlist index */ 499 PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM ||
473 snprintf(str, len, "%d. %s%s", track->display_index, skipped, name); 500 global_settings.playlist_viewer_track_display ==
501 PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE
502 ))
503 {
504 track->attr |= PLAYLIST_ATTR_RETRIEVE_ID3_ATTEMPTED;
505 struct mp3entry id3;
506 bool retrieve_success = retrieve_id3_tags(track->index, track->name,
507 &id3, METADATA_EXCLUDE_ID3_PATH);
508 if (retrieve_success)
509 {
510 if (!id3viewc)
511 {
512 id3viewc = track->name + strlen(track->name) + 1;
513 }
514 struct mp3entry * pid3 = &id3;
515 id3viewc[0] = '\0';
516 if (global_settings.playlist_viewer_track_display ==
517 PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM)
518 {
519 /* Title & Album */
520 if (pid3->title && pid3->title[0] != '\0')
521 {
522 char* cur_str = id3viewc;
523 int title_len = strlen(pid3->title);
524 int rem_space = MAX_PATH;
525 for (int i = 0; i < title_len && rem_space > 0; i++)
526 {
527 cur_str[0] = pid3->title[i];
528 cur_str++;
529 rem_space--;
530 }
531 if (rem_space > 10)
532 {
533 cur_str[0] = (char) ' ';
534 cur_str[1] = (char) '-';
535 cur_str[2] = (char) ' ';
536 cur_str += 3;
537 rem_space -= 3;
538 cur_str = strmemccpy(cur_str, pid3->album && pid3->album[0] != '\0' ?
539 pid3->album : (char*) str(LANG_TAGNAVI_UNTAGGED), rem_space);
540 if (cur_str)
541 track->attr |= PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED;
542 }
543 }
544 }
545 else if (global_settings.playlist_viewer_track_display ==
546 PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE)
547 {
548 /* Just the title */
549 if (pid3->title && pid3->title[0] != '\0' &&
550 strmemccpy(id3viewc, pid3->title, MAX_PATH)
551 )
552 track->attr |= PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED;
553 }
554 /* Yield to reduce as much as possible the perceived UI lag,
555 because retrieving id3 tags is an expensive operation */
556 yield();
557 }
558 }
559
560 if (!(track->attr & PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED))
561 {
562 /* Simply use a formatted file name */
563 char name[MAX_PATH];
564 format_name(name, track->name, sizeof(name));
565 if (global_settings.playlist_viewer_indices)
566 /* Display playlist index */
567 snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
568 else
569 snprintf(str, len, "%s%s", skipped, name);
570 }
474 else 571 else
475 snprintf(str, len, "%s%s", skipped, name); 572 {
476 573 if (!id3viewc)
574 {
575 id3viewc = track->name + strlen(track->name) + 1;
576 }
577 if (global_settings.playlist_viewer_indices)
578 /* Display playlist index */
579 snprintf(str, len, "%d. %s%s", track->display_index, skipped, id3viewc);
580 else
581 snprintf(str, len, "%s%s", skipped, id3viewc);
582 }
477} 583}
478 584
479/* Update playlist in case something has changed or forced */ 585/* Update playlist in case something has changed or forced */
@@ -512,20 +618,7 @@ static bool update_playlist(bool force)
512static enum pv_onplay_result show_track_info(const struct playlist_entry *current_track) 618static enum pv_onplay_result show_track_info(const struct playlist_entry *current_track)
513{ 619{
514 struct mp3entry id3; 620 struct mp3entry id3;
515 bool id3_retrieval_successful = false; 621 bool id3_retrieval_successful = retrieve_id3_tags(current_track->index, current_track->name, &id3, 0);
516
517 if (!viewer.playlist &&
518 (audio_status() & AUDIO_STATUS_PLAY) &&
519 (playlist_get_resume_info(&viewer.current_playing_track) == current_track->index))
520 {
521 copy_mp3entry(&id3, audio_current_track()); /* retrieve id3 from RAM */
522 id3_retrieval_successful = true;
523 }
524 else
525 {
526 /* Read from disk, the database, doesn't store frequency, file size or codec (g4470) ChrisS*/
527 id3_retrieval_successful = get_metadata(&id3, -1, current_track->name);
528 }
529 622
530 return id3_retrieval_successful && 623 return id3_retrieval_successful &&
531 browse_id3_ex(&id3, viewer.playlist, current_track->display_index, 624 browse_id3_ex(&id3, viewer.playlist, current_track->display_index,
@@ -790,11 +883,17 @@ static int playlist_callback_voice(int selected_item, void *data)
790 883
791 switch(global_settings.playlist_viewer_track_display) 884 switch(global_settings.playlist_viewer_track_display)
792 { 885 {
793 case 1: /*full path*/ 886 case PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH:
887 /*full path*/
794 talk_fullpath(track->name, true); 888 talk_fullpath(track->name, true);
795 break; 889 break;
796 default: 890 default:
797 case 0: /*filename only*/ 891 case PLAYLIST_VIEWER_ENTRY_SHOW_FILE_NAME:
892 /*filename only*/
893 case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM:
894 /* If loading from tags failed, only talk the file name */
895 case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE:
896 /* If loading from tags failed, only talk the file name */
798 talk_file_or_spell(NULL, track->name, NULL, true); 897 talk_file_or_spell(NULL, track->name, NULL, true);
799 break; 898 break;
800 } 899 }
@@ -1107,7 +1206,7 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename,
1107 } 1206 }
1108 } 1207 }
1109 else 1208 else
1110 onplay(current_track->name, FILE_ATTR_AUDIO, CONTEXT_STD, true); 1209 onplay(current_track->name, FILE_ATTR_AUDIO, CONTEXT_STD, true, ONPLAY_NO_CUSTOMACTION);
1111 break; 1210 break;
1112 } 1211 }
1113#endif /* HAVE_HOTKEY */ 1212#endif /* HAVE_HOTKEY */
@@ -1154,7 +1253,8 @@ static int say_search_item(int selected_item, void *data)
1154{ 1253{
1155 struct playlist_search_data *s_data = data; 1254 struct playlist_search_data *s_data = data;
1156 playlist_get_track_info(viewer.playlist, s_data->found_indicies[selected_item], s_data->track); 1255 playlist_get_track_info(viewer.playlist, s_data->found_indicies[selected_item], s_data->track);
1157 if(global_settings.playlist_viewer_track_display == 1) /* full path*/ 1256 if(global_settings.playlist_viewer_track_display == PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH)
1257 /* full path*/
1158 talk_fullpath(s_data->track->filename, false); 1258 talk_fullpath(s_data->track->filename, false);
1159 else talk_file_or_spell(NULL, s_data->track->filename, NULL, false); 1259 else talk_file_or_spell(NULL, s_data->track->filename, NULL, false);
1160 return 0; 1260 return 0;
@@ -1197,7 +1297,8 @@ bool search_playlist(void)
1197 1297
1198 playlist_get_track_info(viewer.playlist, i, &track); 1298 playlist_get_track_info(viewer.playlist, i, &track);
1199 const char *trackname = track.filename; 1299 const char *trackname = track.filename;
1200 if (track_display == 0) /* if we only display filename only search filename */ 1300 if (track_display != PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH)
1301 /* if we only display filename only search filename */
1201 trackname = strrchr(track.filename, '/'); 1302 trackname = strrchr(track.filename, '/');
1202 1303
1203 if (trackname && strcasestr(trackname, search_str)) 1304 if (trackname && strcasestr(trackname, search_str))
@@ -1219,7 +1320,6 @@ bool search_playlist(void)
1219 gui_synclist_init(&playlist_lists, playlist_search_callback_name, 1320 gui_synclist_init(&playlist_lists, playlist_search_callback_name,
1220 &s_data, false, 1, NULL); 1321 &s_data, false, 1, NULL);
1221 gui_synclist_set_title(&playlist_lists, str(LANG_SEARCH_RESULTS), NOICON); 1322 gui_synclist_set_title(&playlist_lists, str(LANG_SEARCH_RESULTS), NOICON);
1222 gui_synclist_set_icon_callback(&playlist_lists, NULL);
1223 if(global_settings.talk_file) 1323 if(global_settings.talk_file)
1224 gui_synclist_set_voice_callback(&playlist_lists, 1324 gui_synclist_set_voice_callback(&playlist_lists,
1225 global_settings.talk_file? 1325 global_settings.talk_file?