summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorChristian Soffke <christian.soffke@gmail.com>2024-07-25 20:49:20 +0200
committerChristian Soffke <christian.soffke@gmail.com>2024-07-28 20:18:41 +0200
commit545271c4de82c3b5da05ca91629d0de150c90d21 (patch)
tree51b579da8c05bdabeb64c426f883e1dca2f89782 /apps
parent6d19214eeb13835f3343675417651e2eb03e270f (diff)
downloadrockbox-545271c4de82c3b5da05ca91629d0de150c90d21.tar.gz
rockbox-545271c4de82c3b5da05ca91629d0de150c90d21.zip
plugins: extract redundant functionality from stats/properties
Also: - Enables cpu boosting for Stats (*much* faster on some players) - Displays file size in Stats Change-Id: I888ba054e1f8c2985fbf8dca36e11e6ef130e7ca
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/lib/mul_id3.c188
-rw-r--r--apps/plugins/lib/mul_id3.h32
-rw-r--r--apps/plugins/properties.c155
-rw-r--r--apps/plugins/stats.c207
4 files changed, 251 insertions, 331 deletions
diff --git a/apps/plugins/lib/mul_id3.c b/apps/plugins/lib/mul_id3.c
index edf44f7282..c4b511c626 100644
--- a/apps/plugins/lib/mul_id3.c
+++ b/apps/plugins/lib/mul_id3.c
@@ -40,6 +40,13 @@ struct multiple_tracks_id3 {
40 40
41static struct multiple_tracks_id3 mul_id3; 41static struct multiple_tracks_id3 mul_id3;
42 42
43static const int32_t units[] =
44{
45 LANG_BYTE,
46 LANG_KIBIBYTE,
47 LANG_MEBIBYTE,
48 LANG_GIBIBYTE
49};
43 50
44/* Calculate modified FNV hash of string 51/* Calculate modified FNV hash of string
45 * has good avalanche behaviour and uniform distribution 52 * has good avalanche behaviour and uniform distribution
@@ -130,9 +137,7 @@ void collect_id3(struct mp3entry *id3, bool is_first_track)
130 mul_id3.filesize += id3->filesize; 137 mul_id3.filesize += id3->filesize;
131} 138}
132 139
133/* (!) Note scale factor applied to returned metadata: 140/* (!) Note unit conversion below
134 * - Unit for filesize will be KiB instead of Bytes
135 * - Unit for length will be s instead of ms
136 * 141 *
137 * Use result only as input for browse_id3, 142 * Use result only as input for browse_id3,
138 * with the track_ct parameter set to > 1. 143 * with the track_ct parameter set to > 1.
@@ -159,8 +164,8 @@ void finalize_id3(struct mp3entry *id3)
159 id3->track_string = NULL; 164 id3->track_string = NULL;
160 id3->year_string = NULL; 165 id3->year_string = NULL;
161 id3->year = mul_id3.year; 166 id3->year = mul_id3.year;
162 mul_id3.length /= 1000; 167 mul_id3.length /= 1000; /* convert from ms to s */
163 mul_id3.filesize >>= 10; 168 mul_id3.filesize >>= 10; /* convert from B to KiB */
164 id3->length = mul_id3.length > ULONG_MAX ? 0 : mul_id3.length; 169 id3->length = mul_id3.length > ULONG_MAX ? 0 : mul_id3.length;
165 id3->filesize = mul_id3.filesize > INT_MAX ? 0 : mul_id3.filesize; 170 id3->filesize = mul_id3.filesize > INT_MAX ? 0 : mul_id3.filesize;
166 id3->frequency = mul_id3.frequency; 171 id3->frequency = mul_id3.frequency;
@@ -172,3 +177,176 @@ void finalize_id3(struct mp3entry *id3)
172 id3->track_level = 0; 177 id3->track_level = 0;
173 id3->album_level = 0; 178 id3->album_level = 0;
174} 179}
180
181unsigned long human_size(unsigned long long byte_count, int32_t *unit_lang_id)
182{
183 const size_t n = sizeof(units)/sizeof(units[0]);
184 unsigned int i;
185
186 /* margin set at 10K boundary: 10239 B +1 => 10 KB */
187 for(i = 0; i < n-1 && byte_count >= 10*1024; i++)
188 byte_count >>= 10; /* div by 1024 */
189
190 *unit_lang_id = units[i];
191 return (unsigned long)byte_count;
192}
193
194/* missing filetype attribute for images */
195static const char *image_exts[] = {"bmp","jpg","jpe","jpeg","png","ppm"};
196/* and videos */
197static const char *video_exts[] = {"mpg","mpeg","mpv","m2v"};
198
199static void prn(const char *str, int y)
200{
201 rb->lcd_puts(0, y, str);
202#ifdef HAVE_REMOTE_LCD
203 rb->lcd_remote_puts(0, y, str);
204#endif
205}
206
207void display_dir_stats(struct dir_stats *stats)
208{
209 char buf[32];
210 int32_t lang_size_unit;
211 unsigned long display_size = human_size(stats->byte_count, &lang_size_unit);
212 rb->lcd_clear_display();
213#ifdef HAVE_REMOTE_LCD
214 rb->lcd_remote_clear_display();
215#endif
216 rb->snprintf(buf, sizeof(buf), "Files: %d (%lu %s)", stats->file_count,
217 display_size, rb->str(lang_size_unit));
218 prn(buf, 0);
219 rb->snprintf(buf, sizeof(buf), "Audio: %d", stats->audio_file_count);
220 prn(buf, 1);
221 if (stats->count_all)
222 {
223 rb->snprintf(buf, sizeof(buf), "Playlists: %d", stats->m3u_file_count);
224 prn(buf, 2);
225 rb->snprintf(buf, sizeof(buf), "Images: %d", stats->img_file_count);
226 prn(buf, 3);
227 rb->snprintf(buf, sizeof(buf), "Videos: %d", stats->vid_file_count);
228 prn(buf, 4);
229 rb->snprintf(buf, sizeof(buf), "Directories: %d", stats->dir_count);
230 prn(buf, 5);
231 rb->snprintf(buf, sizeof(buf), "Max files in Dir: %d",
232 stats->max_files_in_dir);
233 prn(buf, 6);
234 }
235 else
236 {
237 rb->snprintf(buf, sizeof(buf), "Directories: %d", stats->dir_count);
238 prn(buf, 2);
239 }
240 rb->lcd_update();
241#ifdef HAVE_REMOTE_LCD
242 rb->lcd_remote_update();
243#endif
244
245}
246
247/* Recursively scans directories in search of files
248 * and informs the user of the progress.
249 */
250bool collect_dir_stats(struct dir_stats *stats, bool (*id3_cb)(const char*))
251{
252 bool result = true;
253 unsigned int files_in_dir = 0;
254 static unsigned int id3_count;
255 static unsigned long last_displayed, last_get_action;
256 struct dirent* entry;
257 int dirlen = rb->strlen(stats->dirname);
258 DIR* dir = rb->opendir(stats->dirname);
259 if (!dir)
260 {
261 rb->splashf(HZ*2, "open error: %s", stats->dirname);
262 return false;
263 }
264 else if (!stats->dirname[1]) /* root dir */
265 stats->dirname[0] = dirlen = 0;
266
267 /* walk through the directory content */
268 while(result && (0 != (entry = rb->readdir(dir))))
269 {
270 struct dirinfo info = rb->dir_get_info(dir, entry);
271 if (info.attribute & ATTR_DIRECTORY)
272 {
273 if (!rb->strcmp((char *)entry->d_name, ".") ||
274 !rb->strcmp((char *)entry->d_name, ".."))
275 continue; /* skip these */
276
277 rb->snprintf(stats->dirname + dirlen, sizeof(stats->dirname) - dirlen,
278 "/%s", entry->d_name); /* append name to current directory */
279 if (!id3_cb)
280 {
281 stats->dir_count++; /* new directory */
282 if (*rb->current_tick - last_displayed > (HZ/2))
283 {
284 if (last_displayed)
285 display_dir_stats(stats);
286 last_displayed = *(rb->current_tick);
287 }
288 }
289 result = collect_dir_stats(stats, id3_cb); /* recursion */
290 }
291 else if (!id3_cb)
292 {
293 char *ptr;
294 stats->file_count++; /* new file */
295 files_in_dir++;
296 stats->byte_count += info.size;
297
298 int attr = rb->filetype_get_attr(entry->d_name);
299 if (attr == FILE_ATTR_AUDIO)
300 stats->audio_file_count++;
301 else if (attr == FILE_ATTR_M3U)
302 stats->m3u_file_count++;
303 /* image or video file attributes have to be compared manually */
304 else if (stats->count_all &&
305 (ptr = rb->strrchr(entry->d_name,'.')))
306 {
307 unsigned int i;
308 ptr++;
309 for(i = 0; i < ARRAYLEN(image_exts); i++)
310 {
311 if(!rb->strcasecmp(ptr, image_exts[i]))
312 {
313 stats->img_file_count++;
314 break;
315 }
316 }
317 if (i >= ARRAYLEN(image_exts)) {
318 for(i = 0; i < ARRAYLEN(video_exts); i++) {
319 if(!rb->strcasecmp(ptr, video_exts[i])) {
320 stats->vid_file_count++;
321 break;
322 }
323 }
324 }
325 }
326 }
327 else if (rb->filetype_get_attr(entry->d_name) == FILE_ATTR_AUDIO)
328 {
329 rb->splash_progress(id3_count++, stats->audio_file_count,
330 "%s (%s)",
331 rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT));
332 rb->snprintf(stats->dirname + dirlen, sizeof(stats->dirname) - dirlen,
333 "/%s", entry->d_name); /* append name to current directory */
334 id3_cb(stats->dirname); /* allow metadata to be collected */
335 }
336
337 if (TIME_AFTER(*(rb->current_tick), last_get_action + HZ/8))
338 {
339 if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
340 {
341 stats->canceled = true;
342 result = false;
343 }
344 last_get_action = *(rb->current_tick);
345 }
346 rb->yield();
347 }
348 rb->closedir(dir);
349 if (stats->max_files_in_dir < files_in_dir)
350 stats->max_files_in_dir = files_in_dir;
351 return result;
352}
diff --git a/apps/plugins/lib/mul_id3.h b/apps/plugins/lib/mul_id3.h
index d08095de5c..1bb311c441 100644
--- a/apps/plugins/lib/mul_id3.h
+++ b/apps/plugins/lib/mul_id3.h
@@ -21,7 +21,39 @@
21#ifndef MUL_ID3_H 21#ifndef MUL_ID3_H
22#define MUL_ID3_H 22#define MUL_ID3_H
23 23
24struct dir_stats {
25 char dirname[MAX_PATH];
26 unsigned int dir_count;
27 unsigned int file_count;
28 unsigned int audio_file_count;
29 unsigned int m3u_file_count;
30 unsigned int img_file_count;
31 unsigned int vid_file_count;
32 unsigned int max_files_in_dir;
33 unsigned long long byte_count;
34 bool count_all;
35 bool canceled;
36};
37
38/* create mp3entry that contains matching metadata from multiple tracks */
24void collect_id3(struct mp3entry *id3, bool is_first_track); 39void collect_id3(struct mp3entry *id3, bool is_first_track);
25void finalize_id3(struct mp3entry *id3); 40void finalize_id3(struct mp3entry *id3);
26 41
42/* Traverse directory, collecting stats/track metadata.
43 *
44 * 1) If id3_cb is null, dir_properties calculates all dir stats, including the
45 * audio file count.
46 *
47 * 2) If id3_cb points to a function, dir_properties will call it for every audio
48 * file encountered, to allow the file's metadata to be collected. The displayed
49 * progress bar's maximum value is set to the audio file count.
50 * Stats are assumed to have already been generated by a preceding run.
51 *
52 * If the count_all parameter is set to false, images and videos are not counted,
53 * nor is the playlist, image, video or max file in dir count displayed.
54 */
55bool collect_dir_stats(struct dir_stats *stats, bool (*id3_cb)(const char*));
56void display_dir_stats(struct dir_stats *stats);
57unsigned long human_size(unsigned long long byte_count, int32_t *unit_lang_id);
58
27#endif /* MUL_ID3_H */ 59#endif /* MUL_ID3_H */
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index 1156bd5ca9..c932474f8c 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -25,15 +25,6 @@
25 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) 25 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
26#endif 26#endif
27 27
28struct dir_stats {
29 char dirname[MAX_PATH];
30 unsigned int dir_count;
31 unsigned int file_count;
32 unsigned int audio_file_count;
33 unsigned long long byte_count;
34 bool canceled;
35};
36
37enum props_types { 28enum props_types {
38 PROPS_FILE = 0, 29 PROPS_FILE = 0,
39 PROPS_PLAYLIST, 30 PROPS_PLAYLIST,
@@ -42,7 +33,7 @@ enum props_types {
42 PROPS_DIR 33 PROPS_DIR
43}; 34};
44 35
45static int props_type = PROPS_FILE; 36static int props_type;
46 37
47static struct mp3entry id3; 38static struct mp3entry id3;
48static int mul_id3_count; 39static int mul_id3_count;
@@ -57,8 +48,8 @@ static char str_audio_filecount[64];
57static char str_date[64]; 48static char str_date[64];
58static char str_time[64]; 49static char str_time[64];
59 50
60static unsigned long nsize; 51static unsigned long display_size;
61static int32_t size_unit; 52static int32_t lang_size_unit;
62static struct tm tm; 53static struct tm tm;
63 54
64#define NUM_FILE_PROPERTIES 5 55#define NUM_FILE_PROPERTIES 5
@@ -86,26 +77,6 @@ static const unsigned char* const props_dir[] =
86 ID2P(LANG_MENU_SHOW_ID3_INFO), str_audio_filecount, 77 ID2P(LANG_MENU_SHOW_ID3_INFO), str_audio_filecount,
87}; 78};
88 79
89static const int32_t units[] =
90{
91 LANG_BYTE,
92 LANG_KIBIBYTE,
93 LANG_MEBIBYTE,
94 LANG_GIBIBYTE
95};
96
97static unsigned int human_size_log(unsigned long long size)
98{
99 const size_t n = sizeof(units)/sizeof(units[0]);
100
101 unsigned int i;
102 /* margin set at 10K boundary: 10239 B +1 => 10 KB */
103 for(i=0; i < n-1 && size >= 10*1024; i++)
104 size >>= 10; /* div by 1024 */
105
106 return i;
107}
108
109static bool file_properties(const char* selected_file) 80static bool file_properties(const char* selected_file)
110{ 81{
111 bool found = false; 82 bool found = false;
@@ -118,12 +89,9 @@ static bool file_properties(const char* selected_file)
118 struct dirinfo info = rb->dir_get_info(dir, entry); 89 struct dirinfo info = rb->dir_get_info(dir, entry);
119 if(!rb->strcmp(entry->d_name, str_filename)) 90 if(!rb->strcmp(entry->d_name, str_filename))
120 { 91 {
121 unsigned int log; 92 display_size = human_size(info.size, &lang_size_unit);
122 log = human_size_log((unsigned long)info.size);
123 nsize = ((unsigned long)info.size) >> (log*10);
124 size_unit = units[log];
125 rb->snprintf(str_size, sizeof str_size, "%lu %s", 93 rb->snprintf(str_size, sizeof str_size, "%lu %s",
126 nsize, rb->str(size_unit)); 94 display_size, rb->str(lang_size_unit));
127 rb->gmtime_r(&info.mtime, &tm); 95 rb->gmtime_r(&info.mtime, &tm);
128 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", 96 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d",
129 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 97 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
@@ -141,99 +109,10 @@ static bool file_properties(const char* selected_file)
141 return found; 109 return found;
142} 110}
143 111
144/* Recursively scans directories in search of files
145 * and informs the user of the progress.
146 */
147static bool _dir_properties(struct dir_stats *stats, bool (*id3_cb)(const char*))
148{
149 bool result = true;
150 static unsigned long last_lcd_update, last_get_action;
151 struct dirent* entry;
152 int dirlen = rb->strlen(stats->dirname);
153 DIR* dir = rb->opendir(stats->dirname);
154 if (!dir)
155 {
156 rb->splashf(HZ*2, "open error: %s", stats->dirname);
157 return false;
158 }
159
160 /* walk through the directory content */
161 while(result && (0 != (entry = rb->readdir(dir))))
162 {
163 struct dirinfo info = rb->dir_get_info(dir, entry);
164 if (info.attribute & ATTR_DIRECTORY)
165 {
166 if (!rb->strcmp((char *)entry->d_name, ".") ||
167 !rb->strcmp((char *)entry->d_name, ".."))
168 continue; /* skip these */
169
170 rb->snprintf(stats->dirname + dirlen, sizeof(stats->dirname) - dirlen,
171 "/%s", entry->d_name); /* append name to current directory */
172
173 if (!id3_cb)
174 {
175 stats->dir_count++; /* new directory */
176 if (*rb->current_tick - last_lcd_update > (HZ/2))
177 {
178 unsigned int log;
179 last_lcd_update = *(rb->current_tick);
180 rb->lcd_clear_display();
181 rb->lcd_putsf(0, 0, "Directories: %d", stats->dir_count);
182 rb->lcd_putsf(0, 1, "Files: %d (Audio: %d)",
183 stats->file_count, stats->audio_file_count);
184 log = human_size_log(stats->byte_count);
185 rb->lcd_putsf(0, 2, "Size: %lu %s",
186 (unsigned long)(stats->byte_count >> (10*log)),
187 rb->str(units[log]));
188 rb->lcd_update();
189 }
190 }
191
192 result = _dir_properties(stats, id3_cb); /* recursion */
193 }
194 else if (!id3_cb)
195 {
196 stats->file_count++; /* new file */
197 stats->byte_count += info.size;
198 if (rb->filetype_get_attr(entry->d_name) == FILE_ATTR_AUDIO)
199 stats->audio_file_count++;
200 }
201 else if (rb->filetype_get_attr(entry->d_name) == FILE_ATTR_AUDIO)
202 {
203 rb->splash_progress(mul_id3_count, stats->audio_file_count, "%s (%s)",
204 rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT));
205 rb->snprintf(stats->dirname + dirlen, sizeof(stats->dirname) - dirlen,
206 "/%s", entry->d_name); /* append name to current directory */
207 id3_cb(stats->dirname); /* allow metadata to be collected */
208 }
209 112
210 if (TIME_AFTER(*(rb->current_tick), last_get_action + HZ/8))
211 {
212 if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
213 {
214 stats->canceled = true;
215 result = false;
216 }
217 last_get_action = *(rb->current_tick);
218 }
219 rb->yield();
220 }
221 rb->closedir(dir);
222 return result;
223}
224
225/* 1) If id3_cb is null, dir_properties calculates all dir stats, including the
226 * audio file count.
227 *
228 * 2) If id3_cb points to a function, dir_properties will call it for every audio
229 * file encountered, to allow the file's metadata to be collected. The displayed
230 * progress bar's maximum value is set to the audio file count.
231 * Stats are assumed to have already been generated by a preceding run.
232 */
233static bool dir_properties(const char* selected_file, struct dir_stats *stats, 113static bool dir_properties(const char* selected_file, struct dir_stats *stats,
234 bool (*id3_cb)(const char*)) 114 bool (*id3_cb)(const char*))
235{ 115{
236 unsigned int log;
237 bool success; 116 bool success;
238 117
239 rb->strlcpy(stats->dirname, selected_file, sizeof(stats->dirname)); 118 rb->strlcpy(stats->dirname, selected_file, sizeof(stats->dirname));
@@ -243,8 +122,8 @@ static bool dir_properties(const char* selected_file, struct dir_stats *stats,
243#ifdef HAVE_ADJUSTABLE_CPU_FREQ 122#ifdef HAVE_ADJUSTABLE_CPU_FREQ
244 rb->cpu_boost(true); 123 rb->cpu_boost(true);
245#endif 124#endif
246 success = _dir_properties(stats, id3_cb); 125 success = collect_dir_stats(stats, id3_cb);
247 126
248#ifdef HAVE_ADJUSTABLE_CPU_FREQ 127#ifdef HAVE_ADJUSTABLE_CPU_FREQ
249 rb->cpu_boost(false); 128 rb->cpu_boost(false);
250#endif 129#endif
@@ -259,10 +138,9 @@ static bool dir_properties(const char* selected_file, struct dir_stats *stats,
259 rb->snprintf(str_filecount, sizeof str_filecount, "%d", stats->file_count); 138 rb->snprintf(str_filecount, sizeof str_filecount, "%d", stats->file_count);
260 rb->snprintf(str_audio_filecount, sizeof str_filecount, "%d", 139 rb->snprintf(str_audio_filecount, sizeof str_filecount, "%d",
261 stats->audio_file_count); 140 stats->audio_file_count);
262 log = human_size_log(stats->byte_count); 141 display_size = human_size(stats->byte_count, &lang_size_unit);
263 nsize = (long) (stats->byte_count >> (log*10)); 142 rb->snprintf(str_size, sizeof str_size, "%lu %s", display_size,
264 size_unit = units[log]; 143 rb->str(lang_size_unit));
265 rb->snprintf(str_size, sizeof str_size, "%ld %s", nsize, rb->str(size_unit));
266 } 144 }
267 return true; 145 return true;
268} 146}
@@ -320,8 +198,8 @@ static int speak_property_selection(int selected_item, void *data)
320 rb->talk_file_or_spell(str_dirname, str_filename, NULL, true); 198 rb->talk_file_or_spell(str_dirname, str_filename, NULL, true);
321 break; 199 break;
322 case LANG_PROPERTIES_SIZE: 200 case LANG_PROPERTIES_SIZE:
323 rb->talk_number(nsize, true); 201 rb->talk_number(display_size, true);
324 rb->talk_id(size_unit, true); 202 rb->talk_id(lang_size_unit, true);
325 break; 203 break;
326 case LANG_PROPERTIES_DATE: 204 case LANG_PROPERTIES_DATE:
327 rb->talk_date(&tm, true); 205 rb->talk_date(&tm, true);
@@ -399,10 +277,8 @@ static int browse_file_or_dir(struct dir_stats *stats)
399 277
400static bool determine_file_or_dir(void) 278static bool determine_file_or_dir(void)
401{ 279{
402 DIR* dir;
403 struct dirent* entry; 280 struct dirent* entry;
404 281 DIR* dir = rb->opendir(str_dirname);
405 dir = rb->opendir(str_dirname);
406 if (dir) 282 if (dir)
407 { 283 {
408 while(0 != (entry = rb->readdir(dir))) 284 while(0 != (entry = rb->readdir(dir)))
@@ -482,7 +358,6 @@ enum plugin_status plugin_start(const void* parameter)
482{ 358{
483 int ret; 359 int ret;
484 static struct dir_stats stats; 360 static struct dir_stats stats;
485
486 const char *file = parameter; 361 const char *file = parameter;
487 if(!parameter) 362 if(!parameter)
488 return PLUGIN_ERROR; 363 return PLUGIN_ERROR;
@@ -490,12 +365,10 @@ enum plugin_status plugin_start(const void* parameter)
490#ifdef HAVE_TOUCHSCREEN 365#ifdef HAVE_TOUCHSCREEN
491 rb->touchscreen_set_mode(rb->global_settings->touch_mode); 366 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
492#endif 367#endif
493
494 if (file[0] == '/') /* single file or folder selected */ 368 if (file[0] == '/') /* single file or folder selected */
495 { 369 {
496 const char* file_name = rb->strrchr(file, '/') + 1; 370 const char* file_name = rb->strrchr(file, '/') + 1;
497 int dirlen = (file_name - file); 371 const int dirlen = (file_name - file);
498
499 rb->strlcpy(str_dirname, file, dirlen + 1); 372 rb->strlcpy(str_dirname, file, dirlen + 1);
500 rb->snprintf(str_filename, sizeof str_filename, "%s", file + dirlen); 373 rb->snprintf(str_filename, sizeof str_filename, "%s", file + dirlen);
501 374
diff --git a/apps/plugins/stats.c b/apps/plugins/stats.c
index b48259a0e4..8a511bea42 100644
--- a/apps/plugins/stats.c
+++ b/apps/plugins/stats.c
@@ -19,184 +19,27 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "plugin.h" 21#include "plugin.h"
22#include "lib/pluginlib_actions.h" 22#include "lib/mul_id3.h" /* collect_dir_stats & display_dir_stats */
23 23
24
25static int files, dirs, audiofiles, m3ufiles, imagefiles, videofiles, largestdir;
26static int lasttick;
27static bool cancel;
28
29
30/* we use PLA */
31#define STATS_STOP PLA_EXIT
32
33#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
34 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
35 || (CONFIG_KEYPAD == IPOD_4G_PAD)
36#define STATS_STOP2 PLA_UP
37#else
38#define STATS_STOP2 PLA_CANCEL
39#endif
40
41/* this set the context to use with PLA */
42static const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
43
44/* we don't have yet a filetype attribute for image files */
45static const char *image_exts[] = {"bmp","jpg","jpe","jpeg","png","ppm"};
46
47/* neither for video ones */
48static const char *video_exts[] = {"mpg","mpeg","mpv","m2v"};
49
50static void prn(const char *str, int y)
51{
52 rb->lcd_puts(0,y,str);
53#ifdef HAVE_REMOTE_LCD
54 rb->lcd_remote_puts(0,y,str);
55#endif
56}
57
58static void update_screen(void)
59{
60 char buf[32];
61
62 rb->lcd_clear_display();
63#ifdef HAVE_REMOTE_LCD
64 rb->lcd_remote_clear_display();
65#endif
66
67 rb->snprintf(buf, sizeof(buf), "Total Files: %d", files);
68 prn(buf,0);
69 rb->snprintf(buf, sizeof(buf), "Audio: %d", audiofiles);
70 prn(buf,1);
71 rb->snprintf(buf, sizeof(buf), "Playlists: %d", m3ufiles);
72 prn(buf,2);
73 rb->snprintf(buf, sizeof(buf), "Images: %d", imagefiles);
74 prn(buf,3);
75 rb->snprintf(buf, sizeof(buf), "Videos: %d", videofiles);
76 prn(buf,4);
77 rb->snprintf(buf, sizeof(buf), "Directories: %d", dirs);
78 prn(buf,5);
79 rb->snprintf(buf, sizeof(buf), "Max files in Dir: %d", largestdir);
80 prn(buf,6);
81
82 rb->lcd_update();
83#ifdef HAVE_REMOTE_LCD
84 rb->lcd_remote_update();
85#endif
86}
87
88static void traversedir(char* location, char* name)
89{
90 int button;
91 struct dirent *entry;
92 DIR* dir;
93 char fullpath[MAX_PATH];
94 int files_in_dir = 0;
95
96 rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name);
97 dir = rb->opendir(fullpath);
98 if (dir) {
99 entry = rb->readdir(dir);
100 while (entry) {
101 if (cancel)
102 break;
103 /* Skip .. and . */
104 if (rb->strcmp(entry->d_name, ".") && rb->strcmp(entry->d_name, ".."))
105 {
106 struct dirinfo info = rb->dir_get_info(dir, entry);
107 if (info.attribute & ATTR_DIRECTORY) {
108 traversedir(fullpath, entry->d_name);
109 dirs++;
110 }
111 else {
112 files_in_dir++; files++;
113
114 /* get the filetype from the filename */
115 int attr = rb->filetype_get_attr(entry->d_name);
116 switch (attr & FILE_ATTR_MASK)
117 {
118 case FILE_ATTR_AUDIO:
119 audiofiles++;
120 break;
121
122 case FILE_ATTR_M3U:
123 m3ufiles++;
124 break;
125
126 default:
127 {
128 /* use hardcoded filetype_exts to count
129 * image and video files until we get
130 * new attributes added to filetypes.h */
131 char *ptr = rb->strrchr(entry->d_name,'.');
132 if(ptr) {
133 unsigned i;
134 ptr++;
135 for(i=0;i<ARRAYLEN(image_exts);i++) {
136 if(!rb->strcasecmp(ptr,image_exts[i])) {
137 imagefiles++; break;
138 }
139 }
140
141 if (i >= ARRAYLEN(image_exts)) {
142 /* not found above - try video files */
143 for(i=0;i<ARRAYLEN(video_exts);i++) {
144 if(!rb->strcasecmp(ptr,video_exts[i])) {
145 videofiles++; break;
146 }
147 }
148 }
149 }
150 } /* default: */
151 } /* switch */
152 }
153 }
154
155 if (*rb->current_tick - lasttick > (HZ/2)) {
156 update_screen();
157 lasttick = *rb->current_tick;
158 button = pluginlib_getaction(TIMEOUT_NOBLOCK, plugin_contexts,
159 ARRAYLEN(plugin_contexts));
160 if (button == STATS_STOP || button == STATS_STOP2) {
161 cancel = true;
162 break;
163 }
164 }
165
166 entry = rb->readdir(dir);
167 }
168 rb->closedir(dir);
169 }
170 if (largestdir < files_in_dir)
171 largestdir = files_in_dir;
172}
173
174/* this is the plugin entry point */
175enum plugin_status plugin_start(const void* parameter) 24enum plugin_status plugin_start(const void* parameter)
176{ 25{
177 int button;
178
179 (void)parameter; 26 (void)parameter;
180 27 int button, success;
181 files = 0; 28 static struct dir_stats stats;
182 dirs = 0; 29 stats.dirname[0] = '/';
183 audiofiles = 0; 30 stats.count_all = true;
184 m3ufiles = 0; 31#ifdef HAVE_ADJUSTABLE_CPU_FREQ
185 imagefiles = 0; 32 rb->cpu_boost(true);
186 videofiles = 0; 33#endif
187 largestdir = 0; 34 display_dir_stats(&stats);
188 cancel = false; 35 success = collect_dir_stats(&stats, NULL);
189 36#ifdef HAVE_ADJUSTABLE_CPU_FREQ
190 rb->splash(HZ, "Counting..."); 37 rb->cpu_boost(false);
191 update_screen(); 38#endif
192 lasttick = *rb->current_tick; 39 if (!success)
193
194 traversedir("", "");
195 if (cancel) {
196 rb->splash(HZ, "Aborted");
197 return PLUGIN_OK; 40 return PLUGIN_OK;
198 } 41
199 update_screen(); 42 display_dir_stats(&stats);
200#ifdef HAVE_BACKLIGHT 43#ifdef HAVE_BACKLIGHT
201#ifdef HAVE_REMOTE_LCD 44#ifdef HAVE_REMOTE_LCD
202 rb->remote_backlight_on(); 45 rb->remote_backlight_on();
@@ -204,21 +47,15 @@ enum plugin_status plugin_start(const void* parameter)
204 rb->backlight_on(); 47 rb->backlight_on();
205#endif 48#endif
206 rb->splash(HZ, "Done"); 49 rb->splash(HZ, "Done");
207 update_screen(); 50 display_dir_stats(&stats);
208 while (1) { 51 while (1) {
209 52 switch (button = rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK))
210 button = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 53 {
211 ARRAYLEN(plugin_contexts)); 54 case ACTION_STD_CANCEL:
212 switch (button) {
213 case STATS_STOP:
214 case STATS_STOP2:
215 return PLUGIN_OK; 55 return PLUGIN_OK;
216 break;
217 default: 56 default:
218 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) { 57 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
219 return PLUGIN_USB_CONNECTED; 58 return PLUGIN_USB_CONNECTED;
220 }
221 break;
222 } 59 }
223 } 60 }
224 return PLUGIN_OK; 61 return PLUGIN_OK;