Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 14569) +++ apps/lang/english.lang (working copy) @@ -11241,3 +11241,31 @@ usbstack: "Device Driver" + + 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) "; @@ -529,7 +583,8 @@ struct playlist_viewer * local_viewer = (struct playlist_viewer *)data; struct playlist_entry *track= playlist_buffer_get_track(&(local_viewer->buffer), 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)),