Database: Add ability to insert multiple files into playlists
You could only add single files to playlists from the database browser before. This enables adding any database selection to a new or existing playlist. Change-Id: I811c7167641c589944bb2afc18dcc1d299a7b979
This commit is contained in:
parent
cc79f1b543
commit
7f265ee8dd
11 changed files with 142 additions and 67 deletions
26
apps/misc.c
26
apps/misc.c
|
@ -1387,6 +1387,32 @@ int string_option(const char *option, const char *const oplist[], bool ignore_ca
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure part of path only contain chars valid for a FAT32 long name.
|
||||
* Double quotes are replaced with single quotes, other unsupported chars
|
||||
* are replaced with an underscore.
|
||||
*
|
||||
* path - path to modify.
|
||||
* offset - where in path to start checking.
|
||||
* count - number of chars to check.
|
||||
*/
|
||||
void fix_path_part(char* path, int offset, int count)
|
||||
{
|
||||
static const char invalid_chars[] = "*/:<>?\\|";
|
||||
int i;
|
||||
|
||||
path += offset;
|
||||
|
||||
for (i = 0; i <= count; i++, path++)
|
||||
{
|
||||
if (*path == 0)
|
||||
return;
|
||||
if (*path == '"')
|
||||
*path = '\'';
|
||||
else if (strchr(invalid_chars, *path))
|
||||
*path = '_';
|
||||
}
|
||||
}
|
||||
|
||||
/* open but with a builtin printf for assembling the path */
|
||||
int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...)
|
||||
{
|
||||
|
|
|
@ -124,6 +124,8 @@ int split_string(char *str, const char needle, char *vector[], int vector_length
|
|||
#ifndef O_PATH
|
||||
#define O_PATH 0x2000
|
||||
#endif
|
||||
|
||||
void fix_path_part(char* path, int offset, int count);
|
||||
int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...);
|
||||
int open_utf8(const char* pathname, int flags);
|
||||
int string_option(const char *option, const char *const oplist[], bool ignore_case);
|
||||
|
|
|
@ -70,7 +70,8 @@ static const char *selected_file = NULL;
|
|||
static char selected_file_path[MAX_PATH];
|
||||
static int selected_file_attr = 0;
|
||||
static int onplay_result = ONPLAY_OK;
|
||||
static bool (*ctx_playlist_insert)(int position, bool queue, bool create_new);
|
||||
static bool (*ctx_current_playlist_insert)(int position, bool queue, bool create_new);
|
||||
static int (*ctx_add_to_playlist)(const char* playlist, bool new_playlist);
|
||||
extern struct menu_item_ex file_menu; /* settings_menu.c */
|
||||
|
||||
/* redefine MAKE_MENU so the MENU_EXITAFTERTHISMENU flag can be added easily */
|
||||
|
@ -626,11 +627,11 @@ static int add_to_playlist(void* arg)
|
|||
#ifdef HAVE_TAGCACHE
|
||||
if (context == CONTEXT_ID3DB)
|
||||
{
|
||||
tagtree_insert_selection_playlist(position, queue);
|
||||
tagtree_current_playlist_insert(position, queue);
|
||||
}
|
||||
else if (context == CONTEXT_STD && ctx_playlist_insert != NULL)
|
||||
else if (context == CONTEXT_STD && ctx_current_playlist_insert != NULL)
|
||||
{
|
||||
ctx_playlist_insert(position, queue, false);
|
||||
ctx_current_playlist_insert(position, queue, false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -837,7 +838,7 @@ static int treeplaylist_callback(int action,
|
|||
void onplay_show_playlist_menu(const char* path, void (*playlist_insert_cb))
|
||||
{
|
||||
context = CONTEXT_STD;
|
||||
ctx_playlist_insert = playlist_insert_cb;
|
||||
ctx_current_playlist_insert = playlist_insert_cb;
|
||||
selected_file = path;
|
||||
if (dir_exists(path))
|
||||
selected_file_attr = ATTR_DIRECTORY;
|
||||
|
@ -850,13 +851,13 @@ void onplay_show_playlist_menu(const char* path, void (*playlist_insert_cb))
|
|||
static bool cat_add_to_a_playlist(void)
|
||||
{
|
||||
return catalog_add_to_a_playlist(selected_file, selected_file_attr,
|
||||
false, NULL);
|
||||
false, NULL, ctx_add_to_playlist);
|
||||
}
|
||||
|
||||
static bool cat_add_to_a_new_playlist(void)
|
||||
{
|
||||
return catalog_add_to_a_playlist(selected_file, selected_file_attr,
|
||||
true, NULL);
|
||||
true, NULL, ctx_add_to_playlist);
|
||||
}
|
||||
|
||||
static int cat_playlist_callback(int action,
|
||||
|
@ -871,11 +872,12 @@ MAKE_ONPLAYMENU(cat_playlist_menu, ID2P(LANG_ADD_TO_PL),
|
|||
cat_playlist_callback, Icon_Playlist,
|
||||
&cat_add_to_list, &cat_add_to_new);
|
||||
|
||||
void onplay_show_playlist_cat_menu(char* track_name)
|
||||
void onplay_show_playlist_cat_menu(const char* track_name, int attr, void (*add_to_pl_cb))
|
||||
{
|
||||
context = CONTEXT_STD;
|
||||
ctx_add_to_playlist = add_to_pl_cb;
|
||||
selected_file = track_name;
|
||||
selected_file_attr = FILE_ATTR_AUDIO;
|
||||
selected_file_attr = attr;
|
||||
do_menu(&cat_playlist_menu, NULL, NULL, false);
|
||||
}
|
||||
|
||||
|
@ -892,13 +894,6 @@ static int cat_playlist_callback(int action,
|
|||
{
|
||||
return ACTION_EXIT_MENUITEM;
|
||||
}
|
||||
#ifdef HAVE_TAGCACHE
|
||||
if (context == CONTEXT_ID3DB &&
|
||||
((selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO))
|
||||
{
|
||||
return ACTION_EXIT_MENUITEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (action)
|
||||
{
|
||||
|
@ -2026,13 +2021,31 @@ int onplay(char* file, int attr, int from, bool hotkey)
|
|||
const struct menu_item_ex *menu;
|
||||
onplay_result = ONPLAY_OK;
|
||||
context = from;
|
||||
ctx_playlist_insert = NULL;
|
||||
if (file == NULL)
|
||||
selected_file = NULL;
|
||||
else
|
||||
ctx_current_playlist_insert = NULL;
|
||||
selected_file = NULL;
|
||||
#ifdef HAVE_TAGCACHE
|
||||
if (context == CONTEXT_ID3DB &&
|
||||
(attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO)
|
||||
{
|
||||
strmemccpy(selected_file_path, file, MAX_PATH);
|
||||
selected_file = selected_file_path;
|
||||
ctx_add_to_playlist = tagtree_add_to_playlist;
|
||||
if (file != NULL)
|
||||
{
|
||||
/* add a leading slash so that catalog_add_to_a_playlist
|
||||
later prefills the name when creating a new playlist */
|
||||
snprintf(selected_file_path, MAX_PATH, "/%s", file);
|
||||
selected_file = selected_file_path;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ctx_add_to_playlist = NULL;
|
||||
if (file != NULL)
|
||||
{
|
||||
strmemccpy(selected_file_path, file, MAX_PATH);
|
||||
selected_file = selected_file_path;
|
||||
}
|
||||
|
||||
}
|
||||
selected_file_attr = attr;
|
||||
int menu_selection;
|
||||
|
|
|
@ -75,7 +75,8 @@ const struct hotkey_assignment *get_hotkey(int action);
|
|||
#endif
|
||||
|
||||
/* needed for the playlist viewer.. eventually clean this up */
|
||||
void onplay_show_playlist_cat_menu(char* track_name);
|
||||
void onplay_show_playlist_cat_menu(const char* track_name, int attr,
|
||||
void (*add_to_pl_cb));
|
||||
void onplay_show_playlist_menu(const char* path, void (*playlist_insert_cb));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -389,9 +389,12 @@ bool catalog_view_playlists(void)
|
|||
return (display_playlists(NULL, CATBROWSE_CATVIEW) >= 0);
|
||||
}
|
||||
|
||||
static int (*ctx_add_to_playlist)(const char* playlist, bool new_playlist);
|
||||
bool catalog_add_to_a_playlist(const char* sel, int sel_attr,
|
||||
bool new_playlist, char *m3u8name)
|
||||
bool new_playlist, char *m3u8name,
|
||||
void (*add_to_pl_cb))
|
||||
{
|
||||
int result;
|
||||
char playlist[MAX_PATH + 7]; /* room for /.m3u8\0*/
|
||||
if ((browser_status & CATBROWSE_PLAYLIST) == CATBROWSE_PLAYLIST)
|
||||
return false;
|
||||
|
@ -437,8 +440,13 @@ bool catalog_add_to_a_playlist(const char* sel, int sel_attr,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (add_to_playlist(playlist, new_playlist, sel, sel_attr) == 0)
|
||||
return true;
|
||||
if (add_to_pl_cb != NULL)
|
||||
{
|
||||
ctx_add_to_playlist = add_to_pl_cb;
|
||||
result = ctx_add_to_playlist(playlist, new_playlist);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
result = add_to_playlist(playlist, new_playlist, sel, sel_attr);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
|
|
@ -41,9 +41,13 @@ bool catalog_view_playlists(void);
|
|||
* new_playlist : whether we want to create a new playlist or add to an
|
||||
* existing one.
|
||||
* m3u8name : filename to save the playlist to, NULL to show the keyboard
|
||||
* add_to_pl_cb : can be NULL, or a function responsible for handling the
|
||||
* insert operations itself, in case the caller wants full
|
||||
* control over how and what files are actually added.
|
||||
* ret : true if the file was successfully added
|
||||
*/
|
||||
bool catalog_add_to_a_playlist(const char* sel, int sel_attr,
|
||||
bool new_playlist, char* m3u8name);
|
||||
bool new_playlist, char* m3u8name,
|
||||
void (*add_to_pl_cb));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -630,7 +630,7 @@ static enum pv_onplay_result onplay_menu(int index)
|
|||
break;
|
||||
case 1:
|
||||
/* add to catalog */
|
||||
onplay_show_playlist_cat_menu(current_track->name);
|
||||
onplay_show_playlist_cat_menu(current_track->name, FILE_ATTR_AUDIO, NULL);
|
||||
ret = PV_ONPLAY_UNCHANGED;
|
||||
break;
|
||||
case 2:
|
||||
|
|
|
@ -77,32 +77,6 @@ static char* strip_filename(char* buf, int buf_size, const char* fullpath)
|
|||
return (sep + 1);
|
||||
}
|
||||
|
||||
/* Make sure part of path only contain chars valid for a FAT32 long name.
|
||||
* Double quotes are replaced with single quotes, other unsupported chars
|
||||
* are replaced with an underscore.
|
||||
*
|
||||
* path - path to modify.
|
||||
* offset - where in path to start checking.
|
||||
* count - number of chars to check.
|
||||
*/
|
||||
static void fix_path_part(char* path, int offset, int count)
|
||||
{
|
||||
static const char invalid_chars[] = "*/:<>?\\|";
|
||||
int i;
|
||||
|
||||
path += offset;
|
||||
|
||||
for (i = 0; i <= count; i++, path++)
|
||||
{
|
||||
if (*path == 0)
|
||||
return;
|
||||
if (*path == '"')
|
||||
*path = '\'';
|
||||
else if (strchr(invalid_chars, *path))
|
||||
*path = '_';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_JPEG_COVER
|
||||
static const char * const extensions[] = { "jpeg", "jpg", "bmp" };
|
||||
static const unsigned char extension_lens[] = { 4, 3, 3 };
|
||||
|
|
|
@ -2069,10 +2069,14 @@ int tagtree_get_filename(struct tree_context* c, char *buf, int buflen)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool insert_all_playlist(struct tree_context *c, int position, bool queue)
|
||||
|
||||
static bool insert_all_playlist(struct tree_context *c,
|
||||
const char* playlist, bool new_playlist,
|
||||
int position, bool queue)
|
||||
{
|
||||
struct tagcache_search tcs;
|
||||
int i, n;
|
||||
int fd = -1;
|
||||
unsigned long last_tick;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
|
@ -2084,7 +2088,7 @@ static bool insert_all_playlist(struct tree_context *c, int position, bool queue
|
|||
return false;
|
||||
}
|
||||
|
||||
if (position == PLAYLIST_REPLACE)
|
||||
if (playlist == NULL && position == PLAYLIST_REPLACE)
|
||||
{
|
||||
if (playlist_remove_all_tracks(NULL) == 0)
|
||||
position = PLAYLIST_INSERT_LAST;
|
||||
|
@ -2094,6 +2098,19 @@ static bool insert_all_playlist(struct tree_context *c, int position, bool queue
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (playlist != NULL)
|
||||
{
|
||||
if (new_playlist)
|
||||
fd = open_utf8(playlist, O_CREAT|O_WRONLY|O_TRUNC);
|
||||
else
|
||||
fd = open(playlist, O_CREAT|O_WRONLY|O_APPEND, 0666);
|
||||
|
||||
if(fd < 0)
|
||||
{
|
||||
cpu_boost(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
last_tick = current_tick + HZ/2; /* Show splash after 0.5 seconds have passed */
|
||||
splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */
|
||||
|
@ -2115,26 +2132,36 @@ static bool insert_all_playlist(struct tree_context *c, int position, bool queue
|
|||
continue;
|
||||
}
|
||||
|
||||
if (playlist_insert_track(NULL, buf, position, queue, false) < 0)
|
||||
if (playlist == NULL)
|
||||
{
|
||||
logf("playlist_insert_track failed");
|
||||
break;
|
||||
if (playlist_insert_track(NULL, buf, position, queue, false) < 0)
|
||||
{
|
||||
logf("playlist_insert_track failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (fdprintf(fd, "%s\n", buf) <= 0)
|
||||
break;
|
||||
|
||||
yield();
|
||||
|
||||
if (position == PLAYLIST_INSERT_FIRST)
|
||||
if (playlist == NULL && position == PLAYLIST_INSERT_FIRST)
|
||||
{
|
||||
position = PLAYLIST_INSERT;
|
||||
}
|
||||
}
|
||||
playlist_sync(NULL);
|
||||
if (playlist == NULL)
|
||||
playlist_sync(NULL);
|
||||
else
|
||||
close(fd);
|
||||
tagcache_search_finish(&tcs);
|
||||
cpu_boost(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tagtree_insert_selection_playlist(int position, bool queue)
|
||||
static bool tagtree_insert_selection(int position, bool queue,
|
||||
const char* playlist, bool new_playlist)
|
||||
{
|
||||
char buf[MAX_PATH];
|
||||
int dirlevel = tc->dirlevel;
|
||||
|
@ -2201,7 +2228,7 @@ bool tagtree_insert_selection_playlist(int position, bool queue)
|
|||
else
|
||||
{
|
||||
logf("insert_all_playlist");
|
||||
if (!insert_all_playlist(tc, position, queue))
|
||||
if (!insert_all_playlist(tc, playlist, new_playlist, position, queue))
|
||||
splash(HZ*2, ID2P(LANG_FAILED));
|
||||
}
|
||||
|
||||
|
@ -2214,6 +2241,20 @@ bool tagtree_insert_selection_playlist(int position, bool queue)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool tagtree_current_playlist_insert(int position, bool queue)
|
||||
{
|
||||
return tagtree_insert_selection(position, queue, NULL, false);
|
||||
}
|
||||
|
||||
|
||||
int tagtree_add_to_playlist(const char* playlist, bool new_playlist)
|
||||
{
|
||||
if (!new_playlist)
|
||||
tagtree_load(tc); /* because display_playlists was called */
|
||||
return tagtree_insert_selection(0, false, playlist, new_playlist) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int tagtree_play_folder(struct tree_context* c)
|
||||
{
|
||||
int start_index = c->selected_item;
|
||||
|
@ -2224,7 +2265,7 @@ static int tagtree_play_folder(struct tree_context* c)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!insert_all_playlist(c, PLAYLIST_INSERT_LAST, false))
|
||||
if (!insert_all_playlist(c, NULL, false, PLAYLIST_INSERT_LAST, false))
|
||||
return -2;
|
||||
|
||||
if (global_settings.playlist_shuffle)
|
||||
|
|
|
@ -39,7 +39,8 @@ void tagtree_exit(struct tree_context* c, bool is_visible);
|
|||
int tagtree_load(struct tree_context* c);
|
||||
char* tagtree_get_entry_name(struct tree_context *c, int id,
|
||||
char* buf, size_t bufsize);
|
||||
bool tagtree_insert_selection_playlist(int position, bool queue);
|
||||
bool tagtree_current_playlist_insert(int position, bool queue);
|
||||
int tagtree_add_to_playlist(const char* playlist, bool new_playlist);
|
||||
char *tagtree_get_title(struct tree_context* c);
|
||||
int tagtree_get_attr(struct tree_context* c);
|
||||
int tagtree_get_icon(struct tree_context* c);
|
||||
|
|
|
@ -811,7 +811,12 @@ static int dirbrowse(void)
|
|||
tagtree_get_filename(&tc, buf, sizeof(buf));
|
||||
}
|
||||
else
|
||||
{
|
||||
attr = ATTR_DIRECTORY;
|
||||
tagtree_get_entry_name(&tc, tc.selected_item,
|
||||
buf, sizeof(buf));
|
||||
fix_path_part(buf, 0, sizeof(buf));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -956,7 +961,7 @@ int create_playlist(void)
|
|||
#endif
|
||||
|
||||
trigger_cpu_boost();
|
||||
ret = catalog_add_to_a_playlist(tc.currdir, ATTR_DIRECTORY, true, NULL);
|
||||
ret = catalog_add_to_a_playlist(tc.currdir, ATTR_DIRECTORY, true, NULL, NULL);
|
||||
cancel_cpu_boost();
|
||||
|
||||
return (ret) ? 1 : 0;
|
||||
|
|
Loading…
Reference in a new issue