New version in the unlikely event that someone will test it out..
those 3 tests in the previous message should actually be working now.
This patch is still limited to creating in the wps context menu and
loading .bmarks in the filebrowser, but those 2 things are the main
things and they work!
if the name of the current playlist cant be determined (i.e its not
dirplay or m3u) it creates a numbered /bookmark_*.bmark file which you
can go and rename later (unless someone comes up with a better way to
name them?)
next thing to do is the recent bookmark list and finish the bookmark
selection screen.
Jonathan
Index: apps/misc.h
===================================================================
--- apps/misc.h (revision 18276)
+++ apps/misc.h (working copy)
@@ -111,6 +111,7 @@
#endif
int open_utf8(const char* pathname, int flags);
+bool file_copy(const char* src, const char* target);
#ifdef BOOTFILE
#if !defined(USB_NONE) && !defined(USB_IPODSTYLE)
Index: apps/playlist.c
===================================================================
--- apps/playlist.c (revision 18276)
+++ apps/playlist.c (working copy)
@@ -71,6 +71,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include "sscanf.h"
#include "playlist.h"
#include "ata_idle_notify.h"
#include "file.h"
@@ -705,6 +706,8 @@
return -1;
}
+ playlist->filename[0] = '\0';
+
switch (position)
{
case PLAYLIST_PREPEND:
@@ -1854,6 +1857,11 @@
mutex_lock(&playlist->control_mutex);
+ if (playlist->bmark_fd >= 0)
+ {
+ close(playlist->bmark_fd);
+ playlist->bmark_fd = -1;
+ }
cache = &(playlist->control_cache[playlist->num_cached++]);
cache->command = command;
@@ -1936,6 +1944,7 @@
"%s", PLAYLIST_CONTROL_FILE);
playlist->fd = -1;
playlist->control_fd = -1;
+ playlist->bmark_fd = -1;
playlist->max_playlist_size = global_settings.max_files_in_playlist;
playlist->indices = buffer_alloc(
playlist->max_playlist_size * sizeof(int));
@@ -2291,6 +2300,9 @@
case '#':
current_command = PLAYLIST_COMMAND_COMMENT;
break;
+ case 'B':
+ current_command = PLAYLIST_COMMAND_RESUMEPOINT;
+ break;
default:
result = -1;
exit_loop = true;
@@ -3608,3 +3620,101 @@
return result;
}
+
+bool playlist_add_bookmark(const char *bmark_filename, bool createnew)
+{
+ struct playlist_info *pl = ¤t_playlist;
+ struct playlist_resume_point resume_pt;
+ /* grab the currently playing track */
+ struct mp3entry *id3 = audio_current_track();
+ if(!id3)
+ return false;
+ resume_pt.track_position = id3->offset;
+ playlist_get_resume_info(&resume_pt.playlist_index);
+ sync_control(pl, true);
+
+ if (createnew || pl->bmark_fd < 0)
+ {
+ if (pl->bmark_fd >= 0)
+ close(pl->bmark_fd);
+ if (file_copy(PLAYLIST_CONTROL_FILE, bmark_filename) == false)
+ return false;
+ pl->bmark_fd = open(bmark_filename, O_RDWR|O_APPEND);
+ if (pl->bmark_fd < 0)
+ return false;
+ }
+ fdprintf(pl->bmark_fd, "B:%d:%ld\n", resume_pt.playlist_index, resume_pt.track_position);
+ return true;
+}
+
+/* setup the playlist from a bmark file and find any resume points in the bmark
+ if successful *resumes_count will be set to the number of available resumes
+ current_playlist.bmark_fd will also be set the to correct file and at the end
+ and ready to add new points if the playlist isnt changed */
+bool playlist_resume_bookmark(const char *bmark_filename, bool get_last_point,
+ struct playlist_resume_point *resumes, int *resumes_count)
+{
+ int maxresumes = *resumes_count, i=0;
+ struct playlist_info *pl = ¤t_playlist;
+ char buf[MAX_PATH];
+ *resumes_count = 0;
+ playlist_close(pl); /* may not be the best way to do this */
+ if (file_copy(bmark_filename, PLAYLIST_CONTROL_FILE) == false)
+ return false;
+ if (playlist_resume() >= 0)
+ {
+ /* playlist is loaded, open the origional bmark file and find any resume points */
+ pl->bmark_fd = open(bmark_filename, O_RDWR);
+ if (pl->bmark_fd < 0)
+ return false;
+ while (read_line(pl->bmark_fd, buf, MAX_PATH) > 0 &&
+ ((*resumes_count < maxresumes) || get_last_point))
+ {
+ if (buf[0] == 'B')
+ {
+ struct playlist_resume_point *r = &resumes[i];
+ if (sscanf(buf, "B:%d:%ld", &r->playlist_index, &r->track_position) == 2)
+ {
+ (*resumes_count)++;
+ if (!get_last_point)
+ i++;
+ }
+ }
+ }
+ lseek(pl->bmark_fd, SEEK_END, 0);
+ return true;
+ }
+ return false;
+}
+
+#define PREVIOUS_BMARK_FILE ROCKBOX_DIR "/previous.bmark"
+bool playlist_backup_current(void)
+{
+ struct playlist_info *pl = ¤t_playlist;
+ struct playlist_resume_point resume_pt;
+ /* grab the currently playing track */
+ struct mp3entry *id3 = audio_current_track();
+ int fd;
+ if(!id3)
+ return false;
+ resume_pt.track_position = id3->offset;
+ playlist_get_resume_info(&resume_pt.playlist_index);
+ sync_control(pl, true);
+ if (file_copy(PLAYLIST_CONTROL_FILE, PREVIOUS_BMARK_FILE) == false)
+ return false;
+ fd = open(PREVIOUS_BMARK_FILE, O_WRONLY|O_APPEND);
+ if (fd < 0)
+ return false;
+ fdprintf(fd, "B:%d:%ld\n", resume_pt.playlist_index, resume_pt.track_position);
+ close(fd);
+ return true;
+}
+bool playlist_resume_backup(void)
+{
+ struct playlist_resume_point resumes;
+ int resume_count = 1;
+ if (!playlist_resume_bookmark(PREVIOUS_BMARK_FILE, true, &resumes, &resume_count) || resume_count < 1)
+ return false;
+ playlist_start(resumes.playlist_index,resumes.track_position);
+ return true;
+}
Index: apps/playlist.h
===================================================================
--- apps/playlist.h (revision 18276)
+++ apps/playlist.h (working copy)
@@ -42,7 +42,8 @@
PLAYLIST_COMMAND_SHUFFLE,
PLAYLIST_COMMAND_UNSHUFFLE,
PLAYLIST_COMMAND_RESET,
- PLAYLIST_COMMAND_COMMENT
+ PLAYLIST_COMMAND_COMMENT,
+ PLAYLIST_COMMAND_RESUMEPOINT
};
enum {
@@ -76,6 +77,8 @@
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? */
+ int bmark_fd; /* fd of the bmark file if it exists. set to -1 if
+ the control changes and it exists */
int dirlen; /* Length of the path to the playlist file */
unsigned long *indices; /* array of indices */
const struct dircache_entry **filenames; /* Entries from dircache */
@@ -113,6 +116,12 @@
int display_index; /* index of track for display */
};
+struct playlist_resume_point
+{
+ int playlist_index; /* index into the playlist for the current track */
+ long track_position; /* position in the current song to resume from */
+};
+
/* Exported functions only for current playlist. */
void playlist_init(void);
void playlist_shutdown(void);
@@ -168,4 +177,11 @@
void* context);
int playlist_remove_all_tracks(struct playlist_info *playlist);
+/* bookmark stuff */
+bool playlist_add_bookmark(const char *bmark_filename, bool createnew);
+bool playlist_resume_bookmark(const char *bmark_filename, bool get_last_point,
+ struct playlist_resume_point *resumes, int *resumes_count);
+bool playlist_backup_current(void);
+bool playlist_resume_backup(void);
+
#endif /* __PLAYLIST_H__ */
Index: apps/onplay.c
===================================================================
--- apps/onplay.c (revision 18276)
+++ apps/onplay.c (working copy)
@@ -684,77 +684,10 @@
/* Paste a file to a new directory. Will overwrite always. */
static bool clipboard_pastefile(const char *src, const char *target, bool copy)
{
- int src_fd, target_fd;
- size_t buffersize;
- ssize_t size, bytesread, byteswritten;
- char *buffer;
bool result = false;
if (copy) {
- /* See if we can get the plugin buffer for the file copy buffer */
- buffer = (char *) plugin_get_buffer(&buffersize);
- if (buffer == NULL || buffersize < 512) {
- /* Not large enough, try for a disk sector worth of stack
- instead */
- buffersize = 512;
- buffer = (char *) __builtin_alloca(buffersize);
- }
-
- if (buffer == NULL) {
- return false;
- }
-
- buffersize &= ~0x1ff; /* Round buffer size to multiple of sector
- size */
-
- src_fd = open(src, O_RDONLY);
-
- if (src_fd >= 0) {
- target_fd = creat(target);
-
- if (target_fd >= 0) {
- result = true;
-
- size = filesize(src_fd);
-
- if (size == -1) {
- result = false;
- }
-
- while(size > 0) {
- bytesread = read(src_fd, buffer, buffersize);
-
- if (bytesread == -1) {
- result = false;
- break;
- }
-
- size -= bytesread;
-
- while(bytesread > 0) {
- byteswritten = write(target_fd, buffer, bytesread);
-
- if (byteswritten == -1) {
- result = false;
- size = 0;
- break;
- }
-
- bytesread -= byteswritten;
- draw_slider();
- }
- }
-
- close(target_fd);
-
- /* Copy failed. Cleanup. */
- if (!result) {
- remove(target);
- }
- }
-
- close(src_fd);
- }
+ result = file_copy(src, target);
} else {
result = rename(src, target) == 0;
#ifdef HAVE_MULTIVOLUME
Index: apps/filetree.c
===================================================================
--- apps/filetree.c (revision 18276)
+++ apps/filetree.c (working copy)
@@ -491,7 +491,10 @@
case FILE_ATTR_BMARK:
gui_syncsplash(0, ID2P(LANG_WAIT));
- bookmark_load(buf, false);
+ if (bookmark_load(buf, false) == true)
+ {
+ start_wps = true;
+ }
reload_dir = true;
break;
Index: apps/bookmark.c
===================================================================
--- apps/bookmark.c (revision 18276)
+++ apps/bookmark.c (working copy)
@@ -110,7 +110,24 @@
/* ----------------------------------------------------------------------- */
bool bookmark_create_menu(void)
{
- write_bookmark(true, create_bookmark());
+ char buffer[MAX_PATH];
+ char* name = playlist_get_name(NULL, buffer, MAX_PATH);
+ if (name == NULL)
+ create_numbered_filename(buffer, "/", "bmark_",
+ ".bmark", 2 IF_CNFN_NUM_(, NULL));
+ else if (!strcmp("/", buffer))
+ strcpy(buffer, "/root_dir.bmark");
+ else
+ {
+ int len = strlen(name);
+ if(buffer[len-1] == '/')
+ len--;
+ strcpy(&buffer[len], ".bmark");
+ }
+ int lang_id = playlist_add_bookmark(buffer, false) ?
+ LANG_BOOKMARK_CREATE_SUCCESS :
+ LANG_BOOKMARK_CREATE_FAILURE;
+ gui_syncsplash(HZ, ID2P(lang_id));
return false;
}
@@ -415,44 +432,75 @@
/* ----------------------------------------------------------------------- */
/* This function loads the bookmark information into the resume memory. */
-/* This is an interface function. */
/* ------------------------------------------------------------------------*/
-bool bookmark_load(const char* file, bool autoload)
+
+static char bookmark_resume_points[MAX_BOOKMARKS][MAX_BOOKMARK_SIZE];
+static int selection = -1;
+char * bmark_get_name(int selected_item, void * data,
+ char * buffer, size_t buffer_len)
{
- int fd;
- char* bookmark = NULL;
-
- if(autoload)
+ (void)buffer; (void)buffer_len; (void)data;
+ return bookmark_resume_points[selected_item];
+}
+int bmark_action_callback(int action, struct gui_synclist *lists)
+{
+ if (action == ACTION_STD_OK)
{
- fd = open(file, O_RDONLY);
- if(fd >= 0)
- {
- if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)) > 0)
- bookmark=global_read_buffer;
- close(fd);
- }
+ selection = lists->selected_item;
+ return ACTION_STD_CANCEL;
}
- else
+ if (action == ACTION_STD_CANCEL)
+ selection = -1;
+ return action;
+}
+bool bookmark_load(const char* file, bool autoload)
+{
+ struct playlist_resume_point resumes[MAX_BOOKMARKS];
+ int resume_count = MAX_BOOKMARKS;
+ int i;
+ struct playlist_track_info info;
+ int audio_playing = audio_status();
+ /* dump the current playlist and position incase the user wants to cancel */
+ if (audio_playing)
+ playlist_backup_current();
+
+ if (playlist_resume_bookmark(file, false, resumes, &resume_count) && resume_count > 0)
{
- /* This is not an auto-load, so list the bookmarks */
- bookmark = select_bookmark(file, false);
- }
-
- if (bookmark != NULL)
- {
- if (!play_bookmark(bookmark))
+ if (resume_count > 1)
{
- /* Selected bookmark not found. */
- if (!autoload)
+ for (i=0;i<resume_count;i++)
{
- gui_syncsplash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
+ if (playlist_get_track_info(NULL, resumes[i].playlist_index, &info) > -1)
+ {
+ snprintf(bookmark_resume_points[i], MAX_BOOKMARK_SIZE, "%s: %d",
+ info.filename, resumes[i].track_position);
+ }
}
-
- return false;
+ struct simplelist_info list;
+ simplelist_info_init(&list, ID2P(LANG_BOOKMARK_SELECT_BOOKMARK),
+ resume_count, NULL);
+ list.action_callback = bmark_action_callback;
+ list.get_name = bmark_get_name;
+ selection = -1;
+ simplelist_show_list(&list);
+ if (selection == -1)
+ {
+ if (audio_playing)
+ return playlist_resume_backup();
+ return false;
+ }
}
+ else
+ selection = 0;
+
+ playlist_start(resumes[selection].playlist_index,
+ resumes[selection].track_position);
+ return true;
}
-
- return true;
+ else if (audio_playing)
+ return playlist_resume_backup();
+
+ return false;
}
Index: apps/misc.c
===================================================================
--- apps/misc.c (revision 18276)
+++ apps/misc.c (working copy)
@@ -55,6 +55,7 @@
#include "sound.h"
#include "playlist.h"
#include "yesno.h"
+#include "plugin.h"
#ifdef HAVE_MMC
#include "ata_mmc.h"
@@ -1208,7 +1209,79 @@
return fd;
}
+/** Copy a file from src to dst **/
+bool file_copy(const char* src, const char* target)
+{
+ int src_fd, target_fd;
+ size_t buffersize;
+ ssize_t size, bytesread, byteswritten;
+ char *buffer;
+ bool result = false;
+ /* See if we can get the plugin buffer for the file copy buffer */
+ buffer = (char *) plugin_get_buffer(&buffersize);
+ if (buffer == NULL || buffersize < 512) {
+ /* Not large enough, try for a disk sector worth of stack
+ instead */
+ buffersize = 512;
+ buffer = (char *) __builtin_alloca(buffersize);
+ }
+ if (buffer == NULL) {
+ return false;
+ }
+
+ buffersize &= ~0x1ff; /* Round buffer size to multiple of sector
+ size */
+
+ src_fd = open(src, O_RDONLY);
+
+ if (src_fd >= 0) {
+ target_fd = creat(target);
+
+ if (target_fd >= 0) {
+ result = true;
+
+ size = filesize(src_fd);
+
+ if (size == -1) {
+ result = false;
+ }
+
+ while(size > 0) {
+ bytesread = read(src_fd, buffer, buffersize);
+
+ if (bytesread == -1) {
+ result = false;
+ break;
+ }
+
+ size -= bytesread;
+
+ while(bytesread > 0) {
+ byteswritten = write(target_fd, buffer, bytesread);
+
+ if (byteswritten == -1) {
+ result = false;
+ size = 0;
+ break;
+ }
+
+ bytesread -= byteswritten;
+ // draw_slider();
+ }
+ }
+
+ close(target_fd);
+
+ /* Copy failed. Cleanup. */
+ if (!result) {
+ remove(target);
+ }
+ }
+ close(src_fd);
+ }
+ return result;
+}
#ifdef HAVE_LCD_COLOR
/*
* Helper function to convert a string of 6 hex digits to a native colour