RGB <-> HSV colorspace conversion lib
[maemo-rb.git] / apps / bookmark.c
blob62b286333e65ddc1d3ec3d39ef98c7a946b8077d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C)2003 by Benjamin Metzler
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
17 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdbool.h>
25 #include "applimits.h"
26 #include "lcd.h"
27 #include "button.h"
28 #include "usb.h"
29 #include "audio.h"
30 #include "playlist.h"
31 #include "settings.h"
32 #include "tree.h"
33 #include "bookmark.h"
34 #include "dir.h"
35 #include "status.h"
36 #include "system.h"
37 #include "errno.h"
38 #include "icons.h"
39 #include "atoi.h"
40 #include "string.h"
41 #include "menu.h"
42 #include "lang.h"
43 #include "screens.h"
44 #include "status.h"
45 #include "debug.h"
46 #include "kernel.h"
47 #include "sprintf.h"
48 #include "talk.h"
49 #include "misc.h"
50 #include "abrepeat.h"
51 #include "splash.h"
52 #include "yesno.h"
54 #ifdef HAVE_LCD_COLOR
55 #include "backdrop.h"
56 #endif
58 #define MAX_BOOKMARKS 10
59 #define MAX_BOOKMARK_SIZE 350
60 #define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/most-recent.bmark"
62 static bool add_bookmark(const char* bookmark_file_name, const char* bookmark);
63 static bool check_bookmark(const char* bookmark);
64 static char* create_bookmark(void);
65 static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id);
66 static void display_bookmark(const char* bookmark,
67 int bookmark_id,
68 int bookmark_count);
69 static void say_bookmark(const char* bookmark,
70 int bookmark_id);
71 static bool generate_bookmark_file_name(const char *in);
72 static char* get_bookmark(const char* bookmark_file, int bookmark_count);
73 static bool parse_bookmark(const char *bookmark,
74 int *resume_index,
75 int *resume_offset,
76 int *resume_seed,
77 int *resume_first_index,
78 char* resume_file,
79 unsigned int resume_file_size,
80 long* ms,
81 int * repeat_mode,
82 bool *shuffle,
83 char* file_name);
84 static char* select_bookmark(const char* bookmark_file_name);
85 static bool system_check(void);
86 static bool write_bookmark(bool create_bookmark_file);
87 static int get_bookmark_count(const char* bookmark_file_name);
89 static char global_temp_buffer[MAX_PATH+1];
90 static char global_bookmark_file_name[MAX_PATH];
91 static char global_read_buffer[MAX_BOOKMARK_SIZE];
92 static char global_bookmark[MAX_BOOKMARK_SIZE];
93 static char global_filename[MAX_PATH];
95 /* ----------------------------------------------------------------------- */
96 /* This is the interface function from the main menu. */
97 /* ----------------------------------------------------------------------- */
98 bool bookmark_create_menu(void)
100 write_bookmark(true);
101 return false;
104 /* ----------------------------------------------------------------------- */
105 /* This function acts as the load interface from the main menu */
106 /* This function determines the bookmark file name and then loads that file*/
107 /* for the user. The user can then select a bookmark to load. */
108 /* If no file/directory is currently playing, the menu item does not work. */
109 /* ----------------------------------------------------------------------- */
110 bool bookmark_load_menu(void)
112 bool success = true;
113 int offset;
114 int seed;
115 int index;
116 char* bookmark;
118 if(!system_check())
119 return false;
120 else
122 char* name = playlist_get_name(NULL, global_temp_buffer,
123 sizeof(global_temp_buffer));
124 if (generate_bookmark_file_name(name))
126 bookmark = select_bookmark(global_bookmark_file_name);
127 if (!bookmark)
128 return false; /* User exited without selecting a bookmark */
130 success = parse_bookmark(bookmark,
131 &index,
132 &offset,
133 &seed,
134 NULL,
135 global_temp_buffer,
136 sizeof(global_temp_buffer),
137 NULL,
138 &global_settings.repeat_mode,
139 &global_settings.playlist_shuffle,
140 global_filename);
142 else
144 /* something bad happened while creating bookmark name*/
145 success = false;
148 if (success)
149 bookmark_play(global_temp_buffer, index, offset, seed,
150 global_filename);
153 return success;
156 /* ----------------------------------------------------------------------- */
157 /* Gives the user a list of the Most Recent Bookmarks. This is an */
158 /* interface function */
159 /* ----------------------------------------------------------------------- */
160 bool bookmark_mrb_load()
162 bool success = true;
163 int offset;
164 int seed;
165 int index;
166 char* bookmark;
168 bookmark = select_bookmark(RECENT_BOOKMARK_FILE);
169 if (!bookmark)
170 return false; /* User exited without selecting a bookmark */
172 success = parse_bookmark(bookmark,
173 &index,
174 &offset,
175 &seed,
176 NULL,
177 global_temp_buffer,
178 sizeof(global_temp_buffer),
179 NULL,
180 &global_settings.repeat_mode,
181 &global_settings.playlist_shuffle,
182 global_filename);
184 if (success)
185 bookmark_play(global_temp_buffer, index, offset, seed,
186 global_filename);
188 return success;
192 /* ----------------------------------------------------------------------- */
193 /* This function handles an autobookmark creation. This is an interface */
194 /* function. */
195 /* ----------------------------------------------------------------------- */
196 bool bookmark_autobookmark(void)
198 if (!system_check())
199 return false;
201 audio_pause(); /* first pause playback */
202 switch (global_settings.autocreatebookmark)
204 case BOOKMARK_YES:
205 return write_bookmark(true);
207 case BOOKMARK_NO:
208 return false;
210 case BOOKMARK_RECENT_ONLY_YES:
211 return write_bookmark(false);
213 #ifdef HAVE_LCD_BITMAP
214 unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY)};
215 struct text_message message={(char **)lines, 1};
216 #else
217 unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY),
218 str(LANG_RESUME_CONFIRM_PLAYER)};
219 struct text_message message={(char **)lines, 2};
220 #endif
221 #ifdef HAVE_LCD_COLOR
222 show_main_backdrop(); /* switch to main backdrop as we may come from wps */
223 #endif
224 gui_syncstatusbar_draw(&statusbars, false);
225 if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
227 if (global_settings.autocreatebookmark == BOOKMARK_RECENT_ONLY_ASK)
228 return write_bookmark(false);
229 else
230 return write_bookmark(true);
232 return false;
235 /* ----------------------------------------------------------------------- */
236 /* This function takes the current current resume information and writes */
237 /* that to the beginning of the bookmark file. */
238 /* This file will contain N number of bookmarks in the following format: */
239 /* resume_index*resume_offset*resume_seed*resume_first_index* */
240 /* resume_file*milliseconds*MP3 Title* */
241 /* ------------------------------------------------------------------------*/
242 static bool write_bookmark(bool create_bookmark_file)
244 bool success=false;
245 char* bookmark;
247 if (!system_check())
248 return false; /* something didn't happen correctly, do nothing */
250 bookmark = create_bookmark();
251 if (!bookmark)
252 return false; /* something didn't happen correctly, do nothing */
254 if (global_settings.usemrb)
255 success = add_bookmark(RECENT_BOOKMARK_FILE, bookmark);
258 /* writing the bookmark */
259 if (create_bookmark_file)
261 char* name = playlist_get_name(NULL, global_temp_buffer,
262 sizeof(global_temp_buffer));
263 if (generate_bookmark_file_name(name))
265 success = add_bookmark(global_bookmark_file_name, bookmark);
269 if (success)
270 gui_syncsplash(HZ, true, str(LANG_BOOKMARK_CREATE_SUCCESS));
271 else
272 gui_syncsplash(HZ, true, str(LANG_BOOKMARK_CREATE_FAILURE));
274 return true;
277 /* ----------------------------------------------------------------------- */
278 /* This function adds a bookmark to a file. */
279 /* ------------------------------------------------------------------------*/
280 static bool add_bookmark(const char* bookmark_file_name, const char* bookmark)
282 int temp_bookmark_file = 0;
283 int bookmark_file = 0;
284 int bookmark_count = 0;
285 char* playlist = NULL;
286 char* cp;
287 char* tmp;
288 int len = 0;
289 bool unique = false;
291 /* Opening up a temp bookmark file */
292 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
293 "%s.tmp", bookmark_file_name);
294 temp_bookmark_file = open(global_temp_buffer,
295 O_WRONLY | O_CREAT | O_TRUNC);
296 if (temp_bookmark_file < 0)
297 return false; /* can't open the temp file */
299 if (!strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE) &&
300 (global_settings.usemrb == BOOKMARK_UNIQUE_ONLY))
302 playlist = strchr(bookmark,'/');
303 cp = strrchr(bookmark,';');
304 len = cp - playlist;
305 unique = true;
308 /* Writing the new bookmark to the begining of the temp file */
309 write(temp_bookmark_file, bookmark, strlen(bookmark));
310 write(temp_bookmark_file, "\n", 1);
311 bookmark_count++;
313 /* Reading in the previous bookmarks and writing them to the temp file */
314 bookmark_file = open(bookmark_file_name, O_RDONLY);
315 if (bookmark_file >= 0)
317 while (read_line(bookmark_file, global_read_buffer,
318 sizeof(global_read_buffer)))
320 /* The MRB has a max of MAX_BOOKMARKS in it */
321 /* This keeps it from getting too large */
322 if ((strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE)==0))
324 if(bookmark_count >= MAX_BOOKMARKS)
325 break;
328 cp = strchr(global_read_buffer,'/');
329 tmp = strrchr(global_read_buffer,';');
330 if (check_bookmark(global_read_buffer) &&
331 (!unique || len != tmp -cp || strncmp(playlist,cp,len)))
333 bookmark_count++;
334 write(temp_bookmark_file, global_read_buffer,
335 strlen(global_read_buffer));
336 write(temp_bookmark_file, "\n", 1);
339 close(bookmark_file);
341 close(temp_bookmark_file);
343 remove(bookmark_file_name);
344 rename(global_temp_buffer, bookmark_file_name);
346 return true;
350 /* ----------------------------------------------------------------------- */
351 /* This function takes the system resume data and formats it into a valid */
352 /* bookmark. */
353 /* ----------------------------------------------------------------------- */
354 static char* create_bookmark()
356 int resume_index = 0;
357 char *file;
359 /* grab the currently playing track */
360 struct mp3entry *id3 = audio_current_track();
361 if(!id3)
362 return NULL;
364 /* Get some basic resume information */
365 /* queue_resume and queue_resume_index are not used and can be ignored.*/
366 playlist_get_resume_info(&resume_index);
368 /* Get the currently playing file minus the path */
369 /* This is used when displaying the available bookmarks */
370 file = strrchr(id3->path,'/');
371 if(NULL == file)
372 return NULL;
374 /* create the bookmark */
375 snprintf(global_bookmark, sizeof(global_bookmark),
376 "%d;%ld;%d;%d;%ld;%d;%d;%s;%s",
377 resume_index,
378 id3->offset,
379 playlist_get_seed(NULL),
381 id3->elapsed,
382 global_settings.repeat_mode,
383 global_settings.playlist_shuffle,
384 playlist_get_name(NULL, global_temp_buffer,
385 sizeof(global_temp_buffer)),
386 file+1);
388 /* checking to see if the bookmark is valid */
389 if (check_bookmark(global_bookmark))
390 return global_bookmark;
391 else
392 return NULL;
395 static bool check_bookmark(const char* bookmark)
397 return parse_bookmark(bookmark,
398 NULL,NULL,NULL, NULL,
399 NULL,0,NULL,NULL,
400 NULL, NULL);
403 /* ----------------------------------------------------------------------- */
404 /* This function will determine if an autoload is necessary. This is an */
405 /* interface function. */
406 /* ------------------------------------------------------------------------*/
407 bool bookmark_autoload(const char* file)
409 int key;
410 int fd;
411 int i;
412 bool done = false;
414 if(global_settings.autoloadbookmark == BOOKMARK_NO)
415 return false;
417 /*Checking to see if a bookmark file exists.*/
418 if(!generate_bookmark_file_name(file))
420 return false;
422 fd = open(global_bookmark_file_name, O_RDONLY);
423 if(fd<0)
424 return false;
425 if(-1 == lseek(fd, 0, SEEK_END))
427 close(fd);
428 return false;
430 close(fd);
431 if(global_settings.autoloadbookmark == BOOKMARK_YES)
433 return bookmark_load(global_bookmark_file_name, true);
435 else
437 /* Prompting user to confirm bookmark load */
438 FOR_NB_SCREENS(i)
439 screens[i].clear_display();
441 gui_syncstatusbar_draw(&statusbars, false);
443 FOR_NB_SCREENS(i)
445 #ifdef HAVE_LCD_BITMAP
446 screens[i].setmargins(0, STATUSBAR_HEIGHT);
447 screens[i].puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY));
448 screens[i].puts(0,1, str(LANG_CONFIRM_WITH_PLAY_RECORDER));
449 screens[i].puts(0,2, str(LANG_BOOKMARK_SELECT_LIST_BOOKMARKS));
450 screens[i].puts(0,3, str(LANG_CANCEL_WITH_ANY_RECORDER));
451 screens[i].update();
452 #else
453 screens[i].puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY));
454 screens[i].puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
455 #endif
458 while(!done)
460 /* Wait for a key to be pushed */
461 key = button_get(true);
462 switch(key)
464 #ifdef HAVE_LCD_BITMAP
465 #ifdef BOOKMARK_RC_DOWN
466 case BOOKMARK_RC_DOWN:
467 #endif
468 case BOOKMARK_DOWN:
469 return bookmark_load(global_bookmark_file_name, false);
470 #endif
471 #ifdef SETTINGS_RC_OK
472 case SETTINGS_RC_OK:
473 #endif
474 case SETTINGS_OK:
475 return bookmark_load(global_bookmark_file_name, true);
477 default:
478 /* Handle sys events, ignore button releases & repeats */
479 if (default_event_handler(key) ||
480 !(key & (BUTTON_REPEAT|BUTTON_REL)))
481 done = true;
482 break;
485 return false;
489 /* ----------------------------------------------------------------------- */
490 /* This function loads the bookmark information into the resume memory. */
491 /* This is an interface function. */
492 /* ------------------------------------------------------------------------*/
493 bool bookmark_load(const char* file, bool autoload)
495 int fd;
496 bool success = true;
497 int offset;
498 int seed;
499 int index;
500 char* bookmark = NULL;;
502 if(autoload)
504 fd = open(file, O_RDONLY);
505 if(fd >= 0)
507 if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)))
508 bookmark=global_read_buffer;
509 close(fd);
512 else
514 /* This is not an auto-load, so list the bookmarks */
515 bookmark=select_bookmark(file);
516 if(!bookmark)
517 return true; /* User exited without selecting a bookmark */
520 if(bookmark)
522 success = parse_bookmark(bookmark,
523 &index,
524 &offset,
525 &seed,
526 NULL,
527 global_temp_buffer,
528 sizeof(global_temp_buffer),
529 NULL,
530 &global_settings.repeat_mode,
531 &global_settings.playlist_shuffle,
532 global_filename);
536 if(success)
537 bookmark_play(global_temp_buffer, index, offset, seed,
538 global_filename);
540 return success;
544 static int get_bookmark_count(const char* bookmark_file_name)
546 int read_count = 0;
547 int file = open(bookmark_file_name, O_RDONLY);
549 if(file < 0)
550 return -1;
552 /* Get the requested bookmark */
553 while(read_line(file, global_read_buffer, sizeof(global_read_buffer)))
555 if(check_bookmark(global_read_buffer))
556 read_count++;
559 close(file);
560 return read_count;
565 /* ----------------------------------------------------------------------- */
566 /* This displays a the bookmarks in a file and allows the user to */
567 /* select one to play. */
568 /* ------------------------------------------------------------------------*/
569 static char* select_bookmark(const char* bookmark_file_name)
571 int bookmark_id = 0;
572 int bookmark_id_prev = -1;
573 int key;
574 int lastkey = BUTTON_NONE;
575 char* bookmark = NULL;
576 int bookmark_count = 0;
578 #ifdef HAVE_LCD_BITMAP
579 int i;
580 int x = lcd_getxmargin();
581 int y = lcd_getymargin();
582 FOR_NB_SCREENS(i)
583 screens[i].setmargins(0, 0);
584 #endif
586 bookmark_count = get_bookmark_count(bookmark_file_name);
588 while(true)
590 if(bookmark_id < 0)
591 bookmark_id = bookmark_count -1;
592 if(bookmark_id >= bookmark_count)
593 bookmark_id = 0;
595 if (bookmark_id != bookmark_id_prev)
597 bookmark = get_bookmark(bookmark_file_name, bookmark_id);
598 bookmark_id_prev = bookmark_id;
601 if (!bookmark)
603 /* if there were no bookmarks in the file, delete the file and exit. */
604 if(bookmark_id <= 0)
606 gui_syncsplash(HZ, true, str(LANG_BOOKMARK_LOAD_EMPTY));
607 remove(bookmark_file_name);
608 return NULL;
610 else
612 bookmark_id_prev = bookmark_id;
613 bookmark_id--;
616 else
618 display_bookmark(bookmark, bookmark_id, bookmark_count);
619 if (global_settings.talk_menu) /* for voice UI */
620 say_bookmark(bookmark, bookmark_id);
623 /* waiting for the user to click a button */
624 key = button_get(true);
625 switch(key)
627 #ifdef BOOKMARK_RC_SELECT
628 case BOOKMARK_RC_SELECT:
629 #endif
630 case BOOKMARK_SELECT:
631 #ifdef BOOKMARK_SELECT_PRE
632 if (lastkey != BOOKMARK_SELECT_PRE)
633 break;
634 #endif
635 /* User wants to use this bookmark */
636 #ifdef HAVE_LCD_BITMAP
637 if (global_settings.statusbar)
639 FOR_NB_SCREENS(i)
640 screens[i].setmargins(0, STATUSBAR_HEIGHT);
642 else
644 FOR_NB_SCREENS(i)
645 screens[i].setmargins(0, 0);
647 #endif
648 return bookmark;
649 #ifdef BOOKMARK_RC_DELETE
650 case BOOKMARK_RC_DELETE:
651 #endif
652 case BOOKMARK_DELETE:
653 /* User wants to delete this bookmark */
654 delete_bookmark(bookmark_file_name, bookmark_id);
655 bookmark_id_prev=-2;
656 bookmark_count--;
657 if(bookmark_id >= bookmark_count)
658 bookmark_id = bookmark_count -1;
659 break;
661 #ifdef SETTINGS_RC_DEC
662 case SETTINGS_RC_DEC:
663 case SETTINGS_RC_DEC | BUTTON_REPEAT:
664 #endif
665 case SETTINGS_DEC:
666 case SETTINGS_DEC | BUTTON_REPEAT:
667 bookmark_id--;
668 break;
670 #ifdef SETTINGS_RC_DEC
671 case SETTINGS_RC_INC:
672 case SETTINGS_RC_INC | BUTTON_REPEAT:
673 #endif
674 case SETTINGS_INC:
675 case SETTINGS_INC | BUTTON_REPEAT:
676 bookmark_id++;
677 break;
679 #ifdef SETTINGS_RC_CANCEL
680 case SETTINGS_RC_CANCEL:
681 #endif
682 #ifdef SETTINGS_RC_CANCEL2
683 case SETTINGS_RC_CANCEL2:
684 #endif
685 case SETTINGS_CANCEL:
686 #ifdef SETTINGS_CANCEL2
687 case SETTINGS_CANCEL2:
688 #endif
689 #ifdef SETTINGS_RC_OK2
690 case SETTINGS_RC_OK2:
691 #endif
692 #ifdef SETTINGS_OK2
693 case SETTINGS_OK2:
694 #endif
695 #ifdef HAVE_LCD_BITMAP
696 FOR_NB_SCREENS(i)
697 screens[i].setmargins(x, y);
698 #endif
699 return NULL;
701 default:
702 if(default_event_handler(key) == SYS_USB_CONNECTED)
703 return NULL;
704 break;
706 lastkey = key;
709 return NULL;
713 /* ----------------------------------------------------------------------- */
714 /* This function takes a location in a bookmark file and deletes that */
715 /* bookmark. */
716 /* ------------------------------------------------------------------------*/
717 static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id)
719 int temp_bookmark_file = 0;
720 int bookmark_file = 0;
721 int bookmark_count = 0;
723 /* Opening up a temp bookmark file */
724 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
725 "%s.tmp", bookmark_file_name);
726 temp_bookmark_file = open(global_temp_buffer,
727 O_WRONLY | O_CREAT | O_TRUNC);
728 bookmark_file = open(bookmark_file_name, O_RDONLY);
730 if (temp_bookmark_file < 0 || bookmark_file < 0)
731 return false; /* can't open one of the files */
733 /* Reading in the previous bookmarks and writing them to the temp file */
734 while (read_line(bookmark_file, global_read_buffer,
735 sizeof(global_read_buffer)))
737 /* The MRB has a max of MAX_BOOKMARKS in it */
738 /* This keeps it from getting too large */
739 if ((strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE)==0))
741 if(bookmark_count >= MAX_BOOKMARKS)
742 break;
745 if (check_bookmark(global_read_buffer))
747 if (bookmark_id != bookmark_count)
749 write(temp_bookmark_file, global_read_buffer,
750 strlen(global_read_buffer));
751 write(temp_bookmark_file, "\n", 1);
753 bookmark_count++;
757 close(bookmark_file);
758 close(temp_bookmark_file);
760 remove(bookmark_file_name);
761 rename(global_temp_buffer, bookmark_file_name);
763 return true;
766 /* ----------------------------------------------------------------------- */
767 /* This function parses a bookmark and displays it for the user. */
768 /* ------------------------------------------------------------------------*/
769 static void display_bookmark(const char* bookmark,
770 int bookmark_id,
771 int bookmark_count)
773 int resume_index = 0;
774 long ms = 0;
775 int repeat_mode = 0;
776 bool playlist_shuffle = false;
777 int len;
778 char *dot;
779 int i;
781 /* getting the index and the time into the file */
782 parse_bookmark(bookmark,
783 &resume_index, NULL, NULL, NULL, NULL, 0,
784 &ms, &repeat_mode, &playlist_shuffle,
785 global_filename);
787 FOR_NB_SCREENS(i)
789 screens[i].clear_display();
790 screens[i].stop_scroll();
793 #ifdef HAVE_LCD_BITMAP
794 /* bookmark shuffle and repeat states*/
795 switch (repeat_mode)
797 #if (AB_REPEAT_ENABLE == 1)
798 case REPEAT_AB:
799 statusbar_icon_play_mode(Icon_RepeatAB);
800 break;
801 #endif
803 case REPEAT_ONE:
804 statusbar_icon_play_mode(Icon_RepeatOne);
805 break;
807 case REPEAT_ALL:
808 statusbar_icon_play_mode(Icon_Repeat);
809 break;
811 if(playlist_shuffle)
812 statusbar_icon_shuffle();
814 /* File Name */
815 len=strlen(global_filename);
816 if (len>3)
817 dot=strrchr(global_filename + len - 4, '.');
818 else
819 dot=NULL;
820 if (dot)
821 *dot='\0';
822 FOR_NB_SCREENS(i)
823 screens[i].puts_scroll(0, 0, (unsigned char *)global_filename);
824 if (dot)
825 *dot='.';
827 /* bookmark number */
828 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d/%2d",
829 str(LANG_BOOKMARK_SELECT_BOOKMARK_TEXT),
830 bookmark_id + 1, bookmark_count);
831 FOR_NB_SCREENS(i)
832 screens[i].puts_scroll(0, 1, (unsigned char *)global_temp_buffer);
834 /* bookmark resume index */
835 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d",
836 str(LANG_BOOKMARK_SELECT_INDEX_TEXT), resume_index+1);
837 FOR_NB_SCREENS(i)
838 screens[i].puts_scroll(0, 2, (unsigned char *)global_temp_buffer);
840 /* elapsed time*/
841 if ( ms < 3600000 )
843 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %ld:%02d",
844 str(LANG_BOOKMARK_SELECT_TIME_TEXT),
845 ms / 60000,
846 (unsigned int)(ms % 60000) / 1000);
847 /* unsigned int: hinting for 16bits archs */
849 else
851 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
852 "%s: %ld:%02ld:%02d",
853 str(LANG_BOOKMARK_SELECT_TIME_TEXT),
854 ms / 3600000,
855 ms % 3600000 / 60000,
856 (unsigned int)(ms % 60000) / 1000);
858 FOR_NB_SCREENS(i)
859 screens[i].puts_scroll(0, 3, (unsigned char *)global_temp_buffer);
861 /* commands */
862 FOR_NB_SCREENS(i)
864 screens[i].puts_scroll(0, 4, str(LANG_BOOKMARK_SELECT_PLAY));
865 screens[i].puts_scroll(0, 5, str(LANG_BOOKMARK_SELECT_EXIT));
866 screens[i].puts_scroll(0, 6, str(LANG_BOOKMARK_SELECT_DELETE));
868 #else
869 (void)bookmark_id;
870 len=strlen(global_filename);
871 if (len>3)
872 dot=strrchr(global_filename+len-4,'.');
873 else
874 dot=NULL;
875 if (dot)
876 *dot='\0';
877 if ( ms < 3600000 )
879 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
880 "%2d, %ld:%02ld, %s,",
881 (bookmark_count+1),
882 ms / 60000,
883 ms % 60000 / 1000,
884 global_filename);
886 else
888 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
889 "%2d, %ld:%02ld:%02ld, %s,",
890 (bookmark_count+1),
891 ms / 60000,
892 ms % 3600000 / 60000,
893 ms % 60000 / 1000,
894 global_filename);
897 gui_syncstatusbar_draw(&statusbars, false);
899 FOR_NB_SCREENS(i)
901 screens[i].puts_scroll(0,0,global_temp_buffer);
902 screens[i].puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
904 if (dot)
905 *dot='.';
906 #endif
908 #ifdef HAVE_LCD_BITMAP
909 FOR_NB_SCREENS(i)
910 screens[i].update();
911 #endif
915 /* ----------------------------------------------------------------------- */
916 /* This function parses a bookmark, says the voice UI part of it. */
917 /* ------------------------------------------------------------------------*/
918 static void say_bookmark(const char* bookmark,
919 int bookmark_id)
921 int resume_index;
922 long ms;
923 char dir[MAX_PATH];
924 bool enqueue = false; /* only the first voice is not queued */
926 parse_bookmark(bookmark,
927 &resume_index,
928 NULL, NULL, NULL,
929 dir, sizeof(dir),
930 &ms, NULL, NULL,
931 NULL);
932 /* disabled, because transition between talkbox and voice UI clip is not nice */
933 #if 0
934 if (global_settings.talk_dir >= 3)
935 { /* "talkbox" enabled */
936 char* last = strrchr(dir, '/');
937 if (last)
938 { /* compose filename for talkbox */
939 strncpy(last + 1, dir_thumbnail_name, sizeof(dir)-(last-dir)-1);
940 talk_file(dir, enqueue);
941 enqueue = true;
944 #endif
945 talk_id(VOICE_EXT_BMARK, enqueue);
946 talk_number(bookmark_id + 1, true);
947 talk_id(LANG_BOOKMARK_SELECT_INDEX_TEXT, true);
948 talk_number(resume_index + 1, true);
949 talk_id(LANG_BOOKMARK_SELECT_TIME_TEXT, true);
950 if (ms / 60000)
951 talk_value(ms / 60000, UNIT_MIN, true);
952 talk_value((ms % 60000) / 1000, UNIT_SEC, true);
956 /* ----------------------------------------------------------------------- */
957 /* This function retrieves a given bookmark from a file. */
958 /* If the bookmark requested is beyond the number of bookmarks available */
959 /* in the file, it will return the last one. */
960 /* It also returns the index number of the bookmark in the file */
961 /* ------------------------------------------------------------------------*/
962 static char* get_bookmark(const char* bookmark_file, int bookmark_count)
964 int read_count = -1;
965 int result = 0;
966 int file = open(bookmark_file, O_RDONLY);
968 if (file < 0)
969 return NULL;
971 if (bookmark_count < 0)
972 return NULL;
974 /* Get the requested bookmark */
975 while (read_count < bookmark_count)
977 /*Reading in a single bookmark */
978 result = read_line(file,
979 global_read_buffer,
980 sizeof(global_read_buffer));
982 /* Reading past the last bookmark in the file
983 causes the loop to stop */
984 if (result <= 0)
985 break;
987 read_count++;
990 close(file);
991 if (read_count == bookmark_count)
992 return global_read_buffer;
993 else
994 return NULL;
997 /* ----------------------------------------------------------------------- */
998 /* This function takes a bookmark and parses it. This function also */
999 /* validates the bookmark. Passing in NULL for an output variable */
1000 /* indicates that value is not requested. */
1001 /* ----------------------------------------------------------------------- */
1002 static bool parse_bookmark(const char *bookmark,
1003 int *resume_index,
1004 int *resume_offset,
1005 int *resume_seed,
1006 int *resume_first_index,
1007 char* resume_file,
1008 unsigned int resume_file_size,
1009 long* ms,
1010 int * repeat_mode, bool *shuffle,
1011 char* file_name)
1013 /* First check to see if a valid line was passed in. */
1014 int bookmark_len = strlen(bookmark);
1015 int local_resume_index = 0;
1016 int local_resume_offset = 0;
1017 int local_resume_seed = 0;
1018 int local_resume_first_index = 0;
1019 int local_mS = 0;
1020 int local_shuffle = 0;
1021 int local_repeat_mode = 0;
1022 char* local_resume_file = NULL;
1023 char* local_file_name = NULL;
1024 char* field;
1025 char* end;
1026 static char bookmarkcopy[MAX_BOOKMARK_SIZE];
1028 /* Don't do anything if the bookmark length is 0 */
1029 if (bookmark_len <= 0)
1030 return false;
1032 /* Making a dup of the bookmark to use with strtok_r */
1033 strncpy(bookmarkcopy, bookmark, sizeof(bookmarkcopy));
1034 bookmarkcopy[sizeof(bookmarkcopy) - 1] = 0;
1036 /* resume_index */
1037 if ((field = strtok_r(bookmarkcopy, ";", &end)))
1038 local_resume_index = atoi(field);
1039 else
1040 return false;
1042 /* resume_offset */
1043 if ((field = strtok_r(NULL, ";", &end)))
1044 local_resume_offset = atoi(field);
1045 else
1046 return false;
1048 /* resume_seed */
1049 if ((field = strtok_r(NULL, ";", &end)))
1050 local_resume_seed = atoi(field);
1051 else
1052 return false;
1054 /* resume_first_index */
1055 if ((field = strtok_r(NULL, ";", &end)))
1056 local_resume_first_index = atoi(field);
1057 else
1058 return false;
1060 /* Milliseconds into MP3. Used for the bookmark select menu */
1061 if ((field = strtok_r(NULL, ";", &end)))
1062 local_mS = atoi(field);
1063 else
1064 return false;
1066 /* repeat_mode */
1067 if ((field = strtok_r(NULL, ";", &end)))
1068 local_repeat_mode = atoi(field);
1069 else
1070 return false;
1072 /* shuffle mode */
1073 if ((field = strtok_r(NULL, ";", &end)))
1074 local_shuffle = atoi(field);
1075 else
1076 return false;
1078 /* resume_file & file_name (for the bookmark select menu)*/
1079 if (end)
1081 local_resume_file = strtok_r(NULL, ";", &end);
1083 if (end)
1084 local_file_name = strtok_r(NULL, ";", &end);
1086 else
1087 return false;
1089 /* Only return the values the calling function wants */
1090 if (resume_index)
1091 *resume_index = local_resume_index;
1093 if (resume_offset)
1094 *resume_offset = local_resume_offset;
1096 if (resume_seed)
1097 *resume_seed = local_resume_seed;
1099 if (resume_first_index)
1100 *resume_first_index = local_resume_first_index;
1102 if (resume_file && local_resume_file)
1104 strncpy(resume_file, local_resume_file,
1105 MIN(strlen(local_resume_file), resume_file_size-1));
1106 resume_file[MIN(strlen(local_resume_file), resume_file_size-1)]=0;
1109 if (ms)
1110 *ms = local_mS;
1112 if (shuffle)
1113 *shuffle = local_shuffle;
1115 if (repeat_mode)
1116 *repeat_mode = local_repeat_mode;
1118 if (file_name && local_file_name)
1120 strncpy(file_name, local_file_name,MAX_PATH-1);
1121 file_name[MAX_PATH-1] = 0;
1124 return true;
1127 /* ----------------------------------------------------------------------- */
1128 /* This function is used by multiple functions and is used to generate a */
1129 /* bookmark named based off of the input. */
1130 /* Changing this function could result in how the bookmarks are stored. */
1131 /* it would be here that the centralized/decentralized bookmark code */
1132 /* could be placed. */
1133 /* ----------------------------------------------------------------------- */
1134 static bool generate_bookmark_file_name(const char *in)
1136 int len = strlen(in);
1138 /* if this is a root dir MP3, rename the bookmark file root_dir.bmark */
1139 /* otherwise, name it based on the in variable */
1140 if (!strcmp("/", in))
1141 strcpy(global_bookmark_file_name, "/root_dir.bmark");
1142 else
1144 strcpy(global_bookmark_file_name, in);
1145 if(global_bookmark_file_name[len-1] == '/')
1146 len--;
1147 strcpy(&global_bookmark_file_name[len], ".bmark");
1150 return true;
1153 /* ----------------------------------------------------------------------- */
1154 /* Returns the bookmark name for the current playlist */
1155 /* ----------------------------------------------------------------------- */
1156 bool bookmark_exist(void)
1158 bool exist=false;
1160 if(system_check())
1162 char* name = playlist_get_name(NULL, global_temp_buffer,
1163 sizeof(global_temp_buffer));
1164 if (generate_bookmark_file_name(name))
1166 int fd=open(global_bookmark_file_name, O_RDONLY);
1167 if (fd >=0)
1169 close(fd);
1170 exist=true;
1175 return exist;
1178 /* ----------------------------------------------------------------------- */
1179 /* Checks the current state of the system and returns if it is in a */
1180 /* bookmarkable state. */
1181 /* ----------------------------------------------------------------------- */
1182 /* Inputs: */
1183 /* ----------------------------------------------------------------------- */
1184 /* Outputs: */
1185 /* return bool: Indicates if the system was in a bookmarkable state */
1186 /* ----------------------------------------------------------------------- */
1187 static bool system_check(void)
1189 int resume_index = 0;
1190 struct mp3entry *id3 = audio_current_track();
1192 if (!id3)
1194 /* no track playing */
1195 return false;
1198 /* Checking to see if playing a queued track */
1199 if (playlist_get_resume_info(&resume_index) == -1)
1201 /* something bad happened while getting the queue information */
1202 return false;
1204 else if (playlist_modified(NULL))
1206 /* can't bookmark while in the queue */
1207 return false;
1210 return true;