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 char* filesize2string(long long size
, char* pstr
, int len
)
44 /* margin set at 10K boundary: 10239 B +1 => 10 KB
45 routine below is 200 bytes smaller than cascaded if/else :)
46 not using build-in function because of huge values (long long) */
47 const char* kgb
[4] = { "B", "KB", "MB", "GB" };
51 if((size
< 10240) || (i
> 2))
53 /* depends on the order in the above array */
54 rb
->snprintf(pstr
, len
, "%ld %s", (long)size
, kgb
[i
]);
57 size
>>= 10; /* div by 1024 */
63 static bool file_properties(char* selected_file
)
71 char* ptr
= rb
->strrchr(selected_file
, '/') + 1;
72 int dirlen
= (ptr
- selected_file
);
73 rb
->strlcpy(tstr
, selected_file
, dirlen
+ 1);
75 dir
= rb
->opendir(tstr
);
78 while(0 != (entry
= rb
->readdir(dir
)))
80 if(!rb
->strcmp(entry
->d_name
, selected_file
+dirlen
))
82 rb
->snprintf(str_dirname
, sizeof str_dirname
, "Path: %s",
84 rb
->snprintf(str_filename
, sizeof str_filename
, "Name: %s",
85 selected_file
+dirlen
);
86 rb
->snprintf(str_size
, sizeof str_size
, "Size: %s",
87 filesize2string(entry
->size
, tstr
, sizeof tstr
));
88 rb
->snprintf(str_date
, sizeof str_date
, "Date: %04d/%02d/%02d",
89 ((entry
->wrtdate
>> 9 ) & 0x7F) + 1980, /* year */
90 ((entry
->wrtdate
>> 5 ) & 0x0F), /* month */
91 ((entry
->wrtdate
) & 0x1F)); /* day */
92 rb
->snprintf(str_time
, sizeof str_time
, "Time: %02d:%02d",
93 ((entry
->wrttime
>> 11) & 0x1F), /* hour */
94 ((entry
->wrttime
>> 5 ) & 0x3F)); /* minutes */
98 #if (CONFIG_CODEC == SWCODEC)
99 int fd
= rb
->open(selected_file
, O_RDONLY
);
101 rb
->get_metadata(&id3
, fd
, selected_file
))
103 if (!rb
->mp3info(&id3
, selected_file
))
106 long dur
= id3
.length
/ 1000; /* seconds */
107 rb
->snprintf(str_artist
, sizeof str_artist
,
108 "Artist: %s", id3
.artist
? id3
.artist
: "");
109 rb
->snprintf(str_title
, sizeof str_title
,
110 "Title: %s", id3
.title
? id3
.title
: "");
111 rb
->snprintf(str_album
, sizeof str_album
,
112 "Album: %s", id3
.album
? id3
.album
: "");
118 rb
->snprintf(str_duration
, sizeof str_duration
,
119 "Duration: %d:%02d", (int)(dur
/ 60),
122 rb
->snprintf(str_duration
, sizeof str_duration
,
123 "Duration: %d:%02d:%02d",
125 (int)(dur
% 3600 / 60),
130 #if (CONFIG_CODEC == SWCODEC)
143 char dirname
[MAX_PATH
];
152 static bool _dir_properties(DPS
* dps
)
154 /* recursively scan directories in search of files
155 and informs the user of the progress */
159 struct dirent
* entry
;
162 dirlen
= rb
->strlen(dps
->dirname
);
163 dir
= rb
->opendir(dps
->dirname
);
165 return false; /* open error */
167 /* walk through the directory content */
168 while(result
&& (0 != (entry
= rb
->readdir(dir
))))
170 /* append name to current directory */
171 rb
->snprintf(dps
->dirname
+dirlen
, dps
->len
-dirlen
, "/%s",
174 if (entry
->attribute
& ATTR_DIRECTORY
)
176 if (!rb
->strcmp((char *)entry
->d_name
, ".") ||
177 !rb
->strcmp((char *)entry
->d_name
, ".."))
178 continue; /* skip these */
180 dps
->dc
++; /* new directory */
181 rb
->lcd_clear_display();
182 rb
->lcd_puts(0,0,"SCANNING...");
183 rb
->lcd_puts(0,1,dps
->dirname
);
184 rb
->lcd_puts(0,2,entry
->d_name
);
185 rb
->snprintf(dps
->tstr
, 64, "Directories: %d", dps
->dc
);
186 rb
->lcd_puts(0,3,dps
->tstr
);
187 rb
->snprintf(dps
->tstr
, 64, "Files: %d", dps
->fc
);
188 rb
->lcd_puts(0,4,dps
->tstr
);
189 rb
->snprintf(dps
->tstr
, 64, "Size: %s",
190 filesize2string(dps
->bc
, dps
->tstr2
, 64));
191 rb
->lcd_puts(0,5,dps
->tstr
);
195 result
= _dir_properties(dps
);
199 dps
->fc
++; /* new file */
200 dps
->bc
+= entry
->size
;
202 if(ACTION_STD_CANCEL
== rb
->get_action(CONTEXT_STD
,TIMEOUT_NOBLOCK
))
210 static bool dir_properties(char* selected_file
)
214 rb
->strlcpy(dps
.dirname
, selected_file
, MAX_PATH
);
219 if(false == _dir_properties(&dps
))
222 rb
->strlcpy(str_dirname
, selected_file
, MAX_PATH
);
223 rb
->snprintf(str_dircount
, sizeof str_dircount
, "Subdirs: %d", dps
.dc
);
224 rb
->snprintf(str_filecount
, sizeof str_filecount
, "Files: %d", dps
.fc
);
225 rb
->snprintf(str_size
, sizeof str_size
, "Size: %s",
226 filesize2string(dps
.bc
, tstr
, sizeof tstr
));
231 static const char * get_props(int selected_item
, void* data
,
232 char *buffer
, size_t buffer_len
)
236 switch(selected_item
)
239 rb
->strlcpy(buffer
, str_dirname
, buffer_len
);
242 rb
->strlcpy(buffer
, its_a_dir
? str_dircount
: str_filename
,
246 rb
->strlcpy(buffer
, its_a_dir
? str_filecount
: str_size
, buffer_len
);
249 rb
->strlcpy(buffer
, its_a_dir
? str_size
: str_date
, buffer_len
);
252 rb
->strlcpy(buffer
, its_a_dir
? "" : str_time
, buffer_len
);
255 rb
->strlcpy(buffer
, its_a_dir
? "" : str_artist
, buffer_len
);
258 rb
->strlcpy(buffer
, its_a_dir
? "" : str_title
, buffer_len
);
261 rb
->strlcpy(buffer
, its_a_dir
? "" : str_album
, buffer_len
);
264 rb
->strlcpy(buffer
, its_a_dir
? "" : str_duration
, buffer_len
);
272 enum plugin_status
plugin_start(const void* parameter
)
274 struct gui_synclist properties_lists
;
275 #ifdef HAVE_LCD_BITMAP
279 bool quit
= false, usb
= false;
281 if(!parameter
) return PLUGIN_ERROR
;
282 rb
->strcpy(file
, (const char *) parameter
);
284 /* determine if it's a file or a directory */
287 struct dirent
* entry
;
288 char* ptr
= rb
->strrchr(file
, '/') + 1;
289 int dirlen
= (ptr
- file
);
290 rb
->strlcpy(str_dirname
, file
, dirlen
+ 1);
292 dir
= rb
->opendir(str_dirname
);
295 while(0 != (entry
= rb
->readdir(dir
)))
297 if(!rb
->strcmp(entry
->d_name
, file
+dirlen
))
299 its_a_dir
= entry
->attribute
& ATTR_DIRECTORY
? true : false;
306 /* now we know if it's a file or a dir or maybe something failed */
310 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
311 rb
->splashf(0, "File/Dir not found: %s", file
);
312 rb
->action_userabort(TIMEOUT_BLOCK
);
316 /* get the info depending on its_a_dir */
317 if(!(its_a_dir
? dir_properties(file
) : file_properties(file
)))
319 /* something went wrong (to do: tell user what it was (nesting,...) */
320 rb
->splash(0, "Failed to gather information");
321 rb
->action_userabort(TIMEOUT_BLOCK
);
325 #ifdef HAVE_LCD_BITMAP
327 rb
->viewportmanager_theme_enable(i
, true, NULL
);
330 rb
->gui_synclist_init(&properties_lists
, &get_props
, file
, false, 1, NULL
);
331 rb
->gui_synclist_set_title(&properties_lists
, its_a_dir
?
332 "Directory properties" :
333 "File properties", NOICON
);
334 rb
->gui_synclist_set_icon_callback(&properties_lists
, NULL
);
335 rb
->gui_synclist_set_nb_items(&properties_lists
, num_properties
);
336 rb
->gui_synclist_limit_scroll(&properties_lists
, true);
337 rb
->gui_synclist_select_item(&properties_lists
, 0);
338 rb
->gui_synclist_draw(&properties_lists
);
342 button
= rb
->get_action(CONTEXT_LIST
, HZ
);
343 /* HZ so the status bar redraws corectly */
344 if (rb
->gui_synclist_do_button(&properties_lists
,&button
,LIST_WRAP_ON
))
348 case ACTION_STD_CANCEL
:
352 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
361 #ifdef HAVE_LCD_BITMAP
363 rb
->viewportmanager_theme_undo(i
, false);
366 return usb
? PLUGIN_USB_CONNECTED
: PLUGIN_OK
;