From 7f265ee8dd062a015e214b16f9c41fc27e867f22 Mon Sep 17 00:00:00 2001 From: Christian Soffke Date: Tue, 16 Aug 2022 13:10:13 +0200 Subject: [PATCH] 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 --- apps/misc.c | 26 +++++++++++++++++ apps/misc.h | 2 ++ apps/onplay.c | 57 ++++++++++++++++++++++--------------- apps/onplay.h | 3 +- apps/playlist_catalog.c | 16 ++++++++--- apps/playlist_catalog.h | 6 +++- apps/playlist_viewer.c | 2 +- apps/recorder/albumart.c | 26 ----------------- apps/tagtree.c | 61 +++++++++++++++++++++++++++++++++------- apps/tagtree.h | 3 +- apps/tree.c | 7 ++++- 11 files changed, 142 insertions(+), 67 deletions(-) diff --git a/apps/misc.c b/apps/misc.c index 93b5247ae9..e6c8a219ea 100644 --- a/apps/misc.c +++ b/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, ...) { diff --git a/apps/misc.h b/apps/misc.h index df2c649b0e..51684cb658 100644 --- a/apps/misc.h +++ b/apps/misc.h @@ -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); diff --git a/apps/onplay.c b/apps/onplay.c index ce2b3310f3..f92ed76050 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -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; diff --git a/apps/onplay.h b/apps/onplay.h index 807bfe8cf7..ae23bdaefd 100644 --- a/apps/onplay.h +++ b/apps/onplay.h @@ -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 diff --git a/apps/playlist_catalog.c b/apps/playlist_catalog.c index c3cbc93a20..b6939208ac 100644 --- a/apps/playlist_catalog.c +++ b/apps/playlist_catalog.c @@ -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); } diff --git a/apps/playlist_catalog.h b/apps/playlist_catalog.h index bb16e2dad9..fb71821093 100644 --- a/apps/playlist_catalog.h +++ b/apps/playlist_catalog.h @@ -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 diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index c9b027ea63..4e3d8bade2 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c @@ -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: diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c index c0d9e6d86f..50794c06c8 100644 --- a/apps/recorder/albumart.c +++ b/apps/recorder/albumart.c @@ -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 }; diff --git a/apps/tagtree.c b/apps/tagtree.c index 11ea8ecf4e..85359cac04 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -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) diff --git a/apps/tagtree.h b/apps/tagtree.h index 5c938b1541..6eaaf3dfac 100644 --- a/apps/tagtree.h +++ b/apps/tagtree.h @@ -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); diff --git a/apps/tree.c b/apps/tree.c index d2a7111e5f..5dd88c8e9d 100644 --- a/apps/tree.c +++ b/apps/tree.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;