1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Peter D'Hoye
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
25 bool its_a_dir
= false;
27 char str_filename
[MAX_PATH
];
28 char str_dirname
[MAX_PATH
];
30 char str_dircount
[64];
31 char str_filecount
[64];
35 char str_title
[MAX_PATH
];
36 char str_artist
[MAX_PATH
];
37 char str_album
[MAX_PATH
];
38 char str_duration
[32];
42 static const char* props_file
[] =
44 "[Path]", str_dirname
,
45 "[Filename]", str_filename
,
49 "[Artist]", str_artist
,
52 "[Duration]", str_duration
,
54 static const char* props_dir
[] =
56 "[Path]", str_dirname
,
57 "[Subdirs]", str_dircount
,
58 "[Files]", str_filecount
,
62 static const char human_size_prefix
[4] = { '\0', 'K', 'M', 'G' };
63 static unsigned human_size_log(unsigned long long size
)
65 const size_t n
= sizeof(human_size_prefix
)/sizeof(human_size_prefix
[0]);
68 /* margin set at 10K boundary: 10239 B +1 => 10 KB */
69 for(i
=0; i
< n
-1 && size
>= 10*1024; i
++)
70 size
>>= 10; /* div by 1024 */
75 static bool file_properties(char* selected_file
)
83 char* ptr
= rb
->strrchr(selected_file
, '/') + 1;
84 int dirlen
= (ptr
- selected_file
);
85 rb
->strlcpy(tstr
, selected_file
, dirlen
+ 1);
87 dir
= rb
->opendir(tstr
);
90 while(0 != (entry
= rb
->readdir(dir
)))
92 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
93 if(!rb
->strcmp(entry
->d_name
, selected_file
+dirlen
))
96 rb
->snprintf(str_dirname
, sizeof str_dirname
, "%s", tstr
);
97 rb
->snprintf(str_filename
, sizeof str_filename
, "%s",
98 selected_file
+dirlen
);
99 log
= human_size_log((unsigned long)info
.size
);
100 rb
->snprintf(str_size
, sizeof str_size
, "%lu %cB",
101 ((unsigned long)info
.size
) >> (log
*10), human_size_prefix
[log
]);
102 rb
->snprintf(str_date
, sizeof str_date
, "%04d/%02d/%02d",
103 ((info
.wrtdate
>> 9 ) & 0x7F) + 1980, /* year */
104 ((info
.wrtdate
>> 5 ) & 0x0F), /* month */
105 ((info
.wrtdate
) & 0x1F)); /* day */
106 rb
->snprintf(str_time
, sizeof str_time
, "%02d:%02d",
107 ((info
.wrttime
>> 11) & 0x1F), /* hour */
108 ((info
.wrttime
>> 5 ) & 0x3F)); /* minutes */
112 #if (CONFIG_CODEC == SWCODEC)
113 int fd
= rb
->open(selected_file
, O_RDONLY
);
115 rb
->get_metadata(&id3
, fd
, selected_file
))
117 if (!rb
->mp3info(&id3
, selected_file
))
120 long dur
= id3
.length
/ 1000; /* seconds */
121 rb
->snprintf(str_artist
, sizeof str_artist
,
122 "%s", id3
.artist
? id3
.artist
: "");
123 rb
->snprintf(str_title
, sizeof str_title
,
124 "%s", id3
.title
? id3
.title
: "");
125 rb
->snprintf(str_album
, sizeof str_album
,
126 "%s", id3
.album
? id3
.album
: "");
132 rb
->snprintf(str_duration
, sizeof str_duration
,
133 "%d:%02d", (int)(dur
/ 60),
136 rb
->snprintf(str_duration
, sizeof str_duration
,
139 (int)(dur
% 3600 / 60),
144 #if (CONFIG_CODEC == SWCODEC)
157 char dirname
[MAX_PATH
];
161 unsigned long long bc
;
164 static bool _dir_properties(DPS
* dps
)
166 /* recursively scan directories in search of files
167 and informs the user of the progress */
169 static long lasttick
=0;
172 struct dirent
* entry
;
175 dirlen
= rb
->strlen(dps
->dirname
);
176 dir
= rb
->opendir(dps
->dirname
);
178 return false; /* open error */
180 /* walk through the directory content */
181 while(result
&& (0 != (entry
= rb
->readdir(dir
))))
183 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
184 /* append name to current directory */
185 rb
->snprintf(dps
->dirname
+dirlen
, dps
->len
-dirlen
, "/%s",
188 if (info
.attribute
& ATTR_DIRECTORY
)
192 if (!rb
->strcmp((char *)entry
->d_name
, ".") ||
193 !rb
->strcmp((char *)entry
->d_name
, ".."))
194 continue; /* skip these */
196 dps
->dc
++; /* new directory */
197 if (*rb
->current_tick
- lasttick
> (HZ
/8))
199 lasttick
= *rb
->current_tick
;
200 rb
->lcd_clear_display();
201 rb
->lcd_puts(0,0,"SCANNING...");
202 rb
->lcd_puts(0,1,dps
->dirname
);
203 rb
->lcd_puts(0,2,entry
->d_name
);
204 rb
->lcd_putsf(0,3,"Directories: %d", dps
->dc
);
205 rb
->lcd_putsf(0,4,"Files: %d", dps
->fc
);
206 log
= human_size_log(dps
->bc
);
207 rb
->lcd_putsf(0,5,"Size: %lu %cB", (unsigned long)(dps
->bc
>> (10*log
)),
208 human_size_prefix
[log
]);
213 result
= _dir_properties(dps
);
217 dps
->fc
++; /* new file */
218 dps
->bc
+= info
.size
;
220 if(ACTION_STD_CANCEL
== rb
->get_action(CONTEXT_STD
,TIMEOUT_NOBLOCK
))
228 static bool dir_properties(char* selected_file
)
237 rb
->strlcpy(dps
.dirname
, selected_file
, MAX_PATH
);
239 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
243 if(false == _dir_properties(&dps
))
246 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
247 rb
->cpu_boost(false);
250 rb
->strlcpy(str_dirname
, selected_file
, MAX_PATH
);
251 rb
->snprintf(str_dircount
, sizeof str_dircount
, "%d", dps
.dc
);
252 rb
->snprintf(str_filecount
, sizeof str_filecount
, "%d", dps
.fc
);
253 log
= human_size_log(dps
.bc
);
254 rb
->snprintf(str_size
, sizeof str_size
, "%ld %cB",
255 (long) (dps
.bc
>> (log
*10)), human_size_prefix
[log
]);
260 static const char * get_props(int selected_item
, void* data
,
261 char *buffer
, size_t buffer_len
)
266 if(selected_item
>= (int)(sizeof(props_dir
) / sizeof(props_dir
[0])))
268 rb
->strlcpy(buffer
, "ERROR", buffer_len
);
272 rb
->strlcpy(buffer
, props_dir
[selected_item
], buffer_len
);
277 if(selected_item
>= (int)(sizeof(props_file
) / sizeof(props_file
[0])))
279 rb
->strlcpy(buffer
, "ERROR", buffer_len
);
283 rb
->strlcpy(buffer
, props_file
[selected_item
], buffer_len
);
289 enum plugin_status
plugin_start(const void* parameter
)
291 struct gui_synclist properties_lists
;
293 bool quit
= false, usb
= false;
295 if(!parameter
) return PLUGIN_ERROR
;
296 rb
->strcpy(file
, (const char *) parameter
);
297 #ifdef HAVE_TOUCHSCREEN
298 rb
->touchscreen_set_mode(rb
->global_settings
->touch_mode
);
301 /* determine if it's a file or a directory */
304 struct dirent
* entry
;
305 char* ptr
= rb
->strrchr(file
, '/') + 1;
306 int dirlen
= (ptr
- file
);
307 rb
->strlcpy(str_dirname
, file
, dirlen
+ 1);
309 dir
= rb
->opendir(str_dirname
);
312 while(0 != (entry
= rb
->readdir(dir
)))
314 if(!rb
->strcmp(entry
->d_name
, file
+dirlen
))
316 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
317 its_a_dir
= info
.attribute
& ATTR_DIRECTORY
? true : false;
324 /* now we know if it's a file or a dir or maybe something failed */
328 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
329 rb
->splashf(0, "File/Dir not found: %s", file
);
330 rb
->action_userabort(TIMEOUT_BLOCK
);
334 /* get the info depending on its_a_dir */
335 if(!(its_a_dir
? dir_properties(file
) : file_properties(file
)))
337 /* something went wrong (to do: tell user what it was (nesting,...) */
338 rb
->splash(0, "Failed to gather information");
339 rb
->action_userabort(TIMEOUT_BLOCK
);
343 #ifdef HAVE_LCD_BITMAP
345 rb
->viewportmanager_theme_enable(i
, true, NULL
);
348 rb
->gui_synclist_init(&properties_lists
, &get_props
, file
, false, 2, NULL
);
349 rb
->gui_synclist_set_title(&properties_lists
, its_a_dir
?
350 "Directory properties" :
351 "File properties", NOICON
);
352 rb
->gui_synclist_set_icon_callback(&properties_lists
, NULL
);
353 rb
->gui_synclist_set_nb_items(&properties_lists
, num_properties
* 2);
354 rb
->gui_synclist_limit_scroll(&properties_lists
, true);
355 rb
->gui_synclist_select_item(&properties_lists
, 0);
356 rb
->gui_synclist_draw(&properties_lists
);
360 button
= rb
->get_action(CONTEXT_LIST
, HZ
);
361 /* HZ so the status bar redraws corectly */
362 if (rb
->gui_synclist_do_button(&properties_lists
,&button
,LIST_WRAP_ON
))
366 case ACTION_STD_CANCEL
:
370 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
379 #ifdef HAVE_LCD_BITMAP
381 rb
->viewportmanager_theme_undo(i
, false);
384 return usb
? PLUGIN_USB_CONNECTED
: PLUGIN_OK
;