summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Soffke <christian.soffke@gmail.com>2023-01-10 18:50:05 +0100
committerChristian Soffke <christian.soffke@gmail.com>2023-01-19 15:56:35 -0500
commit32f365bf3cdcaadb22087041bfc44574737b557d (patch)
treeeff68bbaa18d6b1ff8e2d0fd581c461412a55ad6
parent4d53d1b52b858d4a1e90fc74fb93cda957d00cb4 (diff)
downloadrockbox-32f365bf3cdcaadb22087041bfc44574737b557d.tar.gz
rockbox-32f365bf3cdcaadb22087041bfc44574737b557d.zip
database: make parent tables work with plugin
Enables the use of PictureFlow and the Properties plugin with parent tables of ALLSUBENTRIES, such as an album or album artist, instead of individual tracks. Change-Id: I18c4779ed116a48c732ae32b9629e7e0d93ce7c8
-rw-r--r--apps/misc.h3
-rw-r--r--apps/onplay.c35
-rw-r--r--apps/plugin.c3
-rw-r--r--apps/plugin.h6
-rw-r--r--apps/plugins/properties.c94
-rw-r--r--apps/tagtree.c138
-rw-r--r--apps/tagtree.h2
7 files changed, 205 insertions, 76 deletions
diff --git a/apps/misc.h b/apps/misc.h
index 51684cb658..403a8c53ac 100644
--- a/apps/misc.h
+++ b/apps/misc.h
@@ -187,6 +187,9 @@ enum current_activity {
ACTIVITY_USBSCREEN
};
+/* custom string representation of activity */
+#define MAKE_ACT_STR(act) ((char[3]){'>', 'A'+ (act), 0x0})
+
void beep_play(unsigned int frequency, unsigned int duration,
unsigned int amplitude);
diff --git a/apps/onplay.c b/apps/onplay.c
index f92ed76050..96c2ddd4e3 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -1611,8 +1611,33 @@ static bool list_viewers(void)
return false;
}
+#ifdef HAVE_TAGCACHE
+static bool prepare_database_sel(void *param)
+{
+ if (context == CONTEXT_ID3DB &&
+ (selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO)
+ {
+ if (!strcmp(param, "properties"))
+ strmemccpy(selected_file_path, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER),
+ sizeof(selected_file_path));
+ else if (!tagtree_get_subentry_filename(selected_file_path, MAX_PATH))
+ {
+ onplay_result = ONPLAY_RELOAD_DIR;
+ return false;
+ }
+
+ selected_file = selected_file_path;
+ }
+ return true;
+}
+#endif
+
static bool onplay_load_plugin(void *param)
{
+#ifdef HAVE_TAGCACHE
+ if (!prepare_database_sel(param))
+ return false;
+#endif
int ret = filetype_load_plugin((const char*)param, selected_file);
if (ret == PLUGIN_USB_CONNECTED)
onplay_result = ONPLAY_RELOAD_DIR;
@@ -1717,10 +1742,8 @@ static int clipboard_callback(int action,
#ifdef HAVE_TAGCACHE
if (context == CONTEXT_ID3DB)
{
- if (((selected_file_attr & FILE_ATTR_MASK) ==
- FILE_ATTR_AUDIO) &&
- (this_item == &track_info_item ||
- this_item == &pictureflow_item))
+ if (this_item == &track_info_item ||
+ this_item == &pictureflow_item)
return action;
return ACTION_EXIT_MENUITEM;
}
@@ -1895,6 +1918,10 @@ static int hotkey_tree_pl_insert_shuffled(void)
static int hotkey_tree_run_plugin(void *param)
{
+#ifdef HAVE_TAGCACHE
+ if (!prepare_database_sel(param))
+ return ONPLAY_RELOAD_DIR;
+#endif
if (filetype_load_plugin((const char*)param, selected_file) == PLUGIN_GOTO_WPS)
return ONPLAY_START_PLAY;
diff --git a/apps/plugin.c b/apps/plugin.c
index c28954e9eb..00fac21b8d 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -825,6 +825,9 @@ static const struct plugin_api rockbox_api = {
splash_progress_set_delay,
fix_path_part,
onplay_show_playlist_cat_menu,
+#if defined(HAVE_TAGCACHE)
+ tagtree_subentries_do_action,
+#endif
};
static int plugin_buffer_handle;
diff --git a/apps/plugin.h b/apps/plugin.h
index 850e7484d9..20df7e72f2 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -103,6 +103,7 @@ int plugin_open(const char *plugin, const char *parameter);
#include "buflib.h"
#include "buffering.h"
#include "tagcache.h"
+#include "tagtree.h"
#include "viewport.h"
#include "ata_idle_notify.h"
#include "settings_list.h"
@@ -157,7 +158,7 @@ int plugin_open(const char *plugin, const char *parameter);
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 263
+#define PLUGIN_API_VERSION 264
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
@@ -950,6 +951,9 @@ struct plugin_api {
void (*fix_path_part)(char* path, int offset, int count);
void (*onplay_show_playlist_cat_menu)(const char* track_name, int attr,
void (*add_to_pl_cb));
+#ifdef HAVE_TAGCACHE
+ bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name));
+#endif
};
/* plugin header */
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index 46cf818fb4..7dacda3579 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -19,6 +19,11 @@
*
****************************************************************************/
#include "plugin.h"
+#include "lib/id3.h"
+
+#ifdef HAVE_TAGCACHE
+#include "lib/mul_id3.h"
+#endif
#if !defined(ARRAY_SIZE)
#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
@@ -35,12 +40,16 @@ struct dir_stats {
enum props_types {
PROPS_FILE = 0,
PROPS_ID3,
+ PROPS_MUL_ID3,
PROPS_DIR
};
static int props_type = PROPS_FILE;
static struct mp3entry id3;
+#ifdef HAVE_TAGCACHE
+static int mul_id3_count;
+#endif
static char str_filename[MAX_PATH];
static char str_dirname[MAX_PATH];
@@ -118,14 +127,8 @@ static bool file_properties(const char* selected_file)
rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d",
tm.tm_hour, tm.tm_min, tm.tm_sec);
- int fd = rb->open(selected_file, O_RDONLY);
- if (fd >= 0)
- {
- if (rb->get_metadata(&id3, fd, selected_file))
- props_type = PROPS_ID3;
-
- rb->close(fd);
- }
+ if (retrieve_id3(&id3, selected_file, false))
+ props_type = PROPS_ID3;
found = true;
break;
}
@@ -369,6 +372,19 @@ static bool determine_file_or_dir(void)
return false;
}
+#ifdef HAVE_TAGCACHE
+bool mul_id3_add(const char *file_name)
+{
+ if (!retrieve_id3(&id3, file_name, false))
+ return false;
+
+ collect_id3(&id3, mul_id3_count == 0);
+ mul_id3_count++;
+
+ return true;
+}
+#endif
+
enum plugin_status plugin_start(const void* parameter)
{
static struct dir_stats stats =
@@ -380,40 +396,62 @@ enum plugin_status plugin_start(const void* parameter)
};
const char *file = parameter;
- if(!parameter || (file[0] != '/')) return PLUGIN_ERROR;
+ if(!parameter)
+ return PLUGIN_ERROR;
#ifdef HAVE_TOUCHSCREEN
rb->touchscreen_set_mode(rb->global_settings->touch_mode);
#endif
- const char* file_name = rb->strrchr(file, '/') + 1;
- int dirlen = (file_name - file);
+#ifdef HAVE_TAGCACHE
+ if (!rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))) /* db table selected */
+ {
+ props_type = PROPS_MUL_ID3;
+ init_mul_id3();
+ mul_id3_count = 0;
- rb->strlcpy(str_dirname, file, dirlen + 1);
- rb->snprintf(str_filename, sizeof str_filename, "%s", file+dirlen);
+ if (!rb->tagtree_subentries_do_action(&mul_id3_add) || mul_id3_count == 0)
+ return PLUGIN_ERROR;
- if(!determine_file_or_dir())
- {
- /* weird: we couldn't find the entry. This Should Never Happen (TM) */
- rb->splashf(0, "File/Dir not found: %s", file);
- rb->action_userabort(TIMEOUT_BLOCK);
- return PLUGIN_OK;
+ if (mul_id3_count > 1) /* otherwise, the retrieved id3 can be used as-is */
+ write_id3_mul_tracks(&id3);
}
-
- /* get the info depending on its_a_dir */
- if(!(props_type == PROPS_DIR ? dir_properties(file, &stats) : file_properties(file)))
+ else
+#endif
+ if (file[0] == '/') /* single track selected */
{
- /* something went wrong (to do: tell user what it was (nesting,...) */
- rb->splash(0, ID2P(LANG_PROPERTIES_FAIL));
- rb->action_userabort(TIMEOUT_BLOCK);
- return PLUGIN_OK;
+ const char* file_name = rb->strrchr(file, '/') + 1;
+ int dirlen = (file_name - file);
+
+ rb->strlcpy(str_dirname, file, dirlen + 1);
+ rb->snprintf(str_filename, sizeof str_filename, "%s", file+dirlen);
+
+ if(!determine_file_or_dir())
+ {
+ /* weird: we couldn't find the entry. This Should Never Happen (TM) */
+ rb->splashf(0, "File/Dir not found: %s", file);
+ rb->action_userabort(TIMEOUT_BLOCK);
+ return PLUGIN_OK;
+ }
+
+ /* get the info depending on its_a_dir */
+ if(!(props_type == PROPS_DIR ? dir_properties(file, &stats) : file_properties(file)))
+ {
+ /* something went wrong (to do: tell user what it was (nesting,...) */
+ rb->splash(0, ID2P(LANG_PROPERTIES_FAIL));
+ rb->action_userabort(TIMEOUT_BLOCK);
+ return PLUGIN_OK;
+ }
}
+ else
+ return PLUGIN_ERROR;
FOR_NB_SCREENS(i)
rb->viewportmanager_theme_enable(i, true, NULL);
- bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm) :
- browse_file_or_dir(&stats);
+ bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm) :
+ (props_type == PROPS_MUL_ID3 ? rb->browse_id3(&id3, 0, 0, NULL) :
+ browse_file_or_dir(&stats));
FOR_NB_SCREENS(i)
rb->viewportmanager_theme_undo(i, false);
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 85359cac04..4248538f77 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -407,7 +407,7 @@ static int get_tag(int *tag)
static int get_clause(int *condition)
{
- /* one or two operator conditionals */
+ /* one or two operator conditionals */
#define OPS2VAL(op1, op2) ((int)op1 << 8 | (int)op2)
#define CLAUSE(op1, op2, symbol) {OPS2VAL(op1, op2), symbol }
@@ -2160,6 +2160,27 @@ static bool insert_all_playlist(struct tree_context *c,
return true;
}
+static bool goto_allsubentries(int newtable)
+{
+ int i = 0;
+ while (i < 2 && (newtable == NAVIBROWSE || newtable == ALLSUBENTRIES))
+ {
+ tagtree_enter(tc, false);
+ tagtree_load(tc);
+ newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
+ i++;
+ }
+ return (newtable == PLAYTRACK);
+}
+
+static void reset_tc_to_prev(int dirlevel, int selected_item)
+{
+ while (tc->dirlevel > dirlevel)
+ tagtree_exit(tc, false);
+ tc->selected_item = selected_item;
+ tagtree_load(tc);
+}
+
static bool tagtree_insert_selection(int position, bool queue,
const char* playlist, bool new_playlist)
{
@@ -2167,6 +2188,7 @@ static bool tagtree_insert_selection(int position, bool queue,
int dirlevel = tc->dirlevel;
int selected_item = tc->selected_item;
int newtable;
+ int ret;
show_search_progress(
#ifdef HAVE_DISK_STORAGE
@@ -2176,71 +2198,101 @@ static bool tagtree_insert_selection(int position, bool queue,
#endif
, 0);
-
- /* We need to set the table to allsubentries. */
newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
- /* Insert a single track? */
- if (newtable == PLAYTRACK)
+ if (newtable == PLAYTRACK) /* Insert a single track? */
{
if (tagtree_get_filename(tc, buf, sizeof buf) < 0)
- {
- logf("tagtree_get_filename failed");
return false;
- }
+
playlist_insert_track(NULL, buf, position, queue, true);
return true;
}
- if (newtable == NAVIBROWSE)
- {
- tagtree_enter(tc, false);
- tagtree_load(tc);
- newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
- }
- else if (newtable != ALLSUBENTRIES)
+ ret = goto_allsubentries(newtable);
+ if (ret)
{
- logf("unsupported table: %d", newtable);
- return false;
+ if (tc->filesindir <= 0)
+ splash(HZ, ID2P(LANG_END_PLAYLIST));
+ else if (!insert_all_playlist(tc, playlist, new_playlist, position, queue))
+ splash(HZ*2, ID2P(LANG_FAILED));
}
- /* Now the current table should be allsubentries. */
- if (newtable != PLAYTRACK)
- {
- tagtree_enter(tc, false);
- tagtree_load(tc);
- newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
+ reset_tc_to_prev(dirlevel, selected_item);
+ return ret;
+}
+
+/* Execute action_cb for all subentries of the current table's
+ * selected item, handing over each entry's filename in the
+ * callback function parameter.
+ */
+bool tagtree_subentries_do_action(bool (*action_cb)(const char *file_name))
+{
+ struct tagcache_search tcs;
+ int i, n;
+ unsigned long last_tick;
+ char buf[MAX_PATH];
+ int ret = true;
+ int dirlevel = tc->dirlevel;
+ int selected_item = tc->selected_item;
+ int newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
- /* And now the newtable should be playtrack. */
- if (newtable != PLAYTRACK)
+ cpu_boost(true);
+ if (!goto_allsubentries(newtable))
+ ret = false;
+ else if (tagcache_search(&tcs, tag_filename))
+ {
+ last_tick = current_tick + HZ/2;
+ splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */
+ n = tc->filesindir;
+ for (i = 0; i < n; i++)
{
- logf("newtable: %d !!", newtable);
- while (tc->dirlevel > dirlevel)
- tagtree_exit(tc, false);
- tagtree_load(tc);
- return false;
+ splash_progress(i, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT));
+ if (TIME_AFTER(current_tick, last_tick + HZ/4))
+ {
+ if (action_userabort(TIMEOUT_NOBLOCK))
+ break;
+ last_tick = current_tick;
+ }
+
+ if (!tagcache_retrieve(&tcs, tagtree_get_entry(tc, i)->extraseek,
+ tcs.type, buf, sizeof buf)
+ || !action_cb(buf))
+ {
+ ret = false;
+ break;
+ }
+ yield();
}
- }
- if (tc->filesindir <= 0)
- splash(HZ, ID2P(LANG_END_PLAYLIST));
+ tagcache_search_finish(&tcs);
+ }
else
{
- logf("insert_all_playlist");
- if (!insert_all_playlist(tc, playlist, new_playlist, position, queue))
- splash(HZ*2, ID2P(LANG_FAILED));
+ splash(HZ, ID2P(LANG_TAGCACHE_BUSY));
+ ret = false;
}
+ reset_tc_to_prev(dirlevel, selected_item);
+ cpu_boost(false);
+ return ret;
+}
- /* Finally return the dirlevel to its original value. */
- while (tc->dirlevel > dirlevel)
- tagtree_exit(tc, false);
- tc->selected_item = selected_item;
- tagtree_load(tc);
+/* Try to return first subentry's filename for current selection
+ */
+bool tagtree_get_subentry_filename(char *buf, size_t bufsize)
+{
+ int ret = true;
+ int dirlevel = tc->dirlevel;
+ int selected_item = tc->selected_item;
+ int newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
- return true;
-}
+ if (!goto_allsubentries(newtable) || tagtree_get_filename(tc, buf, bufsize) < 0)
+ ret = false;
+ reset_tc_to_prev(dirlevel, selected_item);
+ return ret;
+}
bool tagtree_current_playlist_insert(int position, bool queue)
{
diff --git a/apps/tagtree.h b/apps/tagtree.h
index 6eaaf3dfac..39ab545bd0 100644
--- a/apps/tagtree.h
+++ b/apps/tagtree.h
@@ -45,6 +45,8 @@ char *tagtree_get_title(struct tree_context* c);
int tagtree_get_attr(struct tree_context* c);
int tagtree_get_icon(struct tree_context* c);
int tagtree_get_filename(struct tree_context* c, char *buf, int buflen);
+bool tagtree_get_subentry_filename(char *buf, size_t bufsize);
+bool tagtree_subentries_do_action(bool (*action_cb)(const char *file_name));
#endif
#endif