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 static const struct plugin_api
* rb
;
27 MEM_FUNCTION_WRAPPERS(rb
);
29 bool its_a_dir
= false;
31 char str_filename
[MAX_PATH
];
32 char str_dirname
[MAX_PATH
];
34 char str_dircount
[64];
35 char str_filecount
[64];
39 char str_title
[MAX_PATH
];
40 char str_artist
[MAX_PATH
];
41 char str_album
[MAX_PATH
];
45 static char* filesize2string(long long size
, char* pstr
, int len
)
47 /* margin set at 10K boundary: 10239 B +1 => 10 KB
48 routine below is 200 bytes smaller than cascaded if/else :)
49 not using build-in function because of huge values (long long) */
50 const char* kgb
[4] = { "B", "KB", "MB", "GB" };
54 if((size
< 10240) || (i
> 2))
56 /* depends on the order in the above array */
57 rb
->snprintf(pstr
, len
, "%ld %s", (long)size
, kgb
[i
]);
60 size
>>= 10; /* div by 1024 */
66 static bool file_properties(char* selected_file
)
74 char* ptr
= rb
->strrchr(selected_file
, '/') + 1;
75 int dirlen
= (ptr
- selected_file
);
76 rb
->strncpy(tstr
, selected_file
, dirlen
);
79 dir
= rb
->opendir(tstr
);
82 while(0 != (entry
= rb
->readdir(dir
)))
84 if(!rb
->strcmp(entry
->d_name
, selected_file
+dirlen
))
86 rb
->snprintf(str_dirname
, sizeof str_dirname
, "Path: %s",
88 rb
->snprintf(str_filename
, sizeof str_filename
, "Name: %s",
89 selected_file
+dirlen
);
90 rb
->snprintf(str_size
, sizeof str_size
, "Size: %s",
91 filesize2string(entry
->size
, tstr
, sizeof tstr
));
92 rb
->snprintf(str_date
, sizeof str_date
, "Date: %04d/%02d/%02d",
93 ((entry
->wrtdate
>> 9 ) & 0x7F) + 1980, /* year */
94 ((entry
->wrtdate
>> 5 ) & 0x0F), /* month */
95 ((entry
->wrtdate
) & 0x1F)); /* day */
96 rb
->snprintf(str_time
, sizeof str_time
, "Time: %02d:%02d",
97 ((entry
->wrttime
>> 11) & 0x1F), /* hour */
98 ((entry
->wrttime
>> 5 ) & 0x3F)); /* minutes */
102 #if (CONFIG_CODEC == SWCODEC)
103 int fd
= rb
->open(selected_file
, O_RDONLY
);
105 rb
->get_metadata(&id3
, fd
, selected_file
))
107 if (!rb
->mp3info(&id3
, selected_file
))
110 rb
->snprintf(str_artist
, sizeof str_artist
,
111 "Artist: %s", id3
.artist
? id3
.artist
: "");
112 rb
->snprintf(str_title
, sizeof str_title
,
113 "Title: %s", id3
.title
? id3
.title
: "");
114 rb
->snprintf(str_album
, sizeof str_album
,
115 "Album: %s", id3
.album
? id3
.album
: "");
118 #if (CONFIG_CODEC == SWCODEC)
131 char dirname
[MAX_PATH
];
140 static bool _dir_properties(DPS
* dps
)
142 /* recursively scan directories in search of files
143 and informs the user of the progress */
147 struct dirent
* entry
;
150 dirlen
= rb
->strlen(dps
->dirname
);
151 dir
= rb
->opendir(dps
->dirname
);
153 return false; /* open error */
155 /* walk through the directory content */
156 while(result
&& (0 != (entry
= rb
->readdir(dir
))))
158 /* append name to current directory */
159 rb
->snprintf(dps
->dirname
+dirlen
, dps
->len
-dirlen
, "/%s",
162 if (entry
->attribute
& ATTR_DIRECTORY
)
164 if (!rb
->strcmp((char *)entry
->d_name
, ".") ||
165 !rb
->strcmp((char *)entry
->d_name
, ".."))
166 continue; /* skip these */
168 dps
->dc
++; /* new directory */
169 rb
->lcd_clear_display();
170 rb
->lcd_puts(0,0,"SCANNING...");
171 rb
->lcd_puts(0,1,dps
->dirname
);
172 rb
->lcd_puts(0,2,entry
->d_name
);
173 rb
->snprintf(dps
->tstr
, 64, "Directories: %d", dps
->dc
);
174 rb
->lcd_puts(0,3,dps
->tstr
);
175 rb
->snprintf(dps
->tstr
, 64, "Files: %d", dps
->fc
);
176 rb
->lcd_puts(0,4,dps
->tstr
);
177 rb
->snprintf(dps
->tstr
, 64, "Size: %s",
178 filesize2string(dps
->bc
, dps
->tstr2
, 64));
179 rb
->lcd_puts(0,5,dps
->tstr
);
183 result
= _dir_properties(dps
);
187 dps
->fc
++; /* new file */
188 dps
->bc
+= entry
->size
;
190 if(ACTION_STD_CANCEL
== rb
->get_action(CONTEXT_STD
,TIMEOUT_NOBLOCK
))
198 static bool dir_properties(char* selected_file
)
202 rb
->strncpy(dps
.dirname
, selected_file
, MAX_PATH
);
207 if(false == _dir_properties(&dps
))
210 rb
->strncpy(str_dirname
, selected_file
, MAX_PATH
);
211 rb
->snprintf(str_dircount
, sizeof str_dircount
, "Subdirs: %d", dps
.dc
);
212 rb
->snprintf(str_filecount
, sizeof str_filecount
, "Files: %d", dps
.fc
);
213 rb
->snprintf(str_size
, sizeof str_size
, "Size: %s",
214 filesize2string(dps
.bc
, tstr
, sizeof tstr
));
219 char * get_props(int selected_item
, void* data
, char *buffer
, size_t buffer_len
)
223 switch(selected_item
)
226 rb
->strncpy(buffer
, str_dirname
, buffer_len
);
229 rb
->strncpy(buffer
, its_a_dir
? str_dircount
: str_filename
,
233 rb
->strncpy(buffer
, its_a_dir
? str_filecount
: str_size
, buffer_len
);
236 rb
->strncpy(buffer
, its_a_dir
? str_size
: str_date
, buffer_len
);
239 rb
->strncpy(buffer
, its_a_dir
? "" : str_time
, buffer_len
);
242 rb
->strncpy(buffer
, its_a_dir
? "" : str_artist
, buffer_len
);
245 rb
->strncpy(buffer
, its_a_dir
? "" : str_title
, buffer_len
);
248 rb
->strncpy(buffer
, its_a_dir
? "" : str_album
, buffer_len
);
251 rb
->strncpy(buffer
, "ERROR", buffer_len
);
257 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
260 struct gui_synclist properties_lists
;
262 bool prev_show_statusbar
;
265 rb
->strcpy(file
, (const char *) parameter
);
267 /* determine if it's a file or a directory */
270 struct dirent
* entry
;
271 char* ptr
= rb
->strrchr(file
, '/') + 1;
272 int dirlen
= (ptr
- file
);
273 rb
->strncpy(str_dirname
, file
, dirlen
);
274 str_dirname
[dirlen
] = 0;
276 dir
= rb
->opendir(str_dirname
);
279 while(0 != (entry
= rb
->readdir(dir
)))
281 if(!rb
->strcmp(entry
->d_name
, file
+dirlen
))
283 its_a_dir
= entry
->attribute
& ATTR_DIRECTORY
? true : false;
290 /* now we know if it's a file or a dir or maybe something failed */
294 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
295 rb
->splashf(0, "File/Dir not found: %s", file
);
296 rb
->action_userabort(TIMEOUT_BLOCK
);
300 /* get the info depending on its_a_dir */
301 if(!(its_a_dir
? dir_properties(file
) : file_properties(file
)))
303 /* something went wrong (to do: tell user what it was (nesting,...) */
304 rb
->splash(0, "Failed to gather information");
305 rb
->action_userabort(TIMEOUT_BLOCK
);
309 /* prepare the list for the user */
310 prev_show_statusbar
= rb
->global_settings
->statusbar
;
311 rb
->global_settings
->statusbar
= false;
313 rb
->gui_synclist_init(&properties_lists
, &get_props
, file
, false, 1, NULL
);
314 rb
->gui_synclist_set_title(&properties_lists
, its_a_dir
?
315 "Directory properties" :
316 "File properties", NOICON
);
317 rb
->gui_synclist_set_icon_callback(&properties_lists
, NULL
);
318 rb
->gui_synclist_set_nb_items(&properties_lists
, num_properties
);
319 rb
->gui_synclist_limit_scroll(&properties_lists
, true);
320 rb
->gui_synclist_select_item(&properties_lists
, 0);
321 rb
->gui_synclist_draw(&properties_lists
);
325 button
= rb
->get_action(CONTEXT_LIST
,TIMEOUT_BLOCK
);
326 if (rb
->gui_synclist_do_button(&properties_lists
,&button
,LIST_WRAP_ON
))
330 case ACTION_STD_CANCEL
:
334 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
336 rb
->global_settings
->statusbar
= prev_show_statusbar
;
337 return PLUGIN_USB_CONNECTED
;
341 rb
->global_settings
->statusbar
= prev_show_statusbar
;