summaryrefslogtreecommitdiff
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 {
187 ACTIVITY_USBSCREEN 187 ACTIVITY_USBSCREEN
188}; 188};
189 189
190/* custom string representation of activity */
191#define MAKE_ACT_STR(act) ((char[3]){'>', 'A'+ (act), 0x0})
192
190void beep_play(unsigned int frequency, unsigned int duration, 193void beep_play(unsigned int frequency, unsigned int duration,
191 unsigned int amplitude); 194 unsigned int amplitude);
192 195
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)
1611 return false; 1611 return false;
1612} 1612}
1613 1613
1614#ifdef HAVE_TAGCACHE
1615static bool prepare_database_sel(void *param)
1616{
1617 if (context == CONTEXT_ID3DB &&
1618 (selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO)
1619 {
1620 if (!strcmp(param, "properties"))
1621 strmemccpy(selected_file_path, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER),
1622 sizeof(selected_file_path));
1623 else if (!tagtree_get_subentry_filename(selected_file_path, MAX_PATH))
1624 {
1625 onplay_result = ONPLAY_RELOAD_DIR;
1626 return false;
1627 }
1628
1629 selected_file = selected_file_path;
1630 }
1631 return true;
1632}
1633#endif
1634
1614static bool onplay_load_plugin(void *param) 1635static bool onplay_load_plugin(void *param)
1615{ 1636{
1637#ifdef HAVE_TAGCACHE
1638 if (!prepare_database_sel(param))
1639 return false;
1640#endif
1616 int ret = filetype_load_plugin((const char*)param, selected_file); 1641 int ret = filetype_load_plugin((const char*)param, selected_file);
1617 if (ret == PLUGIN_USB_CONNECTED) 1642 if (ret == PLUGIN_USB_CONNECTED)
1618 onplay_result = ONPLAY_RELOAD_DIR; 1643 onplay_result = ONPLAY_RELOAD_DIR;
@@ -1717,10 +1742,8 @@ static int clipboard_callback(int action,
1717#ifdef HAVE_TAGCACHE 1742#ifdef HAVE_TAGCACHE
1718 if (context == CONTEXT_ID3DB) 1743 if (context == CONTEXT_ID3DB)
1719 { 1744 {
1720 if (((selected_file_attr & FILE_ATTR_MASK) == 1745 if (this_item == &track_info_item ||
1721 FILE_ATTR_AUDIO) && 1746 this_item == &pictureflow_item)
1722 (this_item == &track_info_item ||
1723 this_item == &pictureflow_item))
1724 return action; 1747 return action;
1725 return ACTION_EXIT_MENUITEM; 1748 return ACTION_EXIT_MENUITEM;
1726 } 1749 }
@@ -1895,6 +1918,10 @@ static int hotkey_tree_pl_insert_shuffled(void)
1895 1918
1896static int hotkey_tree_run_plugin(void *param) 1919static int hotkey_tree_run_plugin(void *param)
1897{ 1920{
1921#ifdef HAVE_TAGCACHE
1922 if (!prepare_database_sel(param))
1923 return ONPLAY_RELOAD_DIR;
1924#endif
1898 if (filetype_load_plugin((const char*)param, selected_file) == PLUGIN_GOTO_WPS) 1925 if (filetype_load_plugin((const char*)param, selected_file) == PLUGIN_GOTO_WPS)
1899 return ONPLAY_START_PLAY; 1926 return ONPLAY_START_PLAY;
1900 1927
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 = {
825 splash_progress_set_delay, 825 splash_progress_set_delay,
826 fix_path_part, 826 fix_path_part,
827 onplay_show_playlist_cat_menu, 827 onplay_show_playlist_cat_menu,
828#if defined(HAVE_TAGCACHE)
829 tagtree_subentries_do_action,
830#endif
828}; 831};
829 832
830static int plugin_buffer_handle; 833static 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);
103#include "buflib.h" 103#include "buflib.h"
104#include "buffering.h" 104#include "buffering.h"
105#include "tagcache.h" 105#include "tagcache.h"
106#include "tagtree.h"
106#include "viewport.h" 107#include "viewport.h"
107#include "ata_idle_notify.h" 108#include "ata_idle_notify.h"
108#include "settings_list.h" 109#include "settings_list.h"
@@ -157,7 +158,7 @@ int plugin_open(const char *plugin, const char *parameter);
157#define PLUGIN_MAGIC 0x526F634B /* RocK */ 158#define PLUGIN_MAGIC 0x526F634B /* RocK */
158 159
159/* increase this every time the api struct changes */ 160/* increase this every time the api struct changes */
160#define PLUGIN_API_VERSION 263 161#define PLUGIN_API_VERSION 264
161 162
162/* update this to latest version if a change to the api struct breaks 163/* update this to latest version if a change to the api struct breaks
163 backwards compatibility (and please take the opportunity to sort in any 164 backwards compatibility (and please take the opportunity to sort in any
@@ -950,6 +951,9 @@ struct plugin_api {
950 void (*fix_path_part)(char* path, int offset, int count); 951 void (*fix_path_part)(char* path, int offset, int count);
951 void (*onplay_show_playlist_cat_menu)(const char* track_name, int attr, 952 void (*onplay_show_playlist_cat_menu)(const char* track_name, int attr,
952 void (*add_to_pl_cb)); 953 void (*add_to_pl_cb));
954#ifdef HAVE_TAGCACHE
955 bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name));
956#endif
953}; 957};
954 958
955/* plugin header */ 959/* 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 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "plugin.h" 21#include "plugin.h"
22#include "lib/id3.h"
23
24#ifdef HAVE_TAGCACHE
25#include "lib/mul_id3.h"
26#endif
22 27
23#if !defined(ARRAY_SIZE) 28#if !defined(ARRAY_SIZE)
24 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) 29 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
@@ -35,12 +40,16 @@ struct dir_stats {
35enum props_types { 40enum props_types {
36 PROPS_FILE = 0, 41 PROPS_FILE = 0,
37 PROPS_ID3, 42 PROPS_ID3,
43 PROPS_MUL_ID3,
38 PROPS_DIR 44 PROPS_DIR
39}; 45};
40 46
41static int props_type = PROPS_FILE; 47static int props_type = PROPS_FILE;
42 48
43static struct mp3entry id3; 49static struct mp3entry id3;
50#ifdef HAVE_TAGCACHE
51static int mul_id3_count;
52#endif
44 53
45static char str_filename[MAX_PATH]; 54static char str_filename[MAX_PATH];
46static char str_dirname[MAX_PATH]; 55static char str_dirname[MAX_PATH];
@@ -118,14 +127,8 @@ static bool file_properties(const char* selected_file)
118 rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", 127 rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d",
119 tm.tm_hour, tm.tm_min, tm.tm_sec); 128 tm.tm_hour, tm.tm_min, tm.tm_sec);
120 129
121 int fd = rb->open(selected_file, O_RDONLY); 130 if (retrieve_id3(&id3, selected_file, false))
122 if (fd >= 0) 131 props_type = PROPS_ID3;
123 {
124 if (rb->get_metadata(&id3, fd, selected_file))
125 props_type = PROPS_ID3;
126
127 rb->close(fd);
128 }
129 found = true; 132 found = true;
130 break; 133 break;
131 } 134 }
@@ -369,6 +372,19 @@ static bool determine_file_or_dir(void)
369 return false; 372 return false;
370} 373}
371 374
375#ifdef HAVE_TAGCACHE
376bool mul_id3_add(const char *file_name)
377{
378 if (!retrieve_id3(&id3, file_name, false))
379 return false;
380
381 collect_id3(&id3, mul_id3_count == 0);
382 mul_id3_count++;
383
384 return true;
385}
386#endif
387
372enum plugin_status plugin_start(const void* parameter) 388enum plugin_status plugin_start(const void* parameter)
373{ 389{
374 static struct dir_stats stats = 390 static struct dir_stats stats =
@@ -380,40 +396,62 @@ enum plugin_status plugin_start(const void* parameter)
380 }; 396 };
381 397
382 const char *file = parameter; 398 const char *file = parameter;
383 if(!parameter || (file[0] != '/')) return PLUGIN_ERROR; 399 if(!parameter)
400 return PLUGIN_ERROR;
384 401
385#ifdef HAVE_TOUCHSCREEN 402#ifdef HAVE_TOUCHSCREEN
386 rb->touchscreen_set_mode(rb->global_settings->touch_mode); 403 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
387#endif 404#endif
388 405
389 const char* file_name = rb->strrchr(file, '/') + 1; 406#ifdef HAVE_TAGCACHE
390 int dirlen = (file_name - file); 407 if (!rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))) /* db table selected */
408 {
409 props_type = PROPS_MUL_ID3;
410 init_mul_id3();
411 mul_id3_count = 0;
391 412
392 rb->strlcpy(str_dirname, file, dirlen + 1); 413 if (!rb->tagtree_subentries_do_action(&mul_id3_add) || mul_id3_count == 0)
393 rb->snprintf(str_filename, sizeof str_filename, "%s", file+dirlen); 414 return PLUGIN_ERROR;
394 415
395 if(!determine_file_or_dir()) 416 if (mul_id3_count > 1) /* otherwise, the retrieved id3 can be used as-is */
396 { 417 write_id3_mul_tracks(&id3);
397 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
398 rb->splashf(0, "File/Dir not found: %s", file);
399 rb->action_userabort(TIMEOUT_BLOCK);
400 return PLUGIN_OK;
401 } 418 }
402 419 else
403 /* get the info depending on its_a_dir */ 420#endif
404 if(!(props_type == PROPS_DIR ? dir_properties(file, &stats) : file_properties(file))) 421 if (file[0] == '/') /* single track selected */
405 { 422 {
406 /* something went wrong (to do: tell user what it was (nesting,...) */ 423 const char* file_name = rb->strrchr(file, '/') + 1;
407 rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); 424 int dirlen = (file_name - file);
408 rb->action_userabort(TIMEOUT_BLOCK); 425
409 return PLUGIN_OK; 426 rb->strlcpy(str_dirname, file, dirlen + 1);
427 rb->snprintf(str_filename, sizeof str_filename, "%s", file+dirlen);
428
429 if(!determine_file_or_dir())
430 {
431 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
432 rb->splashf(0, "File/Dir not found: %s", file);
433 rb->action_userabort(TIMEOUT_BLOCK);
434 return PLUGIN_OK;
435 }
436
437 /* get the info depending on its_a_dir */
438 if(!(props_type == PROPS_DIR ? dir_properties(file, &stats) : file_properties(file)))
439 {
440 /* something went wrong (to do: tell user what it was (nesting,...) */
441 rb->splash(0, ID2P(LANG_PROPERTIES_FAIL));
442 rb->action_userabort(TIMEOUT_BLOCK);
443 return PLUGIN_OK;
444 }
410 } 445 }
446 else
447 return PLUGIN_ERROR;
411 448
412 FOR_NB_SCREENS(i) 449 FOR_NB_SCREENS(i)
413 rb->viewportmanager_theme_enable(i, true, NULL); 450 rb->viewportmanager_theme_enable(i, true, NULL);
414 451
415 bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm) : 452 bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm) :
416 browse_file_or_dir(&stats); 453 (props_type == PROPS_MUL_ID3 ? rb->browse_id3(&id3, 0, 0, NULL) :
454 browse_file_or_dir(&stats));
417 455
418 FOR_NB_SCREENS(i) 456 FOR_NB_SCREENS(i)
419 rb->viewportmanager_theme_undo(i, false); 457 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)
407 407
408static int get_clause(int *condition) 408static int get_clause(int *condition)
409{ 409{
410 /* one or two operator conditionals */ 410 /* one or two operator conditionals */
411 #define OPS2VAL(op1, op2) ((int)op1 << 8 | (int)op2) 411 #define OPS2VAL(op1, op2) ((int)op1 << 8 | (int)op2)
412 #define CLAUSE(op1, op2, symbol) {OPS2VAL(op1, op2), symbol } 412 #define CLAUSE(op1, op2, symbol) {OPS2VAL(op1, op2), symbol }
413 413
@@ -2160,6 +2160,27 @@ static bool insert_all_playlist(struct tree_context *c,
2160 return true; 2160 return true;
2161} 2161}
2162 2162
2163static bool goto_allsubentries(int newtable)
2164{
2165 int i = 0;
2166 while (i < 2 && (newtable == NAVIBROWSE || newtable == ALLSUBENTRIES))
2167 {
2168 tagtree_enter(tc, false);
2169 tagtree_load(tc);
2170 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
2171 i++;
2172 }
2173 return (newtable == PLAYTRACK);
2174}
2175
2176static void reset_tc_to_prev(int dirlevel, int selected_item)
2177{
2178 while (tc->dirlevel > dirlevel)
2179 tagtree_exit(tc, false);
2180 tc->selected_item = selected_item;
2181 tagtree_load(tc);
2182}
2183
2163static bool tagtree_insert_selection(int position, bool queue, 2184static bool tagtree_insert_selection(int position, bool queue,
2164 const char* playlist, bool new_playlist) 2185 const char* playlist, bool new_playlist)
2165{ 2186{
@@ -2167,6 +2188,7 @@ static bool tagtree_insert_selection(int position, bool queue,
2167 int dirlevel = tc->dirlevel; 2188 int dirlevel = tc->dirlevel;
2168 int selected_item = tc->selected_item; 2189 int selected_item = tc->selected_item;
2169 int newtable; 2190 int newtable;
2191 int ret;
2170 2192
2171 show_search_progress( 2193 show_search_progress(
2172#ifdef HAVE_DISK_STORAGE 2194#ifdef HAVE_DISK_STORAGE
@@ -2176,71 +2198,101 @@ static bool tagtree_insert_selection(int position, bool queue,
2176#endif 2198#endif
2177 , 0); 2199 , 0);
2178 2200
2179
2180 /* We need to set the table to allsubentries. */
2181 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable; 2201 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
2182 2202
2183 /* Insert a single track? */ 2203 if (newtable == PLAYTRACK) /* Insert a single track? */
2184 if (newtable == PLAYTRACK)
2185 { 2204 {
2186 if (tagtree_get_filename(tc, buf, sizeof buf) < 0) 2205 if (tagtree_get_filename(tc, buf, sizeof buf) < 0)
2187 {
2188 logf("tagtree_get_filename failed");
2189 return false; 2206 return false;
2190 } 2207
2191 playlist_insert_track(NULL, buf, position, queue, true); 2208 playlist_insert_track(NULL, buf, position, queue, true);
2192 2209
2193 return true; 2210 return true;
2194 } 2211 }
2195 2212
2196 if (newtable == NAVIBROWSE) 2213 ret = goto_allsubentries(newtable);
2197 { 2214 if (ret)
2198 tagtree_enter(tc, false);
2199 tagtree_load(tc);
2200 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
2201 }
2202 else if (newtable != ALLSUBENTRIES)
2203 { 2215 {
2204 logf("unsupported table: %d", newtable); 2216 if (tc->filesindir <= 0)
2205 return false; 2217 splash(HZ, ID2P(LANG_END_PLAYLIST));
2218 else if (!insert_all_playlist(tc, playlist, new_playlist, position, queue))
2219 splash(HZ*2, ID2P(LANG_FAILED));
2206 } 2220 }
2207 2221
2208 /* Now the current table should be allsubentries. */ 2222 reset_tc_to_prev(dirlevel, selected_item);
2209 if (newtable != PLAYTRACK) 2223 return ret;
2210 { 2224}
2211 tagtree_enter(tc, false); 2225
2212 tagtree_load(tc); 2226/* Execute action_cb for all subentries of the current table's
2213 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable; 2227 * selected item, handing over each entry's filename in the
2228 * callback function parameter.
2229 */
2230bool tagtree_subentries_do_action(bool (*action_cb)(const char *file_name))
2231{
2232 struct tagcache_search tcs;
2233 int i, n;
2234 unsigned long last_tick;
2235 char buf[MAX_PATH];
2236 int ret = true;
2237 int dirlevel = tc->dirlevel;
2238 int selected_item = tc->selected_item;
2239 int newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
2214 2240
2215 /* And now the newtable should be playtrack. */ 2241 cpu_boost(true);
2216 if (newtable != PLAYTRACK) 2242 if (!goto_allsubentries(newtable))
2243 ret = false;
2244 else if (tagcache_search(&tcs, tag_filename))
2245 {
2246 last_tick = current_tick + HZ/2;
2247 splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */
2248 n = tc->filesindir;
2249 for (i = 0; i < n; i++)
2217 { 2250 {
2218 logf("newtable: %d !!", newtable); 2251 splash_progress(i, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT));
2219 while (tc->dirlevel > dirlevel) 2252 if (TIME_AFTER(current_tick, last_tick + HZ/4))
2220 tagtree_exit(tc, false); 2253 {
2221 tagtree_load(tc); 2254 if (action_userabort(TIMEOUT_NOBLOCK))
2222 return false; 2255 break;
2256 last_tick = current_tick;
2257 }
2258
2259 if (!tagcache_retrieve(&tcs, tagtree_get_entry(tc, i)->extraseek,
2260 tcs.type, buf, sizeof buf)
2261 || !action_cb(buf))
2262 {
2263 ret = false;
2264 break;
2265 }
2266 yield();
2223 } 2267 }
2224 }
2225 2268
2226 if (tc->filesindir <= 0) 2269 tagcache_search_finish(&tcs);
2227 splash(HZ, ID2P(LANG_END_PLAYLIST)); 2270 }
2228 else 2271 else
2229 { 2272 {
2230 logf("insert_all_playlist"); 2273 splash(HZ, ID2P(LANG_TAGCACHE_BUSY));
2231 if (!insert_all_playlist(tc, playlist, new_playlist, position, queue)) 2274 ret = false;
2232 splash(HZ*2, ID2P(LANG_FAILED));
2233 } 2275 }
2276 reset_tc_to_prev(dirlevel, selected_item);
2277 cpu_boost(false);
2278 return ret;
2279}
2234 2280
2235 /* Finally return the dirlevel to its original value. */ 2281/* Try to return first subentry's filename for current selection
2236 while (tc->dirlevel > dirlevel) 2282 */
2237 tagtree_exit(tc, false); 2283bool tagtree_get_subentry_filename(char *buf, size_t bufsize)
2238 tc->selected_item = selected_item; 2284{
2239 tagtree_load(tc); 2285 int ret = true;
2286 int dirlevel = tc->dirlevel;
2287 int selected_item = tc->selected_item;
2288 int newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
2240 2289
2241 return true; 2290 if (!goto_allsubentries(newtable) || tagtree_get_filename(tc, buf, bufsize) < 0)
2242} 2291 ret = false;
2243 2292
2293 reset_tc_to_prev(dirlevel, selected_item);
2294 return ret;
2295}
2244 2296
2245bool tagtree_current_playlist_insert(int position, bool queue) 2297bool tagtree_current_playlist_insert(int position, bool queue)
2246{ 2298{
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);
45int tagtree_get_attr(struct tree_context* c); 45int tagtree_get_attr(struct tree_context* c);
46int tagtree_get_icon(struct tree_context* c); 46int tagtree_get_icon(struct tree_context* c);
47int tagtree_get_filename(struct tree_context* c, char *buf, int buflen); 47int tagtree_get_filename(struct tree_context* c, char *buf, int buflen);
48bool tagtree_get_subentry_filename(char *buf, size_t bufsize);
49bool tagtree_subentries_do_action(bool (*action_cb)(const char *file_name));
48 50
49#endif 51#endif
50#endif 52#endif