diff options
Diffstat (limited to 'apps/playlist_viewer.c')
-rw-r--r-- | apps/playlist_viewer.c | 208 |
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 | ||
145 | static void format_line(const struct playlist_entry* track, char* str, | 146 | static void format_line(struct playlist_entry* track, char* str, |
146 | int len); | 147 | int len); |
147 | 148 | ||
148 | static bool update_playlist(bool force); | 149 | static 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 | ||
163 | static 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 | ||
252 | static 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 | |||
230 | static int playlist_entry_load(struct playlist_entry *entry, int index, | 271 | static 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 | ||
256 | static 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) |
279 | static bool playlist_buffer_needs_reload(struct playlist_buffer* pb, | 306 | static 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 */ |
461 | static void format_line(const struct playlist_entry* track, char* str, | 490 | static 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) | |||
512 | static enum pv_onplay_result show_track_info(const struct playlist_entry *current_track) | 618 | static 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? |