Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang (revision 15946)
+++ apps/lang/english.lang (working copy)
@@ -11512,4 +11512,31 @@
ipodvideo: "Treble Cutoff"
-
+
+ id: LANG_DISPLAY_TRACK_TITLE_ONLY
+ desc: track display options
+ user:
+
+ *: "EXTM3U title only"
+
+
+ *: "EXTM3U title only"
+
+
+ *: "title only"
+
+
+
+ id: LANG_DISPLAY_TRACK_TITLE_TIME
+ desc: track display options
+ user:
+
+ *: "EXTM3U title and time"
+
+
+ *: "EXTM3U title and time"
+
+
+ *: "title and time"
+
+
Index: apps/playlist.c
===================================================================
--- apps/playlist.c (revision 14569)
+++ apps/playlist.c (working copy)
@@ -250,6 +250,27 @@
}
/*
+ * check if there is extm3u header
+ */
+static int check_for_extm3u(struct playlist_info* playlist)
+{
+ char header[7];
+
+ if(playlist->fd == -1)
+ playlist->fd = open(playlist->filename, O_RDONLY);
+ if(playlist->fd < 0)
+ return -1; /* failed */
+ if(lseek(playlist->fd,0,SEEK_SET) < 0) /* reset seek position*/
+ return -1; /* failed */
+
+ if (read(playlist->fd,header,sizeof(header)) < 0)
+ return -1;
+
+ playlist->is_extm3u = (strncmp(header,"#EXTM3U",7) == 0);
+ return 0;
+}
+
+/*
* Initialize a new playlist for viewing/editing/playing. dir is the
* directory where the playlist is located and file is the filename.
*/
@@ -269,7 +290,10 @@
}
update_playlist_filename(playlist, dir, file);
-
+
+ if (file)
+ check_for_extm3u(playlist);
+
if (playlist->control_fd >= 0)
{
update_control(playlist, PLAYLIST_COMMAND_PLAYLIST,
@@ -478,6 +502,8 @@
playlist->fd = open(playlist->filename, O_RDONLY);
if(playlist->fd < 0)
return -1; /* failure */
+ if(lseek(playlist->fd,0,SEEK_SET) < 0) /* reset seek position*/
+ return -1; /* failed */
#ifdef HAVE_LCD_BITMAP
if(global_settings.statusbar)
@@ -1365,6 +1391,78 @@
return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf));
}
+/* fill in track title and song length to according extm3u comments
+* should not call if playlist->is_extm3u is false;
+* pass in null pointer to title_buf or zero title_buf_size to parse
+* length only.
+* a typical extm3u line: header time title
+* #EXTINF:111,example title */
+static int get_extm3u_info(struct playlist_info* playlist, int seek,
+ char *title_buf, int title_buf_size,
+ int *length)
+{
+ /* header + time can take up 13 characters for a 3 hour song */
+ int tmp_buf_size = MIN(seek - 1,title_buf_size +13);
+ int offset = MAX(0,seek - tmp_buf_size - 2);
+ char tmp_buf[MAX_PATH*2 + 13];
+ char *end_char;
+
+ if(-1 == playlist->fd)
+ playlist->fd = open(playlist->filename, O_RDONLY);
+ if(playlist->fd < 0)
+ return -1; /* failed */
+
+ /* read the lines before seek position to find extm3u comments */
+ if (lseek(playlist->fd, offset, SEEK_SET) != offset)
+ return -1;
+ else
+ {
+ if (read(playlist->fd, tmp_buf, tmp_buf_size) < 0)
+ return -1;
+
+ /* Can skip 8 chars because a valid extm3u line
+ * should have more than 8 chars*/
+ int i = tmp_buf_size - 8;
+ int j = tmp_buf_size - 1;
+
+ /* locate the start of extm3u comment line*/
+ while (i > 0 && (tmp_buf[i] != '\n') && (tmp_buf[i] != '\r'))
+ i--;
+
+ if (strncmp(&tmp_buf[++i],"#EXTINF:",8) != 0)
+ return -1; /*line too long or no comment*/
+
+ i += 8; /*skip the header*/
+ *length = atoi(&tmp_buf[i]);
+
+ if (*length == 0)
+ return -1; /*cannot retrieve song length*/
+
+ if (!title_buf || title_buf_size == 0)
+ return 0; /* finished! since title is not requested*/
+
+ /*skip the time part*/
+ while (i < tmp_buf_size && tmp_buf[i] != ',')
+ i++;
+
+ if (tmp_buf[i] != ',' || i == j)
+ return -1; /*no title or not proper format*/
+
+ /*kill white spaces and new lines*/
+ while(j > i && (tmp_buf[j] == ' ' || tmp_buf[j] == '\t' ||
+ tmp_buf[j] == '\n' || tmp_buf[j] == '\r'))
+ j--;
+
+ tmp_buf[j+1] = '\0';
+
+ if (!playlist->utf8)
+ iso_decode(&tmp_buf[i+1], title_buf, -1, j - i + 1);
+ else
+ strncpy(title_buf,&tmp_buf[i+1],title_buf_size);
+ }
+ return 0;
+}
+
static int get_next_directory(char *dir){
return get_next_dir(dir,true,false);
}
@@ -3335,6 +3433,16 @@
sizeof(info->filename)) < 0)
return -1;
+ /* check info->has_extm3u so that if caller to this function
+ * explicitly asked for no extm3u info, extm3u info is not parsed */
+ if (info->has_extm3u && playlist->is_extm3u)
+ {
+ info->has_extm3u = !(get_extm3u_info(playlist, seek, info->title,
+ sizeof(info->title), &(info->length)) < 0);
+ }
+ else
+ info->has_extm3u = false;
+
info->attr = 0;
if (control_file)
Index: apps/playlist.h
===================================================================
--- apps/playlist.h (revision 14569)
+++ apps/playlist.h (working copy)
@@ -71,6 +71,7 @@
char filename[MAX_PATH]; /* path name of m3u playlist on disk */
char control_filename[MAX_PATH]; /* full path of control file */
bool utf8; /* playlist is in .m3u8 format */
+ bool is_extm3u; /*playlist contains extm3u infomation */
int fd; /* descriptor of the open playlist file */
int control_fd; /* descriptor of the open control file */
bool control_created; /* has control file been created? */
@@ -109,6 +110,11 @@
int attr; /* playlist attributes for track */
int index; /* index of track in playlist */
int display_index; /* index of track for display */
+ bool has_extm3u; /* Does it have extm3u information? */
+
+ /* used if extm3u information is present in playlist */
+ unsigned int length; /* song length in seconds */
+ char title[MAX_PATH*2]; /* track title */
};
/* Exported functions only for current playlist. */
Index: apps/playlist_viewer.c
===================================================================
--- apps/playlist_viewer.c (revision 14569)
+++ apps/playlist_viewer.c (working copy)
@@ -65,6 +65,10 @@
int display_index; /* Display index */
bool queued; /* Is track queued? */
bool skipped; /* Is track marked as bad? */
+ bool has_extm3u; /* Does it have extm3u information? */
+
+ /* used if extm3u information is present in playlist */
+ unsigned int length; /* song length in seconds */
};
enum direction
@@ -110,7 +114,8 @@
static void playlist_buffer_load_entries(struct playlist_buffer * pb, int index,
enum direction direction);
static int playlist_entry_load(struct playlist_entry *entry, int index,
- char* name_buffer, int remaining_size);
+ char* name_buffer, int remaining_size,
+ bool load_extm3u);
static struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer *pb,
int index);
@@ -118,7 +123,8 @@
static bool playlist_viewer_init(struct playlist_viewer * viewer,
char* filename, bool reload);
-static void format_name(char* dest, const char* src);
+static void format_name(char* dest, const char* name,
+ int len, unsigned int track_length);
static void format_line(const struct playlist_entry* track, char* str,
int len);
@@ -146,14 +152,18 @@
char* p = pb->name_buffer;
int remaining = pb->buffer_size;
int i;
-
+ bool load_extm3u = (global_settings.playlist_viewer_track_display == 2 ||
+ global_settings.playlist_viewer_track_display == 3);
+
pb->first_index = index;
if (num_entries > MAX_PLAYLIST_ENTRIES)
num_entries = MAX_PLAYLIST_ENTRIES;
+
for(i=0; itracks[i]), index, p, remaining);
+ int len = playlist_entry_load(&(pb->tracks[i]), index, p, remaining,
+ load_extm3u);
if (len < 0)
{
/* Out of name buffer space */
@@ -195,10 +205,14 @@
}
static int playlist_entry_load(struct playlist_entry *entry, int index,
- char* name_buffer, int remaining_size)
+ char* name_buffer, int remaining_size,
+ bool load_extm3u)
{
struct playlist_track_info info;
int len;
+
+ /* Explicitly disable loading extm3u if not needed for display*/
+ info.has_extm3u = load_extm3u;
/* Playlist viewer orders songs based on display index. We need to
convert to real playlist index to access track */
@@ -206,18 +220,32 @@
viewer.num_tracks;
if (playlist_get_track_info(viewer.playlist, index, &info) < 0)
return -1;
+
+ if (info.has_extm3u)
+ len = strlen(info.title) + 1;
+ else
+ len = strlen(info.filename) + 1;
- len = strlen(info.filename) + 1;
-
if (len <= remaining_size)
{
- strcpy(name_buffer, info.filename);
-
+ if (info.has_extm3u)
+ {
+ entry->has_extm3u = true;
+ entry->length = info.length;
+ strcpy(name_buffer, info.title);
+ }
+ else
+ {
+ entry->has_extm3u = false;
+ strcpy(name_buffer, info.filename);
+ }
+
entry->name = name_buffer;
entry->index = info.index;
entry->display_index = info.display_index;
entry->queued = info.attr & PLAYLIST_ATTR_QUEUED;
entry->skipped = info.attr & PLAYLIST_ATTR_SKIPPED;
+
return len;
}
return -1;
@@ -358,18 +386,42 @@
return true;
}
-/* Format trackname for display purposes */
-static void format_name(char* dest, const char* src)
+/* Format name for display purposes */
+static void format_name(char* dest, const char* name,
+ int len, unsigned int track_length)
{
switch (global_settings.playlist_viewer_track_display)
{
+ case 3:
+ {
+ /* track title and time; fall through if no extm3u info
+ * (i.e. track_length is 0) */
+ if (track_length)
+ {
+ snprintf(dest,len,"%s (%02d:%02d)",name,
+ track_length / 60, track_length %60);
+ break;
+ }
+ }
+ case 2:
+ {
+ /* track title only; fall through if no extm3u info*/
+ if (track_length)
+ {
+ strcpy(dest, name);
+ break;
+ }
+ }
case 0:
default:
{
/* Only display the filename */
- char* p = strrchr(src, '/');
+ char* p = strrchr(name, '/');
- strcpy(dest, p+1);
+ if (p != NULL)
+ strcpy(dest, p+1);
+ else
+ strcpy(dest, name);
/* Remove the extension */
char* q = strrchr(dest, '.');
@@ -380,9 +432,11 @@
break;
}
case 1:
+ {
/* Full path */
- strcpy(dest, src);
- break;
+ strcpy(dest, name);
+ break;
+ }
}
}
@@ -390,11 +444,11 @@
static void format_line(const struct playlist_entry* track, char* str,
int len)
{
- char name[MAX_PATH];
+ char name[MAX_PATH*2];
char *skipped = "";
+ format_name(name, track->name, len, (track->has_extm3u) ?
+ track->length : 0);
- format_name(name, track->name);
-
if (track->skipped)
skipped = "(ERR) ";
@@ -551,7 +605,7 @@
{
struct playlist_viewer * local_viewer = (struct playlist_viewer *)data;
struct playlist_entry *track = playlist_buffer_get_track(&(local_viewer->buffer), get_track_num(local_viewer,selected_item));
- format_line(track, buffer, MAX_PATH);
+ format_line(track, buffer, MAX_PATH*2);
return(buffer);
}
@@ -690,11 +745,25 @@
break;
}
case ACTION_STD_MENU:
+ {
+ int old_view_setting = global_settings.playlist_viewer_track_display;
+
if (viewer_menu())
{
ret = true;
goto exit;
}
+
+ if (old_view_setting != global_settings.playlist_viewer_track_display)
+ {
+ /* playlist needs update when view mode changes because probably
+ * not all needed information is present */
+
+ update_playlist(true);
+ if (viewer.num_tracks <= 0)
+ exit = true;
+ }
+
gui_synclist_set_icon_callback(
&playlist_lists,
global_settings.playlist_viewer_icons?
@@ -702,7 +771,7 @@
);
gui_synclist_draw(&playlist_lists);
break;
-
+ }
case ACTION_NONE:
gui_syncstatusbar_draw(&statusbars, false);
break;
@@ -727,8 +796,10 @@
{
int *found_indicies = (int*)data;
static struct playlist_track_info track;
+ /* Explicitly ask for no extm3u info */
+ track.has_extm3u = false;
playlist_get_track_info(viewer.playlist,found_indicies[selected_item],&track);
- format_name(buffer,track.filename);
+ format_name(buffer,track.filename,MAX_PATH*2,0);
return(buffer);
}
@@ -806,3 +877,5 @@
return ret;
}
+
+
Index: apps/settings_list.c
===================================================================
--- apps/settings_list.c (revision 14943)
+++ apps/settings_list.c (working copy)
@@ -680,8 +680,11 @@
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,title with time", NULL, 4,
+ ID2P(LANG_DISPLAY_TRACK_NAME_ONLY), ID2P(LANG_DISPLAY_FULL_PATH),
+ ID2P(LANG_DISPLAY_TRACK_TITLE_ONLY),
+ ID2P(LANG_DISPLAY_TRACK_TITLE_TIME)),
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)),