diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index c518d3573c..1ee1ffac0f 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -2031,6 +2031,34 @@
*: "Full Path"
+
+ id: LANG_DISPLAY_TITLEALBUM_FROMTAGS
+ desc: track display options
+ user: core
+
+ *: "Title & Album from ID3 tags"
+
+
+ *: "Title & Album from ID3 tags"
+
+
+ *: "Title and Album from tags"
+
+
+
+ id: LANG_DISPLAY_TITLE_FROMTAGS
+ desc: track display options
+ user: core
+
+ *: "Title from ID3 tags"
+
+
+ *: "Title from ID3 tags"
+
+
+ *: "Title from tags"
+
+
id: LANG_BUILDING_DATABASE
desc: splash database building progress
diff --git a/apps/lang/francais.lang b/apps/lang/francais.lang
index 518b48fb96..b8883d4997 100644
--- a/apps/lang/francais.lang
+++ b/apps/lang/francais.lang
@@ -2004,6 +2004,34 @@
*: "Chemin complet"
+
+ id: LANG_DISPLAY_TITLEALBUM_FROMTAGS
+ desc: track display options
+ user: core
+
+ *: "Title & Album from ID3 tags"
+
+
+ *: "Titre & Album depuis les tags ID3"
+
+
+ *: "Titre et Album depuis les tags"
+
+
+
+ id: LANG_DISPLAY_TITLE_FROMTAGS
+ desc: track display options
+ user: core
+
+ *: "Title from ID3 tags"
+
+
+ *: "Titre depuis les tags ID3"
+
+
+ *: "Titre depuis les tags"
+
+
id: LANG_BUILDING_DATABASE
desc: splash database building progress
diff --git a/apps/playlist.h b/apps/playlist.h
index f7426df9a3..2fb1ce100e 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -33,6 +33,8 @@
#define PLAYLIST_ATTR_QUEUED 0x01
#define PLAYLIST_ATTR_INSERTED 0x02
#define PLAYLIST_ATTR_SKIPPED 0x04
+#define PLAYLIST_ATTR_RETRIEVE_ID3_ATTEMPTED 0x08
+#define PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED 0x10
#define PLAYLIST_DISPLAY_COUNT 10
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index 5bf547a3fc..d556f3b557 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -50,6 +50,7 @@
#include "playlist_menu.h"
#include "menus/exported_menus.h"
#include "yesno.h"
+#include "playback.h"
/* Maximum number of tracks we can have loaded at one time */
#define MAX_PLAYLIST_ENTRIES 200
@@ -142,7 +143,7 @@ static bool playlist_viewer_init(struct playlist_viewer * viewer,
const char* filename, bool reload,
int *most_recent_selection);
-static void format_line(const struct playlist_entry* track, char* str,
+static void format_line(struct playlist_entry* track, char* str,
int len);
static bool update_playlist(bool force);
@@ -159,6 +160,27 @@ static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
pb->num_loaded = 0;
}
+static int playlist_buffer_get_index(struct playlist_buffer *pb, int index)
+{
+ int buffer_index;
+ if (pb->direction == FORWARD)
+ {
+ if (index >= pb->first_index)
+ buffer_index = index-pb->first_index;
+ else /* rotation : track0 in buffer + requested track */
+ buffer_index = viewer.num_tracks-pb->first_index+index;
+ }
+ else
+ {
+ if (index <= pb->first_index)
+ buffer_index = pb->first_index-index;
+ else /* rotation : track0 in buffer + dist from the last track
+ to the requested track (num_tracks-requested track) */
+ buffer_index = pb->first_index+viewer.num_tracks-index;
+ }
+ return buffer_index;
+}
+
/*
* Loads the entries following 'index' in the playlist buffer
*/
@@ -227,6 +249,25 @@ static void playlist_buffer_load_entries_screen(struct playlist_buffer * pb,
playlist_buffer_load_entries(pb, start, direction);
}
+static bool retrieve_id3_tags(const int index, const char* name, struct mp3entry *id3, int flags)
+{
+ bool id3_retrieval_successful = false;
+
+ if (!viewer.playlist &&
+ (audio_status() & AUDIO_STATUS_PLAY) &&
+ (playlist_get_resume_info(&viewer.current_playing_track) == index))
+ {
+ copy_mp3entry(id3, audio_current_track()); /* retrieve id3 from RAM */
+ id3_retrieval_successful = true;
+ }
+ else
+ {
+ /* Read from disk, the database, doesn't store frequency, file size or codec (g4470) ChrisS*/
+ id3_retrieval_successful = get_metadata_ex(id3, -1, name, flags);
+ }
+ return id3_retrieval_successful;
+}
+
static int playlist_entry_load(struct playlist_entry *entry, int index,
char* name_buffer, int remaining_size)
{
@@ -242,6 +283,13 @@ static int playlist_entry_load(struct playlist_entry *entry, int index,
len = strlcpy(name_buffer, info.filename, remaining_size) + 1;
+ if (global_settings.playlist_viewer_track_display >
+ PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH && len <= remaining_size)
+ {
+ /* Allocate space for the id3viewc if the option is enabled */
+ len += MAX_PATH + 1;
+ }
+
if (len <= remaining_size)
{
entry->name = name_buffer;
@@ -253,27 +301,6 @@ static int playlist_entry_load(struct playlist_entry *entry, int index,
return -1;
}
-static int playlist_buffer_get_index(struct playlist_buffer *pb, int index)
-{
- int buffer_index;
- if (pb->direction == FORWARD)
- {
- if (index >= pb->first_index)
- buffer_index = index-pb->first_index;
- else /* rotation : track0 in buffer + requested track */
- buffer_index = viewer.num_tracks-pb->first_index+index;
- }
- else
- {
- if (index <= pb->first_index)
- buffer_index = pb->first_index-index;
- else /* rotation : track0 in buffer + dist from the last track
- to the requested track (num_tracks-requested track) */
- buffer_index = pb->first_index+viewer.num_tracks-index;
- }
- return buffer_index;
-}
-
#define distance(a, b) \
a>b? (a) - (b) : (b) - (a)
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)
{
switch (global_settings.playlist_viewer_track_display)
{
- case 0:
+ case PLAYLIST_VIEWER_ENTRY_SHOW_FILE_NAME:
+ case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM: /* If loading from tags failed, only display the file name */
+ case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE: /* If loading from tags failed, only display the file name */
default:
{
/* Only display the filename */
@@ -450,7 +479,7 @@ static void format_name(char* dest, const char* src, size_t bufsz)
strrsplt(dest, '.');
break;
}
- case 1:
+ case PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH:
/* Full path */
strlcpy(dest, src, bufsz);
break;
@@ -458,22 +487,99 @@ static void format_name(char* dest, const char* src, size_t bufsz)
}
/* Format display line */
-static void format_line(const struct playlist_entry* track, char* str,
+static void format_line(struct playlist_entry* track, char* str,
int len)
{
- char name[MAX_PATH];
+ char *id3viewc = NULL;
char *skipped = "";
- format_name(name, track->name, sizeof(name));
-
if (track->attr & PLAYLIST_ATTR_SKIPPED)
skipped = "(ERR) ";
-
- if (global_settings.playlist_viewer_indices)
- /* Display playlist index */
- snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
+ if (!(track->attr & PLAYLIST_ATTR_RETRIEVE_ID3_ATTEMPTED) &&
+ (global_settings.playlist_viewer_track_display ==
+ PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM ||
+ global_settings.playlist_viewer_track_display ==
+ PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE
+ ))
+ {
+ track->attr |= PLAYLIST_ATTR_RETRIEVE_ID3_ATTEMPTED;
+ struct mp3entry id3;
+ bool retrieve_success = retrieve_id3_tags(track->index, track->name,
+ &id3, METADATA_EXCLUDE_ID3_PATH);
+ if (retrieve_success)
+ {
+ if (!id3viewc)
+ {
+ id3viewc = track->name + strlen(track->name) + 1;
+ }
+ struct mp3entry * pid3 = &id3;
+ id3viewc[0] = '\0';
+ if (global_settings.playlist_viewer_track_display ==
+ PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM)
+ {
+ /* Title & Album */
+ if (pid3->title && pid3->title[0] != '\0')
+ {
+ char* cur_str = id3viewc;
+ int title_len = strlen(pid3->title);
+ int rem_space = MAX_PATH;
+ for (int i = 0; i < title_len && rem_space > 0; i++)
+ {
+ cur_str[0] = pid3->title[i];
+ cur_str++;
+ rem_space--;
+ }
+ if (rem_space > 10)
+ {
+ cur_str[0] = (char) ' ';
+ cur_str[1] = (char) '-';
+ cur_str[2] = (char) ' ';
+ cur_str += 3;
+ rem_space -= 3;
+ cur_str = strmemccpy(cur_str, pid3->album && pid3->album[0] != '\0' ?
+ pid3->album : (char*) str(LANG_TAGNAVI_UNTAGGED), rem_space);
+ if (cur_str)
+ track->attr |= PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED;
+ }
+ }
+ }
+ else if (global_settings.playlist_viewer_track_display ==
+ PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE)
+ {
+ /* Just the title */
+ if (pid3->title && pid3->title[0] != '\0' &&
+ strmemccpy(id3viewc, pid3->title, MAX_PATH)
+ )
+ track->attr |= PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED;
+ }
+ /* Yield to reduce as much as possible the perceived UI lag,
+ because retrieving id3 tags is an expensive operation */
+ yield();
+ }
+ }
+
+ if (!(track->attr & PLAYLIST_ATTR_RETRIEVE_ID3_SUCCEEDED))
+ {
+ /* Simply use a formatted file name */
+ char name[MAX_PATH];
+ format_name(name, track->name, sizeof(name));
+ if (global_settings.playlist_viewer_indices)
+ /* Display playlist index */
+ snprintf(str, len, "%d. %s%s", track->display_index, skipped, name);
+ else
+ snprintf(str, len, "%s%s", skipped, name);
+ }
else
- snprintf(str, len, "%s%s", skipped, name);
-
+ {
+ if (!id3viewc)
+ {
+ id3viewc = track->name + strlen(track->name) + 1;
+ }
+ if (global_settings.playlist_viewer_indices)
+ /* Display playlist index */
+ snprintf(str, len, "%d. %s%s", track->display_index, skipped, id3viewc);
+ else
+ snprintf(str, len, "%s%s", skipped, id3viewc);
+ }
}
/* Update playlist in case something has changed or forced */
@@ -512,20 +618,7 @@ static bool update_playlist(bool force)
static enum pv_onplay_result show_track_info(const struct playlist_entry *current_track)
{
struct mp3entry id3;
- bool id3_retrieval_successful = false;
-
- if (!viewer.playlist &&
- (audio_status() & AUDIO_STATUS_PLAY) &&
- (playlist_get_resume_info(&viewer.current_playing_track) == current_track->index))
- {
- copy_mp3entry(&id3, audio_current_track()); /* retrieve id3 from RAM */
- id3_retrieval_successful = true;
- }
- else
- {
- /* Read from disk, the database, doesn't store frequency, file size or codec (g4470) ChrisS*/
- id3_retrieval_successful = get_metadata(&id3, -1, current_track->name);
- }
+ bool id3_retrieval_successful = retrieve_id3_tags(current_track->index, current_track->name, &id3, 0);
return id3_retrieval_successful &&
browse_id3_ex(&id3, viewer.playlist, current_track->display_index,
@@ -790,11 +883,17 @@ static int playlist_callback_voice(int selected_item, void *data)
switch(global_settings.playlist_viewer_track_display)
{
- case 1: /*full path*/
+ case PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH:
+ /*full path*/
talk_fullpath(track->name, true);
break;
default:
- case 0: /*filename only*/
+ case PLAYLIST_VIEWER_ENTRY_SHOW_FILE_NAME:
+ /*filename only*/
+ case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM:
+ /* If loading from tags failed, only talk the file name */
+ case PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE:
+ /* If loading from tags failed, only talk the file name */
talk_file_or_spell(NULL, track->name, NULL, true);
break;
}
@@ -1154,7 +1253,8 @@ static int say_search_item(int selected_item, void *data)
{
struct playlist_search_data *s_data = data;
playlist_get_track_info(viewer.playlist, s_data->found_indicies[selected_item], s_data->track);
- if(global_settings.playlist_viewer_track_display == 1) /* full path*/
+ if(global_settings.playlist_viewer_track_display == PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH)
+ /* full path*/
talk_fullpath(s_data->track->filename, false);
else talk_file_or_spell(NULL, s_data->track->filename, NULL, false);
return 0;
@@ -1197,7 +1297,8 @@ bool search_playlist(void)
playlist_get_track_info(viewer.playlist, i, &track);
const char *trackname = track.filename;
- if (track_display == 0) /* if we only display filename only search filename */
+ if (track_display != PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH)
+ /* if we only display filename only search filename */
trackname = strrchr(track.filename, '/');
if (trackname && strcasestr(trackname, search_str))
diff --git a/apps/settings.h b/apps/settings.h
index 1343538b0b..a9a9f647e3 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -78,6 +78,13 @@ enum
TRIG_TYPE_NEW_FILE
};
+enum {
+ PLAYLIST_VIEWER_ENTRY_SHOW_FILE_NAME = 0,
+ PLAYLIST_VIEWER_ENTRY_SHOW_FULL_PATH = 1,
+ PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE_AND_ALBUM = 2,
+ PLAYLIST_VIEWER_ENTRY_SHOW_ID3_TITLE = 3
+};
+
#ifdef HAVE_CROSSFADE
enum {
CROSSFADE_ENABLE_OFF = 0,
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 3b29703fe9..a9f627bfa6 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -1421,9 +1421,11 @@ const struct settings_list settings[] = {
OFFON_SETTING(0,playlist_viewer_indices,LANG_SHOW_INDICES,true,
"playlist viewer indices",NULL),
CHOICE_SETTING(0, playlist_viewer_track_display, LANG_TRACK_DISPLAY, 0,
- "playlist viewer track display","track name,full path",
- NULL, 2, ID2P(LANG_DISPLAY_TRACK_NAME_ONLY),
- ID2P(LANG_DISPLAY_FULL_PATH)),
+ "playlist viewer track display",
+ "track name,full path,title and album from tags,title from tags",
+ NULL, 4, ID2P(LANG_DISPLAY_TRACK_NAME_ONLY),
+ ID2P(LANG_DISPLAY_FULL_PATH),ID2P(LANG_DISPLAY_TITLEALBUM_FROMTAGS),
+ ID2P(LANG_DISPLAY_TITLE_FROMTAGS)),
CHOICE_SETTING(0, recursive_dir_insert, LANG_RECURSE_DIRECTORY , RECURSE_ON,
"recursive directory insert", off_on_ask, NULL , 3 ,
ID2P(LANG_OFF), ID2P(LANG_ON), ID2P(LANG_ASK)),
diff --git a/manual/appendix/config_file_options.tex b/manual/appendix/config_file_options.tex
index 01deb1f174..cb31068964 100644
--- a/manual/appendix/config_file_options.tex
+++ b/manual/appendix/config_file_options.tex
@@ -58,7 +58,7 @@
playlist viewer indices
& on, off & N/A\\
playlist viewer track display
- & track name,full path
+ & track name,full path,title and album from tags,title from tags
& N/A\\
recursive directory insert
& on, off, ask & N/A\\