diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/properties.c | 283 |
1 files changed, 109 insertions, 174 deletions
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c index 4647216390..d3fac59bde 100644 --- a/apps/plugins/properties.c +++ b/apps/plugins/properties.c | |||
@@ -33,25 +33,17 @@ enum props_types { | |||
33 | PROPS_DIR | 33 | PROPS_DIR |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static int props_type; | ||
37 | |||
38 | static struct gui_synclist properties_lists; | 36 | static struct gui_synclist properties_lists; |
39 | static struct mp3entry id3; | 37 | static struct mp3entry id3; |
40 | static int mul_id3_count; | 38 | static struct tm tm; |
41 | static int skipped_count; | ||
42 | |||
43 | static char str_filename[MAX_PATH]; | ||
44 | static char str_dirname[MAX_PATH]; | ||
45 | static char str_size[64]; | ||
46 | static char str_dircount[64]; | ||
47 | static char str_filecount[64]; | ||
48 | static char str_audio_filecount[64]; | ||
49 | static char str_date[64]; | ||
50 | static char str_time[64]; | ||
51 | |||
52 | static unsigned long display_size; | 39 | static unsigned long display_size; |
53 | static int32_t lang_size_unit; | 40 | static int32_t lang_size_unit; |
54 | static struct tm tm; | 41 | static int props_type, mul_id3_count, skipped_count; |
42 | |||
43 | static char str_filename[MAX_PATH], str_dirname[MAX_PATH], | ||
44 | str_size[64], str_dircount[64], str_filecount[64], | ||
45 | str_audio_filecount[64], str_date[64], str_time[64]; | ||
46 | |||
55 | 47 | ||
56 | #define NUM_FILE_PROPERTIES 5 | 48 | #define NUM_FILE_PROPERTIES 5 |
57 | #define NUM_PLAYLIST_PROPERTIES (1 + NUM_FILE_PROPERTIES) | 49 | #define NUM_PLAYLIST_PROPERTIES (1 + NUM_FILE_PROPERTIES) |
@@ -78,71 +70,28 @@ static const unsigned char* const props_dir[] = | |||
78 | ID2P(LANG_MENU_SHOW_ID3_INFO), str_audio_filecount, | 70 | ID2P(LANG_MENU_SHOW_ID3_INFO), str_audio_filecount, |
79 | }; | 71 | }; |
80 | 72 | ||
81 | static bool file_properties(const char* selected_file) | 73 | static bool dir_properties(const char* selected_file, struct dir_stats *stats) |
82 | { | ||
83 | bool found = false; | ||
84 | struct dirent* entry; | ||
85 | DIR* dir = rb->opendir(str_dirname); | ||
86 | if (dir) | ||
87 | { | ||
88 | while(0 != (entry = rb->readdir(dir))) | ||
89 | { | ||
90 | struct dirinfo info = rb->dir_get_info(dir, entry); | ||
91 | if(!rb->strcmp(entry->d_name, str_filename)) | ||
92 | { | ||
93 | display_size = human_size(info.size, &lang_size_unit); | ||
94 | rb->snprintf(str_size, sizeof str_size, "%lu %s", | ||
95 | display_size, rb->str(lang_size_unit)); | ||
96 | rb->gmtime_r(&info.mtime, &tm); | ||
97 | rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", | ||
98 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
99 | rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", | ||
100 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
101 | |||
102 | if (props_type != PROPS_PLAYLIST && rb->get_metadata(&id3, -1, selected_file)) | ||
103 | props_type = PROPS_ID3; | ||
104 | found = true; | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | rb->closedir(dir); | ||
109 | } | ||
110 | return found; | ||
111 | } | ||
112 | |||
113 | |||
114 | static bool dir_properties(const char* selected_file, struct dir_stats *stats, | ||
115 | bool (*id3_cb)(const char*)) | ||
116 | { | 74 | { |
117 | bool success; | ||
118 | |||
119 | rb->strlcpy(stats->dirname, selected_file, sizeof(stats->dirname)); | 75 | rb->strlcpy(stats->dirname, selected_file, sizeof(stats->dirname)); |
120 | if (id3_cb) | ||
121 | rb->splash_progress_set_delay(HZ / 2); /* hide progress bar for 0.5s */ | ||
122 | 76 | ||
123 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 77 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
124 | rb->cpu_boost(true); | 78 | rb->cpu_boost(true); |
125 | #endif | 79 | #endif |
126 | success = collect_dir_stats(stats, id3_cb); | 80 | bool success = collect_dir_stats(stats, NULL); |
127 | |||
128 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 81 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
129 | rb->cpu_boost(false); | 82 | rb->cpu_boost(false); |
130 | #endif | 83 | #endif |
131 | |||
132 | if (!success) | 84 | if (!success) |
133 | return false; | 85 | return false; |
134 | 86 | ||
135 | if (!id3_cb) | 87 | rb->strlcpy(str_dirname, selected_file, sizeof(str_dirname)); |
136 | { | 88 | rb->snprintf(str_dircount, sizeof str_dircount, "%d", stats->dir_count); |
137 | rb->strlcpy(str_dirname, selected_file, sizeof(str_dirname)); | 89 | rb->snprintf(str_filecount, sizeof str_filecount, "%d", stats->file_count); |
138 | rb->snprintf(str_dircount, sizeof str_dircount, "%d", stats->dir_count); | 90 | rb->snprintf(str_audio_filecount, sizeof str_filecount, "%d", |
139 | rb->snprintf(str_filecount, sizeof str_filecount, "%d", stats->file_count); | 91 | stats->audio_file_count); |
140 | rb->snprintf(str_audio_filecount, sizeof str_filecount, "%d", | 92 | display_size = human_size(stats->byte_count, &lang_size_unit); |
141 | stats->audio_file_count); | 93 | rb->snprintf(str_size, sizeof str_size, "%lu %s", display_size, |
142 | display_size = human_size(stats->byte_count, &lang_size_unit); | 94 | rb->str(lang_size_unit)); |
143 | rb->snprintf(str_size, sizeof str_size, "%lu %s", display_size, | ||
144 | rb->str(lang_size_unit)); | ||
145 | } | ||
146 | return true; | 95 | return true; |
147 | } | 96 | } |
148 | 97 | ||
@@ -157,12 +106,11 @@ static const char * get_props(int selected_item, void* data, | |||
157 | { | 106 | { |
158 | (void)data; | 107 | (void)data; |
159 | if (PROPS_DIR == props_type) | 108 | if (PROPS_DIR == props_type) |
160 | rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_dir)) ? "ERROR" : | 109 | rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_dir)) ? |
161 | (char *) p2str(props_dir[selected_item]), buffer_len); | 110 | "ERROR" : (char *) p2str(props_dir[selected_item]), buffer_len); |
162 | else | 111 | else |
163 | rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_file)) ? "ERROR" : | 112 | rb->strlcpy(buffer, selected_item >= (int)(ARRAY_SIZE(props_file)) ? |
164 | (char *) p2str(props_file[selected_item]), buffer_len); | 113 | "ERROR" : (char *) p2str(props_file[selected_item]), buffer_len); |
165 | |||
166 | return buffer; | 114 | return buffer; |
167 | } | 115 | } |
168 | 116 | ||
@@ -226,15 +174,13 @@ static void setup_properties_list(struct dir_stats *stats) | |||
226 | 174 | ||
227 | static int browse_file_or_dir(struct dir_stats *stats) | 175 | static int browse_file_or_dir(struct dir_stats *stats) |
228 | { | 176 | { |
229 | int button; | ||
230 | |||
231 | if (props_type == PROPS_DIR && stats->audio_file_count) | 177 | if (props_type == PROPS_DIR && stats->audio_file_count) |
232 | rb->gui_synclist_set_nb_items(&properties_lists, NUM_AUDIODIR_PROPERTIES*2); | 178 | rb->gui_synclist_set_nb_items(&properties_lists, NUM_AUDIODIR_PROPERTIES*2); |
233 | rb->gui_synclist_draw(&properties_lists); | 179 | rb->gui_synclist_draw(&properties_lists); |
234 | rb->gui_synclist_speak_item(&properties_lists); | 180 | rb->gui_synclist_speak_item(&properties_lists); |
235 | while(true) | 181 | while(true) |
236 | { | 182 | { |
237 | button = rb->get_action(CONTEXT_LIST, HZ); | 183 | int button = rb->get_action(CONTEXT_LIST, HZ); |
238 | /* HZ so the status bar redraws corectly */ | 184 | /* HZ so the status bar redraws corectly */ |
239 | if (rb->gui_synclist_do_button(&properties_lists, &button)) | 185 | if (rb->gui_synclist_do_button(&properties_lists, &button)) |
240 | continue; | 186 | continue; |
@@ -257,24 +203,55 @@ static int browse_file_or_dir(struct dir_stats *stats) | |||
257 | } | 203 | } |
258 | } | 204 | } |
259 | 205 | ||
260 | static bool determine_file_or_dir(void) | 206 | static bool determine_props_type(const char *file) |
261 | { | 207 | { |
262 | struct dirent* entry; | 208 | if (file[0] == PATH_SEPCH) |
263 | DIR* dir = rb->opendir(str_dirname); | ||
264 | if (dir) | ||
265 | { | 209 | { |
210 | const char* basename = rb->strrchr(file, PATH_SEPCH) + 1; | ||
211 | const int dir_len = (basename - file); | ||
212 | if ((int) sizeof(str_dirname) <= dir_len) | ||
213 | return false; | ||
214 | rb->strlcpy(str_dirname, file, dir_len + 1); | ||
215 | rb->strlcpy(str_filename, basename, sizeof str_filename); | ||
216 | struct dirent* entry; | ||
217 | DIR* dir = rb->opendir(str_dirname); | ||
218 | if (!dir) | ||
219 | return false; | ||
266 | while(0 != (entry = rb->readdir(dir))) | 220 | while(0 != (entry = rb->readdir(dir))) |
267 | { | 221 | { |
268 | if(!rb->strcmp(entry->d_name, str_filename)) | 222 | if(rb->strcmp(entry->d_name, str_filename)) |
223 | continue; | ||
224 | |||
225 | struct dirinfo info = rb->dir_get_info(dir, entry); | ||
226 | if (info.attribute & ATTR_DIRECTORY) | ||
227 | props_type = PROPS_DIR; | ||
228 | else | ||
269 | { | 229 | { |
270 | struct dirinfo info = rb->dir_get_info(dir, entry); | 230 | display_size = human_size(info.size, &lang_size_unit); |
271 | props_type = info.attribute & ATTR_DIRECTORY ? PROPS_DIR : PROPS_FILE; | 231 | rb->snprintf(str_size, sizeof str_size, "%lu %s", |
272 | rb->closedir(dir); | 232 | display_size, rb->str(lang_size_unit)); |
273 | return true; | 233 | rb->gmtime_r(&info.mtime, &tm); |
234 | rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", | ||
235 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
236 | rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", | ||
237 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
238 | |||
239 | if (rb->filetype_get_attr(entry->d_name) == FILE_ATTR_M3U) | ||
240 | props_type = PROPS_PLAYLIST; | ||
241 | else | ||
242 | props_type = rb->get_metadata(&id3, -1, file) ? | ||
243 | PROPS_ID3 : PROPS_FILE; | ||
274 | } | 244 | } |
245 | rb->closedir(dir); | ||
246 | return true; | ||
275 | } | 247 | } |
276 | rb->closedir(dir); | 248 | rb->closedir(dir); |
277 | } | 249 | } |
250 | else if (!rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))) | ||
251 | { | ||
252 | props_type = PROPS_MUL_ID3; | ||
253 | return true; | ||
254 | } | ||
278 | return false; | 255 | return false; |
279 | } | 256 | } |
280 | 257 | ||
@@ -287,40 +264,34 @@ bool mul_id3_add(const char *file_name) | |||
287 | collect_id3(&id3, mul_id3_count == 0); | 264 | collect_id3(&id3, mul_id3_count == 0); |
288 | mul_id3_count++; | 265 | mul_id3_count++; |
289 | } | 266 | } |
290 | |||
291 | return true; | 267 | return true; |
292 | } | 268 | } |
293 | 269 | ||
294 | static bool has_pl_extension(const char* filename) | 270 | /* Assemble track info from a dir, a playlist, or a database table */ |
295 | { | ||
296 | char *dot = rb->strrchr(filename, '.'); | ||
297 | return (dot && (!rb->strcasecmp(dot, ".m3u") || !rb->strcasecmp(dot, ".m3u8"))); | ||
298 | } | ||
299 | |||
300 | /* Assemble track info from a database table, the contents of a playlist file, or a dir */ | ||
301 | static bool assemble_track_info(const char *filename, struct dir_stats *stats) | 271 | static bool assemble_track_info(const char *filename, struct dir_stats *stats) |
302 | { | 272 | { |
303 | if (!filename) | 273 | if (props_type == PROPS_DIR) |
304 | props_type = PROPS_MUL_ID3; | 274 | { |
305 | mul_id3_count = skipped_count = 0; | 275 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
306 | 276 | rb->cpu_boost(true); | |
277 | #endif | ||
278 | rb->strlcpy(stats->dirname, filename, sizeof(stats->dirname)); | ||
279 | rb->splash_progress_set_delay(HZ/2); /* hide progress bar for 0.5s */ | ||
280 | bool success = collect_dir_stats(stats, &mul_id3_add); | ||
281 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
282 | rb->cpu_boost(false); | ||
283 | #endif | ||
284 | if (!success) | ||
285 | return false; | ||
286 | } | ||
287 | else if(props_type == PROPS_PLAYLIST && | ||
288 | !rb->playlist_entries_iterate(filename, NULL, &mul_id3_add)) | ||
289 | return false; | ||
307 | #ifdef HAVE_TAGCACHE | 290 | #ifdef HAVE_TAGCACHE |
308 | if (props_type == PROPS_MUL_ID3 && !rb->tagtree_subentries_do_action(&mul_id3_add)) | 291 | else if (props_type == PROPS_MUL_ID3 && |
292 | !rb->tagtree_subentries_do_action(&mul_id3_add)) | ||
309 | return false; | 293 | return false; |
310 | else | ||
311 | #endif | 294 | #endif |
312 | { | ||
313 | if (props_type == PROPS_DIR) | ||
314 | { | ||
315 | if (!dir_properties(filename, stats, &mul_id3_add)) | ||
316 | return false; | ||
317 | } | ||
318 | else if(props_type == PROPS_PLAYLIST) | ||
319 | { | ||
320 | if (!rb->playlist_entries_iterate(filename, NULL, &mul_id3_add)) | ||
321 | return false; | ||
322 | } | ||
323 | } | ||
324 | 295 | ||
325 | if (mul_id3_count == 0) | 296 | if (mul_id3_count == 0) |
326 | { | 297 | { |
@@ -338,84 +309,48 @@ static bool assemble_track_info(const char *filename, struct dir_stats *stats) | |||
338 | 309 | ||
339 | enum plugin_status plugin_start(const void* parameter) | 310 | enum plugin_status plugin_start(const void* parameter) |
340 | { | 311 | { |
341 | int ret = 0; | ||
342 | static struct dir_stats stats; | 312 | static struct dir_stats stats; |
343 | const char *file = parameter; | 313 | const char *file = parameter; |
344 | if(!parameter) | ||
345 | return PLUGIN_ERROR; | ||
346 | |||
347 | FOR_NB_SCREENS(i) | ||
348 | rb->viewportmanager_theme_enable(i, true, NULL); | ||
349 | #ifdef HAVE_TOUCHSCREEN | 314 | #ifdef HAVE_TOUCHSCREEN |
350 | rb->touchscreen_set_mode(rb->global_settings->touch_mode); | 315 | rb->touchscreen_set_mode(rb->global_settings->touch_mode); |
351 | #endif | 316 | #endif |
352 | if (file[0] == '/') /* single file or folder selected */ | 317 | int ret = file && determine_props_type(file); |
318 | if (!ret) | ||
353 | { | 319 | { |
354 | const char* file_name = rb->strrchr(file, '/') + 1; | 320 | rb->splashf(0, "Could not find: %s", file ?: "(NULL)"); |
355 | const int dirlen = (file_name - file); | 321 | rb->action_userabort(TIMEOUT_BLOCK); |
356 | rb->strlcpy(str_dirname, file, dirlen + 1); | 322 | return PLUGIN_OK; |
357 | rb->snprintf(str_filename, sizeof str_filename, "%s", file + dirlen); | 323 | } |
324 | FOR_NB_SCREENS(i) | ||
325 | rb->viewportmanager_theme_enable(i, true, NULL); | ||
358 | 326 | ||
359 | if(!determine_file_or_dir()) | 327 | if (props_type == PROPS_MUL_ID3) |
328 | ret = assemble_track_info(NULL, NULL); | ||
329 | else if (props_type != PROPS_ID3) | ||
330 | { | ||
331 | setup_properties_list(&stats); /* Show title during dir scan */ | ||
332 | if (props_type == PROPS_DIR) | ||
333 | ret = dir_properties(file, &stats); | ||
334 | } | ||
335 | if (!ret) | ||
336 | { | ||
337 | if (!stats.canceled) | ||
360 | { | 338 | { |
361 | rb->splashf(0, "File/Dir not found: %s", file); | 339 | rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); /* TODO: describe error */ |
362 | rb->action_userabort(TIMEOUT_BLOCK); | 340 | rb->action_userabort(TIMEOUT_BLOCK); |
363 | goto exit; | ||
364 | } | ||
365 | |||
366 | if (props_type == PROPS_FILE) | ||
367 | { | ||
368 | if (has_pl_extension(file)) | ||
369 | props_type = PROPS_PLAYLIST; | ||
370 | |||
371 | ret = !file_properties(file); | ||
372 | } | ||
373 | |||
374 | if (props_type != PROPS_ID3) /* i.e. not handled by browse_id3 */ | ||
375 | { | ||
376 | setup_properties_list(&stats); /* Show title during dir scan */ | ||
377 | if (props_type == PROPS_DIR) | ||
378 | ret = !dir_properties(file, &stats, NULL); | ||
379 | } | ||
380 | if (ret) | ||
381 | { | ||
382 | ret = 0; | ||
383 | if (!stats.canceled) | ||
384 | { | ||
385 | /* TODO: describe error */ | ||
386 | rb->splash(0, ID2P(LANG_PROPERTIES_FAIL)); | ||
387 | rb->action_userabort(TIMEOUT_BLOCK); | ||
388 | } | ||
389 | goto exit; | ||
390 | } | 341 | } |
391 | } | 342 | } |
392 | /* database table selected */ | 343 | else if (props_type == PROPS_ID3) |
393 | else if (rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER)) | ||
394 | || !assemble_track_info(NULL, NULL)) | ||
395 | { | ||
396 | ret = -1; | ||
397 | goto exit; | ||
398 | } | ||
399 | |||
400 | if (props_type == PROPS_ID3) | ||
401 | ret = rb->browse_id3(&id3, 0, 0, &tm, 1); /* Track Info for single file */ | 344 | ret = rb->browse_id3(&id3, 0, 0, &tm, 1); /* Track Info for single file */ |
402 | else if (props_type == PROPS_MUL_ID3) | 345 | else if (props_type == PROPS_MUL_ID3) |
403 | ret = rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count); /* database tracks */ | 346 | ret = rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count); /* database tracks */ |
404 | else if ((ret = browse_file_or_dir(&stats)) < 0) | 347 | else if ((ret = browse_file_or_dir(&stats)) < 0) |
405 | ret = assemble_track_info(file, &stats) ? /* playlist or folder tracks */ | 348 | ret = assemble_track_info(file, &stats) ? /* playlist or folder tracks */ |
406 | rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count) : | 349 | rb->browse_id3(&id3, 0, 0, NULL, mul_id3_count) : |
407 | (stats.canceled ? 0 : -1); | 350 | (stats.canceled ? 0 : -1); |
408 | exit: | 351 | |
409 | FOR_NB_SCREENS(i) | 352 | FOR_NB_SCREENS(i) |
410 | rb->viewportmanager_theme_undo(i, false); | 353 | rb->viewportmanager_theme_undo(i, false); |
411 | 354 | ||
412 | switch (ret) | 355 | return ret == -1 ? PLUGIN_ERROR : ret == 1 ? PLUGIN_USB_CONNECTED : PLUGIN_OK; |
413 | { | ||
414 | case 1: | ||
415 | return PLUGIN_USB_CONNECTED; | ||
416 | case -1: | ||
417 | return PLUGIN_ERROR; | ||
418 | default: | ||
419 | return PLUGIN_OK; | ||
420 | } | ||
421 | } | 356 | } |