Added ID3 database support. Still very early.
[kugel-rb.git] / apps / onplay.c
blobcc08a96a81652166c7b320cf30b7d94864757fd6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
24 #include "debug.h"
25 #include "sprintf.h"
26 #include "lcd.h"
27 #include "dir.h"
28 #include "file.h"
29 #include "mpeg.h"
30 #include "menu.h"
31 #include "lang.h"
32 #include "playlist.h"
33 #include "button.h"
34 #include "kernel.h"
35 #include "keyboard.h"
36 #include "mp3data.h"
37 #include "id3.h"
38 #include "screens.h"
39 #include "tree.h"
40 #include "buffer.h"
41 #include "settings.h"
42 #include "status.h"
43 #include "playlist_viewer.h"
44 #include "talk.h"
45 #include "onplay.h"
46 #include "filetypes.h"
47 #include "plugin.h"
49 static char* selected_file = NULL;
50 static int selected_file_attr = 0;
51 static int onplay_result = ONPLAY_OK;
53 static bool list_viewers(void)
55 struct menu_item menu[16];
56 int m, i, result;
57 int ret = 0;
59 i=filetype_load_menu(menu,sizeof(menu)/sizeof(*menu));
60 if (i)
62 m = menu_init( menu, i, NULL, NULL, NULL, NULL );
63 result = menu_show(m);
64 menu_exit(m);
65 if (result >= 0)
66 ret = filetype_load_plugin(menu[result].desc,selected_file);
68 else
70 splash(HZ*2, true, "No viewers found");
73 if(ret == PLUGIN_USB_CONNECTED)
74 onplay_result = ONPLAY_RELOAD_DIR;
76 return false;
79 /* For playlist options */
80 struct playlist_args {
81 int position;
82 bool queue;
85 static bool add_to_playlist(int position, bool queue)
87 bool new_playlist = !(mpeg_status() & MPEG_STATUS_PLAY);
89 if (new_playlist)
90 playlist_create(NULL, NULL);
92 if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_MPA)
93 playlist_insert_track(NULL, selected_file, position, queue);
94 else if (selected_file_attr & ATTR_DIRECTORY)
96 bool recurse = false;
98 if (global_settings.recursive_dir_insert != RECURSE_ASK)
99 recurse = (bool)global_settings.recursive_dir_insert;
100 else
102 /* Ask if user wants to recurse directory */
103 bool exit = false;
105 lcd_clear_display();
106 lcd_puts_scroll(0,0,str(LANG_RECURSE_DIRECTORY_QUESTION));
107 lcd_puts_scroll(0,1,selected_file);
109 #ifdef HAVE_LCD_BITMAP
110 lcd_puts(0,3,str(LANG_CONFIRM_WITH_PLAY_RECORDER));
111 lcd_puts(0,4,str(LANG_CANCEL_WITH_ANY_RECORDER));
112 #endif
114 lcd_update();
116 while (!exit) {
117 int btn = button_get(true);
118 switch (btn) {
119 case SETTINGS_OK:
120 recurse = true;
121 exit = true;
122 break;
124 default:
125 /* ignore button releases */
126 if (!(btn & BUTTON_REL))
127 exit = true;
128 break;
133 playlist_insert_directory(NULL, selected_file, position, queue,
134 recurse);
136 else if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)
137 playlist_insert_playlist(NULL, selected_file, position, queue);
139 if (new_playlist && (playlist_amount() > 0))
141 /* nothing is currently playing so begin playing what we just
142 inserted */
143 if (global_settings.playlist_shuffle)
144 playlist_shuffle(current_tick, -1);
145 playlist_start(0,0);
146 status_draw(false);
147 onplay_result = ONPLAY_START_PLAY;
150 return false;
153 static bool view_playlist(void)
155 bool was_playing = mpeg_status() & MPEG_STATUS_PLAY;
156 bool result;
158 result = playlist_viewer_ex(selected_file);
160 if (!was_playing && (mpeg_status() & MPEG_STATUS_PLAY) &&
161 onplay_result == ONPLAY_OK)
162 /* playlist was started from viewer */
163 onplay_result = ONPLAY_START_PLAY;
165 return result;
168 /* Sub-menu for playlist options */
169 static bool playlist_options(void)
171 struct menu_item items[7];
172 struct playlist_args args[7]; /* increase these 2 if you add entries! */
173 int m, i=0, pstart=0, result;
174 bool ret = false;
176 if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)
178 items[i].desc = ID2P(LANG_VIEW);
179 items[i].function = view_playlist;
180 i++;
181 pstart++;
184 if (mpeg_status() & MPEG_STATUS_PLAY)
186 items[i].desc = ID2P(LANG_INSERT);
187 args[i].position = PLAYLIST_INSERT;
188 args[i].queue = false;
189 i++;
191 items[i].desc = ID2P(LANG_INSERT_FIRST);
192 args[i].position = PLAYLIST_INSERT_FIRST;
193 args[i].queue = false;
194 i++;
196 items[i].desc = ID2P(LANG_INSERT_LAST);
197 args[i].position = PLAYLIST_INSERT_LAST;
198 args[i].queue = false;
199 i++;
201 items[i].desc = ID2P(LANG_QUEUE);
202 args[i].position = PLAYLIST_INSERT;
203 args[i].queue = true;
204 i++;
206 items[i].desc = ID2P(LANG_QUEUE_FIRST);
207 args[i].position = PLAYLIST_INSERT_FIRST;
208 args[i].queue = true;
209 i++;
211 items[i].desc = ID2P(LANG_QUEUE_LAST);
212 args[i].position = PLAYLIST_INSERT_LAST;
213 args[i].queue = true;
214 i++;
216 else if (((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) ||
217 (selected_file_attr & ATTR_DIRECTORY))
219 items[i].desc = ID2P(LANG_INSERT);
220 args[i].position = PLAYLIST_INSERT;
221 args[i].queue = false;
222 i++;
225 m = menu_init( items, i, NULL, NULL, NULL, NULL );
226 result = menu_show(m);
227 if (result >= 0 && result < pstart)
228 ret = items[result].function();
229 else if (result >= pstart)
230 ret = add_to_playlist(args[result].position, args[result].queue);
231 menu_exit(m);
233 return ret;
237 /* helper function to remove a non-empty directory */
238 static int remove_dir(char* dirname, int len)
240 int result = 0;
241 DIR* dir;
242 int dirlen = strlen(dirname);
244 dir = opendir(dirname);
245 if (!dir)
246 return -1; /* open error */
248 while(true)
250 struct dirent* entry;
251 /* walk through the directory content */
252 entry = readdir(dir);
253 if (!entry)
254 break;
256 /* append name to current directory */
257 snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name);
259 if (entry->attribute & ATTR_DIRECTORY)
260 { /* remove a subdirectory */
261 if (!strcmp(entry->d_name, ".") ||
262 !strcmp(entry->d_name, ".."))
263 continue; /* skip these */
265 result = remove_dir(dirname, len); /* recursion */
266 if (result)
267 break; /* or better continue, delete what we can? */
269 else
270 { /* remove a file */
271 result = remove(dirname);
274 closedir(dir);
276 if (!result)
277 { /* remove the now empty directory */
278 dirname[dirlen] = '\0'; /* terminate to original length */
280 result = rmdir(dirname);
283 return result;
287 /* share code for file and directory deletion, saves space */
288 static bool delete_handler(bool is_dir)
290 bool exit = false;
291 int res;
293 lcd_clear_display();
294 lcd_puts(0,0,str(LANG_REALLY_DELETE));
295 lcd_puts_scroll(0,1,selected_file);
297 #ifdef HAVE_LCD_BITMAP
298 lcd_puts(0,3,str(LANG_CONFIRM_WITH_PLAY_RECORDER));
299 lcd_puts(0,4,str(LANG_CANCEL_WITH_ANY_RECORDER));
300 #endif
302 lcd_update();
304 while (!exit) {
305 int btn = button_get(true);
306 switch (btn) {
307 case SETTINGS_OK:
308 if (is_dir)
310 char pathname[MAX_PATH]; /* space to go deep */
311 strncpy(pathname, selected_file, sizeof pathname);
312 res = remove_dir(pathname, sizeof(pathname));
314 else
316 res = remove(selected_file);
319 if (!res) {
320 onplay_result = ONPLAY_RELOAD_DIR;
321 lcd_clear_display();
322 lcd_puts(0,0,str(LANG_DELETED));
323 lcd_puts_scroll(0,1,selected_file);
324 lcd_update();
325 sleep(HZ);
326 exit = true;
328 break;
330 default:
331 /* ignore button releases */
332 if (!(btn & BUTTON_REL))
333 exit = true;
334 break;
337 return false;
341 static bool delete_file(void)
343 return delete_handler(false);
346 static bool delete_dir(void)
348 return delete_handler(true);
351 static bool rename_file(void)
353 char newname[MAX_PATH];
354 char* ptr = strrchr(selected_file, '/') + 1;
355 int pathlen = (ptr - selected_file);
356 strncpy(newname, selected_file, sizeof newname);
357 if (!kbd_input(newname + pathlen, (sizeof newname)-pathlen)) {
358 if (!strlen(selected_file+pathlen) ||
359 (rename(selected_file, newname) < 0)) {
360 lcd_clear_display();
361 lcd_puts(0,0,str(LANG_RENAME));
362 lcd_puts(0,1,str(LANG_FAILED));
363 lcd_update();
364 sleep(HZ*2);
366 else
367 onplay_result = ONPLAY_RELOAD_DIR;
370 return false;
373 bool create_dir(void)
375 char dirname[MAX_PATH];
376 char *cwd;
377 int rc;
378 int pathlen;
380 cwd = getcwd(NULL, 0);
381 memset(dirname, 0, sizeof dirname);
383 snprintf(dirname, sizeof dirname, "%s/",
384 cwd[1] ? cwd : "");
386 pathlen = strlen(dirname);
387 rc = kbd_input(dirname + pathlen, (sizeof dirname)-pathlen);
388 if(rc < 0)
389 return false;
391 rc = mkdir(dirname, 0);
392 if(rc < 0) {
393 splash(HZ, true, "%s %s", str(LANG_CREATE_DIR), str(LANG_FAILED));
394 } else {
395 onplay_result = ONPLAY_RELOAD_DIR;
398 return true;
401 int onplay(char* file, int attr)
403 struct menu_item items[6]; /* increase this if you add entries! */
404 int m, i=0, result;
406 onplay_result = ONPLAY_OK;
408 if(file)
410 selected_file = file;
411 selected_file_attr = attr;
413 if (((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) ||
414 (attr & ATTR_DIRECTORY) ||
415 ((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U))
417 items[i].desc = ID2P(LANG_PLAYINDICES_PLAYLIST);
418 items[i].function = playlist_options;
419 i++;
422 #ifdef HAVE_MULTIVOLUME
423 if (!(attr & ATTR_VOLUME)) /* no rename+delete for volumes */
424 #endif
426 items[i].desc = ID2P(LANG_RENAME);
427 items[i].function = rename_file;
428 i++;
430 if (!(attr & ATTR_DIRECTORY))
432 items[i].desc = ID2P(LANG_DELETE);
433 items[i].function = delete_file;
434 i++;
436 else
438 items[i].desc = ID2P(LANG_DELETE_DIR);
439 items[i].function = delete_dir;
440 i++;
444 if (!(attr & ATTR_DIRECTORY))
446 items[i].desc = ID2P(LANG_ONPLAY_OPEN_WITH);
447 items[i].function = list_viewers;
448 i++;
452 items[i].desc = ID2P(LANG_CREATE_DIR);
453 items[i].function = create_dir;
454 i++;
456 /* DIY menu handling, since we want to exit after selection */
457 m = menu_init( items, i, NULL, NULL, NULL, NULL );
458 result = menu_show(m);
459 if (result >= 0)
460 items[result].function();
461 menu_exit(m);
463 return onplay_result;