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 human_size_prefix
[4] = { '\0', 'K', 'M', 'G' };
43 static unsigned human_size_log(long long size
)
45 const size_t n
= sizeof(human_size_prefix
)/sizeof(human_size_prefix
[0]);
48 /* margin set at 10K boundary: 10239 B +1 => 10 KB */
49 for(i
=0; i
< n
-1 && size
>= 10*1024; i
++)
50 size
>>= 10; /* div by 1024 */
55 static bool file_properties(char* selected_file
)
63 char* ptr
= rb
->strrchr(selected_file
, '/') + 1;
64 int dirlen
= (ptr
- selected_file
);
65 rb
->strlcpy(tstr
, selected_file
, dirlen
+ 1);
67 dir
= rb
->opendir(tstr
);
70 while(0 != (entry
= rb
->readdir(dir
)))
72 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
73 if(!rb
->strcmp(entry
->d_name
, selected_file
+dirlen
))
76 rb
->snprintf(str_dirname
, sizeof str_dirname
, "Path: %s", tstr
);
77 rb
->snprintf(str_filename
, sizeof str_filename
, "Name: %s",
78 selected_file
+dirlen
);
79 log
= human_size_log(info
.size
);
80 rb
->snprintf(str_size
, sizeof str_size
, "Size: %ld %cB",
81 info
.size
>> (log
*10), human_size_prefix
[log
]);
82 rb
->snprintf(str_date
, sizeof str_date
, "Date: %04d/%02d/%02d",
83 ((info
.wrtdate
>> 9 ) & 0x7F) + 1980, /* year */
84 ((info
.wrtdate
>> 5 ) & 0x0F), /* month */
85 ((info
.wrtdate
) & 0x1F)); /* day */
86 rb
->snprintf(str_time
, sizeof str_time
, "Time: %02d:%02d",
87 ((info
.wrttime
>> 11) & 0x1F), /* hour */
88 ((info
.wrttime
>> 5 ) & 0x3F)); /* minutes */
92 #if (CONFIG_CODEC == SWCODEC)
93 int fd
= rb
->open(selected_file
, O_RDONLY
);
95 rb
->get_metadata(&id3
, fd
, selected_file
))
97 if (!rb
->mp3info(&id3
, selected_file
))
100 long dur
= id3
.length
/ 1000; /* seconds */
101 rb
->snprintf(str_artist
, sizeof str_artist
,
102 "Artist: %s", id3
.artist
? id3
.artist
: "");
103 rb
->snprintf(str_title
, sizeof str_title
,
104 "Title: %s", id3
.title
? id3
.title
: "");
105 rb
->snprintf(str_album
, sizeof str_album
,
106 "Album: %s", id3
.album
? id3
.album
: "");
112 rb
->snprintf(str_duration
, sizeof str_duration
,
113 "Duration: %d:%02d", (int)(dur
/ 60),
116 rb
->snprintf(str_duration
, sizeof str_duration
,
117 "Duration: %d:%02d:%02d",
119 (int)(dur
% 3600 / 60),
124 #if (CONFIG_CODEC == SWCODEC)
137 char dirname
[MAX_PATH
];
144 static bool _dir_properties(DPS
* dps
)
146 /* recursively scan directories in search of files
147 and informs the user of the progress */
149 static long lasttick
=0;
152 struct dirent
* entry
;
155 dirlen
= rb
->strlen(dps
->dirname
);
156 dir
= rb
->opendir(dps
->dirname
);
158 return false; /* open error */
160 /* walk through the directory content */
161 while(result
&& (0 != (entry
= rb
->readdir(dir
))))
163 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
164 /* append name to current directory */
165 rb
->snprintf(dps
->dirname
+dirlen
, dps
->len
-dirlen
, "/%s",
168 if (info
.attribute
& ATTR_DIRECTORY
)
172 if (!rb
->strcmp((char *)entry
->d_name
, ".") ||
173 !rb
->strcmp((char *)entry
->d_name
, ".."))
174 continue; /* skip these */
176 dps
->dc
++; /* new directory */
177 if (*rb
->current_tick
- lasttick
> (HZ
/8))
179 lasttick
= *rb
->current_tick
;
180 rb
->lcd_clear_display();
181 rb
->lcd_puts(0,0,"SCANNING...");
182 rb
->lcd_puts(0,1,dps
->dirname
);
183 rb
->lcd_puts(0,2,entry
->d_name
);
184 rb
->lcd_putsf(0,3,"Directories: %d", dps
->dc
);
185 rb
->lcd_putsf(0,4,"Files: %d", dps
->fc
);
186 log
= human_size_log(dps
->bc
);
187 rb
->lcd_putsf(0,5,"Size: %ld %cB", (long) (dps
->bc
>> (10*log
)),
188 human_size_prefix
[log
]);
193 result
= _dir_properties(dps
);
197 dps
->fc
++; /* new file */
198 dps
->bc
+= info
.size
;
200 if(ACTION_STD_CANCEL
== rb
->get_action(CONTEXT_STD
,TIMEOUT_NOBLOCK
))
208 static bool dir_properties(char* selected_file
)
217 rb
->strlcpy(dps
.dirname
, selected_file
, MAX_PATH
);
219 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
223 if(false == _dir_properties(&dps
))
226 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
227 rb
->cpu_boost(false);
230 rb
->strlcpy(str_dirname
, selected_file
, MAX_PATH
);
231 rb
->snprintf(str_dircount
, sizeof str_dircount
, "Subdirs: %d", dps
.dc
);
232 rb
->snprintf(str_filecount
, sizeof str_filecount
, "Files: %d", dps
.fc
);
233 log
= human_size_log(dps
.bc
);
234 rb
->snprintf(str_size
, sizeof str_size
, "Size: %ld %cB",
235 (long) (dps
.bc
>> (log
*10)), human_size_prefix
[log
]);
240 static const char * get_props(int selected_item
, void* data
,
241 char *buffer
, size_t buffer_len
)
245 switch(selected_item
)
248 rb
->strlcpy(buffer
, str_dirname
, buffer_len
);
251 rb
->strlcpy(buffer
, its_a_dir
? str_dircount
: str_filename
,
255 rb
->strlcpy(buffer
, its_a_dir
? str_filecount
: str_size
, buffer_len
);
258 rb
->strlcpy(buffer
, its_a_dir
? str_size
: str_date
, buffer_len
);
261 rb
->strlcpy(buffer
, its_a_dir
? "" : str_time
, buffer_len
);
264 rb
->strlcpy(buffer
, its_a_dir
? "" : str_artist
, buffer_len
);
267 rb
->strlcpy(buffer
, its_a_dir
? "" : str_title
, buffer_len
);
270 rb
->strlcpy(buffer
, its_a_dir
? "" : str_album
, buffer_len
);
273 rb
->strlcpy(buffer
, its_a_dir
? "" : str_duration
, buffer_len
);
281 enum plugin_status
plugin_start(const void* parameter
)
283 struct gui_synclist properties_lists
;
284 #ifdef HAVE_LCD_BITMAP
288 bool quit
= false, usb
= false;
290 if(!parameter
) return PLUGIN_ERROR
;
291 rb
->strcpy(file
, (const char *) parameter
);
292 #ifdef HAVE_TOUCHSCREEN
293 rb
->touchscreen_set_mode(rb
->global_settings
->touch_mode
);
296 /* determine if it's a file or a directory */
299 struct dirent
* entry
;
300 char* ptr
= rb
->strrchr(file
, '/') + 1;
301 int dirlen
= (ptr
- file
);
302 rb
->strlcpy(str_dirname
, file
, dirlen
+ 1);
304 dir
= rb
->opendir(str_dirname
);
307 while(0 != (entry
= rb
->readdir(dir
)))
309 if(!rb
->strcmp(entry
->d_name
, file
+dirlen
))
311 struct dirinfo info
= rb
->dir_get_info(dir
, entry
);
312 its_a_dir
= info
.attribute
& ATTR_DIRECTORY
? true : false;
319 /* now we know if it's a file or a dir or maybe something failed */
323 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
324 rb
->splashf(0, "File/Dir not found: %s", file
);
325 rb
->action_userabort(TIMEOUT_BLOCK
);
329 /* get the info depending on its_a_dir */
330 if(!(its_a_dir
? dir_properties(file
) : file_properties(file
)))
332 /* something went wrong (to do: tell user what it was (nesting,...) */
333 rb
->splash(0, "Failed to gather information");
334 rb
->action_userabort(TIMEOUT_BLOCK
);
338 #ifdef HAVE_LCD_BITMAP
340 rb
->viewportmanager_theme_enable(i
, true, NULL
);
343 rb
->gui_synclist_init(&properties_lists
, &get_props
, file
, false, 1, NULL
);
344 rb
->gui_synclist_set_title(&properties_lists
, its_a_dir
?
345 "Directory properties" :
346 "File properties", NOICON
);
347 rb
->gui_synclist_set_icon_callback(&properties_lists
, NULL
);
348 rb
->gui_synclist_set_nb_items(&properties_lists
, num_properties
);
349 rb
->gui_synclist_limit_scroll(&properties_lists
, true);
350 rb
->gui_synclist_select_item(&properties_lists
, 0);
351 rb
->gui_synclist_draw(&properties_lists
);
355 button
= rb
->get_action(CONTEXT_LIST
, HZ
);
356 /* HZ so the status bar redraws corectly */
357 if (rb
->gui_synclist_do_button(&properties_lists
,&button
,LIST_WRAP_ON
))
361 case ACTION_STD_CANCEL
:
365 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
374 #ifdef HAVE_LCD_BITMAP
376 rb
->viewportmanager_theme_undo(i
, false);
379 return usb
? PLUGIN_USB_CONNECTED
: PLUGIN_OK
;