diff --git a/apps/onplay.c b/apps/onplay.c index 9b94be0959..88607f7754 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -61,6 +61,7 @@ #if CONFIG_CODEC == SWCODEC #include "eq_menu.h" #endif +#include "playlist_menu.h" static int context; static char* selected_file = NULL; @@ -152,18 +153,7 @@ static bool shuffle_playlist(void) static bool save_playlist(void) { - char filename[MAX_PATH+1]; - - strncpy(filename, DEFAULT_DYNAMIC_PLAYLIST_NAME, sizeof(filename)); - - if (!kbd_input(filename, sizeof(filename))) - { - playlist_save(NULL, filename); - - /* reload in case playlist was saved to cwd */ - onplay_result = ONPLAY_RELOAD_DIR; - } - + save_playlist_screen(NULL); return false; } diff --git a/apps/playlist.c b/apps/playlist.c index 25939bb3ee..84160195b7 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -143,6 +143,7 @@ static void new_playlist(struct playlist_info* playlist, const char *dir, const char *file); static void create_control(struct playlist_info* playlist); static int check_control(struct playlist_info* playlist); +static int recreate_control(struct playlist_info* playlist); static void update_playlist_filename(struct playlist_info* playlist, const char *dir, const char *file); static int add_indices_to_playlist(struct playlist_info* playlist, @@ -321,6 +322,107 @@ static int check_control(struct playlist_info* playlist) return 0; } +/* + * recreate the control file based on current playlist entries + */ +static int recreate_control(struct playlist_info* playlist) +{ + char temp_file[MAX_PATH+1]; + int temp_fd = -1; + int i; + int result = 0; + + if(playlist->control_fd >= 0) + { + char* dir = playlist->filename; + char* file = playlist->filename+playlist->dirlen; + char c = playlist->filename[playlist->dirlen-1]; + + close(playlist->control_fd); + + snprintf(temp_file, sizeof(temp_file), "%s_temp", + playlist->control_filename); + + if (rename(playlist->control_filename, temp_file) < 0) + return -1; + + temp_fd = open(temp_file, O_RDONLY); + if (temp_fd < 0) + return -1; + + playlist->control_fd = open(playlist->control_filename, + O_CREAT|O_RDWR|O_TRUNC); + if (playlist->control_fd < 0) + return -1; + + playlist->filename[playlist->dirlen-1] = '\0'; + + /* cannot call update_control() because of mutex */ + result = fdprintf(playlist->control_fd, "P:%d:%s:%s\n", + PLAYLIST_CONTROL_FILE_VERSION, dir, file); + + playlist->filename[playlist->dirlen-1] = c; + + if (result < 0) + { + close(temp_fd); + return result; + } + } + + playlist->seed = 0; + playlist->shuffle_modified = false; + playlist->deleted = false; + playlist->num_inserted_tracks = 0; + + if (playlist->current) + { + global_settings.resume_seed = -1; + settings_save(); + } + + for (i=0; iamount; i++) + { + if (playlist->indices[i] & PLAYLIST_INSERT_TYPE_MASK) + { + bool queue = playlist->indices[i] & PLAYLIST_QUEUE_MASK; + char inserted_file[MAX_PATH+1]; + + lseek(temp_fd, playlist->indices[i] & PLAYLIST_SEEK_MASK, + SEEK_SET); + read_line(temp_fd, inserted_file, sizeof(inserted_file)); + + result = fdprintf(playlist->control_fd, "%c:%d:%d:", + queue?'Q':'A', i, playlist->last_insert_pos); + if (result > 0) + { + /* save the position in file where name is written */ + int seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR); + + result = fdprintf(playlist->control_fd, "%s\n", + inserted_file); + + playlist->indices[i] = + (playlist->indices[i] & ~PLAYLIST_SEEK_MASK) | seek_pos; + } + + if (result < 0) + break; + + playlist->num_inserted_tracks++; + } + } + + close(temp_fd); + remove(temp_file); + fsync(playlist->control_fd); + + if (result < 0) + return result; + + return 0; +} + /* * store directory and name of playlist file */ @@ -1183,6 +1285,8 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, } else if (max < 0) { + mutex_lock(&playlist->control_mutex); + if (control_file) fd = playlist->control_fd; else @@ -1195,18 +1299,15 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, if(-1 != fd) { - if (control_file) - mutex_lock(&playlist->control_mutex); if (lseek(fd, seek, SEEK_SET) != seek) max = -1; else max = read(fd, tmp_buf, buf_length); - - if (control_file) - mutex_unlock(&playlist->control_mutex); } + mutex_unlock(&playlist->control_mutex); + if (max < 0) { if (control_file) @@ -3114,8 +3215,11 @@ int playlist_save(struct playlist_info* playlist, char *filename) int fd; int i, index; int count = 0; + char path[MAX_PATH+1]; char tmp_buf[MAX_PATH+1]; int result = 0; + bool overwrite_current = false; + int* index_buf = NULL; if (!playlist) playlist = ¤t_playlist; @@ -3124,11 +3228,31 @@ int playlist_save(struct playlist_info* playlist, char *filename) return -1; /* use current working directory as base for pathname */ - if (format_track_path(tmp_buf, filename, sizeof(tmp_buf), + if (format_track_path(path, filename, sizeof(tmp_buf), strlen(filename)+1, getcwd(NULL, -1)) < 0) return -1; - fd = open(tmp_buf, O_CREAT|O_WRONLY|O_TRUNC); + if (!strncmp(playlist->filename, path, strlen(path))) + { + /* Attempting to overwrite current playlist file.*/ + + if (playlist->buffer_size < (int)(playlist->amount * sizeof(int))) + { + /* not enough buffer space to store updated indices */ + gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_ACCESS_ERROR)); + return -1; + } + + /* in_ram buffer is unused for m3u files so we'll use for storing + updated indices */ + index_buf = (int*)playlist->buffer; + + /* use temporary pathname */ + snprintf(path, sizeof(path), "%s_temp", playlist->filename); + overwrite_current = true; + } + + fd = open(path, O_CREAT|O_WRONLY|O_TRUNC); if (fd < 0) { gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_ACCESS_ERROR)); @@ -3146,7 +3270,10 @@ int playlist_save(struct playlist_info* playlist, char *filename) /* user abort */ if (button_get(false) == SETTINGS_CANCEL) + { + result = -1; break; + } control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; @@ -3162,9 +3289,12 @@ int playlist_save(struct playlist_info* playlist, char *filename) break; } + if (overwrite_current) + index_buf[count] = lseek(fd, 0, SEEK_CUR); + if (fdprintf(fd, "%s\n", tmp_buf) < 0) { - gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); + gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_ACCESS_ERROR)); result = -1; break; } @@ -3184,5 +3314,43 @@ int playlist_save(struct playlist_info* playlist, char *filename) close(fd); + if (overwrite_current && result >= 0) + { + result = -1; + + mutex_lock(&playlist->control_mutex); + + /* Replace the current playlist with the new one and update indices */ + close(playlist->fd); + if (remove(playlist->filename) >= 0) + { + if (rename(path, playlist->filename) >= 0) + { + playlist->fd = open(playlist->filename, O_RDONLY); + if (playlist->fd >= 0) + { + index = playlist->first_index; + for (i=0, count=0; iamount; i++) + { + if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK)) + { + playlist->indices[index] = index_buf[count]; + count++; + } + index = (index+1)%playlist->amount; + } + + /* we need to recreate control because inserted tracks are + now part of the playlist and shuffle has been + invalidated */ + result = recreate_control(playlist); + } + } + } + + mutex_unlock(&playlist->control_mutex); + + } + return result; } diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c index c70a510a6e..c390e8077d 100644 --- a/apps/playlist_menu.c +++ b/apps/playlist_menu.c @@ -28,22 +28,11 @@ #include "playlist_viewer.h" #include "talk.h" #include "lang.h" +#include "playlist_menu.h" -/* FIXME: there is a very similar function in onplay.c */ static bool save_playlist(void) { - char filename[MAX_PATH+1]; - - strncpy(filename, DEFAULT_DYNAMIC_PLAYLIST_NAME, sizeof(filename)); - - if (!kbd_input(filename, sizeof(filename))) - { - playlist_save(NULL, filename); - - /* reload in case playlist was saved to cwd */ - reload_directory(); - } - + save_playlist_screen(NULL); return false; } @@ -85,3 +74,26 @@ bool playlist_menu(void) menu_exit(m); return result; } + +int save_playlist_screen(struct playlist_info* playlist) +{ + char* filename; + char temp[MAX_PATH+1]; + int len; + + filename = playlist_get_name(playlist, temp, sizeof(temp)); + + if (!filename || (len=strlen(filename)) <= 4 || + strcasecmp(&filename[len-4], ".m3u")) + filename = DEFAULT_DYNAMIC_PLAYLIST_NAME; + + if (!kbd_input(filename, sizeof(filename))) + { + playlist_save(playlist, filename); + + /* reload in case playlist was saved to cwd */ + reload_directory(); + } + + return 0; +} diff --git a/apps/playlist_menu.h b/apps/playlist_menu.h index e10fc81299..db841c371d 100644 --- a/apps/playlist_menu.h +++ b/apps/playlist_menu.h @@ -19,6 +19,9 @@ #ifndef _PLAYLIST_MENU_H #define _PLAYLIST_MENU_H +#include "playlist.h" + bool playlist_menu(void); +int save_playlist_screen(struct playlist_info* playlist); #endif diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index 6dc168d49a..ddc238cb27 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c @@ -46,6 +46,7 @@ #include "list.h" #include "statusbar.h" #include "splash.h" +#include "playlist_menu.h" /* Maximum number of tracks we can have loaded at one time */ #define MAX_PLAYLIST_ENTRIES 200 @@ -543,17 +544,7 @@ static bool track_display(void) /* Save playlist to disk */ static bool save_playlist(void) { - char filename[MAX_PATH+1]; - - strncpy(filename, DEFAULT_VIEWER_PLAYLIST_NAME, sizeof(filename)); - - if (!kbd_input(filename, sizeof(filename))) - { - playlist_save(viewer.playlist, filename); - /* reload in case playlist was saved to cwd */ - reload_directory(); - } - + save_playlist_screen(viewer.playlist); return false; }